uidgid.c 9.2 KB

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