X-Git-Url: https://git.cameronkatri.com/pw-darwin.git/blobdiff_plain/0f2cd15af6b03e178b23fdd07c57c6775fb28cb8..c8d02e06b734db2f87942aa323b6004b52b8022f:/pw/pw_group.c?ds=sidebyside

diff --git a/pw/pw_group.c b/pw/pw_group.c
index 10e8675..b20ce88 100644
--- a/pw/pw_group.c
+++ b/pw/pw_group.c
@@ -32,12 +32,18 @@ static const char rcsid[] =
 #include <ctype.h>
 #include <err.h>
 #include <termios.h>
+#include <stdbool.h>
 #include <unistd.h>
+#include <grp.h>
+#include <libutil.h>
 
 #include "pw.h"
 #include "bitmap.h"
 
 
+static struct passwd *lookup_pwent(const char *user);
+static void	delete_members(char ***members, int *grmembers, int *i,
+    struct carg *arg, struct group *grp);
 static int      print_group(struct group * grp, int pretty);
 static gid_t    gr_gidpolicy(struct userconf * cnf, struct cargs * args);
 
@@ -45,6 +51,7 @@ int
 pw_group(struct userconf * cnf, int mode, struct cargs * args)
 {
 	int		rc;
+	struct carg    *a_newname = getarg(args, 'l');
 	struct carg    *a_name = getarg(args, 'n');
 	struct carg    *a_gid = getarg(args, 'g');
 	struct carg    *arg;
@@ -60,6 +67,11 @@ pw_group(struct userconf * cnf, int mode, struct cargs * args)
 		NULL
 	};
 
+	if (a_gid != NULL) {
+		if (strspn(a_gid->val, "0123456789") != strlen(a_gid->val))
+			errx(EX_USAGE, "-g expects a number");
+	}
+
 	if (mode == M_LOCK || mode == M_UNLOCK)
 		errx(EX_USAGE, "'lock' command is not available for groups");
 
@@ -134,8 +146,8 @@ pw_group(struct userconf * cnf, int mode, struct cargs * args)
 		if (a_gid)
 			grp->gr_gid = (gid_t) atoi(a_gid->val);
 
-		if ((arg = getarg(args, 'l')) != NULL)
-			grp->gr_name = pw_checkname((u_char *)arg->val, 0);
+		if (a_newname != NULL)
+			grp->gr_name = pw_checkname((u_char *)a_newname->val, 0);
 	} else {
 		if (a_name == NULL)	/* Required */
 			errx(EX_DATAERR, "group name required");
@@ -207,36 +219,42 @@ pw_group(struct userconf * cnf, int mode, struct cargs * args)
 		}
 	}
 
-	if (((arg = getarg(args, 'M')) != NULL || (arg = getarg(args, 'm')) != NULL) && arg->val) {
+	if (((arg = getarg(args, 'M')) != NULL ||
+	    (arg = getarg(args, 'd')) != NULL ||
+	    (arg = getarg(args, 'm')) != NULL) && arg->val) {
 		int	i = 0;
 		char   *p;
 		struct passwd	*pwd;
 
 		/* Make sure this is not stay NULL with -M "" */
 		extendarray(&members, &grmembers, 200);
-		if (arg->ch == 'm') {
+		if (arg->ch == 'd')
+			delete_members(&members, &grmembers, &i, arg, grp);
+		else if (arg->ch == 'm') {
 			int	k = 0;
 
-			while (grp->gr_mem[k] != NULL) {
-				if (extendarray(&members, &grmembers, i + 2) != -1)
-					members[i++] = grp->gr_mem[k];
-				k++;
+			if (grp->gr_mem != NULL) {
+				while (grp->gr_mem[k] != NULL) {
+					if (extendarray(&members, &grmembers, i + 2) != -1)
+						members[i++] = grp->gr_mem[k];
+					k++;
+				}
 			}
 		}
-		for (p = strtok(arg->val, ", \t"); p != NULL; p = strtok(NULL, ", \t")) {
-			int     j;
-			if ((pwd = GETPWNAM(p)) == NULL) {
-				if (!isdigit((unsigned char)*p) || (pwd = getpwuid((uid_t) atoi(p))) == NULL)
-					errx(EX_NOUSER, "user `%s' does not exist", p);
+
+		if (arg->ch != 'd')
+			for (p = strtok(arg->val, ", \t"); p != NULL; p = strtok(NULL, ", \t")) {
+				int	j;
+
+				/*
+				 * Check for duplicates
+				 */
+				pwd = lookup_pwent(p);
+				for (j = 0; j < i && strcmp(members[j], pwd->pw_name) != 0; j++)
+					;
+				if (j == i && extendarray(&members, &grmembers, i + 2) != -1)
+					members[i++] = newstr(pwd->pw_name);
 			}
-			/*
-			 * Check for duplicates
-			 */
-			for (j = 0; j < i && strcmp(members[j], pwd->pw_name)!=0; j++)
-				;
-			if (j == i && extendarray(&members, &grmembers, i + 2) != -1)
-				members[i++] = newstr(pwd->pw_name);
-		}
 		while (i < grmembers)
 			members[i++] = NULL;
 		grp->gr_mem = members;
@@ -258,19 +276,80 @@ pw_group(struct userconf * cnf, int mode, struct cargs * args)
 			warn("group update");
 		return EX_IOERR;
 	}
+
+	arg = a_newname != NULL ? a_newname : a_name;
 	/* grp may have been invalidated */
-	if ((grp = GETGRNAM(a_name->val)) == NULL)
+	if ((grp = GETGRNAM(arg->val)) == NULL)
 		errx(EX_SOFTWARE, "group disappeared during update");
 
 	pw_log(cnf, mode, W_GROUP, "%s(%ld)", grp->gr_name, (long) grp->gr_gid);
 
-	if (members)
-		free(members);
+	free(members);
 
 	return EXIT_SUCCESS;
 }
 
 
+/*
+ * Lookup a passwd entry using a name or UID.
+ */
+static struct passwd *
+lookup_pwent(const char *user)
+{
+	struct passwd *pwd;
+
+	if ((pwd = GETPWNAM(user)) == NULL &&
+	    (!isdigit((unsigned char)*user) ||
+	    (pwd = getpwuid((uid_t) atoi(user))) == NULL))
+		errx(EX_NOUSER, "user `%s' does not exist", user);
+
+	return (pwd);
+}
+
+
+/*
+ * Delete requested members from a group.
+ */
+static void
+delete_members(char ***members, int *grmembers, int *i, struct carg *arg,
+    struct group *grp)
+{
+	bool matchFound;
+	char *user;
+	char *valueCopy;
+	char *valuePtr;
+	int k;
+	struct passwd *pwd;
+
+	if (grp->gr_mem == NULL)
+		return;
+
+	k = 0;
+	while (grp->gr_mem[k] != NULL) {
+		matchFound = false;
+		if ((valueCopy = strdup(arg->val)) == NULL)
+			errx(EX_UNAVAILABLE, "out of memory");
+		valuePtr = valueCopy;
+		while ((user = strsep(&valuePtr, ", \t")) != NULL) {
+			pwd = lookup_pwent(user);
+			if (strcmp(grp->gr_mem[k], pwd->pw_name) == 0) {
+				matchFound = true;
+				break;
+			}
+		}
+		free(valueCopy);
+
+		if (!matchFound &&
+		    extendarray(members, grmembers, *i + 2) != -1)
+			(*members)[(*i)++] = grp->gr_mem[k];
+
+		k++;
+	}
+
+	return;
+}
+
+
 static          gid_t
 gr_gidpolicy(struct userconf * cnf, struct cargs * args)
 {
@@ -338,11 +417,10 @@ static int
 print_group(struct group * grp, int pretty)
 {
 	if (!pretty) {
-		int		buflen = 0;
 		char           *buf = NULL;
 
-		fmtgrent(&buf, &buflen, grp);
-		fputs(buf, stdout);
+		buf = gr_make(grp);
+		printf("%s\n", buf);
 		free(buf);
 	} else {
 		int             i;
@@ -350,8 +428,10 @@ print_group(struct group * grp, int pretty)
 		printf("Group Name: %-15s   #%lu\n"
 		       "   Members: ",
 		       grp->gr_name, (long) grp->gr_gid);
-		for (i = 0; grp->gr_mem[i]; i++)
-			printf("%s%s", i ? "," : "", grp->gr_mem[i]);
+		if (grp->gr_mem != NULL) {
+			for (i = 0; grp->gr_mem[i]; i++)
+				printf("%s%s", i ? "," : "", grp->gr_mem[i]);
+		}
 		fputs("\n\n", stdout);
 	}
 	return EXIT_SUCCESS;