For years I've been using an ultra simple program to allow root access without a password. It was called 'root' and in spite of a couple of bugs which I'd mainly fixed I generally just liked it. So easy to set up - just put the allowed uid's into /etc/rooters and off you go. Well blow me down, I lost the sources. Not on my backups. Not in cvs. What the heck had I done with it? No good googling - 'root' is just too general a name.
So I re-wrote it from scratch and (apologies to the original author), its a darn sight better now (it even evaluates its arguments correctly if they contain spaces, which the old 'root' didn't). I also got it to add /sbin /usr/sbin and /usr/local/sbin to PATH while I was at it, and allowed root to run it themselves. So now, it's just awesome!
Here it is. To compile just do this as root:
cc -o root root.c chown root root chmod 4755 root cp root /usr/local/bin # or anywhere you like
Then put your allowed uids (use 'id -u') into /etc/rooters and then do this as root:
chown root /etc/rooters chmod 600 /etc/rooters
/*
Copyright 2008 Bob Hepple
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
http://bhepple.freeshell.org
http://process-getopt.sourceforge.net
$Id: root.c,v 1.1.1.1 2008/08/23 10:19:38 bhepple Exp $
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#define ROOTERS "/etc/rooters"
#define MAXLINE 1024
#define MAXPATH 1024
extern int errno;
int executable(char *filename, int verbose) {
struct stat buf;
int retval = 0;
if (verbose) printf("Checking %s\n", filename);
if (stat(filename, &buf) == 0) {
if ((buf.st_mode & S_IFMT) == S_IFREG) {
if (buf.st_mode & 0111) {
retval = 1;
goto end;
}
}
}
end:
return(retval);
}
char *find_exec(char *path, char *name, int verbose) {
char *p = path;
static char filename[MAXPATH];
char *retval = NULL;
filename[0] = 0;
if (strchr(name, '/')) {
if (executable(name, verbose)) {
strncpy(filename, name, MAXPATH);
retval = filename;
}
goto end;
}
for (p = path; *p; ) {
char *e = NULL;
while (*p == ':') p++;
if (!*p) break;
e = strchr(p, ':');
if (e) *e = 0;
snprintf(filename, MAXPATH, "%s/%s", p, name);
if (executable(filename, verbose)) {
retval = filename;
goto end;
}
if (!e) break;
p = e + 1;
}
end:
return retval;
}
void usage(char *progname) {
printf("%s: run command as root\n", progname);
printf("Usage: %s [-hvV] command [OPTIONS] [ARGUMENTS]\n\n", progname);
printf("Your id must be in %s which must be chown root; chmod 0600\n",
ROOTERS);
printf("Options:\n");
printf("-h, --help : print this help and exit\n");
printf("-v, --verbose : be verbose\n");
printf("-V, --version : print the version and exit\n");
}
int main(int argc, char **argv, char **envp) {
char *progname = NULL;
char *c;
uid_t ruid = 0;
uid_t euid = 0;
uid_t uid = 0;
int retval = 0;
FILE *rooters = NULL;
struct stat buf;
char inbuf[MAXLINE];
char *path = NULL;
char new_path[MAXPATH];
char *filename = NULL;
int verbose = 0;
progname = argv[0];
for (c = progname + strlen(progname) - 1; c > progname && *c != '/'; c--)
;
if (*c == '/') progname = c + 1;
/* look for, process and remove options: */
if (argc < 2) {
fprintf(stderr, "%s: do what?\n", progname);
retval = 1;
goto end;
}
if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0) ||
(strcmp(argv[1], "-help") == 0)) {
usage(progname);
return(0);
}
if ((strcmp(argv[1], "-V") == 0) || (strcmp(argv[1], "--version") == 0) ||
(strcmp(argv[1], "-version") == 0)) {
printf("%s version 1.0\n", progname);
return(0);
}
if ((strcmp(argv[1], "-v") == 0) || (strcmp(argv[1], "--verbose") == 0) ||
(strcmp(argv[1], "-verbose") == 0)) {
verbose = 1;
argv++; argc--;
}
if (argc < 2) {
fprintf(stderr, "%s: do what?\n", progname);
retval = 1;
goto end;
}
if (*argv[1] == '-') {
fprintf(stderr, "%s: unknown option (%s)\n", progname, argv[1]);
retval = 1;
goto end;
}
/* options are now processed and removed - argv is now the command to run */
ruid = getuid();
euid = geteuid();
if (verbose) printf("real uid = %d, effective uid = %d\n", ruid, euid);
if (euid != 0) {
fprintf(stderr, "%s: is not setuid root - it needs chown root; "
"chmod 4755\n", progname);
retval = 1;
goto end; /* nothing else can be checked */
}
if (stat(ROOTERS, &buf) != 0) {
fprintf(stderr, "%s: can't stat %s\n", progname, ROOTERS);
retval = 1;
}
if (buf.st_mode != (0600 | S_IFREG)) {
fprintf(stderr, "%s: %s must have mode 0600\n", progname, ROOTERS);
retval = 1;
}
if (buf.st_uid != 0) {
fprintf(stderr, "%s: %s must be owned by root\n", progname, ROOTERS);
retval = 1;
}
if ((rooters = fopen(ROOTERS, "r")) == NULL) {
fprintf(stderr, "%s: can't open %s\n", progname, ROOTERS);
retval = 1;
}
while (ruid != 0) { /* if we're already root then fall through */
if (fgets(inbuf, MAXLINE, rooters) == NULL) {
fprintf(stderr, "%s: not permitted\n", progname);
retval = 1;
break;
}
if (sscanf(inbuf, "%d", &uid) != 1) continue;
if (uid == ruid) {
break;
}
}
fclose(rooters);
rooters = NULL;
path = getenv("PATH");
snprintf(new_path, MAXPATH, "%s:/sbin:/usr/sbin:/usr/local/sbin", path);
if (verbose) printf("PATH=%s\n", new_path);
argv++; argc--;
if ((filename = find_exec(new_path, argv[0], verbose)) == NULL) {
fprintf(stderr, "%s: %s: not found\n", progname, argv[0]);
retval = 1;
}
if (retval != 0) {
goto end;
}
if (setuid(0) < 0) {
fprintf(stderr, "%s: setuid(0) failed\n", progname);
retval = 1;
goto end;
}
if (verbose) {
char **arg;
int first = 1;
printf("real uid = %d, effective uid = %d\n", getuid(), geteuid());
printf("Executing: %s as \"", filename);
for (arg = argv; *arg; arg++) {
if (!first) printf(" ");
first = 0;
printf("%s", *arg);
}
printf("\"\n");
}
execve(filename, argv, envp);
fprintf(stderr, "%s: execve(\"%s\") failed errno = %d (%s)\n", progname,
filename, errno, strerror(errno));
retval = 1;
end:
if (rooters) fclose(rooters);
return(retval);
}