Exemplo n.º 1
0
static void change_passwd (struct group *gr)
#endif
{
	char *cp;
	static char pass[BUFSIZ];
	int retries;

	/*
	 * A new password is to be entered and it must be encrypted, etc.
	 * The password will be prompted for twice, and both entries must be
	 * identical. There is no need to validate the old password since
	 * the invoker is either the group owner, or root.
	 */
	printf (_("Changing the password for group %s\n"), group);

	for (retries = 0; retries < RETRIES; retries++) {
		cp = getpass (_("New Password: "******"Re-enter new password: "******"They don't match; try again"));
		}
	}

	if (retries == RETRIES) {
		fprintf (stderr, _("%s: Try again later\n"), Prog);
		exit (1);
	}

	cp = pw_encrypt (pass, crypt_make_salt (NULL, NULL));
	memzero (pass, sizeof pass);
#ifdef SHADOWGRP
	if (is_shadowgrp) {
		gr->gr_passwd = SHADOW_PASSWD_STRING;
		sg->sg_passwd = cp;
	} else
#endif
	{
		gr->gr_passwd = cp;
	}
}
Exemplo n.º 2
0
/*
 * get_old_fields - parse the old gecos and use the old value for the fields
 *                  which are not set on the command line
 */
static void get_old_fields (const char *gecos)
{
	char *cp;		/* temporary character pointer       */
	char old_gecos[BUFSIZ];	/* buffer for old GECOS fields       */
	STRFCPY (old_gecos, gecos);

	/*
	 * Now get the full name. It is the first comma separated field in
	 * the GECOS field.
	 */
	cp = copy_field (old_gecos, fflg ? (char *) 0 : fullnm, slop);

	/*
	 * Now get the room number. It is the next comma separated field,
	 * if there is indeed one.
	 */
	if (NULL != cp) {
		cp = copy_field (cp, rflg ? (char *) 0 : roomno, slop);
	}

	/*
	 * Now get the work phone number. It is the third field.
	 */
	if (NULL != cp) {
		cp = copy_field (cp, wflg ? (char *) 0 : workph, slop);
	}

	/*
	 * Now get the home phone number. It is the fourth field.
	 */
	if (NULL != cp) {
		cp = copy_field (cp, hflg ? (char *) 0 : homeph, slop);
	}

	/*
	 * Anything left over is "slop".
	 */
	if ((NULL != cp) && !oflg) {
		if ('\0' != slop[0]) {
			strcat (slop, ",");
		}

		strcat (slop, cp);
	}
}
Exemplo n.º 3
0
Arquivo: chfn.c Projeto: OPSF/uClinux
/*
 * chfn - change a user's password file information
 *
 *	This command controls the GECOS field information in the password
 *	file entry.
 *
 *	The valid options are
 *
 *	-f	full name
 *	-r	room number
 *	-w	work phone number
 *	-h	home phone number
 *	-o	other information (*)
 *
 *	(*) requires root permission to execute.
 */
int main (int argc, char **argv)
{
	char *cp;		/* temporary character pointer       */
	const struct passwd *pw;	/* password file entry               */
	struct passwd pwent;	/* modified password file entry      */
	char old_gecos[BUFSIZ];	/* buffer for old GECOS fields       */
	char new_gecos[BUFSIZ];	/* buffer for new GECOS fields       */
	int flag;		/* flag currently being processed    */
	int fflg = 0;		/* -f - set full name                */
	int rflg = 0;		/* -r - set room number              */
	int wflg = 0;		/* -w - set work phone number        */
	int hflg = 0;		/* -h - set home phone number        */
	int oflg = 0;		/* -o - set other information        */
	char *user;

#ifdef USE_PAM
	pam_handle_t *pamh = NULL;
	struct passwd *pampw;
	int retval;
#endif

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

	/*
	 * This command behaves different for root and non-root
	 * users.
	 */
	amroot = (getuid () == 0);

	/*
	 * Get the program name. The program name is used as a
	 * prefix to most error messages.
	 */
	Prog = Basename (argv[0]);

	OPENLOG ("chfn");

	/* 
	 * The remaining arguments will be processed one by one and executed
	 * by this command. The name is the last argument if it does not
	 * begin with a "-", otherwise the name is determined from the
	 * environment and must agree with the real UID. Also, the UID will
	 * be checked for any commands which are restricted to root only.
	 */
	while ((flag = getopt (argc, argv, "f:r:w:h:o:")) != EOF) {
		switch (flag) {
		case 'f':
			if (!may_change_field ('f')) {
				fprintf (stderr,
					 _("%s: Permission denied.\n"), Prog);
				exit (E_NOPERM);
			}
			fflg++;
			STRFCPY (fullnm, optarg);
			break;
		case 'h':
			if (!may_change_field ('h')) {
				fprintf (stderr,
					 _("%s: Permission denied.\n"), Prog);
				exit (E_NOPERM);
			}
			hflg++;
			STRFCPY (homeph, optarg);
			break;
		case 'r':
			if (!may_change_field ('r')) {
				fprintf (stderr,
					 _("%s: Permission denied.\n"), Prog);
				exit (E_NOPERM);
			}
			rflg++;
			STRFCPY (roomno, optarg);
			break;
		case 'o':
			if (!amroot) {
				fprintf (stderr,
					 _("%s: Permission denied.\n"), Prog);
				exit (E_NOPERM);
			}
			oflg++;
			STRFCPY (slop, optarg);
			break;
		case 'w':
			if (!may_change_field ('w')) {
				fprintf (stderr,
					 _("%s: Permission denied.\n"), Prog);
				exit (E_NOPERM);
			}
			wflg++;
			STRFCPY (workph, optarg);
			break;
		default:
			usage ();
		}
	}

	/*
	 * Get the name of the user to check. It is either the command line
	 * name, or the name getlogin() returns.
	 */
	if (optind < argc) {
		user = argv[optind];
		pw = getpwnam (user);
		if (!pw) {
			fprintf (stderr, _("%s: unknown user %s\n"), Prog,
				 user);
			exit (E_NOPERM);
		}
	} else {
		pw = get_my_pwent ();
		if (!pw) {
			fprintf (stderr,
				 _
				 ("%s: Cannot determine your user name.\n"),
				 Prog);
			exit (E_NOPERM);
		}
		user = xstrdup (pw->pw_name);
	}

#ifdef	USE_NIS
	/*
	 * Now we make sure this is a LOCAL password entry for this user ...
	 */
	if (__ispwNIS ()) {
		char *nis_domain;
		char *nis_master;

		fprintf (stderr,
			 _("%s: cannot change user `%s' on NIS client.\n"),
			 Prog, user);

		if (!yp_get_default_domain (&nis_domain) &&
		    !yp_master (nis_domain, "passwd.byname", &nis_master)) {
			fprintf (stderr,
				 _
				 ("%s: `%s' is the NIS master for this client.\n"),
				 Prog, nis_master);
		}
		exit (E_NOPERM);
	}
#endif

	/*
	 * Non-privileged users are only allowed to change the gecos field
	 * if the UID of the user matches the current real UID.
	 */
	if (!amroot && pw->pw_uid != getuid ()) {
		fprintf (stderr, _("%s: Permission denied.\n"), Prog);
		closelog ();
		exit (E_NOPERM);
	}
#ifdef WITH_SELINUX
	/*
	 * If the UID of the user does not match the current real UID,
	 * check if the change is allowed by SELinux policy.
	 */
	if ((pw->pw_uid != getuid ())
	    && (selinux_check_passwd_access (PASSWD__CHFN) != 0)) {
		fprintf (stderr, _("%s: Permission denied.\n"), Prog);
		closelog ();
		exit (E_NOPERM);
	}
#endif

#ifndef USE_PAM
	/*
	 * Non-privileged users are optionally authenticated (must enter the
	 * password of the user whose information is being changed) before
	 * any changes can be made. Idea from util-linux chfn/chsh. 
	 * --marekm
	 */
	if (!amroot && getdef_bool ("CHFN_AUTH"))
		passwd_check (pw->pw_name, pw->pw_passwd, "chfn");

#else				/* !USE_PAM */
	retval = PAM_SUCCESS;

	pampw = getpwuid (getuid ());
	if (pampw == NULL) {
		retval = PAM_USER_UNKNOWN;
	}

	if (retval == PAM_SUCCESS) {
		retval = pam_start ("chfn", pampw->pw_name, &conv, &pamh);
	}

	if (retval == PAM_SUCCESS) {
		retval = pam_authenticate (pamh, 0);
		if (retval != PAM_SUCCESS) {
			pam_end (pamh, retval);
		}
	}

	if (retval == PAM_SUCCESS) {
		retval = pam_acct_mgmt (pamh, 0);
		if (retval != PAM_SUCCESS) {
			pam_end (pamh, retval);
		}
	}

	if (retval != PAM_SUCCESS) {
		fprintf (stderr, _("%s: PAM authentication failed\n"), Prog);
		exit (E_NOPERM);
	}
#endif				/* USE_PAM */

	/*
	 * Now get the full name. It is the first comma separated field in
	 * the GECOS field.
	 */
	STRFCPY (old_gecos, pw->pw_gecos);
	cp = copy_field (old_gecos, fflg ? (char *) 0 : fullnm, slop);

	/*
	 * Now get the room number. It is the next comma separated field,
	 * if there is indeed one.
	 */
	if (cp)
		cp = copy_field (cp, rflg ? (char *) 0 : roomno, slop);

	/*
	 * Now get the work phone number. It is the third field.
	 */
	if (cp)
		cp = copy_field (cp, wflg ? (char *) 0 : workph, slop);

	/*
	 * Now get the home phone number. It is the fourth field.
	 */
	if (cp)
		cp = copy_field (cp, hflg ? (char *) 0 : homeph, slop);

	/*
	 * Anything left over is "slop".
	 */
	if (cp && !oflg) {
		if (slop[0])
			strcat (slop, ",");

		strcat (slop, cp);
	}

	/*
	 * If none of the fields were changed from the command line, let the
	 * user interactively change them.
	 */
	if (!fflg && !rflg && !wflg && !hflg && !oflg) {
		printf (_("Changing the user information for %s\n"), user);
		new_fields ();
	}

	/*
	 * Check all of the fields for valid information
	 */
	if (valid_field (fullnm, ":,=")) {
		fprintf (stderr, _("%s: invalid name: \"%s\"\n"), Prog, fullnm);
		closelog ();
		exit (E_NOPERM);
	}
	if (valid_field (roomno, ":,=")) {
		fprintf (stderr, _("%s: invalid room number: \"%s\"\n"),
			 Prog, roomno);
		closelog ();
		exit (E_NOPERM);
	}
	if (valid_field (workph, ":,=")) {
		fprintf (stderr, _("%s: invalid work phone: \"%s\"\n"),
			 Prog, workph);
		closelog ();
		exit (E_NOPERM);
	}
	if (valid_field (homeph, ":,=")) {
		fprintf (stderr, _("%s: invalid home phone: \"%s\"\n"),
			 Prog, homeph);
		closelog ();
		exit (E_NOPERM);
	}
	if (valid_field (slop, ":")) {
		fprintf (stderr,
			 _("%s: \"%s\" contains illegal characters\n"),
			 Prog, slop);
		closelog ();
		exit (E_NOPERM);
	}

	/*
	 * Build the new GECOS field by plastering all the pieces together,
	 * if they will fit ...
	 */
	if (strlen (fullnm) + strlen (roomno) + strlen (workph) +
	    strlen (homeph) + strlen (slop) > (unsigned int) 80) {
		fprintf (stderr, _("%s: fields too long\n"), Prog);
		closelog ();
		exit (E_NOPERM);
	}
	snprintf (new_gecos, sizeof new_gecos, "%s,%s,%s,%s%s%s",
		  fullnm, roomno, workph, homeph, slop[0] ? "," : "", slop);

	/*
	 * Before going any further, raise the ulimit to prevent colliding
	 * into a lowered ulimit, and set the real UID to root to protect
	 * against unexpected signals. Any keyboard signals are set to be
	 * ignored.
	 */
	if (setuid (0)) {
		fprintf (stderr, _("Cannot change ID to root.\n"));
		SYSLOG ((LOG_ERR, "can't setuid(0)"));
		closelog ();
		exit (E_NOPERM);
	}
	pwd_init ();

	/*
	 * The passwd entry is now ready to be committed back to the
	 * password file. Get a lock on the file and open it.
	 */
	if (!pw_lock ()) {
		fprintf (stderr,
			 _
			 ("Cannot lock the password file; try again later.\n"));
		SYSLOG ((LOG_WARN, "can't lock /etc/passwd"));
		closelog ();
		exit (E_NOPERM);
	}
	if (!pw_open (O_RDWR)) {
		fprintf (stderr, _("Cannot open the password file.\n"));
		pw_unlock ();
		SYSLOG ((LOG_ERR, "can't open /etc/passwd"));
		closelog ();
		exit (E_NOPERM);
	}

	/*
	 * Get the entry to update using pw_locate() - we want the real one
	 * from /etc/passwd, not the one from getpwnam() which could contain
	 * the shadow password if (despite the warnings) someone enables
	 * AUTOSHADOW (or SHADOW_COMPAT in libc).  --marekm
	 */
	pw = pw_locate (user);
	if (!pw) {
		pw_unlock ();
		fprintf (stderr,
			 _("%s: %s not found in /etc/passwd\n"), Prog, user);
		exit (E_NOPERM);
	}

	/*
	 * Make a copy of the entry, then change the gecos field. The other
	 * fields remain unchanged.
	 */
	pwent = *pw;
	pwent.pw_gecos = new_gecos;

	/*
	 * Update the passwd file entry. If there is a DBM file, update that
	 * entry as well.
	 */
	if (!pw_update (&pwent)) {
		fprintf (stderr, _("Error updating the password entry.\n"));
		pw_unlock ();
		SYSLOG ((LOG_ERR, "error updating passwd entry"));
		closelog ();
		exit (E_NOPERM);
	}

	/*
	 * Changes have all been made, so commit them and unlock the file.
	 */
	if (!pw_close ()) {
		fprintf (stderr, _("Cannot commit password file changes.\n"));
		pw_unlock ();
		SYSLOG ((LOG_ERR, "can't rewrite /etc/passwd"));
		closelog ();
		exit (E_NOPERM);
	}
	if (!pw_unlock ()) {
		fprintf (stderr, _("Cannot unlock the password file.\n"));
		SYSLOG ((LOG_ERR, "can't unlock /etc/passwd"));
		closelog ();
		exit (E_NOPERM);
	}
	SYSLOG ((LOG_INFO, "changed user `%s' information", user));

	nscd_flush_cache ("passwd");

#ifdef USE_PAM
	if (retval == PAM_SUCCESS)
		pam_end (pamh, PAM_SUCCESS);
#endif				/* USE_PAM */

	closelog ();
	exit (E_SUCCESS);
}
Exemplo n.º 4
0
/*
 * process_flags - parse the command line options
 *
 *	It will not return if an error is encountered.
 */
static void process_flags (int argc, char **argv)
{
	int c;		/* flag currently being processed    */
	static struct option long_options[] = {
		{"full-name",  required_argument, NULL, 'f'},
		{"home-phone", required_argument, NULL, 'h'},
		{"other",      required_argument, NULL, 'o'},
		{"room",       required_argument, NULL, 'r'},
		{"root",       required_argument, NULL, 'R'},
		{"help",       no_argument,       NULL, 'u'},
		{"work-phone", required_argument, NULL, 'w'},
		{NULL, 0, NULL, '\0'}
	};

	/* 
	 * The remaining arguments will be processed one by one and executed
	 * by this command. The name is the last argument if it does not
	 * begin with a "-", otherwise the name is determined from the
	 * environment and must agree with the real UID. Also, the UID will
	 * be checked for any commands which are restricted to root only.
	 */
	while ((c = getopt_long (argc, argv, "f:h:o:r:R:uw:",
	                         long_options, NULL)) != -1) {
		switch (c) {
		case 'f':
			if (!may_change_field ('f')) {
				fprintf (stderr,
				         _("%s: Permission denied.\n"), Prog);
				exit (E_NOPERM);
			}
			fflg = true;
			STRFCPY (fullnm, optarg);
			break;
		case 'h':
			if (!may_change_field ('h')) {
				fprintf (stderr,
				         _("%s: Permission denied.\n"), Prog);
				exit (E_NOPERM);
			}
			hflg = true;
			STRFCPY (homeph, optarg);
			break;
		case 'o':
			if (!amroot) {
				fprintf (stderr,
				         _("%s: Permission denied.\n"), Prog);
				exit (E_NOPERM);
			}
			oflg = true;
			STRFCPY (slop, optarg);
			break;
		case 'r':
			if (!may_change_field ('r')) {
				fprintf (stderr,
				         _("%s: Permission denied.\n"), Prog);
				exit (E_NOPERM);
			}
			rflg = true;
			STRFCPY (roomno, optarg);
			break;
		case 'R': /* no-op, handled in process_root_flag () */
			break;
		case 'u':
			usage (E_SUCCESS);
			/*@notreached@*/break;
		case 'w':
			if (!may_change_field ('w')) {
				fprintf (stderr,
				         _("%s: Permission denied.\n"), Prog);
				exit (E_NOPERM);
			}
			wflg = true;
			STRFCPY (workph, optarg);
			break;
		default:
			usage (E_USAGE);
		}
	}
}
Exemplo n.º 5
0
 /*ARGSUSED*/ int main (int argc, char **argv)
{
#ifndef USE_PAM
	const char *env;
#endif				/* !USE_PAM */
	char **envp = environ;
	TERMIO termio;
	int err = 0;

#ifdef	USE_TERMIO
	ioctl (0, TCGETA, &termio);
	termio.c_iflag |= (ICRNL | IXON);
	termio.c_oflag |= (OPOST | ONLCR);
	termio.c_cflag |= (CREAD);
	termio.c_lflag |= (ISIG | ICANON | ECHO | ECHOE | ECHOK);
	ioctl (0, TCSETAF, &termio);
#endif
#ifdef	USE_TERMIOS
	tcgetattr (0, &termio);
	termio.c_iflag |= (ICRNL | IXON);
	termio.c_oflag |= (CREAD);
	termio.c_lflag |= (ECHO | ECHOE | ECHOK | ICANON | ISIG);
	tcsetattr (0, TCSANOW, &termio);
#endif

	Prog = Basename (argv[0]);
	(void) setlocale (LC_ALL, "");
	(void) bindtextdomain (PACKAGE, LOCALEDIR);
	(void) textdomain (PACKAGE);

#ifdef	USE_SYSLOG
	OPENLOG ("sulogin");
#endif
	initenv ();
	if (argc > 1) {
		close (0);
		close (1);
		close (2);

		if (open (argv[1], O_RDWR) >= 0) {
			dup (0);
			dup (0);
		} else {
#ifdef	USE_SYSLOG
			SYSLOG (LOG_WARN, "cannot open %s\n", argv[1]);
			closelog ();
#endif
			exit (1);
		}
	}
	if (access (PASSWD_FILE, F_OK) == -1) {	/* must be a password file! */
		(void) puts (_("No password file"));
#ifdef	USE_SYSLOG
		SYSLOG (LOG_WARN, "No password file\n");
		closelog ();
#endif
		exit (1);
	}
#if !defined(DEBUG) && defined(SULOGIN_ONLY_INIT)
	if (getppid () != 1) {	/* parent must be INIT */
#ifdef	USE_SYSLOG
		SYSLOG (LOG_WARN, "Pid == %d, not 1\n", getppid ());
		closelog ();
#endif
		exit (1);
	}
#endif
	if ((isatty (0) == 0) || (isatty (1) == 0) || (isatty (2) == 0)) {
#ifdef	USE_SYSLOG
		closelog ();
#endif
		exit (1);	/* must be a terminal */
	}
	/* If we were init, we need to start a new session */
	if (getppid() == 1) {
		setsid();
		if (ioctl(0, TIOCSCTTY, 1) != 0) {
			(void) fputs (_("TIOCSCTTY failed"), stderr);
		}
	}
	while (NULL != *envp) {		/* add inherited environment, */
		addenv (*envp, NULL);	/* some variables change later */
		envp++;
	}

#ifndef USE_PAM
	env = getdef_str ("ENV_TZ");
	if (NULL != env) {
		addenv (('/' == *env) ? tz (env) : env, NULL);
	}
	env = getdef_str ("ENV_HZ");
	if (NULL != env) {
		addenv (env, NULL);	/* set the default $HZ, if one */
	}
#endif				/* !USE_PAM */

	(void) strcpy (name, "root");	/* KLUDGE!!! */

	(void) signal (SIGALRM, catch_signals);	/* exit if the timer expires */
	(void) alarm (ALARM);		/* only wait so long ... */

	while (true) {		/* repeatedly get login/password pairs */
		char *cp;
		pw_entry (name, &pwent);	/* get entry from password file */
		if (pwent.pw_name == (char *) 0) {
			/*
			 * Fail secure
			 */
			(void) puts (_("No password entry for 'root'"));
#ifdef	USE_SYSLOG
			SYSLOG (LOG_WARN, "No password entry for 'root'\n");
			closelog ();
#endif
			exit (1);
		}

		/*
		 * Here we prompt for the root password, or if no password
		 * is given we just exit.
		 */

		/* get a password for root */
		cp = getpass (_(
"\n"
"Type control-d to proceed with normal startup,\n"
"(or give root password for system maintenance):"));
		/*
		 * XXX - can't enter single user mode if root password is
		 * empty.  I think this doesn't happen very often :-). But
		 * it will work with standard getpass() (no NULL on EOF). 
		 * --marekm
		 */
		if ((NULL == cp) || ('\0' == *cp)) {
#ifdef	USE_SYSLOG
			SYSLOG (LOG_INFO, "Normal startup\n");
			closelog ();
#endif
			(void) puts ("");
#ifdef	TELINIT
			execl (PATH_TELINIT, "telinit", RUNLEVEL, (char *) 0);
#endif
			exit (0);
		} else {
			STRFCPY (pass, cp);
			strzero (cp);
		}
		if (valid (pass, &pwent)) {	/* check encrypted passwords ... */
			break;	/* ... encrypted passwords matched */
		}

#ifdef	USE_SYSLOG
		SYSLOG (LOG_WARN, "Incorrect root password\n");
#endif
		sleep (2);
		(void) puts (_("Login incorrect"));
	}
	strzero (pass);
	(void) alarm (0);
	(void) signal (SIGALRM, SIG_DFL);
	environ = newenvp;	/* make new environment active */

	(void) puts (_("Entering System Maintenance Mode"));
#ifdef	USE_SYSLOG
	SYSLOG (LOG_INFO, "System Maintenance Mode\n");
#endif

#ifdef	USE_SYSLOG
	closelog ();
#endif
	/* exec the shell finally. */
	err = shell (pwent.pw_shell, (char *) 0, environ);

	return ((err == ENOENT) ? E_CMD_NOTFOUND : E_CMD_NOEXEC);
}
Exemplo n.º 6
0
int main (int argc, char **argv)
{
	const struct spwd *sp;
	uid_t ruid;
	gid_t rgid;
	const struct passwd *pw;

	/*
	 * Get the program name so that error messages can use it.
	 */
	Prog = Basename (argv[0]);

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

	process_root_flag ("-R", argc, argv);

#ifdef WITH_AUDIT
	audit_help_open ();
#endif
	OPENLOG ("chage");

	ruid = getuid ();
	rgid = getgid ();
	amroot = (ruid == 0);
#ifdef WITH_SELINUX
	if (amroot && (is_selinux_enabled () > 0)) {
		amroot = (selinux_check_passwd_access (PASSWD__ROOTOK) == 0);
	}
#endif

	process_flags (argc, argv);

	check_perms ();

	if (!spw_file_present ()) {
		fprintf (stderr,
		         _("%s: the shadow password file is not present\n"),
		         Prog);
		SYSLOG ((LOG_WARN, "can't find the shadow password file"));
		closelog ();
		exit (E_SHADOW_NOTFOUND);
	}

	open_files (lflg);
	/* Drop privileges */
	if (lflg && (   (setregid (rgid, rgid) != 0)
	             || (setreuid (ruid, ruid) != 0))) {
		fprintf (stderr, _("%s: failed to drop privileges (%s)\n"),
		         Prog, strerror (errno));
		fail_exit (E_NOPERM);
	}

	pw = pw_locate (argv[optind]);
	if (NULL == pw) {
		fprintf (stderr, _("%s: user '%s' does not exist in %s\n"),
		         Prog, argv[optind], pw_dbname ());
		closelog ();
		fail_exit (E_NOPERM);
	}

	STRFCPY (user_name, pw->pw_name);
#ifdef WITH_TCB
	if (shadowtcb_set_user (pw->pw_name) == SHADOWTCB_FAILURE) {
		fail_exit (E_NOPERM);
	}
#endif
	user_uid = pw->pw_uid;

	sp = spw_locate (argv[optind]);
	get_defaults (sp);

	/*
	 * Print out the expiration fields if the user has requested the
	 * list option.
	 */
	if (lflg) {
		if (!amroot && (ruid != user_uid)) {
			fprintf (stderr, _("%s: Permission denied.\n"), Prog);
			fail_exit (E_NOPERM);
		}
#ifdef WITH_AUDIT
		audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
		              "display aging info",
		              user_name, (unsigned int) user_uid, 1);
#endif
		list_fields ();
		fail_exit (E_SUCCESS);
	}

	/*
	 * If none of the fields were changed from the command line, let the
	 * user interactively change them.
	 */
	if (!mflg && !Mflg && !dflg && !Wflg && !Iflg && !Eflg) {
		printf (_("Changing the aging information for %s\n"),
		        user_name);
		if (new_fields () == 0) {
			fprintf (stderr, _("%s: error changing fields\n"),
			         Prog);
			fail_exit (E_NOPERM);
		}
#ifdef WITH_AUDIT
		else {
			audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
			              "change all aging information",
			              user_name, (unsigned int) user_uid, 1);
		}
#endif
	} else {
#ifdef WITH_AUDIT
		if (Mflg) {
			audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
			              "change max age",
			              user_name, (unsigned int) user_uid, 1);
		}
		if (mflg) {
			audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
			              "change min age",
			              user_name, (unsigned int) user_uid, 1);
		}
		if (dflg) {
			audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
			              "change last change date",
			              user_name, (unsigned int) user_uid, 1);
		}
		if (Wflg) {
			audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
			              "change passwd warning",
			              user_name, (unsigned int) user_uid, 1);
		}
		if (Iflg) {
			audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
			              "change inactive days",
			              user_name, (unsigned int) user_uid, 1);
		}
		if (Eflg) {
			audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
			              "change passwd expiration",
			              user_name, (unsigned int) user_uid, 1);
		}
#endif
	}

	update_age (sp, pw);

	close_files ();

	SYSLOG ((LOG_INFO, "changed password expiry for %s", user_name));

	closelog ();
	exit (E_SUCCESS);
}
Exemplo n.º 7
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);
}
Exemplo n.º 8
0
int
main(int argc, char **argv)
{
	char	*cp;			/* temporary character pointer       */
	const struct passwd *pw;	/* password file entry               */
	struct	passwd	pwent;		/* modified password file entry      */
	char	old_gecos[BUFSIZ];	/* buffer for old GECOS fields       */
	char	new_gecos[BUFSIZ];	/* buffer for new GECOS fields       */
	int	flag;			/* flag currently being processed    */
	int	fflg = 0;		/* -f - set full name                */
	int	rflg = 0;		/* -r - set room number              */
	int	wflg = 0;		/* -w - set work phone number        */
	int	hflg = 0;		/* -h - set home phone number        */
	int	oflg = 0;		/* -o - set other information        */
	char *user;

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

	/*
	 * This command behaves different for root and non-root
	 * users.
	 */

	amroot = (getuid () == 0);
#ifdef	NDBM
	pw_dbm_mode = O_RDWR;
#endif

	/*
	 * Get the program name.  The program name is used as a
	 * prefix to most error messages.  It is also used as input
	 * to the openlog() function for error logging.
	 */

	Prog = Basename(argv[0]);

	openlog("chfn", LOG_PID, LOG_AUTH);

	/* 
	 * The remaining arguments will be processed one by one and
	 * executed by this command.  The name is the last argument
	 * if it does not begin with a "-", otherwise the name is
	 * determined from the environment and must agree with the
	 * real UID.  Also, the UID will be checked for any commands
	 * which are restricted to root only.
	 */

	while ((flag = getopt (argc, argv, "f:r:w:h:o:")) != EOF) {
		switch (flag) {
			case 'f':
				if (!may_change_field('f')) {
					fprintf(stderr, _("%s: Permission denied.\n"), Prog);
					exit(1);
				}
				fflg++;
				STRFCPY(fullnm, optarg);
				break;
			case 'r':
				if (!may_change_field('r')) {
					fprintf(stderr, _("%s: Permission denied.\n"), Prog);
					exit(1);
				}
				rflg++;
				STRFCPY(roomno, optarg);
				break;
			case 'w':
				if (!may_change_field('w')) {
					fprintf(stderr, _("%s: Permission denied.\n"), Prog);
					exit(1);
				}
				wflg++;
				STRFCPY(workph, optarg);
				break;
			case 'h':
				if (!may_change_field('h')) {
					fprintf(stderr, _("%s: Permission denied.\n"), Prog);
					exit(1);
				}
				hflg++;
				STRFCPY(homeph, optarg);
				break;
			case 'o':
				if (!amroot) {
					fprintf(stderr, _("%s: Permission denied.\n"), Prog);
					exit(1);
				}
				oflg++;
				STRFCPY(slop, optarg);
				break;
			default:
				usage();
		}
	}

	/*
	 * Get the name of the user to check.  It is either
	 * the command line name, or the name getlogin()
	 * returns.
	 */

	if (optind < argc) {
		user = argv[optind];
		pw = getpwnam(user);
		if (!pw) {
			fprintf(stderr, _("%s: Unknown user %s\n"), Prog, user);
			exit(1);
		}
	} else {
		pw = get_my_pwent();
		if (!pw) {
			fprintf(stderr, _("%s: Cannot determine your user name.\n"), Prog);
			exit(1);
		}
		user = xstrdup(pw->pw_name);
	}

#ifdef	USE_NIS
	/*
	 * Now we make sure this is a LOCAL password entry for
	 * this user ...
	 */

	if (__ispwNIS ()) {
		char	*nis_domain;
		char	*nis_master;

		fprintf (stderr, _("%s: cannot change user `%s' on NIS client.\n"), Prog, user);

		if (! yp_get_default_domain (&nis_domain) &&
				! yp_master (nis_domain, "passwd.byname",
				&nis_master)) {
			fprintf (stderr, _("%s: `%s' is the NIS master for this client.\n"), Prog, nis_master);
		}
		exit (1);
	}
#endif

	/*
	 * Non-privileged users are only allowed to change the
	 * gecos field if the UID of the user matches the current
	 * real UID.
	 */

	if (!amroot && pw->pw_uid != getuid()) {
		fprintf (stderr, _("%s: Permission denied.\n"), Prog);
		closelog();
		exit(1);
	}

	/*
	 * Non-privileged users are optionally authenticated
	 * (must enter the password of the user whose information
	 * is being changed) before any changes can be made.
	 * Idea from util-linux chfn/chsh.  --marekm
	 */

	if (!amroot && getdef_bool("CHFN_AUTH"))
		passwd_check(pw->pw_name, pw->pw_passwd, "chfn");
	
	/*
	 * Now get the full name.  It is the first comma separated field
	 * in the GECOS field.
	 */

	STRFCPY(old_gecos, pw->pw_gecos);
	cp = copy_field (old_gecos, fflg ? (char *) 0:fullnm, slop);

	/*
	 * Now get the room number.  It is the next comma separated field,
	 * if there is indeed one.
	 */

	if (cp)
		cp = copy_field (cp, rflg ? (char *) 0:roomno, slop);

	/*
	 * Now get the work phone number.  It is the third field.
	 */

	if (cp)
		cp = copy_field (cp, wflg ? (char *) 0:workph, slop);

	/*
	 * Now get the home phone number.  It is the fourth field.
	 */

	if (cp)
		cp = copy_field (cp, hflg ? (char *) 0:homeph, slop);

	/*
	 * Anything left over is "slop".
	 */

	if (cp && !oflg) {
		if (slop[0])
			strcat (slop, ",");

		strcat (slop, cp);
	}

	/*
	 * If none of the fields were changed from the command line,
	 * let the user interactively change them.
	 */

	if (!fflg && !rflg && !wflg && !hflg && !oflg) {
		printf(_("Changing the user information for %s\n"), user);
		new_fields();
	}

	/*
	 * Check all of the fields for valid information
	 */

	if (valid_field(fullnm, ":,=")) {
		fprintf(stderr, _("%s: invalid name: \"%s\"\n"), Prog, fullnm);
		closelog();
		exit(1);
	}
	if (valid_field(roomno, ":,=")) {
		fprintf(stderr, _("%s: invalid room number: \"%s\"\n"), Prog, roomno);
		closelog();
		exit(1);
	}
	if (valid_field(workph, ":,=")) {
		fprintf(stderr, _("%s: invalid work phone: \"%s\"\n"), Prog, workph);
		closelog();
		exit(1);
	}
	if (valid_field (homeph, ":,=")) {
		fprintf(stderr, _("%s: invalid home phone: \"%s\"\n"), Prog, homeph);
		closelog();
		exit(1);
	}
	if (valid_field(slop, ":")) {
		fprintf(stderr, _("%s: \"%s\" contains illegal characters\n"), Prog, slop);
		closelog();
		exit(1);
	}

	/*
	 * Build the new GECOS field by plastering all the pieces together,
	 * if they will fit ...
	 */

	if (strlen(fullnm) + strlen(roomno) + strlen(workph) +
			strlen(homeph) + strlen(slop) > (unsigned int) 80) {
		fprintf(stderr, _("%s: fields too long\n"), Prog);
		closelog();
		exit(1);
	}
	snprintf(new_gecos, sizeof new_gecos, "%s,%s,%s,%s%s%s",
		 fullnm, roomno, workph, homeph, slop[0] ? "," : "", slop);

	/*
	 * Before going any further, raise the ulimit to prevent
	 * colliding into a lowered ulimit, and set the real UID
	 * to root to protect against unexpected signals.  Any
	 * keyboard signals are set to be ignored.
	 */

	if (setuid(0)) {
		fprintf(stderr, _("Cannot change ID to root.\n"));
		SYSLOG((LOG_ERR, NOTROOT2));
		closelog();
		exit(1);
	}
	pwd_init();

	/*
	 * The passwd entry is now ready to be committed back to
	 * the password file.  Get a lock on the file and open it.
	 */

	if (!pw_lock()) {
		fprintf(stderr, _("Cannot lock the password file; try again later.\n"));
		SYSLOG((LOG_WARN, PWDBUSY2));
		closelog();
		exit(1);
	}
	if (!pw_open(O_RDWR)) {
		fprintf(stderr, _("Cannot open the password file.\n"));
		pw_unlock();
		SYSLOG((LOG_ERR, OPNERROR2));
		closelog();
		exit(1);
	}

	/*
	 * Get the entry to update using pw_locate() - we want the real
	 * one from /etc/passwd, not the one from getpwnam() which could
	 * contain the shadow password if (despite the warnings) someone
	 * enables AUTOSHADOW (or SHADOW_COMPAT in libc).  --marekm
	 */
	pw = pw_locate(user);
	if (!pw) {
		pw_unlock();
		fprintf(stderr,
			_("%s: %s not found in /etc/passwd\n"), Prog, user);
		exit(1);
	}

	/*
	 * Make a copy of the entry, then change the gecos field.  The other
	 * fields remain unchanged.
	 */
	pwent = *pw;
	pwent.pw_gecos = new_gecos;

	/*
	 * Update the passwd file entry.  If there is a DBM file,
	 * update that entry as well.
	 */

	if (!pw_update(&pwent)) {
		fprintf(stderr, _("Error updating the password entry.\n"));
		pw_unlock();
		SYSLOG((LOG_ERR, UPDERROR2));
		closelog();
		exit(1);
	}
#ifdef NDBM
	if (pw_dbm_present() && !pw_dbm_update(&pwent)) {
		fprintf(stderr, _("Error updating the DBM password entry.\n"));
		pw_unlock ();
		SYSLOG((LOG_ERR, DBMERROR2));
		closelog();
		exit(1);
	}
	endpwent();
#endif

	/*
	 * Changes have all been made, so commit them and unlock the
	 * file.
	 */

	if (!pw_close()) {
		fprintf(stderr, _("Cannot commit password file changes.\n"));
		pw_unlock();
		SYSLOG((LOG_ERR, CLSERROR2));
		closelog();
		exit(1);
	}
	if (!pw_unlock()) {
		fprintf(stderr, _("Cannot unlock the password file.\n"));
		SYSLOG((LOG_ERR, UNLKERROR2));
		closelog();
		exit(1);
	}
	SYSLOG((LOG_INFO, CHGGECOS, user));
	closelog();
	exit (0);
}
Exemplo n.º 9
0
/*
 * passwd - change a user's password file information
 *
 *	This command controls the password file and commands which are used
 * 	to modify it.
 *
 *	The valid options are
 *
 *	-d	delete the password for the named account (*)
 *	-e	expire the password for the named account (*)
 *	-f	execute chfn command to interpret flags
 *	-g	execute gpasswd command to interpret flags
 *	-i #	set sp_inact to # days (*)
 *	-k	change password only if expired
 *	-l	lock the password of the named account (*)
 *	-n #	set sp_min to # days (*)
 *	-r #	change password in # repository
 *	-s	execute chsh command to interpret flags
 *	-S	show password status of named account
 *	-u	unlock the password of the named account (*)
 *	-w #	set sp_warn to # days (*)
 *	-x #	set sp_max to # days (*)
 *
 *	(*) requires root permission to execute.
 *
 *	All of the time fields are entered in days and converted to the
 * 	appropriate internal format. For finer resolute the chage
 *	command must be used.
 */
int main (int argc, char **argv)
{
	const struct passwd *pw;	/* Password file entry for user      */

#ifndef USE_PAM
	char *cp;		/* Miscellaneous character pointing  */

	const struct spwd *sp;	/* Shadow file entry for user   */
#endif				/* !USE_PAM */

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

	/*
	 * The program behaves differently when executed by root than when
	 * executed by a normal user.
	 */
	amroot = (getuid () == 0);

	/*
	 * Get the program name. The program name is used as a prefix to
	 * most error messages.
	 */
	Prog = Basename (argv[0]);

	sanitize_env ();

	OPENLOG ("passwd");

	{
		/*
		 * Parse the command line options.
		 */
		int option_index = 0;
		int c;
		static struct option long_options[] = {
			{"all", no_argument, NULL, 'a'},
			{"delete", no_argument, NULL, 'd'},
			{"expire", no_argument, NULL, 'e'},
			{"help", no_argument, NULL, 'h'},
			{"inactive", required_argument, NULL, 'i'},
			{"keep-tokens", no_argument, NULL, 'k'},
			{"lock", no_argument, NULL, 'l'},
			{"mindays", required_argument, NULL, 'n'},
			{"quiet", no_argument, NULL, 'q'},
			{"root", required_argument, NULL, 'R'},
			{"repository", required_argument, NULL, 'r'},
			{"status", no_argument, NULL, 'S'},
			{"unlock", no_argument, NULL, 'u'},
			{"warndays", required_argument, NULL, 'w'},
			{"maxdays", required_argument, NULL, 'x'},
			{NULL, 0, NULL, '\0'}
		};

		while ((c = getopt_long (argc, argv, "adei:kln:qR:r:Suw:x:",
		                         long_options, &option_index)) != -1) {
			switch (c) {
			case 'a':
				aflg = true;
				break;
			case 'd':
				dflg = true;
				anyflag = true;
				break;
			case 'e':
				eflg = true;
				anyflag = true;
				break;
			case 'i':
				if (   (getlong (optarg, &inact) == 0)
				    || (inact < -1)) {
					fprintf (stderr,
					         _("%s: invalid numeric argument '%s'\n"),
					         Prog, optarg);
					usage (E_BAD_ARG);
				}
				iflg = true;
				anyflag = true;
				break;
			case 'k':
				/* change only if expired, like Linux-PAM passwd -k. */
				kflg = true;	/* ok for users */
				break;
			case 'l':
				lflg = true;
				anyflag = true;
				break;
			case 'n':
				if (   (getlong (optarg, &age_min) == 0)
				    || (age_min < -1)) {
					fprintf (stderr,
					         _("%s: invalid numeric argument '%s'\n"),
					         Prog, optarg);
					usage (E_BAD_ARG);
				}
				nflg = true;
				anyflag = true;
				break;
			case 'q':
				qflg = true;	/* ok for users */
				break;
			case 'R':
				if ('/' != optarg[0]) {
					fprintf (stderr,
					         _("%s: invalid chroot path '%s'\n"),
					         Prog, optarg);
					exit (E_BAD_ARG);
				}
				newroot = optarg;

				if (access (newroot, F_OK) != 0) {
					fprintf(stderr,
					        _("%s: chroot directory %s does not exist\n"),
					        Prog, newroot);
					exit (E_BAD_ARG);
				}
				if ( chroot(newroot) != 0 ) {
					fprintf(stderr,
				            _("%s: unable to chroot to directory %s\n"),
					        Prog, newroot);
					exit (E_BAD_ARG);
				}
				break;
			case 'r':
				/* -r repository (files|nis|nisplus) */
				/* only "files" supported for now */
				if (strcmp (optarg, "files") != 0) {
					fprintf (stderr,
					         _("%s: repository %s not supported\n"),
						 Prog, optarg);
					exit (E_BAD_ARG);
				}
				break;
			case 'S':
				Sflg = true;	/* ok for users */
				break;
			case 'u':
				uflg = true;
				anyflag = true;
				break;
			case 'w':
				if (   (getlong (optarg, &warn) == 0)
				    || (warn < -1)) {
					fprintf (stderr,
					         _("%s: invalid numeric argument '%s'\n"),
					         Prog, optarg);
					usage (E_BAD_ARG);
				}
				wflg = true;
				anyflag = true;
				break;
			case 'x':
				if (   (getlong (optarg, &age_max) == 0)
				    || (age_max < -1)) {
					fprintf (stderr,
					         _("%s: invalid numeric argument '%s'\n"),
					         Prog, optarg);
					usage (E_BAD_ARG);
				}
				xflg = true;
				anyflag = true;
				break;
			default:
				usage (E_BAD_ARG);
			}
		}
	}

	/*
	 * Now I have to get the user name. The name will be gotten from the
	 * command line if possible. Otherwise it is figured out from the
	 * environment.
	 */
	pw = get_my_pwent ();
	if (NULL == pw) {
		fprintf (stderr,
		         _("%s: Cannot determine your user name.\n"), Prog);
		SYSLOG ((LOG_WARN, "Cannot determine the user name of the caller (UID %lu)",
		         (unsigned long) getuid ()));
		exit (E_NOPERM);
	}
	myname = xstrdup (pw->pw_name);
	if (optind < argc) {
		name = argv[optind];
	} else {
		name = myname;
	}

	/*
	 * Make sure that at most one username was specified.
	 */
	if (argc > (optind+1)) {
		usage (E_USAGE);
	}

	/*
	 * The -a flag requires -S, no other flags, no username, and
	 * you must be root.  --marekm
	 */
	if (aflg) {
		if (anyflag || !Sflg || (optind < argc)) {
			usage (E_USAGE);
		}
		if (!amroot) {
			fprintf (stderr, _("%s: Permission denied.\n"), Prog);
			exit (E_NOPERM);
		}
		setpwent ();
		while ( (pw = getpwent ()) != NULL ) {
			print_status (pw);
		}
		endpwent ();
		exit (E_SUCCESS);
	}
#if 0
	/*
	 * Allow certain users (administrators) to change passwords of
	 * certain users. Not implemented yet. --marekm
	 */
	if (may_change_passwd (myname, name))
		amroot = 1;
#endif

	/*
	 * If any of the flags were given, a user name must be supplied on
	 * the command line. Only an unadorned command line doesn't require
	 * the user's name be given. Also, -x, -n, -w, -i, -e, -d,
	 * -l, -u may appear with each other. -S, -k must appear alone.
	 */

	/*
	 * -S now ok for normal users (check status of my own account), and
	 * doesn't require username.  --marekm
	 */
	if (anyflag && optind >= argc) {
		usage (E_USAGE);
	}

	if (   (Sflg && kflg)
	    || (anyflag && (Sflg || kflg))) {
		usage (E_USAGE);
	}

	if (anyflag && !amroot) {
		fprintf (stderr, _("%s: Permission denied.\n"), Prog);
		exit (E_NOPERM);
	}

	pw = xgetpwnam (name);
	if (NULL == pw) {
		fprintf (stderr, _("%s: user '%s' does not exist\n"), Prog, name);
		exit (E_NOPERM);
	}
#ifdef WITH_SELINUX
	/* only do this check when getuid()==0 because it's a pre-condition for
	   changing a password without entering the old one */
	if ((is_selinux_enabled() > 0) && (getuid() == 0) &&
	    (check_selinux_access (name, pw->pw_uid, PASSWD__PASSWD) != 0)) {
		security_context_t user_context = NULL;
		const char *user = "******";
		if (getprevcon (&user_context) == 0) {
			user = user_context;
		}
		SYSLOG ((LOG_ALERT,
		         "%s is not authorized to change the password of %s",
		         user, name));
		fprintf(stderr,
		        _("%s: %s is not authorized to change the password of %s\n"),
		        Prog, user, name);
		if (NULL != user_context) {
			freecon (user_context);
		}
		exit (E_NOPERM);
	}
#endif				/* WITH_SELINUX */

	/*
	 * If the UID of the user does not match the current real UID,
	 * check if I'm root.
	 */
	if (!amroot && (pw->pw_uid != getuid ())) {
		fprintf (stderr,
		         _("%s: You may not view or modify password information for %s.\n"),
		         Prog, name);
		SYSLOG ((LOG_WARN,
			 "%s: can't view or modify password information for %s",
			 Prog, name));
		closelog ();
		exit (E_NOPERM);
	}

	if (Sflg) {
		print_status (pw);
		exit (E_SUCCESS);
	}
#ifndef USE_PAM
	/*
	 * The user name is valid, so let's get the shadow file entry.
	 */
	sp = getspnam (name); /* !USE_PAM, no need for xgetspnam */
	if (NULL == sp) {
		sp = pwd_to_spwd (pw);
	}

	cp = sp->sp_pwdp;

	/*
	 * If there are no other flags, just change the password.
	 */
	if (!anyflag) {
		STRFCPY (crypt_passwd, cp);

		/*
		 * See if the user is permitted to change the password. 
		 * Otherwise, go ahead and set a new password.
		 */
		check_password (pw, sp);

		/*
		 * Let the user know whose password is being changed.
		 */
		if (!qflg) {
			printf (_("Changing password for %s\n"), name);
		}

		if (new_password (pw)) {
			fprintf (stderr,
				 _("The password for %s is unchanged.\n"),
				 name);
			closelog ();
			exit (E_NOPERM);
		}
		do_update_pwd = true;
		do_update_age = true;
	}
#endif				/* !USE_PAM */
	/*
	 * Before going any further, raise the ulimit to prevent colliding
	 * into a lowered ulimit, and set the real UID to root to protect
	 * against unexpected signals. Any keyboard signals are set to be
	 * ignored.
	 */
	pwd_init ();

#ifdef USE_PAM
	/*
	 * Don't set the real UID for PAM...
	 */
	if (!anyflag) {
		do_pam_passwd (name, qflg, kflg);
		exit (E_SUCCESS);
	}
#endif				/* USE_PAM */
	if (setuid (0) != 0) {
		fputs (_("Cannot change ID to root.\n"), stderr);
		SYSLOG ((LOG_ERR, "can't setuid(0)"));
		closelog ();
		exit (E_NOPERM);
	}
	if (spw_file_present ()) {
		update_shadow ();
	} else {
		update_noshadow ();
	}

	nscd_flush_cache ("passwd");
	nscd_flush_cache ("group");

	SYSLOG ((LOG_INFO, "password for '%s' changed by '%s'", name, myname));
	closelog ();
	if (!qflg) {
		if (!anyflag) {
#ifndef USE_PAM
			printf (_("%s: password changed.\n"), Prog);
#endif				/* USE_PAM */
		} else {
			printf (_("%s: password expiry information changed.\n"), Prog);
		}
	}

	return E_SUCCESS;
}
Exemplo n.º 10
0
/*
 * new_password - validate old password and replace with new (both old and
 * new in global "char crypt_passwd[128]")
 */
static int new_password (const struct passwd *pw)
{
	char *clear;		/* Pointer to clear text */
	char *cipher;		/* Pointer to cipher text */
	char *cp;		/* Pointer to getpass() response */
	char orig[200];		/* Original password */
	char pass[200];		/* New password */
	int i;			/* Counter for retries */
	int warned;
	int pass_max_len = -1;
	char *method;

#ifdef HAVE_LIBCRACK_HIST
	int HistUpdate (const char *, const char *);
#endif				/* HAVE_LIBCRACK_HIST */

	/*
	 * Authenticate the user. The user will be prompted for their own
	 * password.
	 */

	if (!amroot && crypt_passwd[0]) {
		clear = getpass (_("Old password: "******"incorrect password for %s",
				 pw->pw_name));
			sleep (1);
			fprintf (stderr,
				 _("Incorrect password for %s.\n"),
				 pw->pw_name);
			return -1;
		}
		STRFCPY (orig, clear);
		strzero (clear);
		strzero (cipher);
	} else {
		orig[0] = '\0';
	}

	/*
	 * Get the new password. The user is prompted for the new password
	 * and has five tries to get it right. The password will be tested
	 * for strength, unless it is the root user. This provides an escape
	 * for initial login passwords.
	 */
	if ((method = getdef_str ("ENCRYPT_METHOD")) == NULL) {
		if (!getdef_bool ("MD5_CRYPT_ENAB")) {
			pass_max_len = getdef_num ("PASS_MAX_LEN", 8);
		}
	} else {
		if (   (strcmp (method, "MD5")    == 0)
#ifdef USE_SHA_CRYPT
		    || (strcmp (method, "SHA256") == 0)
		    || (strcmp (method, "SHA512") == 0)
#endif				/* USE_SHA_CRYPT */
		    ) {
			pass_max_len = -1;
		} else {
			pass_max_len = getdef_num ("PASS_MAX_LEN", 8);
		}
	}
	if (!qflg) {
		if (pass_max_len == -1) {
			printf (_(
"Enter the new password (minimum of %d characters)\n"
"Please use a combination of upper and lower case letters and numbers.\n"),
				getdef_num ("PASS_MIN_LEN", 5));
		} else {
			printf (_(
"Enter the new password (minimum of %d, maximum of %d characters)\n"
"Please use a combination of upper and lower case letters and numbers.\n"),
				getdef_num ("PASS_MIN_LEN", 5), pass_max_len);
		}
	}

	warned = 0;
	for (i = getdef_num ("PASS_CHANGE_TRIES", 5); i > 0; i--) {
		cp = getpass (_("New password: "******"Try again."));
			continue;
		}

		/*
		 * If enabled, warn about weak passwords even if you are
		 * root (enter this password again to use it anyway). 
		 * --marekm
		 */
		if (amroot && !warned && getdef_bool ("PASS_ALWAYS_WARN")
		    && (!obscure (orig, pass, pw) || reuse (pass, pw))) {
			puts (_("\nWarning: weak password (enter it again to use it anyway)."));
			warned++;
			continue;
		}
		cp = getpass (_("Re-enter new password: "******"They don't match; try again.\n"), stderr);
		} else {
			strzero (cp);
			break;
		}
	}
	memzero (orig, sizeof orig);

	if (i == 0) {
		memzero (pass, sizeof pass);
		return -1;
	}

	/*
	 * Encrypt the password, then wipe the cleartext password.
	 */
	cp = pw_encrypt (pass, crypt_make_salt (NULL, NULL));
	memzero (pass, sizeof pass);

#ifdef HAVE_LIBCRACK_HIST
	HistUpdate (pw->pw_name, crypt_passwd);
#endif				/* HAVE_LIBCRACK_HIST */
	STRFCPY (crypt_passwd, cp);
	return 0;
}
Exemplo n.º 11
0
/*
 * process_flags - parse the command line options
 *
 *	It will not return if an error is encountered.
 */
static void process_flags (int argc, char **argv)
{
	int flag;		/* flag currently being processed    */

	/* 
	 * The remaining arguments will be processed one by one and executed
	 * by this command. The name is the last argument if it does not
	 * begin with a "-", otherwise the name is determined from the
	 * environment and must agree with the real UID. Also, the UID will
	 * be checked for any commands which are restricted to root only.
	 */
	while ((flag = getopt (argc, argv, "f:r:w:h:o:")) != EOF) {
		switch (flag) {
		case 'f':
			if (!may_change_field ('f')) {
				fprintf (stderr,
				         _("%s: Permission denied.\n"), Prog);
				exit (E_NOPERM);
			}
			fflg = true;
			STRFCPY (fullnm, optarg);
			break;
		case 'h':
			if (!may_change_field ('h')) {
				fprintf (stderr,
				         _("%s: Permission denied.\n"), Prog);
				exit (E_NOPERM);
			}
			hflg = true;
			STRFCPY (homeph, optarg);
			break;
		case 'r':
			if (!may_change_field ('r')) {
				fprintf (stderr,
				         _("%s: Permission denied.\n"), Prog);
				exit (E_NOPERM);
			}
			rflg = true;
			STRFCPY (roomno, optarg);
			break;
		case 'o':
			if (!amroot) {
				fprintf (stderr,
				         _("%s: Permission denied.\n"), Prog);
				exit (E_NOPERM);
			}
			oflg = true;
			STRFCPY (slop, optarg);
			break;
		case 'w':
			if (!may_change_field ('w')) {
				fprintf (stderr,
				         _("%s: Permission denied.\n"), Prog);
				exit (E_NOPERM);
			}
			wflg = true;
			STRFCPY (workph, optarg);
			break;
		default:
			usage ();
		}
	}
}
Exemplo n.º 12
0
Arquivo: su.c Projeto: Romutk/SPIVT1
/*
 * su - switch user id
 *
 *	su changes the user's ids to the values for the specified user.  if
 *	no new user name is specified, "root" or UID 0 is used by default.
 *
 *	Any additional arguments are passed to the user's shell. In
 *	particular, the argument "-c" will cause the next argument to be
 *	interpreted as a command by the common shell programs.
 */
int main (int argc, char **argv)
{
	const char *cp;
	const char *tty = NULL;	/* Name of tty SU is run from        */
	bool doshell = false;
	bool fakelogin = false;
	bool amroot = false;
	uid_t my_uid;
	struct passwd *pw = NULL;
	char **envp = environ;
	char *shellstr = NULL;
	char *command = NULL;

#ifdef USE_PAM
	char **envcp;
	int ret;
#else				/* !USE_PAM */
	int err = 0;

	RETSIGTYPE (*oldsig) (int);
	int is_console = 0;

	struct spwd *spwd = 0;

#ifdef SU_ACCESS
	char *oldpass;
#endif
#endif				/* !USE_PAM */

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

	change_environment = true;

	/*
	 * Get the program name. The program name is used as a prefix to
	 * most error messages.
	 */
	Prog = Basename (argv[0]);

	OPENLOG ("su");

	/*
	 * Process the command line arguments. 
	 */

	{
		/*
		 * Parse the command line options.
		 */
		int option_index = 0;
		int c;
		static struct option long_options[] = {
			{"command", required_argument, NULL, 'c'},
			{"help", no_argument, NULL, 'h'},
			{"login", no_argument, NULL, 'l'},
			{"preserve-environment", no_argument, NULL, 'p'},
			{"shell", required_argument, NULL, 's'},
			{NULL, 0, NULL, '\0'}
		};

		while ((c =
			getopt_long (argc, argv, "c:hlmps:", long_options,
				     &option_index)) != -1) {
			switch (c) {
			case 'c':
				command = optarg;
				break;
			case 'h':
				usage (E_SUCCESS);
				break;
			case 'l':
				fakelogin = true;
				break;
			case 'm':
			case 'p':
				/* This will only have an effect if the target
				 * user do not have a restricted shell, or if
				 * su is called by root.
				 */
				change_environment = false;
				break;
			case 's':
				shellstr = optarg;
				break;
			default:
				usage (E_USAGE);	/* NOT REACHED */
			}
		}

		if ((optind < argc) && (strcmp (argv[optind], "-") == 0)) {
			fakelogin = true;
			optind++;
			if (   (optind < argc)
			    && (strcmp (argv[optind], "--") == 0)) {
				optind++;
			}
		}
	}

	initenv ();

	my_uid = getuid ();
	amroot = (my_uid == 0);

	/*
	 * Get the tty name. Entries will be logged indicating that the user
	 * tried to change to the named new user from the current terminal.
	 */
	tty = ttyname (0);
	if ((isatty (0) != 0) && (NULL != tty)) {
#ifndef USE_PAM
		is_console = console (tty);
#endif
	} else {
		/*
		 * Be more paranoid, like su from SimplePAMApps.  --marekm
		 */
		if (!amroot) {
			fprintf (stderr,
			         _("%s: must be run from a terminal\n"),
			         Prog);
			exit (1);
		}
		tty = "???";
	}

	/*
	 * The next argument must be either a user ID, or some flag to a
	 * subshell. Pretty sticky since you can't have an argument which
	 * doesn't start with a "-" unless you specify the new user name.
	 * Any remaining arguments will be passed to the user's login shell.
	 */
	if ((optind < argc) && ('-' != argv[optind][0])) {
		STRFCPY (name, argv[optind++]);	/* use this login id */
		if ((optind < argc) && (strcmp (argv[optind], "--") == 0)) {
			optind++;
		}
	}
	if ('\0' == name[0]) {		/* use default user */
		struct passwd *root_pw = getpwnam ("root");
		if ((NULL != root_pw) && (0 == root_pw->pw_uid)) {
			(void) strcpy (name, "root");
		} else {
			root_pw = getpwuid (0);
			if (NULL == root_pw) {
				SYSLOG ((LOG_CRIT, "There is no UID 0 user."));
				su_failure (tty);
			}
			(void) strcpy (name, root_pw->pw_name);
		}
	}

	doshell = (argc == optind);	/* any arguments remaining? */
	if (NULL != command) {
		doshell = false;
	}

	/*
	 * Get the user's real name. The current UID is used to determine
	 * who has executed su. That user ID must exist.
	 */
	pw = get_my_pwent ();
	if (NULL == pw) {
		fprintf (stderr,
		         _("%s: Cannot determine your user name.\n"),
		         Prog);
		SYSLOG ((LOG_WARN, "Cannot determine the user name of the caller (UID %lu)",
		         (unsigned long) my_uid));
		su_failure (tty);
	}
	STRFCPY (oldname, pw->pw_name);

#ifndef USE_PAM
#ifdef SU_ACCESS
	/*
	 * Sort out the password of user calling su, in case needed later
	 * -- chris
	 */
	spwd = getspnam (oldname); /* !USE_PAM, no need for xgetspnam */
	if (NULL != spwd) {
		pw->pw_passwd = spwd->sp_pwdp;
	}
	oldpass = xstrdup (pw->pw_passwd);
#endif				/* SU_ACCESS */

#else				/* USE_PAM */
	ret = pam_start ("su", name, &conv, &pamh);
	if (PAM_SUCCESS != ret) {
		SYSLOG ((LOG_ERR, "pam_start: error %d", ret);
			fprintf (stderr,
			         _("%s: pam_start: error %d\n"),
			         Prog, ret));
		exit (1);
	}
Exemplo n.º 13
0
int
main(int argc, char **argv)
{
	struct	dialup	*dial;
	struct	dialup	dent;
	struct	stat	sb;
	FILE	*fp;
	char	*sh = 0;
	char	*cp;
	char	pass[BUFSIZ];
	int	fd;
	int	found = 0;
	int	opt;

	Prog = Basename(argv[0]);

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

	openlog(Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);

	while ((opt = getopt (argc, argv, "a:d:")) != EOF) {
		switch (opt) {
			case 'a':
				aflg++;
				sh = optarg;
				break;
			case 'd':
				dflg++;
				sh = optarg;
				break;
			default:
				usage ();
		}
	}
	if (! aflg && ! dflg)
		aflg++;

	if (! sh) {
		if (optind >= argc)
			usage ();
		else
			sh = argv[optind];
	}
	if (aflg + dflg != 1)
		usage ();

	/*
	 * Add a new shell to the password file, or update an existing
	 * entry.  Begin by getting an encrypted password for this
	 * shell.
	 */

	if (aflg) {
		int	tries = 3;

		dent.du_shell = sh;
		dent.du_passwd = "";  /* XXX warning: const */

again:
		if (! (cp = getpass(_("Shell password: "******"re-enter Shell password: "******"%s: Passwords do not match, try again.\n"),
				Prog);

			if (--tries)
				goto again;

			exit(1);
		}
		strzero(cp);
		dent.du_passwd = pw_encrypt(pass, crypt_make_salt());
		strzero(pass);
	}

	/*
	 * Create the temporary file for the updated dialup password
	 * information to be placed into.  Turn it into a (FILE *)
	 * for use by putduent().
	 */

	if ((fd = open (DTMP, O_CREAT|O_EXCL|O_RDWR, 0600)) < 0) {
		snprintf(pass, sizeof pass, _("%s: can't create %s"), Prog, DTMP);
		perror (pass);
		exit (1);
	}
	if (! (fp = fdopen (fd, "r+"))) {
		snprintf(pass, sizeof pass, _("%s: can't open %s"), Prog, DTMP);
		perror (pass);
		unlink (DTMP);
		exit (1);
	}

	/*
	 * Scan the dialup password file for the named entry,
	 * copying out other entries along the way.  Copying
	 * stops when a match is found or the file runs out.
	 */

	while ((dial = getduent ())) {
		if (strcmp (dial->du_shell, sh) == 0) {
			found = 1;
			break;
		}
		if (putduent (dial, fp))
			goto failure;
	}

	/*
	 * To delete the entry, just don't copy it.  To update
	 * the entry, output the modified version - works with
	 * new entries as well.
	 */

	if (dflg && ! found) {
		fprintf(stderr, _("%s: Shell %s not found.\n"), Prog, sh);
		goto failure;
	}
	if (aflg)
		if (putduent (&dent, fp))
			goto failure;

	/*
	 * Now copy out the remaining entries.  Flush and close the
	 * new file before doing anything nasty to the existing
	 * file.
	 */


	while ((dial = getduent ()))
		if (putduent (dial, fp))
			goto failure;

	if (fflush (fp))
		goto failure;

	fclose (fp);

	/*
	 * If the original file did not exist, we must create a new
	 * file with owner "root" and mode 400.  Otherwise we copy
	 * the modes from the existing file to the new file.
	 *
	 * After this is done the new file will replace the old file.
	 */

	pwd_init();

	if (! stat (DIALPWD, &sb)) {
		chown (DTMP, sb.st_uid, sb.st_gid);
		chmod (DTMP, sb.st_mode);
		unlink (DIALPWD);
	} else {
		chown (DTMP, 0, 0);
		chmod (DTMP, 0400);
	}
	if (! link (DTMP, DIALPWD))
		unlink (DTMP);

	if (aflg && ! found)
		SYSLOG((LOG_INFO, DIALADD, sh));
	else if (aflg && found)
		SYSLOG((LOG_INFO, DIALCHG, sh));
	else if (dflg)
		SYSLOG((LOG_INFO, DIALREM, sh));

	closelog();
	sync ();
	exit (0);

failure:
	unlink (DTMP);
	closelog();
	exit (1);
}