9user.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951
  1. #include "stdinc.h"
  2. #include "9.h"
  3. enum {
  4. NUserHash = 1009,
  5. };
  6. typedef struct Ubox Ubox;
  7. typedef struct User User;
  8. typedef struct User {
  9. char* uid;
  10. char* uname;
  11. char* leader;
  12. char** group;
  13. int ngroup;
  14. User* next; /* */
  15. User* ihash; /* lookup by .uid */
  16. User* nhash; /* lookup by .uname */
  17. } User;
  18. #pragma varargck type "U" User*
  19. typedef struct Ubox {
  20. User* head;
  21. User* tail;
  22. int nuser;
  23. int len;
  24. User* ihash[NUserHash]; /* lookup by .uid */
  25. User* nhash[NUserHash]; /* lookup by .uname */
  26. } Ubox;
  27. static struct {
  28. VtLock* lock;
  29. Ubox* box;
  30. } ubox;
  31. static char usersDefault[] = {
  32. "adm:adm:adm:sys\n"
  33. "none:none::\n"
  34. "noworld:noworld::\n"
  35. "sys:sys::glenda\n"
  36. "glenda:glenda:glenda:\n"
  37. };
  38. static char* usersMandatory[] = {
  39. "adm",
  40. "none",
  41. "noworld",
  42. "sys",
  43. nil,
  44. };
  45. char* uidadm = "adm";
  46. char* unamenone = "none";
  47. char* uidnoworld = "noworld";
  48. static u32int
  49. userHash(char* s)
  50. {
  51. uchar *p;
  52. u32int hash;
  53. hash = 0;
  54. for(p = (uchar*)s; *p != '\0'; p++)
  55. hash = hash*7 + *p;
  56. return hash % NUserHash;
  57. }
  58. static User*
  59. _userByUid(Ubox* box, char* uid)
  60. {
  61. User *u;
  62. if(box != nil){
  63. for(u = box->ihash[userHash(uid)]; u != nil; u = u->ihash){
  64. if(strcmp(u->uid, uid) == 0)
  65. return u;
  66. }
  67. }
  68. vtSetError("uname: uid '%s' not found", uid);
  69. return nil;
  70. }
  71. char*
  72. unameByUid(char* uid)
  73. {
  74. User *u;
  75. char *uname;
  76. vtRLock(ubox.lock);
  77. if((u = _userByUid(ubox.box, uid)) == nil){
  78. vtRUnlock(ubox.lock);
  79. return nil;
  80. }
  81. uname = vtStrDup(u->uname);
  82. vtRUnlock(ubox.lock);
  83. return uname;
  84. }
  85. static User*
  86. _userByUname(Ubox* box, char* uname)
  87. {
  88. User *u;
  89. if(box != nil){
  90. for(u = box->nhash[userHash(uname)]; u != nil; u = u->nhash){
  91. if(strcmp(u->uname, uname) == 0)
  92. return u;
  93. }
  94. }
  95. vtSetError("uname: uname '%s' not found", uname);
  96. return nil;
  97. }
  98. char*
  99. uidByUname(char* uname)
  100. {
  101. User *u;
  102. char *uid;
  103. vtRLock(ubox.lock);
  104. if((u = _userByUname(ubox.box, uname)) == nil){
  105. vtRUnlock(ubox.lock);
  106. return nil;
  107. }
  108. uid = vtStrDup(u->uid);
  109. vtRUnlock(ubox.lock);
  110. return uid;
  111. }
  112. static int
  113. _groupMember(Ubox* box, char* group, char* member, int whenNoGroup)
  114. {
  115. int i;
  116. User *g, *m;
  117. /*
  118. * Is 'member' a member of 'group'?
  119. * Note that 'group' is a 'uid' and not a 'uname'.
  120. * A 'member' is automatically in their own group.
  121. */
  122. if((g = _userByUid(box, group)) == nil)
  123. return whenNoGroup;
  124. if((m = _userByUname(box, member)) == nil)
  125. return 0;
  126. if(m == g)
  127. return 1;
  128. for(i = 0; i < g->ngroup; i++){
  129. if(strcmp(g->group[i], member) == 0)
  130. return 1;
  131. }
  132. return 0;
  133. }
  134. int
  135. groupWriteMember(char* uname)
  136. {
  137. int ret;
  138. /*
  139. * If there is a ``write'' group, then only its members can write
  140. * to the file system, no matter what the permission bits say.
  141. *
  142. * To users not in the ``write'' group, the file system appears
  143. * read only. This is used to serve sources.cs.bell-labs.com
  144. * to the world.
  145. *
  146. * Note that if there is no ``write'' group, then this routine
  147. * makes it look like everyone is a member -- the opposite
  148. * of what groupMember does.
  149. *
  150. * We use this for sources.cs.bell-labs.com.
  151. * If this slows things down too much on systems that don't
  152. * use this functionality, we could cache the write group lookup.
  153. */
  154. vtRLock(ubox.lock);
  155. ret = _groupMember(ubox.box, "write", uname, 1);
  156. vtRUnlock(ubox.lock);
  157. return ret;
  158. }
  159. static int
  160. _groupRemMember(Ubox* box, User* g, char* member)
  161. {
  162. int i;
  163. if(_userByUname(box, member) == nil)
  164. return 0;
  165. for(i = 0; i < g->ngroup; i++){
  166. if(strcmp(g->group[i], member) == 0)
  167. break;
  168. }
  169. if(i >= g->ngroup){
  170. if(strcmp(g->uname, member) == 0)
  171. vtSetError("uname: '%s' always in own group", member);
  172. else
  173. vtSetError("uname: '%s' not in group '%s'",
  174. member, g->uname);
  175. return 0;
  176. }
  177. vtMemFree(g->group[i]);
  178. box->len -= strlen(member);
  179. if(g->ngroup > 1)
  180. box->len--;
  181. g->ngroup--;
  182. switch(g->ngroup){
  183. case 0:
  184. vtMemFree(g->group);
  185. g->group = nil;
  186. break;
  187. default:
  188. while(i < g->ngroup){
  189. g->group[i] = g->group[i+1];
  190. i++;
  191. }
  192. /*FALLTHROUGH*/
  193. case 1:
  194. g->group = vtMemRealloc(g->group, (g->ngroup)*sizeof(char*));
  195. break;
  196. }
  197. return 1;
  198. }
  199. static int
  200. _groupAddMember(Ubox* box, User* g, char* member)
  201. {
  202. User *u;
  203. if((u = _userByUname(box, member)) == nil)
  204. return 0;
  205. if(_groupMember(box, g->uid, u->uname, 0)){
  206. if(strcmp(g->uname, member) == 0)
  207. vtSetError("uname: '%s' always in own group", member);
  208. else
  209. vtSetError("uname: '%s' already in group '%s'",
  210. member, g->uname);
  211. return 0;
  212. }
  213. g->group = vtMemRealloc(g->group, (g->ngroup+1)*sizeof(char*));
  214. g->group[g->ngroup] = vtStrDup(member);
  215. box->len += strlen(member);
  216. g->ngroup++;
  217. if(g->ngroup > 1)
  218. box->len++;
  219. return 1;
  220. }
  221. int
  222. groupMember(char* group, char* member)
  223. {
  224. int r;
  225. if(group == nil)
  226. return 0;
  227. vtRLock(ubox.lock);
  228. r = _groupMember(ubox.box, group, member, 0);
  229. vtRUnlock(ubox.lock);
  230. return r;
  231. }
  232. int
  233. groupLeader(char* group, char* member)
  234. {
  235. int r;
  236. User *g;
  237. /*
  238. * Is 'member' the leader of 'group'?
  239. * Note that 'group' is a 'uid' and not a 'uname'.
  240. * Uname 'none' cannot be a group leader.
  241. */
  242. if(strcmp(member, unamenone) == 0 || group == nil)
  243. return 0;
  244. vtRLock(ubox.lock);
  245. if((g = _userByUid(ubox.box, group)) == nil){
  246. vtRUnlock(ubox.lock);
  247. return 0;
  248. }
  249. if(g->leader != nil){
  250. if(strcmp(g->leader, member) == 0){
  251. vtRUnlock(ubox.lock);
  252. return 1;
  253. }
  254. r = 0;
  255. }
  256. else
  257. r = _groupMember(ubox.box, group, member, 0);
  258. vtRUnlock(ubox.lock);
  259. return r;
  260. }
  261. static void
  262. userFree(User* u)
  263. {
  264. int i;
  265. vtMemFree(u->uid);
  266. vtMemFree(u->uname);
  267. if(u->leader != nil)
  268. vtMemFree(u->leader);
  269. if(u->ngroup){
  270. for(i = 0; i < u->ngroup; i++)
  271. vtMemFree(u->group[i]);
  272. vtMemFree(u->group);
  273. }
  274. vtMemFree(u);
  275. }
  276. static User*
  277. userAlloc(char* uid, char* uname)
  278. {
  279. User *u;
  280. u = vtMemAllocZ(sizeof(User));
  281. u->uid = vtStrDup(uid);
  282. u->uname = vtStrDup(uname);
  283. return u;
  284. }
  285. int
  286. validUserName(char* name)
  287. {
  288. Rune *r;
  289. static Rune invalid[] = L"#:,()";
  290. for(r = invalid; *r != '\0'; r++){
  291. if(utfrune(name, *r))
  292. return 0;
  293. }
  294. return 1;
  295. }
  296. static int
  297. userFmt(Fmt* fmt)
  298. {
  299. User *u;
  300. int i, r;
  301. u = va_arg(fmt->args, User*);
  302. r = fmtprint(fmt, "%s:%s:", u->uid, u->uname);
  303. if(u->leader != nil)
  304. r += fmtprint(fmt, u->leader);
  305. r += fmtprint(fmt, ":");
  306. if(u->ngroup){
  307. r += fmtprint(fmt, u->group[0]);
  308. for(i = 1; i < u->ngroup; i++)
  309. r += fmtprint(fmt, ",%s", u->group[i]);
  310. }
  311. return r;
  312. }
  313. static int
  314. usersFileWrite(Ubox* box)
  315. {
  316. Fs *fs;
  317. User *u;
  318. int i, r;
  319. Fsys *fsys;
  320. char *p, *q, *s;
  321. File *dir, *file;
  322. if((fsys = fsysGet("main")) == nil)
  323. return 0;
  324. fsysFsRlock(fsys);
  325. fs = fsysGetFs(fsys);
  326. /*
  327. * BUG:
  328. * the owner/group/permissions need to be thought out.
  329. */
  330. r = 0;
  331. if((dir = fileOpen(fs, "/active")) == nil)
  332. goto tidy0;
  333. if((file = fileWalk(dir, uidadm)) == nil)
  334. file = fileCreate(dir, uidadm, ModeDir|0775, uidadm);
  335. fileDecRef(dir);
  336. if(file == nil)
  337. goto tidy;
  338. dir = file;
  339. if((file = fileWalk(dir, "users")) == nil)
  340. file = fileCreate(dir, "users", 0664, uidadm);
  341. fileDecRef(dir);
  342. if(file == nil)
  343. goto tidy;
  344. if(!fileTruncate(file, uidadm))
  345. goto tidy;
  346. p = s = vtMemAlloc(box->len+1);
  347. q = p + box->len+1;
  348. for(u = box->head; u != nil; u = u->next){
  349. p += snprint(p, q-p, "%s:%s:", u->uid, u->uname);
  350. if(u->leader != nil)
  351. p+= snprint(p, q-p, u->leader);
  352. p += snprint(p, q-p, ":");
  353. if(u->ngroup){
  354. p += snprint(p, q-p, u->group[0]);
  355. for(i = 1; i < u->ngroup; i++)
  356. p += snprint(p, q-p, ",%s", u->group[i]);
  357. }
  358. p += snprint(p, q-p, "\n");
  359. }
  360. r = fileWrite(file, s, box->len, 0, uidadm);
  361. vtMemFree(s);
  362. tidy:
  363. if(file != nil)
  364. fileDecRef(file);
  365. tidy0:
  366. fsysFsRUnlock(fsys);
  367. fsysPut(fsys);
  368. return r;
  369. }
  370. static void
  371. uboxRemUser(Ubox* box, User *u)
  372. {
  373. User **h, *up;
  374. h = &box->ihash[userHash(u->uid)];
  375. for(up = *h; up != nil && up != u; up = up->ihash)
  376. h = &up->ihash;
  377. assert(up == u);
  378. *h = up->ihash;
  379. box->len -= strlen(u->uid);
  380. h = &box->nhash[userHash(u->uname)];
  381. for(up = *h; up != nil && up != u; up = up->nhash)
  382. h = &up->nhash;
  383. assert(up == u);
  384. *h = up->nhash;
  385. box->len -= strlen(u->uname);
  386. h = &box->head;
  387. for(up = *h; up != nil && strcmp(up->uid, u->uid) != 0; up = up->next)
  388. h = &up->next;
  389. assert(up == u);
  390. *h = u->next;
  391. u->next = nil;
  392. box->len -= 4;
  393. box->nuser--;
  394. }
  395. static void
  396. uboxAddUser(Ubox* box, User* u)
  397. {
  398. User **h, *up;
  399. h = &box->ihash[userHash(u->uid)];
  400. u->ihash = *h;
  401. *h = u;
  402. box->len += strlen(u->uid);
  403. h = &box->nhash[userHash(u->uname)];
  404. u->nhash = *h;
  405. *h = u;
  406. box->len += strlen(u->uname);
  407. h = &box->head;
  408. for(up = *h; up != nil && strcmp(up->uid, u->uid) < 0; up = up->next)
  409. h = &up->next;
  410. u->next = *h;
  411. *h = u;
  412. box->len += 4;
  413. box->nuser++;
  414. }
  415. static void
  416. uboxDump(Ubox* box)
  417. {
  418. User* u;
  419. consPrint("nuser %d len = %d\n", box->nuser, box->len);
  420. for(u = box->head; u != nil; u = u->next)
  421. consPrint("%U\n", u);
  422. }
  423. static void
  424. uboxFree(Ubox* box)
  425. {
  426. User *next, *u;
  427. for(u = box->head; u != nil; u = next){
  428. next = u->next;
  429. userFree(u);
  430. }
  431. vtMemFree(box);
  432. }
  433. static int
  434. uboxInit(char* users, int len)
  435. {
  436. User *g, *u;
  437. Ubox *box, *obox;
  438. int blank, comment, i, nline, nuser;
  439. char *buf, *f[5], **line, *p, *q, *s;
  440. /*
  441. * Strip out whitespace and comments.
  442. * Note that comments are pointless, they disappear
  443. * when the server writes the database back out.
  444. */
  445. blank = 1;
  446. comment = nline = 0;
  447. s = p = buf = vtMemAlloc(len+1);
  448. for(q = users; *q != '\0'; q++){
  449. if(*q == '\r' || *q == '\t' || *q == ' ')
  450. continue;
  451. if(*q == '\n'){
  452. if(!blank){
  453. if(p != s){
  454. *p++ = '\n';
  455. nline++;
  456. s = p;
  457. }
  458. blank = 1;
  459. }
  460. comment = 0;
  461. continue;
  462. }
  463. if(*q == '#')
  464. comment = 1;
  465. blank = 0;
  466. if(!comment)
  467. *p++ = *q;
  468. }
  469. *p = '\0';
  470. line = vtMemAllocZ((nline+2)*sizeof(char*));
  471. if((i = gettokens(buf, line, nline+2, "\n")) != nline){
  472. fprint(2, "nline %d (%d) botch\n", nline, i);
  473. vtMemFree(line);
  474. vtMemFree(buf);
  475. return 0;
  476. }
  477. /*
  478. * Everything is updated in a local Ubox until verified.
  479. */
  480. box = vtMemAllocZ(sizeof(Ubox));
  481. /*
  482. * First pass - check format, check for duplicates
  483. * and enter in hash buckets.
  484. */
  485. nuser = 0;
  486. for(i = 0; i < nline; i++){
  487. s = vtStrDup(line[i]);
  488. if(getfields(s, f, nelem(f), 0, ":") != 4){
  489. fprint(2, "bad line '%s'\n", line[i]);
  490. vtMemFree(s);
  491. continue;
  492. }
  493. if(*f[0] == '\0' || *f[1] == '\0'){
  494. fprint(2, "bad line '%s'\n", line[i]);
  495. vtMemFree(s);
  496. continue;
  497. }
  498. if(!validUserName(f[0])){
  499. fprint(2, "invalid uid '%s'\n", f[0]);
  500. vtMemFree(s);
  501. continue;
  502. }
  503. if(_userByUid(box, f[0]) != nil){
  504. fprint(2, "duplicate uid '%s'\n", f[0]);
  505. vtMemFree(s);
  506. continue;
  507. }
  508. if(!validUserName(f[1])){
  509. fprint(2, "invalid uname '%s'\n", f[0]);
  510. vtMemFree(s);
  511. continue;
  512. }
  513. if(_userByUname(box, f[1]) != nil){
  514. fprint(2, "duplicate uname '%s'\n", f[1]);
  515. vtMemFree(s);
  516. continue;
  517. }
  518. u = userAlloc(f[0], f[1]);
  519. uboxAddUser(box, u);
  520. line[nuser] = line[i];
  521. nuser++;
  522. vtMemFree(s);
  523. }
  524. assert(box->nuser == nuser);
  525. /*
  526. * Second pass - fill in leader and group information.
  527. */
  528. for(i = 0; i < nuser; i++){
  529. s = vtStrDup(line[i]);
  530. getfields(s, f, nelem(f), 0, ":");
  531. assert(g = _userByUname(box, f[1]));
  532. if(*f[2] != '\0'){
  533. if((u = _userByUname(box, f[2])) == nil)
  534. g->leader = vtStrDup(g->uname);
  535. else
  536. g->leader = vtStrDup(u->uname);
  537. box->len += strlen(g->leader);
  538. }
  539. for(p = f[3]; p != nil; p = q){
  540. if((q = utfrune(p, L',')) != nil)
  541. *q++ = '\0';
  542. if(!_groupAddMember(box, g, p)){
  543. // print/log error here
  544. }
  545. }
  546. vtMemFree(s);
  547. }
  548. vtMemFree(line);
  549. vtMemFree(buf);
  550. for(i = 0; usersMandatory[i] != nil; i++){
  551. if((u = _userByUid(box, usersMandatory[i])) == nil){
  552. vtSetError("user '%s' is mandatory", usersMandatory[i]);
  553. uboxFree(box);
  554. return 0;
  555. }
  556. if(strcmp(u->uid, u->uname) != 0){
  557. vtSetError("uid/uname for user '%s' must match",
  558. usersMandatory[i]);
  559. uboxFree(box);
  560. return 0;
  561. }
  562. }
  563. vtLock(ubox.lock);
  564. obox = ubox.box;
  565. ubox.box = box;
  566. vtUnlock(ubox.lock);
  567. if(obox != nil)
  568. uboxFree(obox);
  569. return 1;
  570. }
  571. int
  572. usersFileRead(char* path)
  573. {
  574. char *p;
  575. File *file;
  576. Fsys *fsys;
  577. int len, r;
  578. uvlong size;
  579. if((fsys = fsysGet("main")) == nil)
  580. return 0;
  581. fsysFsRlock(fsys);
  582. if(path == nil)
  583. path = "/active/adm/users";
  584. r = 0;
  585. if((file = fileOpen(fsysGetFs(fsys), path)) != nil){
  586. if(fileGetSize(file, &size)){
  587. len = size;
  588. p = vtMemAlloc(size+1);
  589. if(fileRead(file, p, len, 0) == len){
  590. p[len] = '\0';
  591. r = uboxInit(p, len);
  592. }
  593. }
  594. fileDecRef(file);
  595. }
  596. fsysFsRUnlock(fsys);
  597. fsysPut(fsys);
  598. return r;
  599. }
  600. static int
  601. cmdUname(int argc, char* argv[])
  602. {
  603. User *u, *up;
  604. int d, dflag, i, r;
  605. char *p, *uid, *uname;
  606. char *createfmt = "fsys main create /active/usr/%s %s %s d775";
  607. char *usage = "usage: uname [-d] uname [uid|:uid|%%newname|=leader|+member|-member]";
  608. dflag = 0;
  609. ARGBEGIN{
  610. default:
  611. return cliError(usage);
  612. case 'd':
  613. dflag = 1;
  614. break;
  615. }ARGEND
  616. if(argc < 1){
  617. if(!dflag)
  618. return cliError(usage);
  619. vtRLock(ubox.lock);
  620. uboxDump(ubox.box);
  621. vtRUnlock(ubox.lock);
  622. return 1;
  623. }
  624. uname = argv[0];
  625. argc--; argv++;
  626. if(argc == 0){
  627. vtRLock(ubox.lock);
  628. if((u = _userByUname(ubox.box, uname)) == nil){
  629. vtRUnlock(ubox.lock);
  630. return 0;
  631. }
  632. consPrint("\t%U\n", u);
  633. vtRUnlock(ubox.lock);
  634. return 1;
  635. }
  636. vtLock(ubox.lock);
  637. u = _userByUname(ubox.box, uname);
  638. while(argc--){
  639. if(argv[0][0] == '%'){
  640. if(u == nil){
  641. vtUnlock(ubox.lock);
  642. return 0;
  643. }
  644. p = &argv[0][1];
  645. if((up = _userByUname(ubox.box, p)) != nil){
  646. vtSetError("uname: uname '%s' already exists",
  647. up->uname);
  648. vtUnlock(ubox.lock);
  649. return 0;
  650. }
  651. for(i = 0; usersMandatory[i] != nil; i++){
  652. if(strcmp(usersMandatory[i], uname) != 0)
  653. continue;
  654. vtSetError("uname: uname '%s' is mandatory",
  655. uname);
  656. vtUnlock(ubox.lock);
  657. return 0;
  658. }
  659. d = strlen(p) - strlen(u->uname);
  660. for(up = ubox.box->head; up != nil; up = up->next){
  661. if(up->leader != nil){
  662. if(strcmp(up->leader, u->uname) == 0){
  663. vtMemFree(up->leader);
  664. up->leader = vtStrDup(p);
  665. ubox.box->len += d;
  666. }
  667. }
  668. for(i = 0; i < up->ngroup; i++){
  669. if(strcmp(up->group[i], u->uname) != 0)
  670. continue;
  671. vtMemFree(up->group[i]);
  672. up->group[i] = vtStrDup(p);
  673. ubox.box->len += d;
  674. break;
  675. }
  676. }
  677. uboxRemUser(ubox.box, u);
  678. vtMemFree(u->uname);
  679. u->uname = vtStrDup(p);
  680. uboxAddUser(ubox.box, u);
  681. }
  682. else if(argv[0][0] == '='){
  683. if(u == nil){
  684. vtUnlock(ubox.lock);
  685. return 0;
  686. }
  687. if((up = _userByUname(ubox.box, &argv[0][1])) == nil){
  688. if(argv[0][1] != '\0'){
  689. vtUnlock(ubox.lock);
  690. return 0;
  691. }
  692. }
  693. if(u->leader != nil){
  694. ubox.box->len -= strlen(u->leader);
  695. vtMemFree(u->leader);
  696. u->leader = nil;
  697. }
  698. if(up != nil){
  699. u->leader = vtStrDup(up->uname);
  700. ubox.box->len += strlen(u->leader);
  701. }
  702. }
  703. else if(argv[0][0] == '+'){
  704. if(u == nil){
  705. vtUnlock(ubox.lock);
  706. return 0;
  707. }
  708. if((up = _userByUname(ubox.box, &argv[0][1])) == nil){
  709. vtUnlock(ubox.lock);
  710. return 0;
  711. }
  712. if(!_groupAddMember(ubox.box, u, up->uname)){
  713. vtUnlock(ubox.lock);
  714. return 0;
  715. }
  716. }
  717. else if(argv[0][0] == '-'){
  718. if(u == nil){
  719. vtUnlock(ubox.lock);
  720. return 0;
  721. }
  722. if((up = _userByUname(ubox.box, &argv[0][1])) == nil){
  723. vtUnlock(ubox.lock);
  724. return 0;
  725. }
  726. if(!_groupRemMember(ubox.box, u, up->uname)){
  727. vtUnlock(ubox.lock);
  728. return 0;
  729. }
  730. }
  731. else{
  732. if(u != nil){
  733. vtSetError("uname: uname '%s' already exists",
  734. u->uname);
  735. vtUnlock(ubox.lock);
  736. return 0;
  737. }
  738. uid = argv[0];
  739. if(*uid == ':')
  740. uid++;
  741. if((u = _userByUid(ubox.box, uid)) != nil){
  742. vtSetError("uname: uid '%s' already exists",
  743. u->uid);
  744. vtUnlock(ubox.lock);
  745. return 0;
  746. }
  747. u = userAlloc(uid, uname);
  748. uboxAddUser(ubox.box, u);
  749. if(argv[0][0] != ':'){
  750. // should have an option for the mode and gid
  751. p = smprint(createfmt, uname, uname, uname);
  752. r = cliExec(p);
  753. vtMemFree(p);
  754. if(r == 0){
  755. vtUnlock(ubox.lock);
  756. return 0;
  757. }
  758. }
  759. }
  760. argv++;
  761. }
  762. if(usersFileWrite(ubox.box) == 0){
  763. vtUnlock(ubox.lock);
  764. return 0;
  765. }
  766. if(dflag)
  767. uboxDump(ubox.box);
  768. vtUnlock(ubox.lock);
  769. return 1;
  770. }
  771. static int
  772. cmdUsers(int argc, char* argv[])
  773. {
  774. Ubox *box;
  775. int dflag, r, wflag;
  776. char *file;
  777. char *usage = "usage: users [-d | -r file] [-w]";
  778. dflag = wflag = 0;
  779. file = nil;
  780. ARGBEGIN{
  781. default:
  782. return cliError(usage);
  783. case 'd':
  784. dflag = 1;
  785. break;
  786. case 'r':
  787. file = ARGF();
  788. if(file == nil)
  789. return cliError(usage);
  790. break;
  791. case 'w':
  792. wflag = 1;
  793. break;
  794. }ARGEND
  795. if(argc)
  796. return cliError(usage);
  797. if(dflag && file)
  798. return cliError("cannot use -d and -r together");
  799. if(dflag)
  800. uboxInit(usersDefault, sizeof(usersDefault));
  801. else if(file){
  802. if(usersFileRead(file) == 0)
  803. return 0;
  804. }
  805. vtRLock(ubox.lock);
  806. box = ubox.box;
  807. consPrint("\tnuser %d len %d\n", box->nuser, box->len);
  808. r = 1;
  809. if(wflag)
  810. r = usersFileWrite(box);
  811. vtRUnlock(ubox.lock);
  812. return r;
  813. }
  814. int
  815. usersInit(void)
  816. {
  817. fmtinstall('U', userFmt);
  818. ubox.lock = vtLockAlloc();
  819. uboxInit(usersDefault, sizeof(usersDefault));
  820. cliAddCmd("users", cmdUsers);
  821. cliAddCmd("uname", cmdUname);
  822. return 1;
  823. }