uidgid.c 9.6 KB

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