xref: /plan9/sys/src/cmd/auth/as.c (revision f54edc786b9c49b2c7ab1c0695cdc8c698b11f4d)
1 /*
2  * as user cmd [arg...] - run cmd with args as user on this cpu server.
3  *	must be hostowner for this to work.
4  *	needs #¤/caphash and #¤/capuse.
5  */
6 #include <u.h>
7 #include <libc.h>
8 #include <bio.h>
9 #include <libsec.h>
10 #include <auth.h>
11 #include "authcmdlib.h"
12 
13 int	debug;
14 
15 int	becomeuser(char*);
16 void	createuser(void);
17 void	*emalloc(ulong);
18 void	*erealloc(void*, ulong);
19 void	initcap(void);
20 int	mkcmd(char*, char*, int);
21 int	myauth(int, char*);
22 int	qidcmp(Qid, Qid);
23 void	runas(char *, char *);
24 void	usage(void);
25 
26 #pragma varargck	argpos clog 1
27 #pragma varargck	argpos fatal 1
28 
29 static void
fatal(char * fmt,...)30 fatal(char *fmt, ...)
31 {
32 	char msg[256];
33 	va_list arg;
34 
35 	va_start(arg, fmt);
36 	vseprint(msg, msg + sizeof msg, fmt, arg);
37 	va_end(arg);
38 	error("%s", msg);
39 }
40 
41 void
main(int argc,char * argv[])42 main(int argc, char *argv[])
43 {
44 	debug = 0;
45 	ARGBEGIN{
46 	case 'd':
47 		debug = 1;
48 		break;
49 	default:
50 		usage();
51 	}ARGEND
52 
53 	initcap();
54 	srand(getpid()*time(0));
55 	runas(argv[0], argv[1]);
56 }
57 
58 void
runas(char * user,char * cmd)59 runas(char *user, char *cmd)
60 {
61 	if(becomeuser(user) < 0)
62 		sysfatal("can't change uid for %s: %r", user);
63 	putenv("service", "rx");
64 	execl("/bin/rc", "rc", "-lc", cmd, nil);
65 	sysfatal("exec /bin/rc: %r");
66 }
67 
68 void *
emalloc(ulong n)69 emalloc(ulong n)
70 {
71 	void *p;
72 
73 	if(p = mallocz(n, 1))
74 		return p;
75 	fatal("out of memory");
76 	return 0;
77 }
78 
79 void *
erealloc(void * p,ulong n)80 erealloc(void *p, ulong n)
81 {
82 	if(p = realloc(p, n))
83 		return p;
84 	fatal("out of memory");
85 	return 0;
86 }
87 
88 void
usage(void)89 usage(void)
90 {
91 	fprint(2, "usage: %s [-c]\n", argv0);
92 	exits("usage");
93 }
94 
95 void
memrandom(void * p,int n)96 memrandom(void *p, int n)
97 {
98 	uchar *cp;
99 
100 	for(cp = (uchar*)p; n > 0; n--)
101 		*cp++ = fastrand();
102 }
103 
104 /*
105  *  keep caphash fd open since opens of it could be disabled
106  */
107 static int caphashfd;
108 
109 void
initcap(void)110 initcap(void)
111 {
112 	caphashfd = open("#¤/caphash", OCEXEC|OWRITE);
113 	if(caphashfd < 0)
114 		fprint(2, "%s: opening #¤/caphash: %r\n", argv0);
115 }
116 
117 /*
118  *  create a change uid capability
119  */
120 char*
mkcap(char * from,char * to)121 mkcap(char *from, char *to)
122 {
123 	uchar rand[20];
124 	char *cap;
125 	char *key;
126 	int nfrom, nto, ncap;
127 	uchar hash[SHA1dlen];
128 
129 	if(caphashfd < 0)
130 		return nil;
131 
132 	/* create the capability */
133 	nto = strlen(to);
134 	nfrom = strlen(from);
135 	ncap = nfrom + 1 + nto + 1 + sizeof(rand)*3 + 1;
136 	cap = emalloc(ncap);
137 	snprint(cap, ncap, "%s@%s", from, to);
138 	memrandom(rand, sizeof(rand));
139 	key = cap+nfrom+1+nto+1;
140 	enc64(key, sizeof(rand)*3, rand, sizeof(rand));
141 
142 	/* hash the capability */
143 	hmac_sha1((uchar*)cap, strlen(cap), (uchar*)key, strlen(key), hash, nil);
144 
145 	/* give the kernel the hash */
146 	key[-1] = '@';
147 	if(write(caphashfd, hash, SHA1dlen) < 0){
148 		free(cap);
149 		return nil;
150 	}
151 
152 	return cap;
153 }
154 
155 int
usecap(char * cap)156 usecap(char *cap)
157 {
158 	int fd, rv;
159 
160 	fd = open("#¤/capuse", OWRITE);
161 	if(fd < 0)
162 		return -1;
163 	rv = write(fd, cap, strlen(cap));
164 	close(fd);
165 	return rv;
166 }
167 
168 int
becomeuser(char * new)169 becomeuser(char *new)
170 {
171 	char *cap;
172 	int rv;
173 
174 	cap = mkcap(getuser(), new);
175 	if(cap == nil)
176 		return -1;
177 	rv = usecap(cap);
178 	free(cap);
179 
180 	newns(new, nil);
181 	return rv;
182 }
183