1410ea80bSDavid du Colombier /*
2410ea80bSDavid du Colombier * as user cmd [arg...] - run cmd with args as user on this cpu server.
3410ea80bSDavid du Colombier * must be hostowner for this to work.
4410ea80bSDavid du Colombier * needs #¤/caphash and #¤/capuse.
5410ea80bSDavid du Colombier */
6410ea80bSDavid du Colombier #include <u.h>
7410ea80bSDavid du Colombier #include <libc.h>
8410ea80bSDavid du Colombier #include <bio.h>
9410ea80bSDavid du Colombier #include <libsec.h>
10410ea80bSDavid du Colombier #include <auth.h>
11410ea80bSDavid du Colombier #include "authcmdlib.h"
12410ea80bSDavid du Colombier
13410ea80bSDavid du Colombier int debug;
14410ea80bSDavid du Colombier
15410ea80bSDavid du Colombier int becomeuser(char*);
16410ea80bSDavid du Colombier void createuser(void);
17410ea80bSDavid du Colombier void *emalloc(ulong);
18410ea80bSDavid du Colombier void *erealloc(void*, ulong);
19410ea80bSDavid du Colombier void initcap(void);
20410ea80bSDavid du Colombier int mkcmd(char*, char*, int);
21410ea80bSDavid du Colombier int myauth(int, char*);
22410ea80bSDavid du Colombier int qidcmp(Qid, Qid);
23410ea80bSDavid du Colombier void runas(char *, char *);
24410ea80bSDavid du Colombier void usage(void);
25410ea80bSDavid du Colombier
26410ea80bSDavid du Colombier #pragma varargck argpos clog 1
27410ea80bSDavid du Colombier #pragma varargck argpos fatal 1
28410ea80bSDavid du Colombier
29410ea80bSDavid du Colombier static void
fatal(char * fmt,...)30410ea80bSDavid du Colombier fatal(char *fmt, ...)
31410ea80bSDavid du Colombier {
32410ea80bSDavid du Colombier char msg[256];
33410ea80bSDavid du Colombier va_list arg;
34410ea80bSDavid du Colombier
35410ea80bSDavid du Colombier va_start(arg, fmt);
36410ea80bSDavid du Colombier vseprint(msg, msg + sizeof msg, fmt, arg);
37410ea80bSDavid du Colombier va_end(arg);
38410ea80bSDavid du Colombier error("%s", msg);
39410ea80bSDavid du Colombier }
40410ea80bSDavid du Colombier
41410ea80bSDavid du Colombier void
main(int argc,char * argv[])42410ea80bSDavid du Colombier main(int argc, char *argv[])
43410ea80bSDavid du Colombier {
44410ea80bSDavid du Colombier debug = 0;
45410ea80bSDavid du Colombier ARGBEGIN{
46410ea80bSDavid du Colombier case 'd':
47410ea80bSDavid du Colombier debug = 1;
48410ea80bSDavid du Colombier break;
49410ea80bSDavid du Colombier default:
50410ea80bSDavid du Colombier usage();
51410ea80bSDavid du Colombier }ARGEND
52410ea80bSDavid du Colombier
53410ea80bSDavid du Colombier initcap();
54410ea80bSDavid du Colombier srand(getpid()*time(0));
55410ea80bSDavid du Colombier runas(argv[0], argv[1]);
56410ea80bSDavid du Colombier }
57410ea80bSDavid du Colombier
58410ea80bSDavid du Colombier void
runas(char * user,char * cmd)59410ea80bSDavid du Colombier runas(char *user, char *cmd)
60410ea80bSDavid du Colombier {
61410ea80bSDavid du Colombier if(becomeuser(user) < 0)
62410ea80bSDavid du Colombier sysfatal("can't change uid for %s: %r", user);
63410ea80bSDavid du Colombier putenv("service", "rx");
64410ea80bSDavid du Colombier execl("/bin/rc", "rc", "-lc", cmd, nil);
65410ea80bSDavid du Colombier sysfatal("exec /bin/rc: %r");
66410ea80bSDavid du Colombier }
67410ea80bSDavid du Colombier
68410ea80bSDavid du Colombier void *
emalloc(ulong n)69410ea80bSDavid du Colombier emalloc(ulong n)
70410ea80bSDavid du Colombier {
71410ea80bSDavid du Colombier void *p;
72410ea80bSDavid du Colombier
73410ea80bSDavid du Colombier if(p = mallocz(n, 1))
74410ea80bSDavid du Colombier return p;
75410ea80bSDavid du Colombier fatal("out of memory");
76410ea80bSDavid du Colombier return 0;
77410ea80bSDavid du Colombier }
78410ea80bSDavid du Colombier
79410ea80bSDavid du Colombier void *
erealloc(void * p,ulong n)80410ea80bSDavid du Colombier erealloc(void *p, ulong n)
81410ea80bSDavid du Colombier {
82410ea80bSDavid du Colombier if(p = realloc(p, n))
83410ea80bSDavid du Colombier return p;
84410ea80bSDavid du Colombier fatal("out of memory");
85410ea80bSDavid du Colombier return 0;
86410ea80bSDavid du Colombier }
87410ea80bSDavid du Colombier
88410ea80bSDavid du Colombier void
usage(void)89410ea80bSDavid du Colombier usage(void)
90410ea80bSDavid du Colombier {
91410ea80bSDavid du Colombier fprint(2, "usage: %s [-c]\n", argv0);
92410ea80bSDavid du Colombier exits("usage");
93410ea80bSDavid du Colombier }
94410ea80bSDavid du Colombier
95410ea80bSDavid du Colombier void
memrandom(void * p,int n)96410ea80bSDavid du Colombier memrandom(void *p, int n)
97410ea80bSDavid du Colombier {
98410ea80bSDavid du Colombier uchar *cp;
99410ea80bSDavid du Colombier
100410ea80bSDavid du Colombier for(cp = (uchar*)p; n > 0; n--)
101410ea80bSDavid du Colombier *cp++ = fastrand();
102410ea80bSDavid du Colombier }
103410ea80bSDavid du Colombier
104410ea80bSDavid du Colombier /*
105410ea80bSDavid du Colombier * keep caphash fd open since opens of it could be disabled
106410ea80bSDavid du Colombier */
107410ea80bSDavid du Colombier static int caphashfd;
108410ea80bSDavid du Colombier
109410ea80bSDavid du Colombier void
initcap(void)110410ea80bSDavid du Colombier initcap(void)
111410ea80bSDavid du Colombier {
112410ea80bSDavid du Colombier caphashfd = open("#¤/caphash", OCEXEC|OWRITE);
113410ea80bSDavid du Colombier if(caphashfd < 0)
114410ea80bSDavid du Colombier fprint(2, "%s: opening #¤/caphash: %r\n", argv0);
115410ea80bSDavid du Colombier }
116410ea80bSDavid du Colombier
117410ea80bSDavid du Colombier /*
118410ea80bSDavid du Colombier * create a change uid capability
119410ea80bSDavid du Colombier */
120410ea80bSDavid du Colombier char*
mkcap(char * from,char * to)121410ea80bSDavid du Colombier mkcap(char *from, char *to)
122410ea80bSDavid du Colombier {
123410ea80bSDavid du Colombier uchar rand[20];
124410ea80bSDavid du Colombier char *cap;
125410ea80bSDavid du Colombier char *key;
126*f54edc78SDavid du Colombier int nfrom, nto, ncap;
127410ea80bSDavid du Colombier uchar hash[SHA1dlen];
128410ea80bSDavid du Colombier
129410ea80bSDavid du Colombier if(caphashfd < 0)
130410ea80bSDavid du Colombier return nil;
131410ea80bSDavid du Colombier
132410ea80bSDavid du Colombier /* create the capability */
133410ea80bSDavid du Colombier nto = strlen(to);
134410ea80bSDavid du Colombier nfrom = strlen(from);
135*f54edc78SDavid du Colombier ncap = nfrom + 1 + nto + 1 + sizeof(rand)*3 + 1;
136*f54edc78SDavid du Colombier cap = emalloc(ncap);
137*f54edc78SDavid du Colombier snprint(cap, ncap, "%s@%s", from, to);
138410ea80bSDavid du Colombier memrandom(rand, sizeof(rand));
139410ea80bSDavid du Colombier key = cap+nfrom+1+nto+1;
140410ea80bSDavid du Colombier enc64(key, sizeof(rand)*3, rand, sizeof(rand));
141410ea80bSDavid du Colombier
142410ea80bSDavid du Colombier /* hash the capability */
143410ea80bSDavid du Colombier hmac_sha1((uchar*)cap, strlen(cap), (uchar*)key, strlen(key), hash, nil);
144410ea80bSDavid du Colombier
145410ea80bSDavid du Colombier /* give the kernel the hash */
146410ea80bSDavid du Colombier key[-1] = '@';
147410ea80bSDavid du Colombier if(write(caphashfd, hash, SHA1dlen) < 0){
148410ea80bSDavid du Colombier free(cap);
149410ea80bSDavid du Colombier return nil;
150410ea80bSDavid du Colombier }
151410ea80bSDavid du Colombier
152410ea80bSDavid du Colombier return cap;
153410ea80bSDavid du Colombier }
154410ea80bSDavid du Colombier
155410ea80bSDavid du Colombier int
usecap(char * cap)156410ea80bSDavid du Colombier usecap(char *cap)
157410ea80bSDavid du Colombier {
158410ea80bSDavid du Colombier int fd, rv;
159410ea80bSDavid du Colombier
160410ea80bSDavid du Colombier fd = open("#¤/capuse", OWRITE);
161410ea80bSDavid du Colombier if(fd < 0)
162410ea80bSDavid du Colombier return -1;
163410ea80bSDavid du Colombier rv = write(fd, cap, strlen(cap));
164410ea80bSDavid du Colombier close(fd);
165410ea80bSDavid du Colombier return rv;
166410ea80bSDavid du Colombier }
167410ea80bSDavid du Colombier
168410ea80bSDavid du Colombier int
becomeuser(char * new)169410ea80bSDavid du Colombier becomeuser(char *new)
170410ea80bSDavid du Colombier {
171410ea80bSDavid du Colombier char *cap;
172410ea80bSDavid du Colombier int rv;
173410ea80bSDavid du Colombier
174410ea80bSDavid du Colombier cap = mkcap(getuser(), new);
175410ea80bSDavid du Colombier if(cap == nil)
176410ea80bSDavid du Colombier return -1;
177410ea80bSDavid du Colombier rv = usecap(cap);
178410ea80bSDavid du Colombier free(cap);
179410ea80bSDavid du Colombier
180410ea80bSDavid du Colombier newns(new, nil);
181410ea80bSDavid du Colombier return rv;
182410ea80bSDavid du Colombier }
183