summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--login-utils/runuser.13
-rw-r--r--login-utils/su-common.c70
-rw-r--r--login-utils/su.13
3 files changed, 42 insertions, 34 deletions
diff --git a/login-utils/runuser.1 b/login-utils/runuser.1
index 0672cd66d..2f88f8157 100644
--- a/login-utils/runuser.1
+++ b/login-utils/runuser.1
@@ -67,7 +67,8 @@ shell.
The primary group to be used. This option is allowed for the root user only.
.TP
.BR \-G , " \-\-supp\-group" = \fIgroup
-A supplemental group to be used. This option is allowed for the root user only.
+Specify a supplemental group. This option is available to the root user only. The first specified
+supplementary group is also used as a primary group if the option \fB\-\-group\fR is unspecified.
.TP
.BR \- , " \-l" , " \-\-login"
Start the shell as a login shell with an environment similar to a real
diff --git a/login-utils/su-common.c b/login-utils/su-common.c
index 2d4707330..fe6d0c8c3 100644
--- a/login-utils/su-common.c
+++ b/login-utils/su-common.c
@@ -575,7 +575,7 @@ modify_environment (const struct passwd *pw, const char *shell)
/* Become the user and group(s) specified by PW. */
static void
-init_groups (const struct passwd *pw, gid_t *groups, int num_groups)
+init_groups (const struct passwd *pw, gid_t *groups, size_t num_groups)
{
int retval;
@@ -746,6 +746,28 @@ evaluate_uid(void)
return (uid_t) 0 == ruid && ruid == euid ? 0 : 1;
}
+static gid_t
+add_supp_group(const char *name, gid_t **groups, size_t *ngroups)
+{
+ struct group *gr;
+
+ if (*ngroups >= NGROUPS_MAX)
+ errx(EXIT_FAILURE,
+ P_("specifying more than %d supplemental group is not possible",
+ "specifying more than %d supplemental groups is not possible",
+ NGROUPS_MAX - 1), NGROUPS_MAX - 1);
+
+ gr = getgrnam(name);
+ if (!gr)
+ errx(EXIT_FAILURE, _("group %s does not exist"), name);
+
+ *groups = xrealloc(*groups, sizeof(gid_t) * (*ngroups + 1));
+ (*groups)[*ngroups] = gr->gr_gid;
+ (*ngroups)++;
+
+ return gr->gr_gid;
+}
+
int
su_main (int argc, char **argv, int mode)
{
@@ -756,10 +778,12 @@ su_main (int argc, char **argv, int mode)
char *shell = NULL;
struct passwd *pw;
struct passwd pw_copy;
- struct group *gr;
- gid_t groups[NGROUPS_MAX];
- int num_supp_groups = 0;
- int use_gid = 0;
+
+ gid_t *groups = NULL;
+ size_t ngroups = 0;
+ bool use_supp = false;
+ bool use_gid = false;
+ gid_t gid = 0;
static const struct option longopts[] = {
{"command", required_argument, NULL, 'c'},
@@ -804,25 +828,13 @@ su_main (int argc, char **argv, int mode)
break;
case 'g':
- gr = getgrnam(optarg);
- if (!gr)
- errx(EXIT_FAILURE, _("group %s does not exist"), optarg);
- use_gid = 1;
- groups[0] = gr->gr_gid;
+ use_gid = true;
+ gid = add_supp_group(optarg, &groups, &ngroups);
break;
case 'G':
- num_supp_groups++;
- if (num_supp_groups >= NGROUPS_MAX)
- errx(EXIT_FAILURE,
- P_("specifying more than %d supplemental group is not possible",
- "specifying more than %d supplemental groups is not possible",
- NGROUPS_MAX - 1),
- NGROUPS_MAX - 1);
- gr = getgrnam(optarg);
- if (!gr)
- errx(EXIT_FAILURE, _("group %s does not exist"), optarg);
- groups[num_supp_groups] = gr->gr_gid;
+ use_supp = true;
+ add_supp_group(optarg, &groups, &ngroups);
break;
case 'l':
@@ -893,7 +905,7 @@ su_main (int argc, char **argv, int mode)
break;
}
- if ((num_supp_groups || use_gid) && restricted)
+ if ((use_supp || use_gid) && restricted)
errx(EXIT_FAILURE, _("only root can specify alternative groups"));
logindefs_load_defaults = load_config;
@@ -919,16 +931,10 @@ su_main (int argc, char **argv, int mode)
: DEFAULT_SHELL);
endpwent ();
- if (num_supp_groups && !use_gid)
- {
- pw->pw_gid = groups[1];
- memmove (groups, groups + 1, sizeof(gid_t) * num_supp_groups);
- }
- else if (use_gid)
- {
+ if (use_supp && !use_gid)
pw->pw_gid = groups[0];
- num_supp_groups++;
- }
+ else if (use_gid)
+ pw->pw_gid = gid;
authenticate (pw);
@@ -953,7 +959,7 @@ su_main (int argc, char **argv, int mode)
shell = xstrdup (shell ? shell : pw->pw_shell);
}
- init_groups (pw, groups, num_supp_groups);
+ init_groups (pw, groups, ngroups);
if (!simulate_login || command)
suppress_pam_info = 1; /* don't print PAM info messages */
diff --git a/login-utils/su.1 b/login-utils/su.1
index f5fecf199..5e529ce3d 100644
--- a/login-utils/su.1
+++ b/login-utils/su.1
@@ -57,7 +57,8 @@ to the shell, which may or may not be useful, depending on the shell.
Specify the primary group. This option is available to the root user only.
.TP
.BR \-G , " \-\-supp\-group" = \fIgroup
-Specify a supplemental group. This option is available to the root user only.
+Specify a supplemental group. This option is available to the root user only. The first specified
+supplementary group is also used as a primary group if the option \fB\-\-group\fR is unspecified.
.TP
.BR \- , " \-l" , " \-\-login"
Start the shell as a login shell with an environment similar to a real