Пример #1
0
/*
 * add_user - create a new user ID
 */
static int add_user (const char *name, uid_t uid, gid_t gid)
{
	struct passwd pwent;

	/* Check if this is a valid user name */
	if (!is_valid_user_name (name)) {
		fprintf (stderr,
		         _("%s: invalid user name '%s'\n"),
		         Prog, name);
		return -1;
	}

	/*
	 * I don't want to fill in the entire password structure members
	 * JUST YET, since there is still more data to be added. So, I fill
	 * in the parts that I have.
	 */
	pwent.pw_name = xstrdup (name);
	pwent.pw_uid = uid;
	pwent.pw_passwd = "x";	/* XXX warning: const */
	pwent.pw_gid = gid;
	pwent.pw_gecos = "";	/* XXX warning: const */
	pwent.pw_dir = "";	/* XXX warning: const */
	pwent.pw_shell = "";	/* XXX warning: const */

	return (pw_update (&pwent) == 0) ? -1 : 0;
}
Пример #2
0
/*
 * check_pw_file - check the content of the passwd file
 */
static void check_pw_file (int *errors, bool *changed)
{
	struct commonio_entry *pfe, *tpfe;
	struct passwd *pwd;
	struct spwd *spw;

	/*
	 * Loop through the entire password file.
	 */
	for (pfe = __pw_get_head (); NULL != pfe; pfe = pfe->next) {
		/*
		 * If this is a NIS line, skip it. You can't "know" what NIS
		 * is going to do without directly asking NIS ...
		 */
		if (('+' == pfe->line[0]) || ('-' == pfe->line[0])) {
			continue;
		}

		/*
		 * Start with the entries that are completely corrupt.  They
		 * have no (struct passwd) entry because they couldn't be
		 * parsed properly.
		 */
		if (NULL == pfe->eptr) {
			/*
			 * Tell the user this entire line is bogus and ask
			 * them to delete it.
			 */
			puts (_("invalid password file entry"));
			printf (_("delete line '%s'? "), pfe->line);
			*errors += 1;

			/*
			 * prompt the user to delete the entry or not
			 */
			if (!yes_or_no (read_only)) {
				continue;
			}

			/*
			 * All password file deletions wind up here. This
			 * code removes the current entry from the linked
			 * list. When done, it skips back to the top of the
			 * loop to try out the next list element.
			 */
		      delete_pw:
			SYSLOG ((LOG_INFO, "delete passwd line '%s'",
			         pfe->line));
			*changed = true;

			__pw_del_entry (pfe);
			continue;
		}

		/*
		 * Password structure is good, start using it.
		 */
		pwd = pfe->eptr;

		/*
		 * Make sure this entry has a unique name.
		 */
		for (tpfe = __pw_get_head (); NULL != tpfe; tpfe = tpfe->next) {
			const struct passwd *ent = tpfe->eptr;

			/*
			 * Don't check this entry
			 */
			if (tpfe == pfe) {
				continue;
			}

			/*
			 * Don't check invalid entries.
			 */
			if (NULL == ent) {
				continue;
			}

			if (strcmp (pwd->pw_name, ent->pw_name) != 0) {
				continue;
			}

			/*
			 * Tell the user this entry is a duplicate of
			 * another and ask them to delete it.
			 */
			puts (_("duplicate password entry"));
			printf (_("delete line '%s'? "), pfe->line);
			*errors += 1;

			/*
			 * prompt the user to delete the entry or not
			 */
			if (yes_or_no (read_only)) {
				goto delete_pw;
			}
		}

		/*
		 * Check for invalid usernames.  --marekm
		 */
		if (!is_valid_user_name (pwd->pw_name)) {
			printf (_("invalid user name '%s'\n"), pwd->pw_name);
			*errors += 1;
		}

		/*
		 * Check for invalid user ID.
		 */
		if (pwd->pw_uid == (uid_t)-1) {
			printf (_("invalid user ID '%lu'\n"), (long unsigned int)pwd->pw_uid);
			*errors += 1;
		}

		/*
		 * Make sure the primary group exists
		 */
		/* local, no need for xgetgrgid */
		if (!quiet && (NULL == getgrgid (pwd->pw_gid))) {

			/*
			 * No primary group, just give a warning
			 */

			printf (_("user '%s': no group %lu\n"),
			        pwd->pw_name, (unsigned long) pwd->pw_gid);
			*errors += 1;
		}

		/*
		 * Make sure the home directory exists
		 */
		if (!quiet && (access (pwd->pw_dir, F_OK) != 0)) {
			/*
			 * Home directory doesn't exist, give a warning
			 */
			printf (_("user '%s': directory '%s' does not exist\n"),
			        pwd->pw_name, pwd->pw_dir);
			*errors += 1;
		}

		/*
		 * Make sure the login shell is executable
		 */
		if (   !quiet
		    && ('\0' != pwd->pw_shell[0])
		    && (access (pwd->pw_shell, F_OK) != 0)) {

			/*
			 * Login shell doesn't exist, give a warning
			 */
			printf (_("user '%s': program '%s' does not exist\n"),
			        pwd->pw_name, pwd->pw_shell);
			*errors += 1;
		}

		/*
		 * Make sure this entry exists in the /etc/shadow file.
		 */

		if (is_shadow) {
			spw = (struct spwd *) spw_locate (pwd->pw_name);
			if (NULL == spw) {
				printf (_("no matching password file entry in %s\n"),
				        spw_file);
				printf (_("add user '%s' in %s? "),
				        pwd->pw_name, spw_file);
				*errors += 1;
				if (yes_or_no (read_only)) {
					struct spwd sp;
					struct passwd pw;

					sp.sp_namp   = pwd->pw_name;
					sp.sp_pwdp   = pwd->pw_passwd;
					sp.sp_min    =
					    getdef_num ("PASS_MIN_DAYS", -1);
					sp.sp_max    =
					    getdef_num ("PASS_MAX_DAYS", -1);
					sp.sp_warn   =
					    getdef_num ("PASS_WARN_AGE", -1);
					sp.sp_inact  = -1;
					sp.sp_expire = -1;
					sp.sp_flag   = SHADOW_SP_FLAG_UNSET;
					sp.sp_lstchg = (long) time ((time_t *) 0) / SCALE;
					if (0 == sp.sp_lstchg) {
						/* Better disable aging than
						 * requiring a password change
						 */
						sp.sp_lstchg = -1;
					}
					*changed = true;

					if (spw_update (&sp) == 0) {
						fprintf (stderr,
						         _("%s: failed to prepare the new %s entry '%s'\n"),
						         Prog, spw_dbname (), sp.sp_namp);
						exit (E_CANTUPDATE);
					}
					/* remove password from /etc/passwd */
					pw = *pwd;
					pw.pw_passwd = SHADOW_PASSWD_STRING;	/* XXX warning: const */
					if (pw_update (&pw) == 0) {
						fprintf (stderr,
						         _("%s: failed to prepare the new %s entry '%s'\n"),
						         Prog, pw_dbname (), pw.pw_name);
						exit (E_CANTUPDATE);
					}
				}
			} else {
				/* The passwd entry has a shadow counterpart.
				 * Make sure no passwords are in passwd.
				 */
				if (strcmp (pwd->pw_passwd, SHADOW_PASSWD_STRING) != 0) {
					printf (_("user %s has an entry in %s, but its password field in %s is not set to 'x'\n"),
					        pwd->pw_name, spw_file, pwd_file);
					*errors += 1;
				}
			}
		}
	}
}