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 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 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 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* 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 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 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* 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* 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 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* 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 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 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 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 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 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 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