Beispiel #1
0
int main (int argc, char **argv)
{
	char buf[BUFSIZ];
	char *name;
	char *newpwd;
	char *cp;

#ifdef	SHADOWGRP
	const struct sgrp *sg;
	struct sgrp newsg;
#endif

	const struct group *gr;
	struct group newgr;
	int errors = 0;
	int line = 0;

	Prog = Basename (argv[0]);

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

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

	process_flags (argc, argv);

	OPENLOG ("chgpasswd");

	check_perms ();

#ifdef SHADOWGRP
	is_shadow_grp = sgr_file_present ();
#endif

	open_files ();

	/*
	 * Read each line, separating the group name from the password. The
	 * group entry for each group will be looked up in the appropriate
	 * file (gshadow or group) and the password changed.
	 */
	while (fgets (buf, (int) sizeof buf, stdin) != (char *) 0) {
		line++;
		cp = strrchr (buf, '\n');
		if (NULL != cp) {
			*cp = '\0';
		} else {
			fprintf (stderr, _("%s: line %d: line too long\n"),
			         Prog, line);
			errors++;
			continue;
		}

		/*
		 * The group's name is the first field. It is separated from
		 * the password with a ":" character which is replaced with a
		 * NUL to give the new password. The new password will then
		 * be encrypted in the normal fashion with a new salt
		 * generated, unless the '-e' is given, in which case it is
		 * assumed to already be encrypted.
		 */

		name = buf;
		cp = strchr (name, ':');
		if (NULL != cp) {
			*cp = '\0';
			cp++;
		} else {
			fprintf (stderr,
			         _("%s: line %d: missing new password\n"),
			         Prog, line);
			errors++;
			continue;
		}
		newpwd = cp;
		if (   (!eflg)
		    && (   (NULL == crypt_method)
		        || (0 != strcmp (crypt_method, "NONE")))) {
			void *arg = NULL;
			const char *salt;
			if (md5flg) {
				crypt_method = "MD5";
			}
#ifdef USE_SHA_CRYPT
			if (sflg) {
				arg = &sha_rounds;
			}
#endif
			salt = crypt_make_salt (crypt_method, arg);
			cp = pw_encrypt (newpwd, salt);
			if (NULL == cp) {
				fprintf (stderr,
				         _("%s: failed to crypt password with salt '%s': %s\n"),
				         Prog, salt, strerror (errno));
				fail_exit (1);
			}
		}

		/*
		 * Get the group file entry for this group. The group must
		 * already exist.
		 */
		gr = gr_locate (name);
		if (NULL == gr) {
			fprintf (stderr,
			         _("%s: line %d: group '%s' does not exist\n"), Prog,
			         line, name);
			errors++;
			continue;
		}
#ifdef SHADOWGRP
		if (is_shadow_grp) {
			/* The gshadow entry should be updated if the
			 * group entry has a password set to 'x'.
			 * But on the other hand, if there is already both
			 * a group and a gshadow password, it's preferable
			 * to update both.
			 */
			sg = sgr_locate (name);

			if (   (NULL == sg)
			    && (strcmp (gr->gr_passwd,
			                SHADOW_PASSWD_STRING) == 0)) {
				static char *empty = NULL;
				/* If the password is set to 'x' in
				 * group, but there are no entries in
				 * gshadow, create one.
				 */
				newsg.sg_name   = name;
				/* newsg.sg_passwd = NULL; will be set later */
				newsg.sg_adm    = ∅
				newsg.sg_mem    = dup_list (gr->gr_mem);
				sg = &newsg;
			}
		} else {
			sg = NULL;
		}
#endif

		/*
		 * The freshly encrypted new password is merged into the
		 * group's entry.
		 */
#ifdef SHADOWGRP
		if (NULL != sg) {
			newsg = *sg;
			newsg.sg_passwd = cp;
		}
		if (   (NULL == sg)
		    || (strcmp (gr->gr_passwd, SHADOW_PASSWD_STRING) != 0))
#endif
		{
			newgr = *gr;
			newgr.gr_passwd = cp;
		}

		/* 
		 * The updated group file entry is then put back and will
		 * be written to the group file later, after all the
		 * other entries have been updated as well.
		 */
#ifdef SHADOWGRP
		if (NULL != sg) {
			if (sgr_update (&newsg) == 0) {
				fprintf (stderr,
				         _("%s: line %d: failed to prepare the new %s entry '%s'\n"),
				         Prog, line, sgr_dbname (), newsg.sg_name);
				errors++;
				continue;
			}
		}
		if (   (NULL == sg)
		    || (strcmp (gr->gr_passwd, SHADOW_PASSWD_STRING) != 0))
#endif
		{
			if (gr_update (&newgr) == 0) {
				fprintf (stderr,
				         _("%s: line %d: failed to prepare the new %s entry '%s'\n"),
				         Prog, line, gr_dbname (), newgr.gr_name);
				errors++;
				continue;
			}
		}
	}

	/*
	 * Any detected errors will cause the entire set of changes to be
	 * aborted. Unlocking the group file will cause all of the
	 * changes to be ignored. Otherwise the file is closed, causing the
	 * changes to be written out all at once, and then unlocked
	 * afterwards.
	 */
	if (0 != errors) {
		fprintf (stderr,
		         _("%s: error detected, changes ignored\n"), Prog);
		fail_exit (1);
	}

	close_files ();

	nscd_flush_cache ("group");

	return (0);
}
Beispiel #2
0
static void get_group (struct group *gr)
#endif
{
	struct group const*tmpgr = NULL;
#ifdef SHADOWGRP
	struct sgrp const*tmpsg = NULL;
#endif

	if (gr_open (O_RDONLY) == 0) {
		fprintf (stderr, _("%s: cannot open %s\n"), Prog, gr_dbname ());
		SYSLOG ((LOG_WARN, "cannot open %s", gr_dbname ()));
		exit (E_NOPERM);
	}

	tmpgr = gr_locate (group);
	if (NULL == tmpgr) {
		fprintf (stderr,
		         _("%s: group '%s' does not exist in %s\n"),
		         Prog, group, gr_dbname ());
		exit (E_BAD_ARG);
	}

	*gr = *tmpgr;
	gr->gr_name = xstrdup (tmpgr->gr_name);
	gr->gr_passwd = xstrdup (tmpgr->gr_passwd);
	gr->gr_mem = dup_list (tmpgr->gr_mem);

	if (gr_close () == 0) {
		fprintf (stderr,
		         _("%s: failure while closing read-only %s\n"),
		         Prog, gr_dbname ());
		SYSLOG ((LOG_ERR,
		         "failure while closing read-only %s",
		         gr_dbname ()));
		exit (E_NOPERM);
	}

#ifdef SHADOWGRP
	if (is_shadowgrp) {
		if (sgr_open (O_RDONLY) == 0) {
			fprintf (stderr,
			         _("%s: cannot open %s\n"),
			         Prog, sgr_dbname ());
			SYSLOG ((LOG_WARN, "cannot open %s", sgr_dbname ()));
			exit (E_NOPERM);
		}
		tmpsg = sgr_locate (group);
		if (NULL != tmpsg) {
			*sg = *tmpsg;
			sg->sg_name = xstrdup (tmpsg->sg_name);
			sg->sg_passwd = xstrdup (tmpsg->sg_passwd);

			sg->sg_mem = dup_list (tmpsg->sg_mem);
			sg->sg_adm = dup_list (tmpsg->sg_adm);
		} else {
			sg->sg_name = xstrdup (group);
			sg->sg_passwd = gr->gr_passwd;
			gr->gr_passwd = SHADOW_PASSWD_STRING;	/* XXX warning: const */

			sg->sg_mem = dup_list (gr->gr_mem);

			sg->sg_adm = (char **) xmalloc (sizeof (char *) * 2);
#ifdef FIRST_MEMBER_IS_ADMIN
			if (sg->sg_mem[0]) {
				sg->sg_adm[0] = xstrdup (sg->sg_mem[0]);
				sg->sg_adm[1] = NULL;
			} else
#endif
			{
				sg->sg_adm[0] = NULL;
			}

		}
		if (sgr_close () == 0) {
			fprintf (stderr,
			         _("%s: failure while closing read-only %s\n"),
			         Prog, sgr_dbname ());
			SYSLOG ((LOG_ERR,
			         "failure while closing read-only %s",
			         sgr_dbname ()));
			exit (E_NOPERM);
		}
	}
#endif				/* SHADOWGRP */
}
Beispiel #3
0
/*
 * add_group - create a new group or add a user to an existing group
 */
static int add_group (const char *name, const char *gid, gid_t *ngid, uid_t uid)
{
	const struct group *grp;
	struct group grent;
	char *members[1];
#ifdef SHADOWGRP
	const struct sgrp *sg;
#endif

	/*
	 * Start by seeing if the named group already exists. This will be
	 * very easy to deal with if it does.
	 */
	grp = getgrnam (gid);
	if (NULL == grp) {
		grp = gr_locate (gid);
	}
	if (NULL != grp) {
		/* The user will use this ID for her primary group */
		*ngid = grp->gr_gid;
		/* Don't check gshadow */
		return 0;
	}

	if (isdigit (gid[0])) {
		/*
		 * The GID is a number, which means either this is a brand
		 * new group, or an existing group.
		 */

		if (get_gid (gid, &grent.gr_gid) == 0) {
			fprintf (stderr,
			         _("%s: invalid group ID '%s'\n"),
			         Prog, gid);
			return -1;
		}

		/* Look in both the system database (getgrgid) and in the
		 * internal database (gr_locate_gid), which may contain
		 * uncommitted changes */
		if (   (getgrgid ((gid_t) grent.gr_gid) != NULL)
		    || (gr_locate_gid ((gid_t) grent.gr_gid) != NULL)) {
			/* The user will use this ID for her
			 * primary group */
			*ngid = (gid_t) grent.gr_gid;
			return 0;
		}

		/* Do not create groups with GID == (gid_t)-1 */
		if (grent.gr_gid == (gid_t)-1) {
			fprintf (stderr,
			         _("%s: invalid group ID '%s'\n"),
			         Prog, gid);
			return -1;
		}
	} else {
		/* The gid parameter can be "" or a name which is not
		 * already the name of an existing group.
		 * In both cases, figure out what group ID can be used.
		 */
		if (find_new_gid(rflg, &grent.gr_gid, &uid) < 0) {
			return -1;
		}
	}

	/*
	 * Now I have all of the fields required to create the new group.
	 */
	if (('\0' != gid[0]) && (!isdigit (gid[0]))) {
		grent.gr_name = xstrdup (gid);
	} else {
		grent.gr_name = xstrdup (name);
/* FIXME: check if the group exists */
	}

	/* Check if this is a valid group name */
	if (!is_valid_group_name (grent.gr_name)) {
		fprintf (stderr,
		         _("%s: invalid group name '%s'\n"),
		         Prog, grent.gr_name);
		if (grent.gr_name)
			free (grent.gr_name);
		return -1;
	}

	grent.gr_passwd = "*";	/* XXX warning: const */
	members[0] = NULL;
	grent.gr_mem = members;

	*ngid = grent.gr_gid;

#ifdef SHADOWGRP
	if (is_shadow_grp) {
		sg = sgr_locate (grent.gr_name);

		if (NULL != sg) {
			fprintf (stderr,
			         _("%s: group '%s' is a shadow group, but does not exist in /etc/group\n"),
			         Prog, grent.gr_name);
			return -1;
		}
	}
#endif

#ifdef SHADOWGRP
	if (is_shadow_grp) {
		struct sgrp sgrent;
		char *admins[1];
		sgrent.sg_name = grent.gr_name;
		sgrent.sg_passwd = "*";	/* XXX warning: const */
		grent.gr_passwd  = "x";	/* XXX warning: const */
		admins[0] = NULL;
		sgrent.sg_adm = admins;
		sgrent.sg_mem = members;

		if (sgr_update (&sgrent) == 0) {
			return -1;
		}
	}
#endif

	if (gr_update (&grent) == 0) {
		return -1;
	}

	return 0;
}
Beispiel #4
0
/*
 * check_sgr_file - check the content of the shadowed group file (gshadow)
 */
static void check_sgr_file (int *errors, bool *changed)
{
	struct group *grp;
	struct commonio_entry *sge, *tsge;
	struct sgrp *sgr;

	/*
	 * Loop through the entire shadow group file.
	 */
	for (sge = __sgr_get_head (); NULL != sge; sge = sge->next) {

		/*
		 * Start with the entries that are completely corrupt. They
		 * have no (struct sgrp) entry because they couldn't be
		 * parsed properly.
		 */
		if (NULL == sge->eptr) {

			/*
			 * Tell the user this entire line is bogus and ask
			 * them to delete it.
			 */
			(void) puts (_("invalid shadow group file entry"));
			printf (_("delete line '%s'? "), sge->line);
			*errors += 1;

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

			/*
			 * All shadow group 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_sg:
			SYSLOG ((LOG_INFO, "delete shadow line '%s'",
			         sge->line));
			*changed = true;

			__sgr_del_entry (sge);
			continue;
		}

		/*
		 * Shadow group structure is good, start using it.
		 */
		sgr = sge->eptr;

		/*
		 * Make sure this entry has a unique name.
		 */
		for (tsge = __sgr_get_head (); NULL != tsge; tsge = tsge->next) {

			const struct sgrp *ent = tsge->eptr;

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

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

			if (strcmp (sgr->sg_name, ent->sg_name) != 0) {
				continue;
			}

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

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

		/*
		 * Make sure this entry exists in the /etc/group file.
		 */
		grp = (struct group *) gr_locate (sgr->sg_name);
		if (grp == NULL) {
			printf (_("no matching group file entry in %s\n"),
			        grp_file);
			printf (_("delete line '%s'? "), sge->line);
			*errors += 1;
			if (yes_or_no (read_only)) {
				goto delete_sg;
			}
		} else {
			/**
			 * Verify that the all members defined in /etc/gshadow are also
			 * present in /etc/group.
			 */
			compare_members_lists (sgr->sg_name,
			                       sgr->sg_mem, grp->gr_mem,
			                       sgr_file, grp_file);
		}

		/*
		 * Make sure each administrator exists
		 */
		if (check_members (sgr->sg_name, sgr->sg_adm,
		                   _("shadow group %s: no administrative user %s\n"),
		                   _("delete administrative member '%s'? "),
		                   "delete admin '%s' from shadow group '%s'",
		                   errors) == 1) {
			*changed = true;
			sge->changed = true;
			__sgr_set_changed ();
		}

		/*
		 * Make sure each member exists
		 */
		if (check_members (sgr->sg_name, sgr->sg_mem,
		                   _("shadow group %s: no user %s\n"),
		                   _("delete member '%s'? "),
		                   "delete member '%s' from shadow group '%s'",
		                   errors) == 1) {
			*changed = true;
			sge->changed = true;
			__sgr_set_changed ();
		}
	}
}
Beispiel #5
0
/*
 * grp_update - update group file entries
 *
 *	grp_update() updates the new records in the memory databases.
 */
static void grp_update (void)
{
	struct group grp;
	const struct group *ogrp;

#ifdef	SHADOWGRP
	struct sgrp sgrp;
	const struct sgrp *osgrp = NULL;
#endif				/* SHADOWGRP */

	/*
	 * Get the current settings for this group.
	 */
	ogrp = gr_locate (group_name);
	if (!ogrp) {
		fprintf (stderr,
		         _("%s: group '%s' does not exist in %s\n"),
		         Prog, group_name, gr_dbname ());
		exit (E_GRP_UPDATE);
	}
	grp = *ogrp;
	new_grent (&grp);
#ifdef	SHADOWGRP
	if (   is_shadow_grp
	    && (pflg || nflg)) {
		osgrp = sgr_locate (group_name);
		if (NULL != osgrp) {
			sgrp = *osgrp;
			new_sgent (&sgrp);
			if (pflg) {
				grp.gr_passwd = SHADOW_PASSWD_STRING;
			}
		}
	}
#endif				/* SHADOWGRP */

	if (gflg) {
		update_primary_groups (ogrp->gr_gid, group_newid);
	}

	/*
	 * Write out the new group file entry.
	 */
	if (gr_update (&grp) == 0) {
		fprintf (stderr,
		         _("%s: failed to prepare the new %s entry '%s'\n"),
		         Prog, gr_dbname (), grp.gr_name);
		exit (E_GRP_UPDATE);
	}
	if (nflg && (gr_remove (group_name) == 0)) {
		fprintf (stderr,
		         _("%s: cannot remove entry '%s' from %s\n"),
		         Prog, grp.gr_name, gr_dbname ());
		exit (E_GRP_UPDATE);
	}
#ifdef	SHADOWGRP

	/*
	 * Make sure there was a shadow entry to begin with.
	 */
	if (   (NULL != osgrp)
	    && (pflg || nflg)) {
		/*
		 * Write out the new shadow group entries as well.
		 */
		if (sgr_update (&sgrp) == 0) {
			fprintf (stderr,
			         _("%s: failed to prepare the new %s entry '%s'\n"),
			         Prog, sgr_dbname (), sgrp.sg_name);
			exit (E_GRP_UPDATE);
		}
		if (nflg && (sgr_remove (group_name) == 0)) {
			fprintf (stderr,
			         _("%s: cannot remove entry '%s' from %s\n"),
			         Prog, group_name, sgr_dbname ());
			exit (E_GRP_UPDATE);
		}
	}
#endif				/* SHADOWGRP */
}
Beispiel #6
0
/*
 * grp_update - update group file entries
 *
 *	grp_update() updates the new records in the memory databases.
 */
static void grp_update (void)
{
	struct group grp;
	const struct group *ogrp;

#ifdef	SHADOWGRP
	struct sgrp sgrp;
	const struct sgrp *osgrp = NULL;
#endif				/* SHADOWGRP */

	/*
	 * Get the current settings for this group.
	 */
	ogrp = gr_locate (group_name);
	if (NULL == ogrp) {
		fprintf (stderr,
		         _("%s: group '%s' does not exist in %s\n"),
		         Prog, group_name, gr_dbname ());
		exit (E_GRP_UPDATE);
	}
	grp = *ogrp;
	new_grent (&grp);
#ifdef	SHADOWGRP
	if (   is_shadow_grp
	    && (pflg || nflg)) {
		osgrp = sgr_locate (group_name);
		if (NULL != osgrp) {
			sgrp = *osgrp;
			new_sgent (&sgrp);
		} else if (   pflg
		           && (strcmp (grp.gr_passwd, SHADOW_PASSWD_STRING) == 0)) {
			static char *empty = NULL;
			/* If there is a gshadow file with no entries for
			 * the group, but the group file indicates a
			 * shadowed password, we force the creation of a
			 * gshadow entry when a new password is requested.
			 */
			memset (&sgrp, 0, sizeof sgrp);
			sgrp.sg_name   = xstrdup (grp.gr_name);
			sgrp.sg_passwd = xstrdup (grp.gr_passwd);
			sgrp.sg_adm    = &empty;
			sgrp.sg_mem    = dup_list (grp.gr_mem);
			new_sgent (&sgrp);
			osgrp = &sgrp; /* entry needs to be committed */
		}
	}
#endif				/* SHADOWGRP */

	if (gflg) {
		update_primary_groups (ogrp->gr_gid, group_newid);
	}

	/*
	 * Write out the new group file entry.
	 */
	if (gr_update (&grp) == 0) {
		fprintf (stderr,
		         _("%s: failed to prepare the new %s entry '%s'\n"),
		         Prog, gr_dbname (), grp.gr_name);
		exit (E_GRP_UPDATE);
	}
	if (nflg && (gr_remove (group_name) == 0)) {
		fprintf (stderr,
		         _("%s: cannot remove entry '%s' from %s\n"),
		         Prog, grp.gr_name, gr_dbname ());
		exit (E_GRP_UPDATE);
	}

#ifdef	SHADOWGRP
	/*
	 * Make sure there was a shadow entry to begin with.
	 */
	if (NULL != osgrp) {
		/*
		 * Write out the new shadow group entries as well.
		 */
		if (sgr_update (&sgrp) == 0) {
			fprintf (stderr,
			         _("%s: failed to prepare the new %s entry '%s'\n"),
			         Prog, sgr_dbname (), sgrp.sg_name);
			exit (E_GRP_UPDATE);
		}
		if (nflg && (sgr_remove (group_name) == 0)) {
			fprintf (stderr,
			         _("%s: cannot remove entry '%s' from %s\n"),
			         Prog, group_name, sgr_dbname ());
			exit (E_GRP_UPDATE);
		}
	}
#endif				/* SHADOWGRP */
}
Beispiel #7
0
/*
 * remove_usergroup - delete the user's group if it is a usergroup
 *
 *	An usergroup is removed if
 *	  + it has the same name as the user
 *	  + it is the primary group of the user
 *	  + it has no other members
 *	  + it is not the primary group of any other user
 */
static void remove_usergroup (void)
{
	const struct group *grp;
	const struct passwd *pwd = NULL;

	grp = gr_locate (user_name);
	if (NULL == grp) {
		/* This user has no usergroup. */
		return;
	}

	if (grp->gr_gid != user_gid) {
		fprintf (stderr,
		         _("%s: group %s not removed because it is not the primary group of user %s.\n"),
		         Prog, grp->gr_name, user_name);
		return;
	}

	if (NULL != grp->gr_mem[0]) {
		/* The usergroup has other members. */
		fprintf (stderr,
		         _("%s: group %s not removed because it has other members.\n"),
		         Prog, grp->gr_name);
		return;
	}

	if (!fflg) {
		/*
		 * Scan the passwd file to check if this group is still
		 * used as a primary group.
		 */
		setpwent ();
		while ((pwd = getpwent ()) != NULL) {
			if (strcmp (pwd->pw_name, user_name) == 0) {
				continue;
			}
			if (pwd->pw_gid == grp->gr_gid) {
				fprintf (stderr,
				         _("%s: group %s is the primary group of another user and is not removed.\n"),
				         Prog, grp->gr_name);
				break;
			}
		}
		endpwent ();
	}

	if (NULL == pwd) {
		/*
		 * We can remove this group, it is not the primary
		 * group of any remaining user.
		 */
		if (gr_remove (user_name) == 0) {
			fprintf (stderr,
			         _("%s: cannot remove entry '%s' from %s\n"),
			         Prog, user_name, gr_dbname ());
			fail_exit (E_GRP_UPDATE);
		}

#ifdef WITH_AUDIT
		audit_logger (AUDIT_DEL_GROUP, Prog,
		              "deleting group",
		              user_name, AUDIT_NO_ID,
		              SHADOW_AUDIT_SUCCESS);
#endif				/* WITH_AUDIT */
		SYSLOG ((LOG_INFO,
		         "removed group '%s' owned by '%s'\n",
		         user_name, user_name));

#ifdef	SHADOWGRP
		if (sgr_locate (user_name) != NULL) {
			if (sgr_remove (user_name) == 0) {
				fprintf (stderr,
				         _("%s: cannot remove entry '%s' from %s\n"),
				         Prog, user_name, sgr_dbname ());
				fail_exit (E_GRP_UPDATE);
			}
#ifdef WITH_AUDIT
			audit_logger (AUDIT_DEL_GROUP, Prog,
			              "deleting shadow group",
			              user_name, AUDIT_NO_ID,
			              SHADOW_AUDIT_SUCCESS);
#endif				/* WITH_AUDIT */
			SYSLOG ((LOG_INFO,
			         "removed shadow group '%s' owned by '%s'\n",
			         user_name, user_name));

		}
#endif				/* SHADOWGRP */
	}
}
Beispiel #8
0
int main (int argc, char **argv)
{
	const struct group *gr;
	struct group grent;
	const struct sgrp *sg;
	struct sgrp sgent;

	Prog = Basename (argv[0]);

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

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

	OPENLOG ("grpconv");

	process_flags (argc, argv);

	if (gr_lock () == 0) {
		fprintf (stderr,
		         _("%s: cannot lock %s; try again later.\n"),
		         Prog, gr_dbname ());
		fail_exit (5);
	}
	gr_locked = true;
	if (gr_open (O_CREAT | O_RDWR) == 0) {
		fprintf (stderr, _("%s: cannot open %s\n"), Prog, gr_dbname ());
		fail_exit (1);
	}

	if (sgr_lock () == 0) {
		fprintf (stderr,
		         _("%s: cannot lock %s; try again later.\n"),
		         Prog, sgr_dbname ());
		fail_exit (5);
	}
	sgr_locked = true;
	if (sgr_open (O_CREAT | O_RDWR) == 0) {
		fprintf (stderr, _("%s: cannot open %s\n"), Prog, sgr_dbname ());
		fail_exit (1);
	}

	/*
	 * Remove /etc/gshadow entries for groups not in /etc/group.
	 */
	(void) sgr_rewind ();
	while ((sg = sgr_next ()) != NULL) {
		if (gr_locate (sg->sg_name) != NULL) {
			continue;
		}

		if (sgr_remove (sg->sg_name) == 0) {
			/*
			 * This shouldn't happen (the entry exists) but...
			 */
			fprintf (stderr,
			         _("%s: cannot remove entry '%s' from %s\n"),
			         Prog, sg->sg_name, sgr_dbname ());
			fail_exit (3);
		}
	}

	/*
	 * Update shadow group passwords if non-shadow password is not "x".
	 * Add any missing shadow group entries.
	 */
	(void) gr_rewind ();
	while ((gr = gr_next ()) != NULL) {
		sg = sgr_locate (gr->gr_name);
		if (NULL != sg) {
			/* update existing shadow group entry */
			sgent = *sg;
			if (strcmp (gr->gr_passwd, SHADOW_PASSWD_STRING) != 0)
				sgent.sg_passwd = gr->gr_passwd;
		} else {
			static char *empty = 0;

			/* add new shadow group entry */
			memset (&sgent, 0, sizeof sgent);
			sgent.sg_name = gr->gr_name;
			sgent.sg_passwd = gr->gr_passwd;
			sgent.sg_adm = &empty;
		}
		/*
		 * XXX - sg_mem is redundant, it is currently always a copy
		 * of gr_mem. Very few programs actually use sg_mem, and all
		 * of them are in the shadow suite. Maybe this field could
		 * be used for something else? Any suggestions?
		 */
		sgent.sg_mem = gr->gr_mem;

		if (sgr_update (&sgent) == 0) {
			fprintf (stderr,
			         _("%s: failed to prepare the new %s entry '%s'\n"),
			         Prog, sgr_dbname (), sgent.sg_name);
			fail_exit (3);
		}
		/* remove password from /etc/group */
		grent = *gr;
		grent.gr_passwd = SHADOW_PASSWD_STRING;	/* XXX warning: const */
		if (gr_update (&grent) == 0) {
			fprintf (stderr,
			         _("%s: failed to prepare the new %s entry '%s'\n"),
			         Prog, gr_dbname (), grent.gr_name);
			fail_exit (3);
		}
	}

	if (sgr_close () == 0) {
		fprintf (stderr,
		         _("%s: failure while writing changes to %s\n"),
		         Prog, sgr_dbname ());
		SYSLOG ((LOG_ERR, "failure while writing changes to %s", sgr_dbname ()));
		fail_exit (3);
	}
	if (gr_close () == 0) {
		fprintf (stderr,
		         _("%s: failure while writing changes to %s\n"),
		         Prog, gr_dbname ());
		SYSLOG ((LOG_ERR, "failure while writing changes to %s", gr_dbname ()));
		fail_exit (3);
	}
	if (sgr_unlock () == 0) {
		fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sgr_dbname ());
		SYSLOG ((LOG_ERR, "failed to unlock %s", sgr_dbname ()));
		/* continue */
	}
	if (gr_unlock () == 0) {
		fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, gr_dbname ());
		SYSLOG ((LOG_ERR, "failed to unlock %s", gr_dbname ()));
		/* continue */
	}

	nscd_flush_cache ("group");

	return 0;
}
Beispiel #9
0
/*
 * grpck - verify group file integrity
 */
int main (int argc, char **argv)
{
    int arg;
    int errors = 0;
    int deleted = 0;
    int i;
    struct commonio_entry *gre, *tgre;
    struct group *grp;
    int sort_mode = 0;

#ifdef	SHADOWGRP
    struct commonio_entry *sge, *tsge;
    struct sgrp *sgr;
    int is_shadow = 0;
#endif

    /*
     * Get my name so that I can use it to report errors.
     */
    Prog = Basename (argv[0]);

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

    OPENLOG ("grpck");

    /*
     * Parse the command line arguments
     */
    while ((arg = getopt (argc, argv, "qrs")) != EOF) {
        switch (arg) {
        case 'q':
            /* quiet - ignored for now */
            break;
        case 'r':
            read_only = 1;
            break;
        case 's':
            sort_mode = 1;
            break;
        default:
            usage ();
        }
    }

    if (sort_mode && read_only) {
        fprintf (stderr, _("%s: -s and -r are incompatibile\n"), Prog);
        exit (E_USAGE);
    }

    /*
     * Make certain we have the right number of arguments
     */
#ifdef	SHADOWGRP
    if (optind != argc && optind + 1 != argc && optind + 2 != argc)
#else
    if (optind != argc && optind + 1 != argc)
#endif
        usage ();

    /*
     * If there are two left over filenames, use those as the group and
     * group password filenames.
     */
    if (optind != argc) {
        grp_file = argv[optind];
        gr_name (grp_file);
    }
#ifdef	SHADOWGRP
    if (optind + 2 == argc) {
        sgr_file = argv[optind + 1];
        sgr_name (sgr_file);
        is_shadow = 1;
    } else if (optind == argc)
        is_shadow = sgr_file_present ();
#endif

    /*
     * Lock the files if we aren't in "read-only" mode
     */
    if (!read_only) {
        if (!gr_lock ()) {
            fprintf (stderr, _("%s: cannot lock file %s\n"),
                     Prog, grp_file);
            if (optind == argc)
                SYSLOG ((LOG_WARN, "cannot lock %s", grp_file));
            closelog ();
            exit (E_CANT_LOCK);
        }
#ifdef	SHADOWGRP
        if (is_shadow && !sgr_lock ()) {
            fprintf (stderr, _("%s: cannot lock file %s\n"),
                     Prog, sgr_file);
            if (optind == argc)
                SYSLOG ((LOG_WARN, "cannot lock %s", sgr_file));
            closelog ();
            exit (E_CANT_LOCK);
        }
#endif
    }

    /*
     * Open the files. Use O_RDONLY if we are in read_only mode,
     * O_RDWR otherwise.
     */
    if (!gr_open (read_only ? O_RDONLY : O_RDWR)) {
        fprintf (stderr, _("%s: cannot open file %s\n"), Prog,
                 grp_file);
        if (optind == argc)
            SYSLOG ((LOG_WARN, "cannot open %s", grp_file));
        closelog ();
        exit (E_CANT_OPEN);
    }
#ifdef	SHADOWGRP
    if (is_shadow && !sgr_open (read_only ? O_RDONLY : O_RDWR)) {
        fprintf (stderr, _("%s: cannot open file %s\n"), Prog,
                 sgr_file);
        if (optind == argc)
            SYSLOG ((LOG_WARN, "cannot open %s", sgr_file));
        closelog ();
        exit (E_CANT_OPEN);
    }
#endif

    if (sort_mode) {
        gr_sort ();
#ifdef	SHADOWGRP
        if (is_shadow)
            sgr_sort ();
#endif
        goto write_and_bye;
    }

    /*
     * Loop through the entire group file.
     */
    for (gre = __gr_get_head (); gre; gre = gre->next) {
        /*
         * Skip all NIS entries.
         */

        if (gre->line[0] == '+' || gre->line[0] == '-')
            continue;

        /*
         * Start with the entries that are completely corrupt. They
         * have no (struct group) entry because they couldn't be
         * parsed properly.
         */
        if (!gre->eptr) {

            /*
             * Tell the user this entire line is bogus and ask
             * them to delete it.
             */
            printf (_("invalid group file entry\n"));
            printf (_("delete line `%s'? "), gre->line);
            errors++;

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

            /*
             * All group 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_gr:
            SYSLOG ((LOG_INFO, "delete group line `%s'",
                     gre->line));
            deleted++;

            __gr_del_entry (gre);
            continue;
        }

        /*
         * Group structure is good, start using it.
         */
        grp = gre->eptr;

        /*
         * Make sure this entry has a unique name.
         */
        for (tgre = __gr_get_head (); tgre; tgre = tgre->next) {

            const struct group *ent = tgre->eptr;

            /*
             * Don't check this entry
             */
            if (tgre == gre)
                continue;

            /*
             * Don't check invalid entries.
             */
            if (!ent)
                continue;

            if (strcmp (grp->gr_name, ent->gr_name) != 0)
                continue;

            /*
             * Tell the user this entry is a duplicate of
             * another and ask them to delete it.
             */
            printf (_("duplicate group entry\n"));
            printf (_("delete line `%s'? "), gre->line);
            errors++;

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

        /*
         * Check for invalid group names.  --marekm
         */
        if (!check_group_name (grp->gr_name)) {
            errors++;
            printf (_("invalid group name `%s'\n"), grp->gr_name);
        }

        /*
         * Workaround for a NYS libc 5.3.12 bug on RedHat 4.2 -
         * groups with no members are returned as groups with one
         * member "", causing grpck to fail.  --marekm
         */
        if (grp->gr_mem[0] && !grp->gr_mem[1]
                && *(grp->gr_mem[0]) == '\0')
            grp->gr_mem[0] = (char *) 0;

        /*
         * Make sure each member exists
         */
        for (i = 0; grp->gr_mem[i]; i++) {
            if (getpwnam (grp->gr_mem[i]))
                continue;
            /*
             * Can't find this user. Remove them
             * from the list.
             */
            errors++;
            printf (_("group %s: no user %s\n"),
                    grp->gr_name, grp->gr_mem[i]);
            printf (_("delete member `%s'? "), grp->gr_mem[i]);

            if (!yes_or_no ())
                continue;

            SYSLOG ((LOG_INFO, "delete member `%s' group `%s'",
                     grp->gr_mem[i], grp->gr_name));
            deleted++;
            delete_member (grp->gr_mem, grp->gr_mem[i]);
            gre->changed = 1;
            __gr_set_changed ();
        }
    }

#ifdef	SHADOWGRP
    if (!is_shadow)
        goto shadow_done;

    /*
     * Loop through the entire shadow group file.
     */
    for (sge = __sgr_get_head (); sge; sge = sge->next) {

        /*
         * Start with the entries that are completely corrupt. They
         * have no (struct sgrp) entry because they couldn't be
         * parsed properly.
         */
        if (!sge->eptr) {

            /*
             * Tell the user this entire line is bogus and ask
             * them to delete it.
             */
            printf (_("invalid shadow group file entry\n"));
            printf (_("delete line `%s'? "), sge->line);
            errors++;

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

            /*
             * All shadow group 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_sg:
            SYSLOG ((LOG_INFO, "delete shadow line `%s'",
                     sge->line));
            deleted++;

            __sgr_del_entry (sge);
            continue;
        }

        /*
         * Shadow group structure is good, start using it.
         */
        sgr = sge->eptr;

        /*
         * Make sure this entry has a unique name.
         */
        for (tsge = __sgr_get_head (); tsge; tsge = tsge->next) {

            const struct sgrp *ent = tsge->eptr;

            /*
             * Don't check this entry
             */
            if (tsge == sge)
                continue;

            /*
             * Don't check invalid entries.
             */
            if (!ent)
                continue;

            if (strcmp (sgr->sg_name, ent->sg_name) != 0)
                continue;

            /*
             * Tell the user this entry is a duplicate of
             * another and ask them to delete it.
             */
            printf (_("duplicate shadow group entry\n"));
            printf (_("delete line `%s'? "), sge->line);
            errors++;

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

        /*
         * Make sure this entry exists in the /etc/group file.
         */
        if (!gr_locate (sgr->sg_name)) {
            printf (_("no matching group file entry\n"));
            printf (_("delete line `%s'? "), sge->line);
            errors++;
            if (yes_or_no ())
                goto delete_sg;
        }

        /*
         * Make sure each administrator exists
         */
        for (i = 0; sgr->sg_adm[i]; i++) {
            if (getpwnam (sgr->sg_adm[i]))
                continue;
            /*
             * Can't find this user. Remove them
             * from the list.
             */
            errors++;
            printf (_
                    ("shadow group %s: no administrative user %s\n"),
                    sgr->sg_name, sgr->sg_adm[i]);
            printf (_("delete administrative member `%s'? "),
                    sgr->sg_adm[i]);

            if (!yes_or_no ())
                continue;

            SYSLOG ((LOG_INFO,
                     "delete admin `%s' from shadow group `%s'",
                     sgr->sg_adm[i], sgr->sg_name));
            deleted++;
            delete_member (sgr->sg_adm, sgr->sg_adm[i]);
            sge->changed = 1;
            __sgr_set_changed ();
        }

        /*
         * Make sure each member exists
         */
        for (i = 0; sgr->sg_mem[i]; i++) {
            if (getpwnam (sgr->sg_mem[i]))
                continue;

            /*
             * Can't find this user. Remove them from the list.
             */
            errors++;
            printf (_("shadow group %s: no user %s\n"),
                    sgr->sg_name, sgr->sg_mem[i]);
            printf (_("delete member `%s'? "), sgr->sg_mem[i]);

            if (!yes_or_no ())
                continue;

            SYSLOG ((LOG_INFO,
                     "delete member `%s' from shadow group `%s'",
                     sgr->sg_mem[i], sgr->sg_name));
            deleted++;
            delete_member (sgr->sg_mem, sgr->sg_mem[i]);
            sge->changed = 1;
            __sgr_set_changed ();
        }
    }

shadow_done:
#endif				/* SHADOWGRP */

    /*
     * All done. If there were no deletions we can just abandon any
     * changes to the files.
     */
    if (deleted) {
write_and_bye:
        if (!gr_close ()) {
            fprintf (stderr, _("%s: cannot update file %s\n"),
                     Prog, grp_file);
            exit (E_CANT_UPDATE);
        }
#ifdef	SHADOWGRP
        if (is_shadow && !sgr_close ()) {
            fprintf (stderr, _("%s: cannot update file %s\n"),
                     Prog, sgr_file);
            exit (E_CANT_UPDATE);
        }
#endif
    }

    /*
     * Don't be anti-social - unlock the files when you're done.
     */
#ifdef	SHADOWGRP
    if (is_shadow)
        sgr_unlock ();
#endif
    (void) gr_unlock ();

    nscd_flush_cache ("group");

    /*
     * Tell the user what we did and exit.
     */
    if (errors)
        printf (deleted ?
                _("%s: the files have been updated\n") :
                _("%s: no changes\n"), Prog);

    exit (errors ? E_BAD_ENTRY : E_OKAY);
}