示例#1
0
void check_uinfo(struct userec *u, int MUST)
{
	int changeIT = 0, changed = 0, pos = 2;
	char ans[5];

	while(1)
	{  // ����dz�
		changeIT = MUST || (strlen(u->username) < 2)
		           ||(strstr(u->username, "  "))||(strstr(u->username, "��"));
		if(!changeIT)
		{
			if(changed)
			{
				pos ++;
				changed = 0;
			}
			break;
		}
		else
		{
			MUST = 0;
			changed = 1;
		}
		/*    getdata(pos, 0, "�����������dz� (Enter nickname): ",
		      u->username, NAMELEN, DOECHO, YEA);
		 */
		move(pos,0);
		prints("�����������dz� (Enter nickname) Ҫ�и���һ�㰡");
		pos++;
		getdata(pos, 0, "> ",
		        u->username, NAMELEN, DOECHO, YEA);
		strcpy(uinfo.username, u->username);
		update_utmp();
	}



	while(1)
	{ // �����ʵ����
		changeIT = MUST || (strlen(u->realname) < 4)
		           ||(strstr(u->realname, "  "))||(strstr(u->realname, "��"));
		if(!changeIT)
		{
			if(changed)
			{
				pos += 2;
				changed = 0;
			}
			break;
		}
		else
		{
			MUST = 0;
			changed = 1;
		}
		move(pos, 0);
		prints("������������ʵ���� (Enter realname) ���ǻ�Ϊ�����ܵ�");
		getdata(pos+1, 0, "> ", u->realname, NAMELEN, DOECHO, YEA);
	}
	while(1)
	{ // ���ͨѶ��ַ
		changeIT = MUST||(strlen(u->address)<10)
		           ||(strstr(u->address,"  "))||(strstr(u->address, "��"));
		if(!changeIT)
		{
			if(changed)
			{
				pos += 2;
				changed = 0;
			}
			break;
		}
		else
		{
			MUST = 0;
			changed = 1;
		}
		move(pos, 0);
		prints("����������ͨѶ��ַ (Enter home address) ��ϸ�����ƻ������\n");
		getdata(pos+1, 0, "> ", u->address, STRLEN - 20, DOECHO, YEA);
	}
	while(1)
	{ // ����ʼ���ַ
		changeIT = MUST||(strchr(u->email, '@') == NULL);
		if(!changeIT)
		{
#ifdef MAILCHECK
			if(changed)
			{
				pos += 4;
				changed = 0;
			}
#else
			if(changed)
			{
				pos += 3;
				changed = 0;
			}
#endif
			break;
		}
		else
		{
			MUST = 0;
			changed = 1;
		}
		move(pos, 0);
		prints("���������ʽΪ: [1;[email protected]\n");
#ifdef MAILCHECK

		prints( "��վ�Ѿ��ṩ�ʼ�ע������, ������ͨ���ʼ����ٵ�ͨ��ע����֤.\n");
#endif

		prints("������������� (�����ṩ�߰� <Enter>)");
#ifdef MAILCHECK

		getdata(pos+3,0,"> ",u->email,48,DOECHO, YEA);
#else

		getdata(pos+2,0,"> ",u->email,48,DOECHO, YEA);
#endif

		if (strchr(u->email, '@') == NULL)
		{
			sprintf(genbuf, "%s.bbs@%s", u->userid, BBSHOST);
			strncpy(u->email, genbuf, 48);
		}
	}
	{ // ����Ա�
		changeIT = MUST||(strchr("MF",u->gender) == NULL);
		if(changeIT)
		{
			getdata(pos, 0, "����������Ա�: M.�� F.Ů [M]: ", ans,2,DOECHO,YEA);
			if(ans[0]!='F'&& ans[0]!='f'||ans[0]=='m')
				u->gender = 'M';
			else
				u->gender = 'F';
			pos ++;
		}
	}
	while(1)
	{ // ��������
		changeIT = MUST||(u->birthyear <20) ||(u->birthyear>98);
		if(!changeIT)
		{
			if(changed)
			{
				pos ++;
				changed = 0;
			}
			break;
		}
		else
		{
			MUST = 0;
			changed = 1;
		}
		getdata(pos, 0, "�����������������(���): ", ans, 5, DOECHO, YEA);
		if(atoi(ans)<1920 || atoi(ans) > 1998 )
		{
			MUST = 1;
			continue;
		}
		u->birthyear = atoi(ans) -1900;
	}
	while(1)
	{ // ��������
		changeIT = MUST||(u->birthmonth <1) ||(u->birthmonth>12);
		if(!changeIT)
		{
			if(changed)
			{
				pos ++;
				changed = 0;
			}
			break;
		}
		else
		{
			MUST = 0;
			changed = 1;
		}
		getdata(pos, 0, "���������������·�: ", ans, 3, DOECHO, YEA);
		u->birthmonth = atoi(ans);
	}
	while(1)
	{ // ��������
		changeIT = MUST||(u->birthday <1) ||(u->birthday>31)
		           ||(u->birthmonth<8&&!(u->birthmonth%2)||u->birthmonth>7&&(u->birthmonth%2))&&u->birthday>30 || u->birthmonth==2&&u->birthday>29;
		if(!changeIT)
		{
			if(changed)
			{
				pos ++;
				changed = 0;
			}
			break;
		}
		else
		{
			MUST = 0;
			changed = 1;
		}
		getdata(pos, 0, "���������ij�����: ", ans, 3, DOECHO, YEA);
		u->birthday = atoi(ans);
	}
}
示例#2
0
/*
 * login - create a new login session for a user
 *
 *	login is typically called by getty as the second step of a
 *	new user session. getty is responsible for setting the line
 *	characteristics to a reasonable set of values and getting
 *	the name of the user to be logged in. login may also be
 *	called to create a new user session on a pty for a variety
 *	of reasons, such as X servers or network logins.
 *
 *	the flags which login supports are
 *	
 *	-p - preserve the environment
 *	-r - perform autologin protocol for rlogin
 *	-f - do not perform authentication, user is preauthenticated
 *	-h - the name of the remote host
 */
int main (int argc, char **argv)
{
	const char *tmptty;
	char tty[BUFSIZ];

#ifdef RLOGIN
	char term[128] = "";
#endif				/* RLOGIN */
#if defined(HAVE_STRFTIME) && !defined(USE_PAM)
	char ptime[80];
#endif
	unsigned int delay;
	unsigned int retries;
	bool failed;
	bool subroot = false;
#ifndef USE_PAM
	bool is_console;
#endif
	int err;
	const char *cp;
	char *tmp;
	char fromhost[512];
	struct passwd *pwd = NULL;
	char **envp = environ;
	const char *failent_user;
	/*@null@*/struct utmp *utent;

#ifdef USE_PAM
	int retcode;
	pid_t child;
	char *pam_user = NULL;
#else
	struct spwd *spwd = NULL;
#endif
	/*
	 * Some quick initialization.
	 */

	sanitize_env ();

	(void) setlocale (LC_ALL, "");
	(void) bindtextdomain (PACKAGE, LOCALEDIR);
	(void) textdomain (PACKAGE);

	initenv ();

	amroot = (getuid () == 0);
	Prog = Basename (argv[0]);

	if (geteuid() != 0) {
		fprintf (stderr, _("%s: Cannot possibly work without effective root\n"), Prog);
		exit (1);
	}

	process_flags (argc, argv);

	if ((isatty (0) == 0) || (isatty (1) == 0) || (isatty (2) == 0)) {
		exit (1);	/* must be a terminal */
	}

	utent = get_current_utmp ();
	/*
	 * Be picky if run by normal users (possible if installed setuid
	 * root), but not if run by root. This way it still allows logins
	 * even if your getty is broken, or if something corrupts utmp,
	 * but users must "exec login" which will use the existing utmp
	 * entry (will not overwrite remote hostname).  --marekm
	 */
	if (!amroot && (NULL == utent)) {
		(void) puts (_("No utmp entry.  You must exec \"login\" from the lowest level \"sh\""));
		exit (1);
	}
	/* NOTE: utent might be NULL afterwards */

	tmptty = ttyname (0);
	if (NULL == tmptty) {
		tmptty = "UNKNOWN";
	}
	STRFCPY (tty, tmptty);

#ifndef USE_PAM
	is_console = console (tty);
#endif

	if (rflg || hflg) {
		/*
		 * Add remote hostname to the environment. I think
		 * (not sure) I saw it once on Irix.  --marekm
		 */
		addenv ("REMOTEHOST", hostname);
	}
	if (fflg) {
		preauth_flag = true;
	}
	if (hflg) {
		reason = PW_RLOGIN;
	}
#ifdef RLOGIN
	if (rflg) {
		assert (NULL == username);
		username = xmalloc (USER_NAME_MAX_LENGTH + 1);
		username[USER_NAME_MAX_LENGTH] = '\0';
		if (do_rlogin (hostname, username, USER_NAME_MAX_LENGTH, term, sizeof term)) {
			preauth_flag = true;
		} else {
			free (username);
			username = NULL;
		}
	}
#endif				/* RLOGIN */

	OPENLOG ("login");

	setup_tty ();

#ifndef USE_PAM
	(void) umask (getdef_num ("UMASK", GETDEF_DEFAULT_UMASK));

	{
		/* 
		 * Use the ULIMIT in the login.defs file, and if
		 * there isn't one, use the default value. The
		 * user may have one for themselves, but otherwise,
		 * just take what you get.
		 */
		long limit = getdef_long ("ULIMIT", -1L);

		if (limit != -1) {
			set_filesize_limit (limit);
		}
	}

#endif
	/*
	 * The entire environment will be preserved if the -p flag
	 * is used.
	 */
	if (pflg) {
		while (NULL != *envp) {	/* add inherited environment, */
			addenv (*envp, NULL); /* some variables change later */
			envp++;
		}
	}

#ifdef RLOGIN
	if (term[0] != '\0') {
		addenv ("TERM", term);
	} else
#endif				/* RLOGIN */
	{
		/* preserve TERM from getty */
		if (!pflg) {
			tmp = getenv ("TERM");
			if (NULL != tmp) {
				addenv ("TERM", tmp);
			}
		}
	}

	init_env ();

	if (optind < argc) {	/* now set command line variables */
		set_env (argc - optind, &argv[optind]);
	}

	if (rflg || hflg) {
		cp = hostname;
#ifdef	HAVE_STRUCT_UTMP_UT_HOST
	} else if ((NULL != utent) && ('\0' != utent->ut_host[0])) {
		cp = utent->ut_host;
#endif				/* HAVE_STRUCT_UTMP_UT_HOST */
	} else {
		cp = "";
	}

	if ('\0' != *cp) {
		snprintf (fromhost, sizeof fromhost,
		          " on '%.100s' from '%.200s'", tty, cp);
	} else {
		snprintf (fromhost, sizeof fromhost,
		          " on '%.100s'", tty);
	}

      top:
	/* only allow ALARM sec. for login */
	(void) signal (SIGALRM, alarm_handler);
	timeout = getdef_unum ("LOGIN_TIMEOUT", ALARM);
	if (timeout > 0) {
		(void) alarm (timeout);
	}

	environ = newenvp;	/* make new environment active */
	delay   = getdef_unum ("FAIL_DELAY", 1);
	retries = getdef_unum ("LOGIN_RETRIES", RETRIES);

#ifdef USE_PAM
	retcode = pam_start ("login", username, &conv, &pamh);
	if (retcode != PAM_SUCCESS) {
		fprintf (stderr,
		         _("login: PAM Failure, aborting: %s\n"),
		         pam_strerror (pamh, retcode));
		SYSLOG ((LOG_ERR, "Couldn't initialize PAM: %s",
		         pam_strerror (pamh, retcode)));
		exit (99);
	}

	/*
	 * hostname & tty are either set to NULL or their correct values,
	 * depending on how much we know. We also set PAM's fail delay to
	 * ours.
	 *
	 * PAM_RHOST and PAM_TTY are used for authentication, only use
	 * information coming from login or from the caller (e.g. no utmp)
	 */
	retcode = pam_set_item (pamh, PAM_RHOST, hostname);
	PAM_FAIL_CHECK;
	retcode = pam_set_item (pamh, PAM_TTY, tty);
	PAM_FAIL_CHECK;
#ifdef HAS_PAM_FAIL_DELAY
	retcode = pam_fail_delay (pamh, 1000000 * delay);
	PAM_FAIL_CHECK;
#endif
	/* if fflg, then the user has already been authenticated */
	if (!fflg) {
		unsigned int failcount = 0;
		char hostn[256];
		char loginprompt[256];	/* That's one hell of a prompt :) */

		/* Make the login prompt look like we want it */
		if (gethostname (hostn, sizeof (hostn)) == 0) {
			snprintf (loginprompt,
			          sizeof (loginprompt),
			          _("%s login: "******"login: "******"TOO MANY LOGIN TRIES (%u)%s FOR '%s'",
				         failcount, fromhost, failent_user));
				fprintf(stderr,
				        _("Maximum number of tries exceeded (%u)\n"),
				        failcount);
				PAM_END;
				exit(0);
			} else if (retcode == PAM_ABORT) {
				/* Serious problems, quit now */
				(void) fputs (_("login: abort requested by PAM\n"), stderr);
				SYSLOG ((LOG_ERR,"PAM_ABORT returned from pam_authenticate()"));
				PAM_END;
				exit(99);
			} else if (retcode != PAM_SUCCESS) {
				SYSLOG ((LOG_NOTICE,"FAILED LOGIN (%u)%s FOR '%s', %s",
				         failcount, fromhost, failent_user,
				         pam_strerror (pamh, retcode)));
				failed = true;
			}

			if (!failed) {
				break;
			}

#ifdef WITH_AUDIT
			audit_fd = audit_open ();
			audit_log_acct_message (audit_fd,
			                        AUDIT_USER_LOGIN,
			                        NULL,    /* Prog. name */
			                        "login",
			                        failent_user,
			                        AUDIT_NO_ID,
			                        hostname,
			                        NULL,    /* addr */
			                        tty,
			                        0);      /* result */
			close (audit_fd);
#endif				/* WITH_AUDIT */

			(void) puts ("");
			(void) puts (_("Login incorrect"));

			if (failcount >= retries) {
				SYSLOG ((LOG_NOTICE,
				         "TOO MANY LOGIN TRIES (%u)%s FOR '%s'",
				         failcount, fromhost, failent_user));
				fprintf(stderr,
				        _("Maximum number of tries exceeded (%u)\n"),
				        failcount);
				PAM_END;
				exit(0);
			}

			/*
			 * Let's give it another go around.
			 * Even if a username was given on the command
			 * line, prompt again for the username.
			 */
			retcode = pam_set_item (pamh, PAM_USER, NULL);
			PAM_FAIL_CHECK;
		}

		/* We don't get here unless they were authenticated above */
		(void) alarm (0);
	}

	/* Check the account validity */
	retcode = pam_acct_mgmt (pamh, 0);
	if (retcode == PAM_NEW_AUTHTOK_REQD) {
		retcode = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
	}
	PAM_FAIL_CHECK;

	/* Open the PAM session */
	get_pam_user (&pam_user);
	retcode = pam_open_session (pamh, hushed (pam_user) ? PAM_SILENT : 0);
	PAM_FAIL_CHECK;

	/* Grab the user information out of the password file for future usage
	 * First get the username that we are actually using, though.
	 *
	 * From now on, we will discard changes of the user (PAM_USER) by
	 * PAM APIs.
	 */
	get_pam_user (&pam_user);
	if (NULL != username) {
		free (username);
	}
	username = pam_user;
	failent_user = get_failent_user (username);

	pwd = xgetpwnam (username);
	if (NULL == pwd) {
		SYSLOG ((LOG_ERR, "cannot find user %s", failent_user));
		exit (1);
	}

	/* This set up the process credential (group) and initialize the
	 * supplementary group access list.
	 * This has to be done before pam_setcred
	 */
	if (setup_groups (pwd) != 0) {
		exit (1);
	}

	retcode = pam_setcred (pamh, PAM_ESTABLISH_CRED);
	PAM_FAIL_CHECK;
	/* NOTE: If pam_setcred changes PAM_USER, this will not be taken
	 * into account.
	 */

#else				/* ! USE_PAM */
	while (true) {	/* repeatedly get login/password pairs */
		/* user_passwd is always a pointer to this constant string
		 * or a passwd or shadow password that will be memzero by
		 * pw_free / spw_free.
		 * Do not free() user_passwd. */
		const char *user_passwd = "!";

		/* Do some cleanup to avoid keeping entries we do not need
		 * anymore. */
		if (NULL != pwd) {
			pw_free (pwd);
			pwd = NULL;
		}
		if (NULL != spwd) {
			spw_free (spwd);
			spwd = NULL;
		}

		failed = false;	/* haven't failed authentication yet */
		if (NULL == username) {	/* need to get a login id */
			if (subroot) {
				closelog ();
				exit (1);
			}
			preauth_flag = false;
			username = xmalloc (USER_NAME_MAX_LENGTH + 1);
			username[USER_NAME_MAX_LENGTH] = '\0';
			login_prompt (_("\n%s login: "******"!",
			 * the account is locked and the user cannot
			 * login, even if they have been
			 * "pre-authenticated."
			 */
			if (   ('!' == user_passwd[0])
			    || ('*' == user_passwd[0])) {
				failed = true;
			}
		}

		if (strcmp (user_passwd, SHADOW_PASSWD_STRING) == 0) {
			spwd = xgetspnam (username);
			if (NULL != spwd) {
				user_passwd = spwd->sp_pwdp;
			} else {
				/* The user exists in passwd, but not in
				 * shadow. SHADOW_PASSWD_STRING indicates
				 * that the password shall be in shadow.
				 */
				SYSLOG ((LOG_WARN,
				         "no shadow password for '%s'%s",
				         username, fromhost));
			}
		}

		/*
		 * The -r and -f flags provide a name which has already
		 * been authenticated by some server.
		 */
		if (preauth_flag) {
			goto auth_ok;
		}

		if (pw_auth (user_passwd, username, reason, (char *) 0) == 0) {
			goto auth_ok;
		}

		SYSLOG ((LOG_WARN, "invalid password for '%s' %s",
		         failent_user, fromhost));
		failed = true;

	      auth_ok:
		/*
		 * This is the point where all authenticated users wind up.
		 * If you reach this far, your password has been
		 * authenticated and so on.
		 */
		if (   !failed
		    && (NULL != pwd)
		    && (0 == pwd->pw_uid)
		    && !is_console) {
			SYSLOG ((LOG_CRIT, "ILLEGAL ROOT LOGIN %s", fromhost));
			failed = true;
		}
		if (   !failed
		    && !login_access (username, ('\0' != *hostname) ? hostname : tty)) {
			SYSLOG ((LOG_WARN, "LOGIN '%s' REFUSED %s",
			         username, fromhost));
			failed = true;
		}
		if (   (NULL != pwd)
		    && getdef_bool ("FAILLOG_ENAB")
		    && !failcheck (pwd->pw_uid, &faillog, failed)) {
			SYSLOG ((LOG_CRIT,
			         "exceeded failure limit for '%s' %s",
			         username, fromhost));
			failed = true;
		}
		if (!failed) {
			break;
		}

		/* don't log non-existent users */
		if ((NULL != pwd) && getdef_bool ("FAILLOG_ENAB")) {
			failure (pwd->pw_uid, tty, &faillog);
		}
		if (getdef_str ("FTMP_FILE") != NULL) {
#ifdef USE_UTMPX
			struct utmpx *failent =
				prepare_utmpx (failent_user,
				               tty,
			/* FIXME: or fromhost? */hostname,
				               utent);
#else				/* !USE_UTMPX */
			struct utmp *failent =
				prepare_utmp (failent_user,
				              tty,
				              hostname,
				              utent);
#endif				/* !USE_UTMPX */
			failtmp (failent_user, failent);
			free (failent);
		}

		retries--;
		if (retries <= 0) {
			SYSLOG ((LOG_CRIT, "REPEATED login failures%s",
			         fromhost));
		}

		/*
		 * If this was a passwordless account and we get here, login
		 * was denied (securetty, faillog, etc.). There was no
		 * password prompt, so do it now (will always fail - the bad
		 * guys won't see that the passwordless account exists at
		 * all).  --marekm
		 */
		if (user_passwd[0] == '\0') {
			pw_auth ("!", username, reason, (char *) 0);
		}

		/*
		 * Authentication of this user failed.
		 * The username must be confirmed in the next try.
		 */
		free (username);
		username = NULL;

		/*
		 * Wait a while (a la SVR4 /usr/bin/login) before attempting
		 * to login the user again. If the earlier alarm occurs
		 * before the sleep() below completes, login will exit.
		 */
		if (delay > 0) {
			(void) sleep (delay);
		}

		(void) puts (_("Login incorrect"));

		/* allow only one attempt with -r or -f */
		if (rflg || fflg || (retries <= 0)) {
			closelog ();
			exit (1);
		}
	}			/* while (true) */
#endif				/* ! USE_PAM */
	assert (NULL != username);
	assert (NULL != pwd);

	(void) alarm (0);		/* turn off alarm clock */

#ifndef USE_PAM			/* PAM does this */
	/*
	 * porttime checks moved here, after the user has been
	 * authenticated. now prints a message, as suggested
	 * by Ivan Nejgebauer <*****@*****.**>.  --marekm
	 */
	if (   getdef_bool ("PORTTIME_CHECKS_ENAB")
	    && !isttytime (username, tty, time ((time_t *) 0))) {
		SYSLOG ((LOG_WARN, "invalid login time for '%s'%s",
		         username, fromhost));
		closelog ();
		bad_time_notify ();
		exit (1);
	}

	check_nologin (pwd->pw_uid == 0);
#endif

	if (getenv ("IFS")) {	/* don't export user IFS ... */
		addenv ("IFS= \t\n", NULL);	/* ... instead, set a safe IFS */
	}

	if (pwd->pw_shell[0] == '*') {	/* subsystem root */
		pwd->pw_shell++;	/* skip the '*' */
		subsystem (pwd);	/* figure out what to execute */
		subroot = true;	/* say I was here again */
		endpwent ();	/* close all of the file which were */
		endgrent ();	/* open in the original rooted file */
		endspent ();	/* system. they will be re-opened */
#ifdef	SHADOWGRP
		endsgent ();	/* in the new rooted file system */
#endif
		goto top;	/* go do all this all over again */
	}

#ifdef WITH_AUDIT
	audit_fd = audit_open ();
	audit_log_acct_message (audit_fd,
	                        AUDIT_USER_LOGIN,
	                        NULL,    /* Prog. name */
	                        "login",
	                        username,
	                        AUDIT_NO_ID,
	                        hostname,
	                        NULL,    /* addr */
	                        tty,
	                        1);      /* result */
	close (audit_fd);
#endif				/* WITH_AUDIT */

#ifndef USE_PAM			/* pam_lastlog handles this */
	if (getdef_bool ("LASTLOG_ENAB")) {	/* give last login and log this one */
		dolastlog (&ll, pwd, tty, hostname);
	}
#endif

#ifndef USE_PAM			/* PAM handles this as well */
	/*
	 * Have to do this while we still have root privileges, otherwise we
	 * don't have access to /etc/shadow.
	 */
	if (NULL != spwd) {		/* check for age of password */
		if (expire (pwd, spwd)) {
			/* The user updated her password, get the new
			 * entries.
			 * Use the x variants because we need to keep the
			 * entry for a long time, and there might be other
			 * getxxyy in between.
			 */
			pw_free (pwd);
			pwd = xgetpwnam (username);
			if (NULL == pwd) {
				SYSLOG ((LOG_ERR,
				         "cannot find user %s after update of expired password",
				         username));
				exit (1);
			}
			spw_free (spwd);
			spwd = xgetspnam (username);
		}
	}
	setup_limits (pwd);	/* nice, ulimit etc. */
#endif				/* ! USE_PAM */
	chown_tty (pwd);

#ifdef USE_PAM
	/*
	 * We must fork before setuid() because we need to call
	 * pam_close_session() as root.
	 */
	(void) signal (SIGINT, SIG_IGN);
	child = fork ();
	if (child < 0) {
		/* error in fork() */
		fprintf (stderr, _("%s: failure forking: %s"),
		         Prog, strerror (errno));
		PAM_END;
		exit (0);
	} else if (child != 0) {
		/*
		 * parent - wait for child to finish, then cleanup
		 * session
		 */
		wait (NULL);
		PAM_END;
		exit (0);
	}
	/* child */
#endif

	/* If we were init, we need to start a new session */
	if (getppid() == 1) {
		setsid();
		if (ioctl(0, TIOCSCTTY, 1) != 0) {
			fprintf (stderr, _("TIOCSCTTY failed on %s"), tty);
		}
	}

	/*
	 * The utmp entry needs to be updated to indicate the new status
	 * of the session, the new PID and SID.
	 */
	update_utmp (username, tty, hostname, utent);

	/* The pwd and spwd entries for the user have been copied.
	 *
	 * Close all the files so that unauthorized access won't occur.
	 */
	endpwent ();		/* stop access to password file */
	endgrent ();		/* stop access to group file */
	endspent ();		/* stop access to shadow passwd file */
#ifdef	SHADOWGRP
	endsgent ();		/* stop access to shadow group file */
#endif

	/* Drop root privileges */
#ifndef USE_PAM
	if (setup_uid_gid (pwd, is_console))
#else
	/* The group privileges were already dropped.
	 * See setup_groups() above.
	 */
	if (change_uid (pwd))
#endif
	{
		exit (1);
	}

	setup_env (pwd);	/* set env vars, cd to the home dir */

#ifdef USE_PAM
	{
		const char *const *env;

		env = (const char *const *) pam_getenvlist (pamh);
		while ((NULL != env) && (NULL != *env)) {
			addenv (*env, NULL);
			env++;
		}
	}
#endif

	(void) setlocale (LC_ALL, "");
	(void) bindtextdomain (PACKAGE, LOCALEDIR);
	(void) textdomain (PACKAGE);

	if (!hushed (username)) {
		addenv ("HUSHLOGIN=FALSE", NULL);
		/*
		 * pam_unix, pam_mail and pam_lastlog should take care of
		 * this
		 */
#ifndef USE_PAM
		motd ();	/* print the message of the day */
		if (   getdef_bool ("FAILLOG_ENAB")
		    && (0 != faillog.fail_cnt)) {
			failprint (&faillog);
			/* Reset the lockout times if logged in */
			if (   (0 != faillog.fail_max)
			    && (faillog.fail_cnt >= faillog.fail_max)) {
				(void) puts (_("Warning: login re-enabled after temporary lockout."));
				SYSLOG ((LOG_WARN,
				         "login '%s' re-enabled after temporary lockout (%d failures)",
				         username, (int) faillog.fail_cnt));
			}
		}
		if (   getdef_bool ("LASTLOG_ENAB")
		    && (ll.ll_time != 0)) {
			time_t ll_time = ll.ll_time;

#ifdef HAVE_STRFTIME
			(void) strftime (ptime, sizeof (ptime),
			                 "%a %b %e %H:%M:%S %z %Y",
			                 localtime (&ll_time));
			printf (_("Last login: %s on %s"),
			        ptime, ll.ll_line);
#else
			printf (_("Last login: %.19s on %s"),
			        ctime (&ll_time), ll.ll_line);
#endif
#ifdef HAVE_LL_HOST		/* __linux__ || SUN4 */
			if ('\0' != ll.ll_host[0]) {
				printf (_(" from %.*s"),
				        (int) sizeof ll.ll_host, ll.ll_host);
			}
#endif
			printf (".\n");
		}
		agecheck (spwd);

		mailcheck ();	/* report on the status of mail */
#endif				/* !USE_PAM */
	} else {
		addenv ("HUSHLOGIN=TRUE", NULL);
	}

	ttytype (tty);

	(void) signal (SIGQUIT, SIG_DFL);	/* default quit signal */
	(void) signal (SIGTERM, SIG_DFL);	/* default terminate signal */
	(void) signal (SIGALRM, SIG_DFL);	/* default alarm signal */
	(void) signal (SIGHUP, SIG_DFL);	/* added this.  --marekm */
	(void) signal (SIGINT, SIG_DFL);	/* default interrupt signal */

	if (0 == pwd->pw_uid) {
		SYSLOG ((LOG_NOTICE, "ROOT LOGIN %s", fromhost));
	} else if (getdef_bool ("LOG_OK_LOGINS")) {
		SYSLOG ((LOG_INFO, "'%s' logged in %s", username, fromhost));
	}
	closelog ();
	tmp = getdef_str ("FAKE_SHELL");
	if (NULL != tmp) {
		err = shell (tmp, pwd->pw_shell, newenvp); /* fake shell */
	} else {
		/* exec the shell finally */
		err = shell (pwd->pw_shell, (char *) 0, newenvp);
	}

	return ((err == ENOENT) ? E_CMD_NOTFOUND : E_CMD_NOEXEC);
}
示例#3
0
static void
do_login(const struct passwd *pwd, char *tty, char *ttyn)
{
#ifdef HAVE_GETSPNAM
    struct spwd *sp;
#endif
    int rootlogin = (pwd->pw_uid == 0);
    gid_t tty_gid;
    struct group *gr;
    const char *home_dir;
    int i;

    if(!rootlogin)
	checknologin();

#ifdef HAVE_GETSPNAM
    sp = getspnam(pwd->pw_name);
#endif

    update_utmp(pwd->pw_name, remote_host ? remote_host : "",
		tty, ttyn);

    gr = getgrnam ("tty");
    if (gr != NULL)
	tty_gid = gr->gr_gid;
    else
	tty_gid = pwd->pw_gid;

    if (chown (ttyn, pwd->pw_uid, tty_gid) < 0) {
	warn("chown %s", ttyn);
	if (rootlogin == 0)
	    exit (1);
    }

    if (chmod (ttyn, S_IRUSR | S_IWUSR | S_IWGRP) < 0) {
	warn("chmod %s", ttyn);
	if (rootlogin == 0)
	    exit (1);
    }

#ifdef HAVE_SETLOGIN
    if(setlogin(pwd->pw_name)){
	warn("setlogin(%s)", pwd->pw_name);
	if(rootlogin == 0)
	    exit(1);
    }
#endif
    if(rootlogin == 0) {
	const char *file = login_conf_get_string("limits");
	if(file == NULL)
	    file = _PATH_LIMITS_CONF;

	read_limits_conf(file, pwd);
    }
	
#ifdef HAVE_SETPCRED
    if (setpcred (pwd->pw_name, NULL) == -1)
	warn("setpcred(%s)", pwd->pw_name);
#endif /* HAVE_SETPCRED */
#ifdef HAVE_INITGROUPS
    if(initgroups(pwd->pw_name, pwd->pw_gid)){
	warn("initgroups(%s, %u)", pwd->pw_name, (unsigned)pwd->pw_gid);
	if(rootlogin == 0)
	    exit(1);
    }
#endif
    if(do_osfc2_magic(pwd->pw_uid))
	exit(1);
    if(setgid(pwd->pw_gid)){
	warn("setgid(%u)", (unsigned)pwd->pw_gid);
	if(rootlogin == 0)
	    exit(1);
    }
    if(setuid(pwd->pw_uid) || (pwd->pw_uid != 0 && setuid(0) == 0)) {
	warn("setuid(%u)", (unsigned)pwd->pw_uid);
	if(rootlogin == 0)
	    exit(1);
    }

    /* make sure signals are set to default actions, apparently some
       OS:es like to ignore SIGINT, which is not very convenient */

    for (i = 1; i < NSIG; ++i)
	signal(i, SIG_DFL);

    /* all kinds of different magic */

#ifdef HAVE_GETSPNAM
    check_shadow(pwd, sp);
#endif

#if defined(HAVE_GETUDBNAM) && defined(HAVE_SETLIM)
    {
	struct udb *udb;
	long t;
	const long maxcpu = 46116860184; /* some random constant */
	udb = getudbnam(pwd->pw_name);
	if(udb == UDB_NULL)
	    errx(1, "Failed to get UDB entry.");
	t = udb->ue_pcpulim[UDBRC_INTER];
	if(t == 0 || t > maxcpu)
	    t = CPUUNLIM;
	else
	    t *= 100 * CLOCKS_PER_SEC;

	if(limit(C_PROC, 0, L_CPU, t) < 0)
	    warn("limit C_PROC");

	t = udb->ue_jcpulim[UDBRC_INTER];
	if(t == 0 || t > maxcpu)
	    t = CPUUNLIM;
	else
	    t *= 100 * CLOCKS_PER_SEC;

	if(limit(C_JOBPROCS, 0, L_CPU, t) < 0)
	    warn("limit C_JOBPROCS");

	nice(udb->ue_nice[UDBRC_INTER]);
    }
#endif
#if defined(HAVE_SGI_GETCAPABILITYBYNAME) && defined(HAVE_CAP_SET_PROC)
	/* XXX SGI capability hack IRIX 6.x (x >= 0?) has something
	   called capabilities, that allow you to give away
	   permissions (such as chown) to specific processes. From 6.5
	   this is default on, and the default capability set seems to
	   not always be the empty set. The problem is that the
	   runtime linker refuses to do just about anything if the
	   process has *any* capabilities set, so we have to remove
	   them here (unless otherwise instructed by /etc/capability).
	   In IRIX < 6.5, these functions was called sgi_cap_setproc,
	   etc, but we ignore this fact (it works anyway). */
	{
	    struct user_cap *ucap = sgi_getcapabilitybyname(pwd->pw_name);
	    cap_t cap;
	    if(ucap == NULL)
		cap = cap_from_text("all=");
	    else
		cap = cap_from_text(ucap->ca_default);
	    if(cap == NULL)
		err(1, "cap_from_text");
	    if(cap_set_proc(cap) < 0)
		err(1, "cap_set_proc");
	    cap_free(cap);
	    free(ucap);
	}
#endif
    home_dir = pwd->pw_dir;
    if (chdir(home_dir) < 0) {
	fprintf(stderr, "No home directory \"%s\"!\n", pwd->pw_dir);
	if (chdir("/"))
	    exit(0);
	home_dir = "/";
	fprintf(stderr, "Logging in with home = \"/\".\n");
    }
#ifdef KRB5
    if (auth == AUTH_KRB5) {
	krb5_start_session (pwd);
    }

    krb5_get_afs_tokens (pwd);

    krb5_finish ();
#endif /* KRB5 */

    add_env("PATH", _PATH_DEFPATH);

    {
	const char *str = login_conf_get_string("environment");
	char buf[MAXPATHLEN];

	if(str == NULL) {
	    login_read_env(_PATH_ETC_ENVIRONMENT);
	} else {
	    while(strsep_copy(&str, ",", buf, sizeof(buf)) != -1) {
		if(buf[0] == '\0')
		    continue;
		login_read_env(buf);
	    }
	}
    }
    {
	const char *str = login_conf_get_string("motd");
	char buf[MAXPATHLEN];

	if(str != NULL) {
	    while(strsep_copy(&str, ",", buf, sizeof(buf)) != -1) {
		if(buf[0] == '\0')
		    continue;
		show_file(buf);
	    }
	} else {
	    str = login_conf_get_string("welcome");
	    if(str != NULL)
		show_file(str);
	}
    }
    add_env("HOME", home_dir);
    add_env("USER", pwd->pw_name);
    add_env("LOGNAME", pwd->pw_name);
    add_env("SHELL", pwd->pw_shell);
    exec_shell(pwd->pw_shell, rootlogin);
}