Skip to content

Commit 8962b03

Browse files
committed
Add support for supplementary groups
Implement supplementary group support for services, allowing them to access resources owned by multiple groups. Uses the @user:group,sup1,sup2 syntax to explicitly specify supplementary groups, as finit does not read group membership from /etc/group.
1 parent 702a606 commit 8962b03

File tree

3 files changed

+64
-1
lines changed

3 files changed

+64
-1
lines changed

doc/config/services.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,27 @@ 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+
> [!IMPORTANT]
125+
> Finit does **not** read supplementary group membership from
126+
> `/etc/group`. If a service needs access to resources owned by
127+
> supplementary groups, they must be explicitly listed in the
128+
> configuration. A maximum of 4 supplementary groups can be specified.
129+
130+
To run a service with supplementary groups, append them after the
131+
primary group, separated by commas:
132+
133+
service @caddy:caddy,www-data,ssl-cert /usr/bin/caddy run
134+
135+
This runs the `caddy` service as user `caddy`, with primary group
136+
`caddy`, and supplementary groups `www-data` and `ssl-cert`. This
137+
is useful when a service needs access to files or resources owned
138+
by multiple groups, such as TLS certificates or shared web content.
139+
123140
For multiple instances of the same command, e.g. a DHCP client or
124141
multiple web servers, add `:ID` somewhere between the `run`, `task`,
125142
`service` keyword and the command, like this:

src/service.c

Lines changed: 43 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,26 @@ 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 */
566+
if (svc->num_supgroups > 0) {
567+
gid_t supgids[MAX_NUM_SUPGROUPS];
568+
int i, n = 0;
569+
570+
for (i = 0; i < svc->num_supgroups; i++) {
571+
int g = getgroup(svc->supgroups[i]);
572+
if (g < 0) {
573+
warn("%s: unknown supplementary group '%s'",
574+
svc_ident(svc, NULL, 0), svc->supgroups[i]);
575+
continue;
576+
}
577+
supgids[n++] = g;
578+
}
579+
if (n > 0 && setgroups(n, supgids))
580+
err(1, "%s: failed setgroups()", svc_ident(svc, NULL, 0));
581+
}
582+
#endif
583+
563584
/* Set desired user+group */
564585
if (gid >= 0) {
565586
if (setgid(gid))
@@ -1957,7 +1978,29 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
19571978
char *ptr = strchr(username, ':');
19581979

19591980
if (ptr) {
1981+
char *sup;
1982+
19601983
*ptr++ = 0;
1984+
/* Check for supplementary groups: group,sup1,sup2,... */
1985+
sup = strchr(ptr, ',');
1986+
if (sup) {
1987+
*sup++ = 0;
1988+
svc->num_supgroups = 0;
1989+
while (sup) {
1990+
char *next = strchr(sup, ',');
1991+
if (next)
1992+
*next++ = 0;
1993+
if (svc->num_supgroups >= MAX_NUM_SUPGROUPS) {
1994+
warn("%s: too many supplementary groups, max %d",
1995+
svc->cmd, MAX_NUM_SUPGROUPS);
1996+
break;
1997+
}
1998+
strlcpy(svc->supgroups[svc->num_supgroups], sup,
1999+
sizeof(svc->supgroups[0]));
2000+
svc->num_supgroups++;
2001+
sup = next;
2002+
}
2003+
}
19612004
strlcpy(svc->group, ptr, sizeof(svc->group));
19622005
}
19632006
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)