Skip to content

Commit 0d48d1d

Browse files
authored
Merge pull request #461 from aanderse/master
Add support for supplementary groups
2 parents 22bc218 + b46592e commit 0d48d1d

File tree

3 files changed

+78
-1
lines changed

3 files changed

+78
-1
lines changed

doc/config/services.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,25 @@ Non-privileged Services
116116

117117
Every `run`, `task`, or `service` can also list the privileges the
118118
`/path/to/cmd` should be executed with. Prefix the command with
119-
`@USR[:GRP]`, group is optional, like this:
119+
`@USR[:GRP[,SUPP,...]]`, where group and supplementary groups are
120+
optional, like this:
120121

121122
run [2345] @joe:users logger "Hello world"
122123

124+
Finit reads the user's supplementary group membership from `/etc/group`
125+
automatically. Any groups the user belongs to will be inherited by
126+
the service.
127+
128+
To specify additional supplementary groups beyond those in `/etc/group`,
129+
append them after the primary group, separated by commas:
130+
131+
service @caddy:caddy,ssl-cert /usr/bin/caddy run
132+
133+
This runs the `caddy` service as user `caddy`, with primary group
134+
`caddy`, inheriting any groups `caddy` is a member of in `/etc/group`,
135+
plus the additional `ssl-cert` group. This is useful when a service
136+
needs access to resources owned by groups not listed in `/etc/group`.
137+
123138
For multiple instances of the same command, e.g. a DHCP client or
124139
multiple web servers, add `:ID` somewhere between the `run`, `task`,
125140
`service` keyword and the command, like this:

src/service.c

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "config.h" /* Generated by configure script */
2626

2727
#include <ctype.h> /* isblank() */
28+
#include <grp.h> /* setgroups() */
2829
#include <sched.h> /* sched_yield() */
2930
#include <string.h>
3031
#include <sys/reboot.h>
@@ -560,6 +561,42 @@ static pid_t service_fork(svc_t *svc)
560561
svc_ident(svc, NULL, 0), rlim2str(i));
561562
}
562563

564+
#ifndef ENABLE_STATIC
565+
/* Set supplementary groups from /etc/group and config */
566+
{
567+
gid_t supgids[NGROUPS_MAX];
568+
int ngroups = NGROUPS_MAX;
569+
int i, j, n = 0;
570+
571+
/* Get user's supplementary groups from /etc/group */
572+
if (uid >= 0 && getgrouplist(svc->username, gid >= 0 ? gid : 0, supgids, &ngroups) >= 0)
573+
n = ngroups;
574+
575+
/* Add explicitly configured supplementary groups */
576+
for (i = 0; i < svc->num_supgroups && n < NGROUPS_MAX; i++) {
577+
int g = getgroup(svc->supgroups[i]);
578+
int found = 0;
579+
580+
if (g < 0) {
581+
warn("%s: unknown supplementary group '%s'",
582+
svc_ident(svc, NULL, 0), svc->supgroups[i]);
583+
continue;
584+
}
585+
/* Skip if already in list from /etc/group */
586+
for (j = 0; j < n; j++) {
587+
if (supgids[j] == (gid_t)g) {
588+
found = 1;
589+
break;
590+
}
591+
}
592+
if (!found)
593+
supgids[n++] = g;
594+
}
595+
if (n > 0 && setgroups(n, supgids))
596+
err(1, "%s: failed setgroups()", svc_ident(svc, NULL, 0));
597+
}
598+
#endif
599+
563600
/* Set desired user+group */
564601
if (gid >= 0) {
565602
if (setgid(gid))
@@ -1957,7 +1994,29 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
19571994
char *ptr = strchr(username, ':');
19581995

19591996
if (ptr) {
1997+
char *sup;
1998+
19601999
*ptr++ = 0;
2000+
/* Check for supplementary groups: group,sup1,sup2,... */
2001+
sup = strchr(ptr, ',');
2002+
if (sup) {
2003+
*sup++ = 0;
2004+
svc->num_supgroups = 0;
2005+
while (sup) {
2006+
char *next = strchr(sup, ',');
2007+
if (next)
2008+
*next++ = 0;
2009+
if (svc->num_supgroups >= MAX_NUM_SUPGROUPS) {
2010+
warn("%s: too many supplementary groups, max %d",
2011+
svc->cmd, MAX_NUM_SUPGROUPS);
2012+
break;
2013+
}
2014+
strlcpy(svc->supgroups[svc->num_supgroups], sup,
2015+
sizeof(svc->supgroups[0]));
2016+
svc->num_supgroups++;
2017+
sup = next;
2018+
}
2019+
}
19612020
strlcpy(svc->group, ptr, sizeof(svc->group));
19622021
}
19632022
strlcpy(svc->username, username, sizeof(svc->username));

src/svc.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ typedef enum {
101101
#define MAX_STR_LEN 64
102102
#define MAX_COND_LEN (MAX_ARG_LEN * 3)
103103
#define MAX_USER_LEN 16
104+
#define MAX_NUM_SUPGROUPS 4
104105
#define MAX_NUM_FDS 64 /* Max number of I/O plugins */
105106
#define MAX_NUM_SVC_ARGS 64
106107

@@ -191,6 +192,8 @@ typedef struct svc {
191192
/* Identity */
192193
char username[MAX_USER_LEN];
193194
char group[MAX_USER_LEN];
195+
char supgroups[MAX_NUM_SUPGROUPS][MAX_USER_LEN];
196+
int num_supgroups;
194197
char capabilities[MAX_CMD_LEN];
195198

196199
/* Command, arguments and service description */

0 commit comments

Comments
 (0)