149 lines
2.4 KiB
C
149 lines
2.4 KiB
C
/*
|
|
* as user cmd [arg...] - run cmd with args as user on this cpu server.
|
|
* must be hostowner for this to work.
|
|
* needs #¤/caphash and #¤/capuse.
|
|
*/
|
|
#include <u.h>
|
|
#include <libc.h>
|
|
#include <bio.h>
|
|
#include <libsec.h>
|
|
#include <auth.h>
|
|
#include <authsrv.h>
|
|
#include "authcmdlib.h"
|
|
|
|
extern int newnsdebug;
|
|
|
|
char *defargv[] = { "/bin/rc", "-i", nil };
|
|
char *namespace = nil;
|
|
|
|
int becomeuser(char*);
|
|
void initcap(void);
|
|
|
|
void
|
|
usage(void)
|
|
{
|
|
fprint(2, "usage: %s [-d] [-n namespace] user [cmd [args...]]\n", argv0);
|
|
exits("usage");
|
|
}
|
|
|
|
void
|
|
run(char **a)
|
|
{
|
|
exec(a[0], a);
|
|
|
|
if(a[0][0] != '/' && a[0][0] != '#' &&
|
|
(a[0][0] != '.' || (a[0][1] != '/' &&
|
|
(a[0][1] != '.' || a[0][2] != '/'))))
|
|
exec(smprint("/bin/%s", a[0]), a);
|
|
|
|
sysfatal("exec: %s: %r", a[0]);
|
|
}
|
|
|
|
void
|
|
main(int argc, char *argv[])
|
|
{
|
|
ARGBEGIN{
|
|
case 'd':
|
|
newnsdebug = 1;
|
|
break;
|
|
case 'n':
|
|
namespace = EARGF(usage());
|
|
break;
|
|
default:
|
|
usage();
|
|
}ARGEND
|
|
|
|
if(argc == 0)
|
|
usage();
|
|
|
|
initcap();
|
|
if(becomeuser(argv[0]) < 0)
|
|
sysfatal("can't change uid for %s: %r", argv[0]);
|
|
if(newns(argv[0], namespace) < 0)
|
|
sysfatal("can't build namespace: %r");
|
|
|
|
argv++;
|
|
if(--argc == 0)
|
|
argv = defargv;
|
|
|
|
run(argv);
|
|
}
|
|
|
|
/*
|
|
* keep caphash fd open since opens of it could be disabled
|
|
*/
|
|
static int caphashfd;
|
|
|
|
void
|
|
initcap(void)
|
|
{
|
|
caphashfd = open("#¤/caphash", OCEXEC|OWRITE);
|
|
if(caphashfd < 0)
|
|
fprint(2, "%s: opening #¤/caphash: %r", argv0);
|
|
}
|
|
|
|
/*
|
|
* create a change uid capability
|
|
*/
|
|
char*
|
|
mkcap(char *from, char *to)
|
|
{
|
|
uchar rand[20];
|
|
char *cap;
|
|
char *key;
|
|
int nfrom, nto;
|
|
uchar hash[SHA1dlen];
|
|
|
|
if(caphashfd < 0)
|
|
return nil;
|
|
|
|
/* create the capability */
|
|
nto = strlen(to);
|
|
nfrom = strlen(from);
|
|
cap = malloc(nfrom+1+nto+1+sizeof(rand)*3+1);
|
|
if(cap == nil)
|
|
sysfatal("malloc: %r");
|
|
sprint(cap, "%s@%s", from, to);
|
|
genrandom(rand, sizeof(rand));
|
|
key = cap+nfrom+1+nto+1;
|
|
enc64(key, sizeof(rand)*3, rand, sizeof(rand));
|
|
|
|
/* hash the capability */
|
|
hmac_sha1((uchar*)cap, strlen(cap), (uchar*)key, strlen(key), hash, nil);
|
|
|
|
/* give the kernel the hash */
|
|
key[-1] = '@';
|
|
if(write(caphashfd, hash, SHA1dlen) < 0){
|
|
free(cap);
|
|
return nil;
|
|
}
|
|
|
|
return cap;
|
|
}
|
|
|
|
int
|
|
usecap(char *cap)
|
|
{
|
|
int fd, rv;
|
|
|
|
fd = open("#¤/capuse", OWRITE);
|
|
if(fd < 0)
|
|
return -1;
|
|
rv = write(fd, cap, strlen(cap));
|
|
close(fd);
|
|
return rv;
|
|
}
|
|
|
|
int
|
|
becomeuser(char *new)
|
|
{
|
|
char *cap;
|
|
int rv;
|
|
|
|
cap = mkcap(getuser(), new);
|
|
if(cap == nil)
|
|
return -1;
|
|
rv = usecap(cap);
|
|
free(cap);
|
|
return rv;
|
|
}
|