9user.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948
  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. for(; i < g->ngroup; i++)
  189. g->group[i] = g->group[i+1];
  190. g->group[i] = nil; /* prevent accidents */
  191. g->group = vtMemRealloc(g->group, g->ngroup * sizeof(char*));
  192. break;
  193. }
  194. return 1;
  195. }
  196. static int
  197. _groupAddMember(Ubox* box, User* g, char* member)
  198. {
  199. User *u;
  200. if((u = _userByUname(box, member)) == nil)
  201. return 0;
  202. if(_groupMember(box, g->uid, u->uname, 0)){
  203. if(strcmp(g->uname, member) == 0)
  204. vtSetError("uname: '%s' always in own group", member);
  205. else
  206. vtSetError("uname: '%s' already in group '%s'",
  207. member, g->uname);
  208. return 0;
  209. }
  210. g->group = vtMemRealloc(g->group, (g->ngroup+1)*sizeof(char*));
  211. g->group[g->ngroup] = vtStrDup(member);
  212. box->len += strlen(member);
  213. g->ngroup++;
  214. if(g->ngroup > 1)
  215. box->len++;
  216. return 1;
  217. }
  218. int
  219. groupMember(char* group, char* member)
  220. {
  221. int r;
  222. if(group == nil)
  223. return 0;
  224. vtRLock(ubox.lock);
  225. r = _groupMember(ubox.box, group, member, 0);
  226. vtRUnlock(ubox.lock);
  227. return r;
  228. }
  229. int
  230. groupLeader(char* group, char* member)
  231. {
  232. int r;
  233. User *g;
  234. /*
  235. * Is 'member' the leader of 'group'?
  236. * Note that 'group' is a 'uid' and not a 'uname'.
  237. * Uname 'none' cannot be a group leader.
  238. */
  239. if(strcmp(member, unamenone) == 0 || group == nil)
  240. return 0;
  241. vtRLock(ubox.lock);
  242. if((g = _userByUid(ubox.box, group)) == nil){
  243. vtRUnlock(ubox.lock);
  244. return 0;
  245. }
  246. if(g->leader != nil){
  247. if(strcmp(g->leader, member) == 0){
  248. vtRUnlock(ubox.lock);
  249. return 1;
  250. }
  251. r = 0;
  252. }
  253. else
  254. r = _groupMember(ubox.box, group, member, 0);
  255. vtRUnlock(ubox.lock);
  256. return r;
  257. }
  258. static void
  259. userFree(User* u)
  260. {
  261. int i;
  262. vtMemFree(u->uid);
  263. vtMemFree(u->uname);
  264. if(u->leader != nil)
  265. vtMemFree(u->leader);
  266. if(u->ngroup){
  267. for(i = 0; i < u->ngroup; i++)
  268. vtMemFree(u->group[i]);
  269. vtMemFree(u->group);
  270. }
  271. vtMemFree(u);
  272. }
  273. static User*
  274. userAlloc(char* uid, char* uname)
  275. {
  276. User *u;
  277. u = vtMemAllocZ(sizeof(User));
  278. u->uid = vtStrDup(uid);
  279. u->uname = vtStrDup(uname);
  280. return u;
  281. }
  282. int
  283. validUserName(char* name)
  284. {
  285. Rune *r;
  286. static Rune invalid[] = L"#:,()";
  287. for(r = invalid; *r != '\0'; r++){
  288. if(utfrune(name, *r))
  289. return 0;
  290. }
  291. return 1;
  292. }
  293. static int
  294. userFmt(Fmt* fmt)
  295. {
  296. User *u;
  297. int i, r;
  298. u = va_arg(fmt->args, User*);
  299. r = fmtprint(fmt, "%s:%s:", u->uid, u->uname);
  300. if(u->leader != nil)
  301. r += fmtprint(fmt, u->leader);
  302. r += fmtprint(fmt, ":");
  303. if(u->ngroup){
  304. r += fmtprint(fmt, u->group[0]);
  305. for(i = 1; i < u->ngroup; i++)
  306. r += fmtprint(fmt, ",%s", u->group[i]);
  307. }
  308. return r;
  309. }
  310. static int
  311. usersFileWrite(Ubox* box)
  312. {
  313. Fs *fs;
  314. User *u;
  315. int i, r;
  316. Fsys *fsys;
  317. char *p, *q, *s;
  318. File *dir, *file;
  319. if((fsys = fsysGet("main")) == nil)
  320. return 0;
  321. fsysFsRlock(fsys);
  322. fs = fsysGetFs(fsys);
  323. /*
  324. * BUG:
  325. * the owner/group/permissions need to be thought out.
  326. */
  327. r = 0;
  328. if((dir = fileOpen(fs, "/active")) == nil)
  329. goto tidy0;
  330. if((file = fileWalk(dir, uidadm)) == nil)
  331. file = fileCreate(dir, uidadm, ModeDir|0775, uidadm);
  332. fileDecRef(dir);
  333. if(file == nil)
  334. goto tidy;
  335. dir = file;
  336. if((file = fileWalk(dir, "users")) == nil)
  337. file = fileCreate(dir, "users", 0664, uidadm);
  338. fileDecRef(dir);
  339. if(file == nil)
  340. goto tidy;
  341. if(!fileTruncate(file, uidadm))
  342. goto tidy;
  343. p = s = vtMemAlloc(box->len+1);
  344. q = p + box->len+1;
  345. for(u = box->head; u != nil; u = u->next){
  346. p += snprint(p, q-p, "%s:%s:", u->uid, u->uname);
  347. if(u->leader != nil)
  348. p+= snprint(p, q-p, u->leader);
  349. p += snprint(p, q-p, ":");
  350. if(u->ngroup){
  351. p += snprint(p, q-p, u->group[0]);
  352. for(i = 1; i < u->ngroup; i++)
  353. p += snprint(p, q-p, ",%s", u->group[i]);
  354. }
  355. p += snprint(p, q-p, "\n");
  356. }
  357. r = fileWrite(file, s, box->len, 0, uidadm);
  358. vtMemFree(s);
  359. tidy:
  360. if(file != nil)
  361. fileDecRef(file);
  362. tidy0:
  363. fsysFsRUnlock(fsys);
  364. fsysPut(fsys);
  365. return r;
  366. }
  367. static void
  368. uboxRemUser(Ubox* box, User *u)
  369. {
  370. User **h, *up;
  371. h = &box->ihash[userHash(u->uid)];
  372. for(up = *h; up != nil && up != u; up = up->ihash)
  373. h = &up->ihash;
  374. assert(up == u);
  375. *h = up->ihash;
  376. box->len -= strlen(u->uid);
  377. h = &box->nhash[userHash(u->uname)];
  378. for(up = *h; up != nil && up != u; up = up->nhash)
  379. h = &up->nhash;
  380. assert(up == u);
  381. *h = up->nhash;
  382. box->len -= strlen(u->uname);
  383. h = &box->head;
  384. for(up = *h; up != nil && strcmp(up->uid, u->uid) != 0; up = up->next)
  385. h = &up->next;
  386. assert(up == u);
  387. *h = u->next;
  388. u->next = nil;
  389. box->len -= 4;
  390. box->nuser--;
  391. }
  392. static void
  393. uboxAddUser(Ubox* box, User* u)
  394. {
  395. User **h, *up;
  396. h = &box->ihash[userHash(u->uid)];
  397. u->ihash = *h;
  398. *h = u;
  399. box->len += strlen(u->uid);
  400. h = &box->nhash[userHash(u->uname)];
  401. u->nhash = *h;
  402. *h = u;
  403. box->len += strlen(u->uname);
  404. h = &box->head;
  405. for(up = *h; up != nil && strcmp(up->uid, u->uid) < 0; up = up->next)
  406. h = &up->next;
  407. u->next = *h;
  408. *h = u;
  409. box->len += 4;
  410. box->nuser++;
  411. }
  412. static void
  413. uboxDump(Ubox* box)
  414. {
  415. User* u;
  416. consPrint("nuser %d len = %d\n", box->nuser, box->len);
  417. for(u = box->head; u != nil; u = u->next)
  418. consPrint("%U\n", u);
  419. }
  420. static void
  421. uboxFree(Ubox* box)
  422. {
  423. User *next, *u;
  424. for(u = box->head; u != nil; u = next){
  425. next = u->next;
  426. userFree(u);
  427. }
  428. vtMemFree(box);
  429. }
  430. static int
  431. uboxInit(char* users, int len)
  432. {
  433. User *g, *u;
  434. Ubox *box, *obox;
  435. int blank, comment, i, nline, nuser;
  436. char *buf, *f[5], **line, *p, *q, *s;
  437. /*
  438. * Strip out whitespace and comments.
  439. * Note that comments are pointless, they disappear
  440. * when the server writes the database back out.
  441. */
  442. blank = 1;
  443. comment = nline = 0;
  444. s = p = buf = vtMemAlloc(len+1);
  445. for(q = users; *q != '\0'; q++){
  446. if(*q == '\r' || *q == '\t' || *q == ' ')
  447. continue;
  448. if(*q == '\n'){
  449. if(!blank){
  450. if(p != s){
  451. *p++ = '\n';
  452. nline++;
  453. s = p;
  454. }
  455. blank = 1;
  456. }
  457. comment = 0;
  458. continue;
  459. }
  460. if(*q == '#')
  461. comment = 1;
  462. blank = 0;
  463. if(!comment)
  464. *p++ = *q;
  465. }
  466. *p = '\0';
  467. line = vtMemAllocZ((nline+2)*sizeof(char*));
  468. if((i = gettokens(buf, line, nline+2, "\n")) != nline){
  469. fprint(2, "nline %d (%d) botch\n", nline, i);
  470. vtMemFree(line);
  471. vtMemFree(buf);
  472. return 0;
  473. }
  474. /*
  475. * Everything is updated in a local Ubox until verified.
  476. */
  477. box = vtMemAllocZ(sizeof(Ubox));
  478. /*
  479. * First pass - check format, check for duplicates
  480. * and enter in hash buckets.
  481. */
  482. nuser = 0;
  483. for(i = 0; i < nline; i++){
  484. s = vtStrDup(line[i]);
  485. if(getfields(s, f, nelem(f), 0, ":") != 4){
  486. fprint(2, "bad line '%s'\n", line[i]);
  487. vtMemFree(s);
  488. continue;
  489. }
  490. if(*f[0] == '\0' || *f[1] == '\0'){
  491. fprint(2, "bad line '%s'\n", line[i]);
  492. vtMemFree(s);
  493. continue;
  494. }
  495. if(!validUserName(f[0])){
  496. fprint(2, "invalid uid '%s'\n", f[0]);
  497. vtMemFree(s);
  498. continue;
  499. }
  500. if(_userByUid(box, f[0]) != nil){
  501. fprint(2, "duplicate uid '%s'\n", f[0]);
  502. vtMemFree(s);
  503. continue;
  504. }
  505. if(!validUserName(f[1])){
  506. fprint(2, "invalid uname '%s'\n", f[0]);
  507. vtMemFree(s);
  508. continue;
  509. }
  510. if(_userByUname(box, f[1]) != nil){
  511. fprint(2, "duplicate uname '%s'\n", f[1]);
  512. vtMemFree(s);
  513. continue;
  514. }
  515. u = userAlloc(f[0], f[1]);
  516. uboxAddUser(box, u);
  517. line[nuser] = line[i];
  518. nuser++;
  519. vtMemFree(s);
  520. }
  521. assert(box->nuser == nuser);
  522. /*
  523. * Second pass - fill in leader and group information.
  524. */
  525. for(i = 0; i < nuser; i++){
  526. s = vtStrDup(line[i]);
  527. getfields(s, f, nelem(f), 0, ":");
  528. assert(g = _userByUname(box, f[1]));
  529. if(*f[2] != '\0'){
  530. if((u = _userByUname(box, f[2])) == nil)
  531. g->leader = vtStrDup(g->uname);
  532. else
  533. g->leader = vtStrDup(u->uname);
  534. box->len += strlen(g->leader);
  535. }
  536. for(p = f[3]; p != nil; p = q){
  537. if((q = utfrune(p, L',')) != nil)
  538. *q++ = '\0';
  539. if(!_groupAddMember(box, g, p)){
  540. // print/log error here
  541. }
  542. }
  543. vtMemFree(s);
  544. }
  545. vtMemFree(line);
  546. vtMemFree(buf);
  547. for(i = 0; usersMandatory[i] != nil; i++){
  548. if((u = _userByUid(box, usersMandatory[i])) == nil){
  549. vtSetError("user '%s' is mandatory", usersMandatory[i]);
  550. uboxFree(box);
  551. return 0;
  552. }
  553. if(strcmp(u->uid, u->uname) != 0){
  554. vtSetError("uid/uname for user '%s' must match",
  555. usersMandatory[i]);
  556. uboxFree(box);
  557. return 0;
  558. }
  559. }
  560. vtLock(ubox.lock);
  561. obox = ubox.box;
  562. ubox.box = box;
  563. vtUnlock(ubox.lock);
  564. if(obox != nil)
  565. uboxFree(obox);
  566. return 1;
  567. }
  568. int
  569. usersFileRead(char* path)
  570. {
  571. char *p;
  572. File *file;
  573. Fsys *fsys;
  574. int len, r;
  575. uvlong size;
  576. if((fsys = fsysGet("main")) == nil)
  577. return 0;
  578. fsysFsRlock(fsys);
  579. if(path == nil)
  580. path = "/active/adm/users";
  581. r = 0;
  582. if((file = fileOpen(fsysGetFs(fsys), path)) != nil){
  583. if(fileGetSize(file, &size)){
  584. len = size;
  585. p = vtMemAlloc(size+1);
  586. if(fileRead(file, p, len, 0) == len){
  587. p[len] = '\0';
  588. r = uboxInit(p, len);
  589. }
  590. }
  591. fileDecRef(file);
  592. }
  593. fsysFsRUnlock(fsys);
  594. fsysPut(fsys);
  595. return r;
  596. }
  597. static int
  598. cmdUname(int argc, char* argv[])
  599. {
  600. User *u, *up;
  601. int d, dflag, i, r;
  602. char *p, *uid, *uname;
  603. char *createfmt = "fsys main create /active/usr/%s %s %s d775";
  604. char *usage = "usage: uname [-d] uname [uid|:uid|%%newname|=leader|+member|-member]";
  605. dflag = 0;
  606. ARGBEGIN{
  607. default:
  608. return cliError(usage);
  609. case 'd':
  610. dflag = 1;
  611. break;
  612. }ARGEND
  613. if(argc < 1){
  614. if(!dflag)
  615. return cliError(usage);
  616. vtRLock(ubox.lock);
  617. uboxDump(ubox.box);
  618. vtRUnlock(ubox.lock);
  619. return 1;
  620. }
  621. uname = argv[0];
  622. argc--; argv++;
  623. if(argc == 0){
  624. vtRLock(ubox.lock);
  625. if((u = _userByUname(ubox.box, uname)) == nil){
  626. vtRUnlock(ubox.lock);
  627. return 0;
  628. }
  629. consPrint("\t%U\n", u);
  630. vtRUnlock(ubox.lock);
  631. return 1;
  632. }
  633. vtLock(ubox.lock);
  634. u = _userByUname(ubox.box, uname);
  635. while(argc--){
  636. if(argv[0][0] == '%'){
  637. if(u == nil){
  638. vtUnlock(ubox.lock);
  639. return 0;
  640. }
  641. p = &argv[0][1];
  642. if((up = _userByUname(ubox.box, p)) != nil){
  643. vtSetError("uname: uname '%s' already exists",
  644. up->uname);
  645. vtUnlock(ubox.lock);
  646. return 0;
  647. }
  648. for(i = 0; usersMandatory[i] != nil; i++){
  649. if(strcmp(usersMandatory[i], uname) != 0)
  650. continue;
  651. vtSetError("uname: uname '%s' is mandatory",
  652. uname);
  653. vtUnlock(ubox.lock);
  654. return 0;
  655. }
  656. d = strlen(p) - strlen(u->uname);
  657. for(up = ubox.box->head; up != nil; up = up->next){
  658. if(up->leader != nil){
  659. if(strcmp(up->leader, u->uname) == 0){
  660. vtMemFree(up->leader);
  661. up->leader = vtStrDup(p);
  662. ubox.box->len += d;
  663. }
  664. }
  665. for(i = 0; i < up->ngroup; i++){
  666. if(strcmp(up->group[i], u->uname) != 0)
  667. continue;
  668. vtMemFree(up->group[i]);
  669. up->group[i] = vtStrDup(p);
  670. ubox.box->len += d;
  671. break;
  672. }
  673. }
  674. uboxRemUser(ubox.box, u);
  675. vtMemFree(u->uname);
  676. u->uname = vtStrDup(p);
  677. uboxAddUser(ubox.box, u);
  678. }
  679. else if(argv[0][0] == '='){
  680. if(u == nil){
  681. vtUnlock(ubox.lock);
  682. return 0;
  683. }
  684. if((up = _userByUname(ubox.box, &argv[0][1])) == nil){
  685. if(argv[0][1] != '\0'){
  686. vtUnlock(ubox.lock);
  687. return 0;
  688. }
  689. }
  690. if(u->leader != nil){
  691. ubox.box->len -= strlen(u->leader);
  692. vtMemFree(u->leader);
  693. u->leader = nil;
  694. }
  695. if(up != nil){
  696. u->leader = vtStrDup(up->uname);
  697. ubox.box->len += strlen(u->leader);
  698. }
  699. }
  700. else if(argv[0][0] == '+'){
  701. if(u == nil){
  702. vtUnlock(ubox.lock);
  703. return 0;
  704. }
  705. if((up = _userByUname(ubox.box, &argv[0][1])) == nil){
  706. vtUnlock(ubox.lock);
  707. return 0;
  708. }
  709. if(!_groupAddMember(ubox.box, u, up->uname)){
  710. vtUnlock(ubox.lock);
  711. return 0;
  712. }
  713. }
  714. else if(argv[0][0] == '-'){
  715. if(u == nil){
  716. vtUnlock(ubox.lock);
  717. return 0;
  718. }
  719. if((up = _userByUname(ubox.box, &argv[0][1])) == nil){
  720. vtUnlock(ubox.lock);
  721. return 0;
  722. }
  723. if(!_groupRemMember(ubox.box, u, up->uname)){
  724. vtUnlock(ubox.lock);
  725. return 0;
  726. }
  727. }
  728. else{
  729. if(u != nil){
  730. vtSetError("uname: uname '%s' already exists",
  731. u->uname);
  732. vtUnlock(ubox.lock);
  733. return 0;
  734. }
  735. uid = argv[0];
  736. if(*uid == ':')
  737. uid++;
  738. if((u = _userByUid(ubox.box, uid)) != nil){
  739. vtSetError("uname: uid '%s' already exists",
  740. u->uid);
  741. vtUnlock(ubox.lock);
  742. return 0;
  743. }
  744. u = userAlloc(uid, uname);
  745. uboxAddUser(ubox.box, u);
  746. if(argv[0][0] != ':'){
  747. // should have an option for the mode and gid
  748. p = smprint(createfmt, uname, uname, uname);
  749. r = cliExec(p);
  750. vtMemFree(p);
  751. if(r == 0){
  752. vtUnlock(ubox.lock);
  753. return 0;
  754. }
  755. }
  756. }
  757. argv++;
  758. }
  759. if(usersFileWrite(ubox.box) == 0){
  760. vtUnlock(ubox.lock);
  761. return 0;
  762. }
  763. if(dflag)
  764. uboxDump(ubox.box);
  765. vtUnlock(ubox.lock);
  766. return 1;
  767. }
  768. static int
  769. cmdUsers(int argc, char* argv[])
  770. {
  771. Ubox *box;
  772. int dflag, r, wflag;
  773. char *file;
  774. char *usage = "usage: users [-d | -r file] [-w]";
  775. dflag = wflag = 0;
  776. file = nil;
  777. ARGBEGIN{
  778. default:
  779. return cliError(usage);
  780. case 'd':
  781. dflag = 1;
  782. break;
  783. case 'r':
  784. file = ARGF();
  785. if(file == nil)
  786. return cliError(usage);
  787. break;
  788. case 'w':
  789. wflag = 1;
  790. break;
  791. }ARGEND
  792. if(argc)
  793. return cliError(usage);
  794. if(dflag && file)
  795. return cliError("cannot use -d and -r together");
  796. if(dflag)
  797. uboxInit(usersDefault, sizeof(usersDefault));
  798. else if(file){
  799. if(usersFileRead(file) == 0)
  800. return 0;
  801. }
  802. vtRLock(ubox.lock);
  803. box = ubox.box;
  804. consPrint("\tnuser %d len %d\n", box->nuser, box->len);
  805. r = 1;
  806. if(wflag)
  807. r = usersFileWrite(box);
  808. vtRUnlock(ubox.lock);
  809. return r;
  810. }
  811. int
  812. usersInit(void)
  813. {
  814. fmtinstall('U', userFmt);
  815. ubox.lock = vtLockAlloc();
  816. uboxInit(usersDefault, sizeof(usersDefault));
  817. cliAddCmd("users", cmdUsers);
  818. cliAddCmd("uname", cmdUname);
  819. return 1;
  820. }