signal(SIGPIPE,  SIG_DFL);
do_child(Session *s, const char *command){	const char *shell, *hostname = NULL, *cp = NULL;	struct passwd * pw = s->pw;	char buf[256];	char cmd[1024];	FILE *f = NULL;	u_int envsize, i;	char **env;	extern char **environ;	struct stat st;	char *argv[10];	int do_xauth = s->auth_proto != NULL && s->auth_data != NULL;	/* login(1) is only called if we execute the login shell */	if (options.use_login && command != NULL)		options.use_login = 0;	if (!options.use_login) {#ifdef HAVE_LOGIN_CAP		if (!login_getcapbool(lc, "ignorenologin", 0) && pw->pw_uid)			f = fopen(login_getcapstr(lc, "nologin", _PATH_NOLOGIN,			    _PATH_NOLOGIN), "r");#else		if (pw->pw_uid)			f = fopen(_PATH_NOLOGIN, "r");#endif		if (f) {			/* /etc/nologin exists.  Print its contents and exit. */			while (fgets(buf, sizeof(buf), f))				fputs(buf, stderr);			fclose(f);			exit(254);		}	}	/* Set login name, uid, gid, and groups. */	/* Login(1) does this as well, and it needs uid 0 for the "-h"	   switch, so we let login(1) to this for us. */	if (!options.use_login) {		if (getuid() == 0 || geteuid() == 0) {#ifdef HAVE_LOGIN_CAP			if (setusercontext(lc, pw, pw->pw_uid,			    (LOGIN_SETALL & ~LOGIN_SETPATH)) < 0) {				perror("unable to set user context");				exit(1);			}#ifdef BSD_AUTH			if (auth_approval(NULL, lc, pw->pw_name, "ssh") <= 0) {				error("approval failure for %s", pw->pw_name);				fprintf(stderr, "Approval failure");				exit(1);			}#endif#else			if (setlogin(pw->pw_name) < 0)				error("setlogin failed: %s", strerror(errno));			if (setgid(pw->pw_gid) < 0) {				perror("setgid");				exit(1);			}			/* Initialize the group list. */			if (initgroups(pw->pw_name, pw->pw_gid) < 0) {				perror("initgroups");				exit(1);			}			endgrent();			/* Permanently switch to the desired uid. */			permanently_set_uid(pw->pw_uid);#endif		}		if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)			fatal("Failed to set uids to %u.", (u_int) pw->pw_uid);	}	/*	 * Get the shell from the password data.  An empty shell field is	 * legal, and means /bin/sh.	 */	shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;#ifdef HAVE_LOGIN_CAP	shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell);#endif#ifdef AFS	/* Try to get AFS tokens for the local cell. */	if (k_hasafs()) {		char cell[64];		if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0)			krb_afslog(cell, 0);		krb_afslog(0, 0);	}#endif /* AFS */	/* Initialize the environment. */	envsize = 100;	env = xmalloc(envsize * sizeof(char *));	env[0] = NULL;	if (!options.use_login) {		/* Set basic environment. */		child_set_env(&env, &envsize, "USER", pw->pw_name);		child_set_env(&env, &envsize, "LOGNAME", pw->pw_name);		child_set_env(&env, &envsize, "HOME", pw->pw_dir);#ifdef HAVE_LOGIN_CAP		(void) setusercontext(lc, pw, pw->pw_uid, LOGIN_SETPATH);		child_set_env(&env, &envsize, "PATH", getenv("PATH"));#else		child_set_env(&env, &envsize, "PATH", _PATH_STDPATH);#endif		snprintf(buf, sizeof buf, "%.200s/%.50s",			 _PATH_MAILDIR, pw->pw_name);		child_set_env(&env, &envsize, "MAIL", buf);		/* Normal systems set SHELL by default. */		child_set_env(&env, &envsize, "SHELL", shell);	}	if (getenv("TZ"))		child_set_env(&env, &envsize, "TZ", getenv("TZ"));	/* Set custom environment options from RSA authentication. */	while (custom_environment) {		struct envstring *ce = custom_environment;		char *s = ce->s;		int i;		for (i = 0; s[i] != '=' && s[i]; i++);		if (s[i] == '=') {			s[i] = 0;			child_set_env(&env, &envsize, s, s + i + 1);		}		custom_environment = ce->next;		xfree(ce->s);		xfree(ce);	}	snprintf(buf, sizeof buf, "%.50s %d %d",		 get_remote_ipaddr(), get_remote_port(), get_local_port());	child_set_env(&env, &envsize, "SSH_CLIENT", buf);	if (s->ttyfd != -1)		child_set_env(&env, &envsize, "SSH_TTY", s->tty);	if (s->term)		child_set_env(&env, &envsize, "TERM", s->term);	if (s->display)		child_set_env(&env, &envsize, "DISPLAY", s->display);	if (original_command)		child_set_env(&env, &envsize, "SSH_ORIGINAL_COMMAND",		    original_command);#ifdef KRB4	{		extern char *ticket;		if (ticket)			child_set_env(&env, &envsize, "KRBTKFILE", ticket);	}#endif /* KRB4 */	if (xauthfile)		child_set_env(&env, &envsize, "XAUTHORITY", xauthfile);	if (auth_get_socket_name() != NULL)		child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME,			      auth_get_socket_name());	/* read $HOME/.ssh/environment. */	if (!options.use_login) {		snprintf(buf, sizeof buf, "%.200s/.ssh/environment",		    pw->pw_dir);		read_environment_file(&env, &envsize, buf);	}	if (debug_flag) {		/* dump the environment */		fprintf(stderr, "Environment:\n");		for (i = 0; env[i]; i++)			fprintf(stderr, "  %.200s\n", env[i]);	}	/* we have to stash the hostname before we close our socket. */	if (options.use_login)		hostname = get_remote_name_or_ip();	/*	 * Close the connection descriptors; note that this is the child, and	 * the server will still have the socket open, and it is important	 * that we do not shutdown it.  Note that the descriptors cannot be	 * closed before building the environment, as we call	 * get_remote_ipaddr there.	 */	if (packet_get_connection_in() == packet_get_connection_out())		close(packet_get_connection_in());	else {		close(packet_get_connection_in());		close(packet_get_connection_out());	}	/*	 * Close all descriptors related to channels.  They will still remain	 * open in the parent.	 */	/* XXX better use close-on-exec? -markus */	channel_close_all();	/*	 * Close any extra file descriptors.  Note that there may still be	 * descriptors left by system functions.  They will be closed later.	 */	endpwent();	/*	 * Close any extra open file descriptors so that we don\'t have them	 * hanging around in clients.  Note that we want to do this after	 * initgroups, because at least on Solaris 2.3 it leaves file	 * descriptors open.	 */	for (i = 3; i < 64; i++)		close(i);	/* Change current directory to the user\'s home directory. */	if (chdir(pw->pw_dir) < 0) {		fprintf(stderr, "Could not chdir to home directory %s: %s\n",			pw->pw_dir, strerror(errno));#ifdef HAVE_LOGIN_CAP		if (login_getcapbool(lc, "requirehome", 0))			exit(1);#endif	}	/*	 * Must take new environment into use so that .ssh/rc, /etc/sshrc and	 * xauth are run in the proper environment.	 */	environ = env;	/*	 * Run $HOME/.ssh/rc, /etc/sshrc, or xauth (whichever is found first	 * in this order).	 */	if (!options.use_login) {		if (stat(_PATH_SSH_USER_RC, &st) >= 0) {			if (debug_flag)				fprintf(stderr, "Running %s %s\n", _PATH_BSHELL,				    _PATH_SSH_USER_RC);			f = popen(_PATH_BSHELL " " _PATH_SSH_USER_RC, "w");			if (f) {				if (do_xauth)					fprintf(f, "%s %s\n", s->auth_proto,					    s->auth_data);				pclose(f);			} else				fprintf(stderr, "Could not run %s\n",				    _PATH_SSH_USER_RC);		} else if (stat(_PATH_SSH_SYSTEM_RC, &st) >= 0) {			if (debug_flag)				fprintf(stderr, "Running %s %s\n", _PATH_BSHELL,				    _PATH_SSH_SYSTEM_RC);			f = popen(_PATH_BSHELL " " _PATH_SSH_SYSTEM_RC, "w");			if (f) {				if (do_xauth)					fprintf(f, "%s %s\n", s->auth_proto,					    s->auth_data);				pclose(f);			} else				fprintf(stderr, "Could not run %s\n",				    _PATH_SSH_SYSTEM_RC);		} else if (do_xauth && options.xauth_location != NULL) {			/* Add authority data to .Xauthority if appropriate. */			char *screen = strchr(s->display, ':');			if (debug_flag) {				fprintf(stderr,				    "Running %.100s add "				    "%.100s %.100s %.100s\n",				    options.xauth_location, s->display,				    s->auth_proto, s->auth_data);				if (screen != NULL)					fprintf(stderr,					    "Adding %.*s/unix%s %s %s\n",					    (int)(screen - s->display),					    s->display, screen,					    s->auth_proto, s->auth_data);			}			snprintf(cmd, sizeof cmd, "%s -q -",			    options.xauth_location);			f = popen(cmd, "w");			if (f) {				fprintf(f, "add %s %s %s\n", s->display,				    s->auth_proto, s->auth_data);				if (screen != NULL)					fprintf(f, "add %.*s/unix%s %s %s\n",					    (int)(screen - s->display),					    s->display, screen,					    s->auth_proto,					    s->auth_data);				pclose(f);			} else {				fprintf(stderr, "Could not run %s\n",				    cmd);			}		}		/* Get the last component of the shell name. */		cp = strrchr(shell, '/');		if (cp)			cp++;		else			cp = shell;	}	/*	 * If we have no command, execute the shell.  In this case, the shell	 * name to be passed in argv[0] is preceded by '-' to indicate that	 * this is a login shell.	 */	if (!command) {		if (!options.use_login) {			char buf[256];			/*			 * Check for mail if we have a tty and it was enabled			 * in server options.			 */			if (s->ttyfd != -1 && options.check_mail) {				char *mailbox;				struct stat mailstat;				mailbox = getenv("MAIL");				if (mailbox != NULL) {					if (stat(mailbox, &mailstat) != 0 ||					    mailstat.st_size == 0)						printf("No mail.\n");					else if (mailstat.st_mtime < mailstat.st_atime)						printf("You have mail.\n");					else						printf("You have new mail.\n");				}			}			/* Start the shell.  Set initial character to '-'. */			buf[0] = '-';			strncpy(buf + 1, cp, sizeof(buf) - 1);			buf[sizeof(buf) - 1] = 0;			/* Execute the shell. */			argv[0] = buf;			argv[1] = NULL;			execve(shell, argv, env);			/* Executing the shell failed. */			perror(shell);			exit(1);		} else {			/* Launch login(1). */			execl("/usr/bin/login", "login", "-h", hostname,			     "-p", "-f", "--", pw->pw_name, NULL);			/* Login couldn't be executed, die. */			perror("login");			exit(1);		}	}	/*	 * Execute the command using the user's shell.  This uses the -c	 * option to execute the command.	 */	argv[0] = (char *) cp;	argv[1] = "-c";	argv[2] = (char *) command;	argv[3] = NULL;	execve(shell, argv, env);	perror(shell);	exit(1);}