9user.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960
  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. char* name;
  23. int nuser;
  24. int len;
  25. User* ihash[NUserHash]; /* lookup by .uid */
  26. User* nhash[NUserHash]; /* lookup by .uname */
  27. } Ubox;
  28. static struct {
  29. VtLock* lock;
  30. Ubox* box;
  31. } ubox;
  32. static char usersDefault[] = {
  33. "adm:adm:adm:sys\n"
  34. "none:none::\n"
  35. "noworld:noworld::\n"
  36. "sys:sys::\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, "adm")) == nil)
  334. file = fileCreate(dir, "adm", 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. if(box->name != nil)
  432. vtMemFree(box->name);
  433. vtMemFree(box);
  434. }
  435. static int
  436. uboxInit(char* name, char* users, int len)
  437. {
  438. User *g, *u;
  439. Ubox *box, *obox;
  440. int blank, comment, i, nuser;
  441. char *buf, *f[5], **line, *p, *q, *s;
  442. /*
  443. * Strip out whitespace and comments.
  444. * Note that comments are pointless, they disappear
  445. * when the server writes the database back out.
  446. */
  447. blank = 1;
  448. comment = nuser = 0;
  449. s = p = buf = vtMemAlloc(len+1);
  450. for(q = users; *q != '\0'; q++){
  451. if(*q == '\r' || *q == '\t' || *q == ' ')
  452. continue;
  453. if(*q == '\n'){
  454. if(!blank){
  455. if(p != s){
  456. *p++ = '\n';
  457. nuser++;
  458. s = p;
  459. }
  460. blank = 1;
  461. }
  462. comment = 0;
  463. continue;
  464. }
  465. if(*q == '#')
  466. comment = 1;
  467. blank = 0;
  468. if(!comment)
  469. *p++ = *q;
  470. }
  471. *p = '\0';
  472. line = vtMemAllocZ((nuser+2)*sizeof(char*));
  473. if((i = gettokens(buf, line, nuser+2, "\n")) != nuser){
  474. fprint(2, "nuser %d (%d) botch\n", nuser, i);
  475. vtMemFree(line);
  476. vtMemFree(buf);
  477. return 0;
  478. }
  479. fprint(2, "nuser %d\n", nuser);
  480. /*
  481. * Everything us updated in a local Ubox until verified.
  482. */
  483. box = vtMemAllocZ(sizeof(Ubox));
  484. if(name != nil)
  485. box->name = vtStrDup(name);
  486. /*
  487. * First pass - check format, check for duplicates
  488. * and enter in hash buckets.
  489. */
  490. for(i = 0; i < nuser; i++){
  491. s = vtStrDup(line[i]);
  492. if(getfields(s, f, nelem(f), 0, ":") != 4){
  493. fprint(2, "bad line '%s'\n", line[i]);
  494. vtMemFree(s);
  495. continue;
  496. }
  497. if(*f[0] == '\0' || *f[1] == '\0'){
  498. fprint(2, "bad line '%s'\n", line[i]);
  499. vtMemFree(s);
  500. continue;
  501. }
  502. if(!validUserName(f[0])){
  503. fprint(2, "invalid uid '%s'\n", f[0]);
  504. vtMemFree(s);
  505. continue;
  506. }
  507. if(_userByUid(box, f[0]) != nil){
  508. fprint(2, "duplicate uid '%s'\n", f[0]);
  509. vtMemFree(s);
  510. continue;
  511. }
  512. if(!validUserName(f[1])){
  513. fprint(2, "invalid uname '%s'\n", f[0]);
  514. vtMemFree(s);
  515. continue;
  516. }
  517. if(_userByUname(box, f[1]) != nil){
  518. fprint(2, "duplicate uname '%s'\n", f[1]);
  519. vtMemFree(s);
  520. continue;
  521. }
  522. u = userAlloc(f[0], f[1]);
  523. uboxAddUser(box, u);
  524. vtMemFree(s);
  525. }
  526. assert(box->nuser == nuser);
  527. /*
  528. * Second pass - fill in leader and group information.
  529. */
  530. for(i = 0; i < nuser; i++){
  531. s = vtStrDup(line[i]);
  532. getfields(s, f, nelem(f), 0, ":");
  533. assert(g = _userByUname(box, f[1]));
  534. if(*f[2] != '\0'){
  535. if((u = _userByUname(box, f[2])) == nil)
  536. g->leader = vtStrDup(g->uname);
  537. else
  538. g->leader = vtStrDup(u->uname);
  539. box->len += strlen(g->leader);
  540. }
  541. for(p = f[3]; p != nil; p = q){
  542. if((q = utfrune(p, L',')) != nil)
  543. *q++ = '\0';
  544. if(!_groupAddMember(box, g, p)){
  545. // print/log error here
  546. }
  547. }
  548. vtMemFree(s);
  549. }
  550. vtMemFree(line);
  551. vtMemFree(buf);
  552. for(i = 0; usersMandatory[i] != nil; i++){
  553. if((u = _userByUid(box, usersMandatory[i])) == nil){
  554. vtSetError("user '%s' is mandatory", usersMandatory[i]);
  555. uboxFree(box);
  556. return 0;
  557. }
  558. if(strcmp(u->uid, u->uname) != 0){
  559. vtSetError("uid/uname for user '%s' must match",
  560. usersMandatory[i]);
  561. uboxFree(box);
  562. return 0;
  563. }
  564. }
  565. vtLock(ubox.lock);
  566. if(name != nil && usersFileWrite(box) == 0){
  567. /*
  568. * What to do here? How much whining?
  569. */
  570. }
  571. obox = ubox.box;
  572. ubox.box = box;
  573. vtUnlock(ubox.lock);
  574. if(obox != nil)
  575. uboxFree(obox);
  576. return 1;
  577. }
  578. static int
  579. usersFileRead(char* path)
  580. {
  581. char *p;
  582. File *file;
  583. Fsys *fsys;
  584. int len, r;
  585. uvlong size;
  586. if((fsys = fsysGet("main")) == nil)
  587. return 0;
  588. fsysFsRlock(fsys);
  589. r = 0;
  590. if((file = fileOpen(fsysGetFs(fsys), path)) != nil){
  591. if(fileGetSize(file, &size)){
  592. len = size;
  593. p = vtMemAlloc(size+1);
  594. if(fileRead(file, p, len, 0) == len){
  595. p[len] = '\0';
  596. r = uboxInit(path, p, len);
  597. }
  598. }
  599. fileDecRef(file);
  600. }
  601. fsysFsRUnlock(fsys);
  602. fsysPut(fsys);
  603. return r;
  604. }
  605. static int
  606. cmdUname(int argc, char* argv[])
  607. {
  608. User *u, *up;
  609. int d, dflag, i, r;
  610. char *p, *uid, *uname;
  611. char *createfmt = "fsys main create /active/usr/%s %s %s d775";
  612. char *usage = "usage: uname uname [uid|:uid|%%newname|=leader|+member|-member]";
  613. dflag = 0;
  614. ARGBEGIN{
  615. default:
  616. return cliError(usage);
  617. case 'd':
  618. dflag = 1;
  619. break;
  620. }ARGEND
  621. if(argc < 1){
  622. if(dflag){
  623. vtRLock(ubox.lock);
  624. if(dflag)
  625. uboxDump(ubox.box);
  626. vtRUnlock(ubox.lock);
  627. return 1;
  628. }
  629. return cliError(usage);
  630. }
  631. uname = argv[0];
  632. argc--; argv++;
  633. if(argc == 0){
  634. vtRLock(ubox.lock);
  635. if((u = _userByUname(ubox.box, uname)) == nil){
  636. vtRUnlock(ubox.lock);
  637. return 0;
  638. }
  639. consPrint("\t%U\n", u);
  640. vtRUnlock(ubox.lock);
  641. return 1;
  642. }
  643. vtLock(ubox.lock);
  644. u = _userByUname(ubox.box, uname);
  645. while(argc--){
  646. if(argv[0][0] == '%'){
  647. if(u == nil){
  648. vtUnlock(ubox.lock);
  649. return 0;
  650. }
  651. p = &argv[0][1];
  652. if((up = _userByUname(ubox.box, p)) != nil){
  653. vtSetError("uname: uname '%s' already exists",
  654. up->uname);
  655. vtUnlock(ubox.lock);
  656. return 0;
  657. }
  658. for(i = 0; usersMandatory[i] != nil; i++){
  659. if(strcmp(usersMandatory[i], uname) != 0)
  660. continue;
  661. vtSetError("uname: uname '%s' is mandatory",
  662. uname);
  663. vtUnlock(ubox.lock);
  664. return 0;
  665. }
  666. d = strlen(p) - strlen(u->uname);
  667. for(up = ubox.box->head; up != nil; up = up->next){
  668. if(up->leader != nil){
  669. if(strcmp(up->leader, u->uname) == 0){
  670. vtMemFree(up->leader);
  671. up->leader = vtStrDup(p);
  672. ubox.box->len += d;
  673. }
  674. }
  675. for(i = 0; i < up->ngroup; i++){
  676. if(strcmp(up->group[i], u->uname) != 0)
  677. continue;
  678. vtMemFree(up->group[i]);
  679. up->group[i] = vtStrDup(p);
  680. ubox.box->len += d;
  681. break;
  682. }
  683. }
  684. uboxRemUser(ubox.box, u);
  685. vtMemFree(u->uname);
  686. u->uname = vtStrDup(p);
  687. uboxAddUser(ubox.box, u);
  688. }
  689. else if(argv[0][0] == '='){
  690. if(u == nil){
  691. vtUnlock(ubox.lock);
  692. return 0;
  693. }
  694. if((up = _userByUname(ubox.box, &argv[0][1])) == nil){
  695. if(argv[0][1] != '\0'){
  696. vtUnlock(ubox.lock);
  697. return 0;
  698. }
  699. }
  700. if(u->leader != nil){
  701. ubox.box->len -= strlen(u->leader);
  702. vtMemFree(u->leader);
  703. u->leader = nil;
  704. }
  705. if(up != nil){
  706. u->leader = vtStrDup(up->uname);
  707. ubox.box->len += strlen(u->leader);
  708. }
  709. }
  710. else if(argv[0][0] == '+'){
  711. if(u == nil){
  712. vtUnlock(ubox.lock);
  713. return 0;
  714. }
  715. if((up = _userByUname(ubox.box, &argv[0][1])) == nil){
  716. vtUnlock(ubox.lock);
  717. return 0;
  718. }
  719. if(!_groupAddMember(ubox.box, u, up->uname)){
  720. vtUnlock(ubox.lock);
  721. return 0;
  722. }
  723. }
  724. else if(argv[0][0] == '-'){
  725. if(u == nil){
  726. vtUnlock(ubox.lock);
  727. return 0;
  728. }
  729. if((up = _userByUname(ubox.box, &argv[0][1])) == nil){
  730. vtUnlock(ubox.lock);
  731. return 0;
  732. }
  733. if(!_groupRemMember(ubox.box, u, up->uname)){
  734. vtUnlock(ubox.lock);
  735. return 0;
  736. }
  737. }
  738. else{
  739. if(u != nil){
  740. vtSetError("uname: uname '%s' already exists",
  741. u->uname);
  742. vtUnlock(ubox.lock);
  743. return 0;
  744. }
  745. uid = argv[0];
  746. if(*uid == ':')
  747. uid++;
  748. if((u = _userByUid(ubox.box, uid)) != nil){
  749. vtSetError("uname: uid '%s' already exists",
  750. u->uid);
  751. vtUnlock(ubox.lock);
  752. return 0;
  753. }
  754. u = userAlloc(uid, uname);
  755. uboxAddUser(ubox.box, u);
  756. if(argv[0][0] != ':'){
  757. // should have an option for the mode and gid
  758. p = smprint(createfmt, uname, uname, uname);
  759. r = cliExec(p);
  760. vtMemFree(p);
  761. if(r != 0){
  762. vtUnlock(ubox.lock);
  763. return 0;
  764. }
  765. }
  766. }
  767. argv++;
  768. }
  769. if(usersFileWrite(ubox.box) == 0){
  770. vtUnlock(ubox.lock);
  771. return 0;
  772. }
  773. if(dflag)
  774. uboxDump(ubox.box);
  775. vtUnlock(ubox.lock);
  776. return 1;
  777. }
  778. static int
  779. cmdUsers(int argc, char* argv[])
  780. {
  781. Ubox *box;
  782. int dflag, r, wflag;
  783. char *usage = "usage: users [-dw] [file]";
  784. dflag = wflag = 0;
  785. ARGBEGIN{
  786. default:
  787. return cliError(usage);
  788. case 'd':
  789. dflag = 1;
  790. break;
  791. case 'w':
  792. wflag = 1;
  793. break;
  794. }ARGEND
  795. switch(argc){
  796. default:
  797. return cliError(usage);
  798. case 0:
  799. if(dflag)
  800. uboxInit(nil, usersDefault, sizeof(usersDefault));
  801. vtRLock(ubox.lock);
  802. box = ubox.box;
  803. if(box->name != nil)
  804. consPrint("\tfile %s\n", box->name);
  805. else
  806. consPrint("\tno file\n");
  807. consPrint("\tnuser %d len %d\n", box->nuser, box->len);
  808. vtRUnlock(ubox.lock);
  809. break;
  810. case 1:
  811. if(dflag)
  812. return cliError(usage);
  813. if(usersFileRead(argv[0]) == 0)
  814. return 0;
  815. break;
  816. }
  817. if(wflag){
  818. vtRLock(ubox.lock);
  819. r = usersFileWrite(ubox.box);
  820. vtRUnlock(ubox.lock);
  821. return r;
  822. }
  823. return 1;
  824. }
  825. int
  826. usersInit(void)
  827. {
  828. fmtinstall('U', userFmt);
  829. ubox.lock = vtLockAlloc();
  830. uboxInit(nil, usersDefault, sizeof(usersDefault));
  831. cliAddCmd("users", cmdUsers);
  832. cliAddCmd("uname", cmdUname);
  833. return 1;
  834. }