abuild-sudo.c 2.59 KB
Newer Older
1 2 3 4 5 6 7 8 9
/* abuild-sudo.c - limited root privileges for users in "abuild" group
 *
 * Copyright (C) 2012 Natanael Copa <ncopa@alpinelinux.org>
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published
 * by the Free Software Foundation. See http://www.gnu.org/ for details.
 */
Natanael Copa's avatar
Natanael Copa committed
10 11 12 13 14

#include <sys/types.h>

#include <err.h>
#include <grp.h>
15
#include <pwd.h>
Natanael Copa's avatar
Natanael Copa committed
16 17 18 19 20 21 22 23 24 25 26
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#ifndef ABUILD_GROUP
#define ABUILD_GROUP "abuild"
#endif

static const char* valid_cmds[] = {
	"/bin/adduser",
27
	"/usr/sbin/adduser",
Natanael Copa's avatar
Natanael Copa committed
28
	"/bin/addgroup",
29
	"/usr/sbin/addgroup",
Natanael Copa's avatar
Natanael Copa committed
30
	"/sbin/apk",
Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
31
	"/usr/bin/abuild-rmtemp",
Natanael Copa's avatar
Natanael Copa committed
32 33 34 35 36 37 38 39
	NULL
};

const char *get_command_path(const char *cmd)
{
	const char *p;
	int i;
	for (i = 0; valid_cmds[i] != NULL; i++) {
40 41
		if (access(valid_cmds[i], F_OK) == -1)
			continue;
Natanael Copa's avatar
Natanael Copa committed
42 43 44 45 46 47 48 49 50 51 52
		p = strrchr(valid_cmds[i], '/') + 1;
		if (strcmp(p, cmd) == 0)
			return valid_cmds[i];
	}
	return NULL;
}

int is_in_group(gid_t group)
{
	int ngroups_max = sysconf(_SC_NGROUPS_MAX) + 1;
	gid_t *buf = malloc(ngroups_max * sizeof(gid_t));
53
	int ngroups;
Natanael Copa's avatar
Natanael Copa committed
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
	int i;
	if (buf == NULL) {
		perror("malloc");
		return 0;
	}
	ngroups = getgroups(ngroups_max, buf);
	for (i = 0; i < ngroups; i++) {
		if (buf[i] == group)
			break;
	}
	free(buf);
	return i < ngroups;
}

int main(int argc, const char *argv[])
{
	struct group *grent;
	const char *cmd;
	const char *path;
73
	int i;
74
	struct passwd *pw;
Natanael Copa's avatar
Natanael Copa committed
75 76 77 78 79

	grent = getgrnam(ABUILD_GROUP);
	if (grent == NULL)
		errx(1, "%s: Group not found", ABUILD_GROUP);

80 81 82 83
	char *name = NULL;
	pw = getpwuid(getuid());
	if (pw)
		name = pw->pw_name;
84

85 86
	if (!is_in_group(grent->gr_gid)) {
		errx(1, "User %s is not a member of group %s\n",
87
			name ? name : "(unknown)", ABUILD_GROUP);
88
	}
89 90

	if (name == NULL)
91
		warnx("Could not find username for uid %d\n", getuid());
92
	setenv("USER", name ?: "", 1);
Natanael Copa's avatar
Natanael Copa committed
93

94 95 96 97 98 99
	cmd = strrchr(argv[0], '/');
	if (cmd)
		cmd++;
	else
		cmd = argv[0];
	cmd = strchr(cmd, '-');
100
	if (cmd == NULL)
Natanael Copa's avatar
Natanael Copa committed
101 102 103 104 105 106 107
		errx(1, "Calling command has no '-'");
	cmd++;

	path = get_command_path(cmd);
	if (path == NULL)
		errx(1, "%s: Not a valid subcommand", cmd);

108 109 110 111 112
	/* we dont allow --allow-untrusted option */
	for (i = 1; i < argc; i++)
		if (strcmp(argv[i], "--allow-untrusted") == 0)
			errx(1, "%s: not allowed option", "--allow-untrusted");

Natanael Copa's avatar
Natanael Copa committed
113
	argv[0] = path;
114
	/* set our uid to root so bbsuid --install works */
Natanael Copa's avatar
Natanael Copa committed
115
	setuid(0);
116 117
	/* set our gid to root so apk commit hooks run with the same gid as for "sudo apk add ..." */
	setgid(0);
Natanael Copa's avatar
Natanael Copa committed
118
	execv(path, (char * const*)argv);
119
	perror(path);
Natanael Copa's avatar
Natanael Copa committed
120 121
	return 1;
}