xref: /plan9/sys/src/cmd/auth/as.c (revision f54edc786b9c49b2c7ab1c0695cdc8c698b11f4d)
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