1 #include "all.h"
2
3 struct {
4 char* name;
5 Userid uid;
6 Userid lead;
7 } minusers[] = {
8 "adm", -1, -1,
9 "none", 0, -1,
10 "tor", 1, 1,
11 "sys", 10000, 0,
12 "map", 10001, 10001,
13 "doc", 10002, 0,
14 "upas", 10003, 10003,
15 "font", 10004, 0,
16 "bootes", 10005, 10005,
17 0
18 };
19
20 static char buf[4096];
21 static Rune ichar[] = L"?=+-/:";
22
23 Uid* chkuid(char *name, int chk);
24 void do_newuser(int, char*[]);
25 char* getword(char*, Rune, char*, int);
26 void pentry(char*, Uid*);
27 int readln(char*, int);
28 void setminusers(void);
29 Uid* uidtop(int);
30
31 void
cmd_users(int argc,char * argv[])32 cmd_users(int argc, char *argv[])
33 {
34 Uid *ui;
35 int u, g, o, line;
36 char *file, *p, *uname, *ulead, *unext;
37
38 file = "/adm/users";
39 if(argc > 1)
40 file = argv[1];
41
42 if(strcmp(file, "default") == 0) {
43 setminusers();
44 return;
45 }
46
47 uidgc.uidbuf = getbuf(devnone, Cuidbuf, 0);
48 if(walkto(file) || con_open(FID2, 0)) {
49 print("cmd_users: cannot access %s\n", file);
50 putbuf(uidgc.uidbuf);
51 return;
52 }
53
54 uidgc.flen = 0;
55 uidgc.find = 0;
56 cons.offset = 0;
57 cons.nuid = 0;
58
59 u = 0;
60 line = 0;
61 while(readln(buf, sizeof buf) != 0) {
62 line++;
63 p = getword(buf, L':', "no : after number", line);
64 if(p == nil)
65 continue;
66 ulead = getword(p, L':', "no : after name", line);
67 if(ulead == nil)
68 continue;
69
70 if(strlen(p) > NAMELEN-1) {
71 print("%s: name too long\n", p);
72 continue;
73 }
74 strcpy(uid[u].name, p);
75 uid[u].uid = number(buf, 0, 10);
76 uid[u].lead = 0;
77 uid[u].ngrp = 0;
78 u++;
79 if(u >= conf.nuid) {
80 print("conf.nuid too small (%ld)\n", conf.nuid);
81 break;
82 }
83 }
84
85 /* Sorted by uid for use in uidtostr */
86 wlock(&uidgc.uidlock);
87 qsort(uid, u, sizeof(uid[0]), byuid);
88 cons.nuid = u;
89 wunlock(&uidgc.uidlock);
90
91 /* Parse group table */
92 uidgc.flen = 0;
93 uidgc.find = 0;
94 cons.offset = 0;
95 cons.ngid = 0;
96
97 g = 0;
98 line = 0;
99 while(readln(buf, sizeof buf) != 0) {
100 line++;
101 uname = getword(buf, L':', 0, 0); /* skip number */
102 if(uname == nil)
103 continue;
104
105 ulead = getword(uname, L':', 0, 0); /* skip name */
106 if(ulead == nil)
107 continue;
108
109 p = getword(ulead, L':', "no : after leader", line);
110 if(p == nil)
111 continue;
112
113 ui = uidpstr(uname);
114 if(ui == nil)
115 continue;
116
117 /* set to owner if name not known */
118 ui->lead = 0;
119 if(ulead[0]) {
120 o = strtouid(ulead);
121 if(o >= 0)
122 ui->lead = o;
123 else
124 ui->lead = ui->uid;
125 }
126 ui->gtab = &gidspace[g];
127 ui->ngrp = 0;
128 while (p != nil) {
129 unext = getword(p, L',', 0, 0);
130 o = strtouid(p);
131 if(o >= 0) {
132 gidspace[g++] = o;
133 ui->ngrp++;
134 }
135 p = unext;
136 }
137 }
138
139 cons.ngid = g;
140
141 putbuf(uidgc.uidbuf);
142 print("%d uids read, %d groups used\n", cons.nuid, cons.ngid);
143 }
144
145 void
cmd_newuser(int argc,char * argv[])146 cmd_newuser(int argc, char *argv[])
147 {
148 if(argc <= 1) {
149 print("usage: newuser args\n");
150 print("\tname -- create a new user\n");
151 print("\tname : -- create a new group\n");
152 print("\tname ? -- show entry for user\n");
153 print("\tname name -- rename\n");
154 print("\tname =[name] -- add/alter/remove leader\n");
155 print("\tname +name -- add member\n");
156 print("\tname -name -- delete member\n");
157 return;
158 }
159 do_newuser(argc, argv);
160 }
161
162 void
do_newuser(int argc,char * argv[])163 do_newuser(int argc, char *argv[])
164 {
165 int i, l, n, nuid;
166 char *p, *md, *q;
167 Rune *r;
168 Userid *s;
169 Uid *ui, *u2;
170
171 nuid = 10000;
172 md = 0;
173 if(argc == 2) {
174 nuid = 1;
175 argv[2] = ":";
176 }
177
178 for(r = ichar; *r; r++)
179 if(utfrune(argv[1], *r)) {
180 print("illegal character in name\n");
181 return;
182 }
183 if(strlen(argv[1]) > NAMELEN-1) {
184 print("name %s too long\n", argv[1]);
185 return;
186 }
187
188 p = argv[2];
189 switch(*p) {
190 case '?':
191 ui = chkuid(argv[1], 1);
192 if(ui == 0)
193 return;
194 pentry(buf, ui);
195 n = strlen(buf);
196 p = buf;
197 while(n > PRINTSIZE-5) {
198 q = p;
199 p += PRINTSIZE-5;
200 n -= PRINTSIZE-5;
201 i = *p;
202 *p = 0;
203 print("%s", q);
204 *p = i;
205 }
206 print("%s\n", p);
207 return;
208
209 case ':':
210 if(chkuid(argv[1], 0))
211 return;
212 while(uidtop(nuid) != 0)
213 nuid++;
214 if(cons.nuid >= conf.nuid) {
215 print("conf.nuid too small (%ld)\n", conf.nuid);
216 return;
217 }
218
219 wlock(&uidgc.uidlock);
220 ui = &uid[cons.nuid++];
221 ui->uid = nuid;
222 ui->lead = 0;
223 if(nuid < 10000) {
224 ui->lead = ui->uid;
225 md = argv[1];
226 }
227 strcpy(ui->name, argv[1]);
228 ui->ngrp = 0;
229 qsort(uid, cons.nuid, sizeof(uid[0]), byuid);
230 wunlock(&uidgc.uidlock);
231 break;
232
233 case '=':
234 ui = chkuid(argv[1], 1);
235 if(ui == 0)
236 return;
237 p++;
238 if(*p == '\0') {
239 ui->lead = 0;
240 break;
241 }
242 u2 = chkuid(p, 1);
243 if(u2 == 0)
244 return;
245 ui->lead = u2->uid;
246 break;
247
248 case '+':
249 ui = chkuid(argv[1], 1);
250 if(ui == 0)
251 return;
252 p++;
253 u2 = chkuid(p, 1);
254 if(u2 == 0)
255 return;
256 if(u2->uid == ui->uid)
257 return;
258 if(cons.ngid+ui->ngrp+1 >= conf.gidspace) {
259 print("conf.gidspace too small (%ld)\n", conf.gidspace);
260 return;
261 }
262 for(i = 0; i < ui->ngrp; i++) {
263 if(ui->gtab[i] == u2->uid) {
264 print("member already in group\n");
265 return;
266 }
267 }
268
269 wlock(&uidgc.uidlock);
270 s = gidspace+cons.ngid;
271 memmove(s, ui->gtab, ui->ngrp*sizeof(*s));
272 ui->gtab = s;
273 s[ui->ngrp++] = u2->uid;
274 cons.ngid += ui->ngrp+1;
275 wunlock(&uidgc.uidlock);
276 break;
277
278 case '-':
279 ui = chkuid(argv[1], 1);
280 if(ui == 0)
281 return;
282 p++;
283 u2 = chkuid(p, 1);
284 if(u2 == 0)
285 return;
286 for(i = 0; i < ui->ngrp; i++)
287 if(ui->gtab[i] == u2->uid)
288 break;
289
290 if(i == ui->ngrp) {
291 print("%s not in group\n", p);
292 return;
293 }
294
295 wlock(&uidgc.uidlock);
296 s = ui->gtab+i;
297 ui->ngrp--;
298 memmove(s, s+1, (ui->ngrp-i)*sizeof(*s));
299 wunlock(&uidgc.uidlock);
300 break;
301
302 default:
303 if(chkuid(argv[2], 0))
304 return;
305
306 for(r = ichar; *r; r++)
307 if(utfrune(argv[2], *r)) {
308 print("illegal character in name\n");
309 return;
310 }
311
312 ui = chkuid(argv[1], 1);
313 if(ui == 0)
314 return;
315
316 if(strlen(argv[2]) > NAMELEN-1) {
317 print("name %s too long\n", argv[2]);
318 return;
319 }
320
321 wlock(&uidgc.uidlock);
322 strcpy(ui->name, argv[2]);
323 wunlock(&uidgc.uidlock);
324 break;
325 }
326
327
328 if(walkto("/adm/users") || con_open(FID2, OWRITE|OTRUNC)) {
329 print("can't open /adm/users for write\n");
330 return;
331 }
332
333 cons.offset = 0;
334 for(i = 0; i < cons.nuid; i++) {
335 pentry(buf, &uid[i]);
336 l = strlen(buf);
337 n = con_write(FID2, buf, cons.offset, l);
338 if(l != n)
339 print("short write on /adm/users\n");
340 cons.offset += n;
341 }
342
343 if(md != 0) {
344 sprint(buf, "create /usr/%s %s %s 755 d", md, md, md);
345 print("%s\n", buf);
346 cmd_exec(buf);
347 }
348 }
349
350 Uid*
chkuid(char * name,int chk)351 chkuid(char *name, int chk)
352 {
353 Uid *u;
354
355 u = uidpstr(name);
356 if(chk == 1) {
357 if(u == 0)
358 print("%s does not exist\n", name);
359 }
360 else {
361 if(u != 0)
362 print("%s already exists\n", name);
363 }
364 return u;
365 }
366
367 void
pentry(char * buf,Uid * u)368 pentry(char *buf, Uid *u)
369 {
370 int i, posn;
371 Uid *p;
372
373 posn = sprint(buf, "%d:%s:", u->uid, u->name);
374 p = uidtop(u->lead);
375 if(p && u->lead != 0)
376 posn += sprint(buf+posn, "%s", p->name);
377
378 posn += sprint(buf+posn, ":");
379 for(i = 0; i < u->ngrp; i++) {
380 p = uidtop(u->gtab[i]);
381 if(i != 0)
382 posn += sprint(buf+posn, ",");
383 if(p != 0)
384 posn += sprint(buf+posn, "%s", p->name);
385 else
386 posn += sprint(buf+posn, "%d", u->gtab[i]);
387 }
388 sprint(buf+posn, "\n");
389 }
390
391 void
setminusers(void)392 setminusers(void)
393 {
394 int u;
395
396 for(u = 0; minusers[u].name; u++) {
397 strcpy(uid[u].name, minusers[u].name);
398 uid[u].uid = minusers[u].uid;
399 uid[u].lead = minusers[u].lead;
400 }
401 cons.nuid = u;
402 qsort(uid, u, sizeof(uid[0]), byuid);
403 }
404
405 Uid*
uidpstr(char * name)406 uidpstr(char *name)
407 {
408 Uid *s, *e;
409
410 s = uid;
411 for(e = s+cons.nuid; s < e; s++) {
412 if(strcmp(name, s->name) == 0)
413 return s;
414 }
415 return 0;
416 }
417
418 char*
getword(char * buf,Rune delim,char * error,int line)419 getword(char *buf, Rune delim, char *error, int line)
420 {
421 char *p;
422
423 p = utfrune(buf, delim);
424 if(p == 0) {
425 if(error)
426 print("cmd_users: %s line %d\n", error, line);
427 return 0;
428 }
429 *p = '\0';
430 return p+1;
431 }
432
433 int
strtouid(char * name)434 strtouid(char *name)
435 {
436 Uid *u;
437 int id;
438
439 rlock(&uidgc.uidlock);
440
441 u = uidpstr(name);
442 id = -2;
443 if(u != 0)
444 id = u->uid;
445
446 runlock(&uidgc.uidlock);
447
448 return id;
449 }
450
451 Uid*
uidtop(int id)452 uidtop(int id)
453 {
454 Uid *bot, *top, *new;
455
456 bot = uid;
457 top = bot + cons.nuid-1;
458
459 while(bot <= top){
460 new = bot + (top - bot)/2;
461 if(new->uid == id)
462 return new;
463 if(new->uid < id)
464 bot = new + 1;
465 else
466 top = new - 1;
467 }
468 return 0;
469 }
470
471 void
uidtostr(char * name,int id,int dolock)472 uidtostr(char *name, int id, int dolock)
473 {
474 Uid *p;
475
476 if(dolock)
477 rlock(&uidgc.uidlock);
478
479 p = uidtop(id);
480 if(p == 0)
481 strcpy(name, "none");
482 else
483 strcpy(name, p->name);
484
485 if(dolock)
486 runlock(&uidgc.uidlock);
487 }
488
489 int
ingroup(int u,int g)490 ingroup(int u, int g)
491 {
492 Uid *p;
493 Userid *s, *e;
494
495 if(u == g)
496 return 1;
497
498 rlock(&uidgc.uidlock);
499 p = uidtop(g);
500 if(p != 0) {
501 s = p->gtab;
502 for(e = s + p->ngrp; s < e; s++) {
503 if(*s == u) {
504 runlock(&uidgc.uidlock);
505 return 1;
506 }
507 }
508 }
509 runlock(&uidgc.uidlock);
510 return 0;
511 }
512
513 int
leadgroup(int ui,int gi)514 leadgroup(int ui, int gi)
515 {
516 int i;
517 Uid *u;
518
519 /* user 'none' cannot be a group leader */
520 if(ui == 0)
521 return 0;
522
523 rlock(&uidgc.uidlock);
524 u = uidtop(gi);
525 if(u == 0) {
526 runlock(&uidgc.uidlock);
527 return 0;
528 }
529 i = u->lead;
530 runlock(&uidgc.uidlock);
531 if(i == ui)
532 return 1;
533 if(i == 0)
534 return ingroup(ui, gi);
535
536 return 0;
537 }
538
539 int
byuid(void * a1,void * a2)540 byuid(void *a1, void *a2)
541 {
542 Uid *u1, *u2;
543
544 u1 = a1;
545 u2 = a2;
546 return u1->uid - u2->uid;
547 }
548
549 int
fchar(void)550 fchar(void)
551 {
552 int n;
553
554 n = BUFSIZE;
555 if(n > MAXDAT)
556 n = MAXDAT;
557 if(uidgc.find >= uidgc.flen) {
558 uidgc.find = 0;
559 uidgc.flen = con_read(FID2, uidgc.uidbuf->iobuf, cons.offset, n);
560 if(uidgc.flen <= 0)
561 return -1;
562 cons.offset += uidgc.flen;
563 }
564 return (uchar)uidgc.uidbuf->iobuf[uidgc.find++];
565 }
566
567 int
readln(char * p,int len)568 readln(char *p, int len)
569 {
570 int n, c;
571
572 n = 0;
573 while(len--) {
574 c = fchar();
575 if(c == -1 || c == '\n')
576 break;
577 n++;
578 *p++ = c;
579 }
580 *p = '\0';
581 return n;
582 }
583