abuild/abuild-sudo.c
Natanael Copa 6f60008bc4 abuild-sudo: fix segfault when there are no controlling term
if there are no controlling reminal getlogin() may return NULL. We use
getpwuid() to try figure out the username and verify that we actually
have a username before we set environment USER.
2017-07-17 17:24:07 +02:00

125 lines
2.6 KiB
C

/* 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.
*/
#include <sys/types.h>
#include <err.h>
#include <grp.h>
#include <pwd.h>
#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",
"/usr/sbin/adduser",
"/bin/addgroup",
"/usr/sbin/addgroup",
"/sbin/apk",
"/usr/bin/abuild-rmtemp",
NULL
};
const char *get_command_path(const char *cmd)
{
const char *p;
int i;
for (i = 0; valid_cmds[i] != NULL; i++) {
if (access(valid_cmds[i], F_OK) == -1)
continue;
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));
int ngroups, ret = 0;
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;
int i;
struct passwd *pw;
grent = getgrnam(ABUILD_GROUP);
if (grent == NULL)
errx(1, "%s: Group not found", ABUILD_GROUP);
char *name = getlogin();
if (name == NULL) {
pw = getpwuid(getuid());
if (pw)
name = pw->pw_name;
}
if (!is_in_group(grent->gr_gid)) {
errx(1, "User %s is not a member of group %s\n",
name ? name : "(unknown)", ABUILD_GROUP);
}
if (name) {
setenv("USER", name, 1);
} else {
warnx("Could not find username for uid %d\n", getuid());
}
cmd = strrchr(argv[0], '/');
if (cmd)
cmd++;
else
cmd = argv[0];
cmd = strchr(cmd, '-');
if (cmd == NULL)
errx(1, "Calling command has no '-'");
cmd++;
path = get_command_path(cmd);
if (path == NULL)
errx(1, "%s: Not a valid subcommand", cmd);
/* 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");
argv[0] = path;
/* set our uid to root so bbsuid --install works */
setuid(0);
/* set our gid to root so apk commit hooks run with the same gid as for "sudo apk add ..." */
setgid(0);
execv(path, (char * const*)argv);
perror(path);
return 1;
}