summaryrefslogtreecommitdiff
path: root/sys/src/cmd/cwfs/uidgid.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/cwfs/uidgid.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/cwfs/uidgid.c')
-rwxr-xr-xsys/src/cmd/cwfs/uidgid.c582
1 files changed, 582 insertions, 0 deletions
diff --git a/sys/src/cmd/cwfs/uidgid.c b/sys/src/cmd/cwfs/uidgid.c
new file mode 100755
index 000000000..88ae3b571
--- /dev/null
+++ b/sys/src/cmd/cwfs/uidgid.c
@@ -0,0 +1,582 @@
+#include "all.h"
+
+struct {
+ char* name;
+ Userid uid;
+ Userid lead;
+} minusers[] = {
+ "adm", -1, -1,
+ "none", 0, -1,
+ "tor", 1, 1,
+ "sys", 10000, 0,
+ "map", 10001, 10001,
+ "doc", 10002, 0,
+ "upas", 10003, 10003,
+ "font", 10004, 0,
+ "bootes", 10005, 10005,
+ 0
+};
+
+static char buf[4096];
+static Rune ichar[] = L"?=+-/:";
+
+Uid* chkuid(char *name, int chk);
+void do_newuser(int, char*[]);
+char* getword(char*, Rune, char*, int);
+void pentry(char*, Uid*);
+int readln(char*, int);
+void setminusers(void);
+Uid* uidtop(int);
+
+void
+cmd_users(int argc, char *argv[])
+{
+ Uid *ui;
+ int u, g, o, line;
+ char *file, *p, *uname, *ulead, *unext;
+
+ file = "/adm/users";
+ if(argc > 1)
+ file = argv[1];
+
+ if(strcmp(file, "default") == 0) {
+ setminusers();
+ return;
+ }
+
+ uidgc.uidbuf = getbuf(devnone, Cuidbuf, 0);
+ if(walkto(file) || con_open(FID2, 0)) {
+ print("cmd_users: cannot access %s\n", file);
+ putbuf(uidgc.uidbuf);
+ return;
+ }
+
+ uidgc.flen = 0;
+ uidgc.find = 0;
+ cons.offset = 0;
+ cons.nuid = 0;
+
+ u = 0;
+ line = 0;
+ while(readln(buf, sizeof buf) != 0) {
+ line++;
+ p = getword(buf, L':', "no : after number", line);
+ if(p == nil)
+ continue;
+ ulead = getword(p, L':', "no : after name", line);
+ if(ulead == nil)
+ continue;
+
+ if(strlen(p) > NAMELEN-1) {
+ print("%s: name too long\n", p);
+ continue;
+ }
+ strcpy(uid[u].name, p);
+ uid[u].uid = number(buf, 0, 10);
+ uid[u].lead = 0;
+ uid[u].ngrp = 0;
+ u++;
+ if(u >= conf.nuid) {
+ print("conf.nuid too small (%ld)\n", conf.nuid);
+ break;
+ }
+ }
+
+ /* Sorted by uid for use in uidtostr */
+ wlock(&uidgc.uidlock);
+ qsort(uid, u, sizeof(uid[0]), byuid);
+ cons.nuid = u;
+ wunlock(&uidgc.uidlock);
+
+ /* Parse group table */
+ uidgc.flen = 0;
+ uidgc.find = 0;
+ cons.offset = 0;
+ cons.ngid = 0;
+
+ g = 0;
+ line = 0;
+ while(readln(buf, sizeof buf) != 0) {
+ line++;
+ uname = getword(buf, L':', 0, 0); /* skip number */
+ if(uname == nil)
+ continue;
+
+ ulead = getword(uname, L':', 0, 0); /* skip name */
+ if(ulead == nil)
+ continue;
+
+ p = getword(ulead, L':', "no : after leader", line);
+ if(p == nil)
+ continue;
+
+ ui = uidpstr(uname);
+ if(ui == nil)
+ continue;
+
+ /* set to owner if name not known */
+ ui->lead = 0;
+ if(ulead[0]) {
+ o = strtouid(ulead);
+ if(o >= 0)
+ ui->lead = o;
+ else
+ ui->lead = ui->uid;
+ }
+ ui->gtab = &gidspace[g];
+ ui->ngrp = 0;
+ while (p != nil) {
+ unext = getword(p, L',', 0, 0);
+ o = strtouid(p);
+ if(o >= 0) {
+ gidspace[g++] = o;
+ ui->ngrp++;
+ }
+ p = unext;
+ }
+ }
+
+ cons.ngid = g;
+
+ putbuf(uidgc.uidbuf);
+ print("%d uids read, %d groups used\n", cons.nuid, cons.ngid);
+}
+
+void
+cmd_newuser(int argc, char *argv[])
+{
+ if(argc <= 1) {
+ print("usage: newuser args\n");
+ print("\tname -- create a new user\n");
+ print("\tname : -- create a new group\n");
+ print("\tname ? -- show entry for user\n");
+ print("\tname name -- rename\n");
+ print("\tname =[name] -- add/alter/remove leader\n");
+ print("\tname +name -- add member\n");
+ print("\tname -name -- delete member\n");
+ return;
+ }
+ do_newuser(argc, argv);
+}
+
+void
+do_newuser(int argc, char *argv[])
+{
+ int i, l, n, nuid;
+ char *p, *md, *q;
+ Rune *r;
+ Userid *s;
+ Uid *ui, *u2;
+
+ nuid = 10000;
+ md = 0;
+ if(argc == 2) {
+ nuid = 1;
+ argv[2] = ":";
+ }
+
+ for(r = ichar; *r; r++)
+ if(utfrune(argv[1], *r)) {
+ print("illegal character in name\n");
+ return;
+ }
+ if(strlen(argv[1]) > NAMELEN-1) {
+ print("name %s too long\n", argv[1]);
+ return;
+ }
+
+ p = argv[2];
+ switch(*p) {
+ case '?':
+ ui = chkuid(argv[1], 1);
+ if(ui == 0)
+ return;
+ pentry(buf, ui);
+ n = strlen(buf);
+ p = buf;
+ while(n > PRINTSIZE-5) {
+ q = p;
+ p += PRINTSIZE-5;
+ n -= PRINTSIZE-5;
+ i = *p;
+ *p = 0;
+ print("%s", q);
+ *p = i;
+ }
+ print("%s\n", p);
+ return;
+
+ case ':':
+ if(chkuid(argv[1], 0))
+ return;
+ while(uidtop(nuid) != 0)
+ nuid++;
+ if(cons.nuid >= conf.nuid) {
+ print("conf.nuid too small (%ld)\n", conf.nuid);
+ return;
+ }
+
+ wlock(&uidgc.uidlock);
+ ui = &uid[cons.nuid++];
+ ui->uid = nuid;
+ ui->lead = 0;
+ if(nuid < 10000) {
+ ui->lead = ui->uid;
+ md = argv[1];
+ }
+ strcpy(ui->name, argv[1]);
+ ui->ngrp = 0;
+ qsort(uid, cons.nuid, sizeof(uid[0]), byuid);
+ wunlock(&uidgc.uidlock);
+ break;
+
+ case '=':
+ ui = chkuid(argv[1], 1);
+ if(ui == 0)
+ return;
+ p++;
+ if(*p == '\0') {
+ ui->lead = 0;
+ break;
+ }
+ u2 = chkuid(p, 1);
+ if(u2 == 0)
+ return;
+ ui->lead = u2->uid;
+ break;
+
+ case '+':
+ ui = chkuid(argv[1], 1);
+ if(ui == 0)
+ return;
+ p++;
+ u2 = chkuid(p, 1);
+ if(u2 == 0)
+ return;
+ if(u2->uid == ui->uid)
+ return;
+ if(cons.ngid+ui->ngrp+1 >= conf.gidspace) {
+ print("conf.gidspace too small (%ld)\n", conf.gidspace);
+ return;
+ }
+ for(i = 0; i < ui->ngrp; i++) {
+ if(ui->gtab[i] == u2->uid) {
+ print("member already in group\n");
+ return;
+ }
+ }
+
+ wlock(&uidgc.uidlock);
+ s = gidspace+cons.ngid;
+ memmove(s, ui->gtab, ui->ngrp*sizeof(*s));
+ ui->gtab = s;
+ s[ui->ngrp++] = u2->uid;
+ cons.ngid += ui->ngrp+1;
+ wunlock(&uidgc.uidlock);
+ break;
+
+ case '-':
+ ui = chkuid(argv[1], 1);
+ if(ui == 0)
+ return;
+ p++;
+ u2 = chkuid(p, 1);
+ if(u2 == 0)
+ return;
+ for(i = 0; i < ui->ngrp; i++)
+ if(ui->gtab[i] == u2->uid)
+ break;
+
+ if(i == ui->ngrp) {
+ print("%s not in group\n", p);
+ return;
+ }
+
+ wlock(&uidgc.uidlock);
+ s = ui->gtab+i;
+ ui->ngrp--;
+ memmove(s, s+1, (ui->ngrp-i)*sizeof(*s));
+ wunlock(&uidgc.uidlock);
+ break;
+
+ default:
+ if(chkuid(argv[2], 0))
+ return;
+
+ for(r = ichar; *r; r++)
+ if(utfrune(argv[2], *r)) {
+ print("illegal character in name\n");
+ return;
+ }
+
+ ui = chkuid(argv[1], 1);
+ if(ui == 0)
+ return;
+
+ if(strlen(argv[2]) > NAMELEN-1) {
+ print("name %s too long\n", argv[2]);
+ return;
+ }
+
+ wlock(&uidgc.uidlock);
+ strcpy(ui->name, argv[2]);
+ wunlock(&uidgc.uidlock);
+ break;
+ }
+
+
+ if(walkto("/adm/users") || con_open(FID2, OWRITE|OTRUNC)) {
+ print("can't open /adm/users for write\n");
+ return;
+ }
+
+ cons.offset = 0;
+ for(i = 0; i < cons.nuid; i++) {
+ pentry(buf, &uid[i]);
+ l = strlen(buf);
+ n = con_write(FID2, buf, cons.offset, l);
+ if(l != n)
+ print("short write on /adm/users\n");
+ cons.offset += n;
+ }
+
+ if(md != 0) {
+ sprint(buf, "create /usr/%s %s %s 755 d", md, md, md);
+ print("%s\n", buf);
+ cmd_exec(buf);
+ }
+}
+
+Uid*
+chkuid(char *name, int chk)
+{
+ Uid *u;
+
+ u = uidpstr(name);
+ if(chk == 1) {
+ if(u == 0)
+ print("%s does not exist\n", name);
+ }
+ else {
+ if(u != 0)
+ print("%s already exists\n", name);
+ }
+ return u;
+}
+
+void
+pentry(char *buf, Uid *u)
+{
+ int i, posn;
+ Uid *p;
+
+ posn = sprint(buf, "%d:%s:", u->uid, u->name);
+ p = uidtop(u->lead);
+ if(p && u->lead != 0)
+ posn += sprint(buf+posn, "%s", p->name);
+
+ posn += sprint(buf+posn, ":");
+ for(i = 0; i < u->ngrp; i++) {
+ p = uidtop(u->gtab[i]);
+ if(i != 0)
+ posn += sprint(buf+posn, ",");
+ if(p != 0)
+ posn += sprint(buf+posn, "%s", p->name);
+ else
+ posn += sprint(buf+posn, "%d", u->gtab[i]);
+ }
+ sprint(buf+posn, "\n");
+}
+
+void
+setminusers(void)
+{
+ int u;
+
+ for(u = 0; minusers[u].name; u++) {
+ strcpy(uid[u].name, minusers[u].name);
+ uid[u].uid = minusers[u].uid;
+ uid[u].lead = minusers[u].lead;
+ }
+ cons.nuid = u;
+ qsort(uid, u, sizeof(uid[0]), byuid);
+}
+
+Uid*
+uidpstr(char *name)
+{
+ Uid *s, *e;
+
+ s = uid;
+ for(e = s+cons.nuid; s < e; s++) {
+ if(strcmp(name, s->name) == 0)
+ return s;
+ }
+ return 0;
+}
+
+char*
+getword(char *buf, Rune delim, char *error, int line)
+{
+ char *p;
+
+ p = utfrune(buf, delim);
+ if(p == 0) {
+ if(error)
+ print("cmd_users: %s line %d\n", error, line);
+ return 0;
+ }
+ *p = '\0';
+ return p+1;
+}
+
+int
+strtouid(char *name)
+{
+ Uid *u;
+ int id;
+
+ rlock(&uidgc.uidlock);
+
+ u = uidpstr(name);
+ id = -2;
+ if(u != 0)
+ id = u->uid;
+
+ runlock(&uidgc.uidlock);
+
+ return id;
+}
+
+Uid*
+uidtop(int id)
+{
+ Uid *bot, *top, *new;
+
+ bot = uid;
+ top = bot + cons.nuid-1;
+
+ while(bot <= top){
+ new = bot + (top - bot)/2;
+ if(new->uid == id)
+ return new;
+ if(new->uid < id)
+ bot = new + 1;
+ else
+ top = new - 1;
+ }
+ return 0;
+}
+
+void
+uidtostr(char *name, int id, int dolock)
+{
+ Uid *p;
+
+ if(dolock)
+ rlock(&uidgc.uidlock);
+
+ p = uidtop(id);
+ if(p == 0)
+ strcpy(name, "none");
+ else
+ strcpy(name, p->name);
+
+ if(dolock)
+ runlock(&uidgc.uidlock);
+}
+
+int
+ingroup(int u, int g)
+{
+ Uid *p;
+ Userid *s, *e;
+
+ if(u == g)
+ return 1;
+
+ rlock(&uidgc.uidlock);
+ p = uidtop(g);
+ if(p != 0) {
+ s = p->gtab;
+ for(e = s + p->ngrp; s < e; s++) {
+ if(*s == u) {
+ runlock(&uidgc.uidlock);
+ return 1;
+ }
+ }
+ }
+ runlock(&uidgc.uidlock);
+ return 0;
+}
+
+int
+leadgroup(int ui, int gi)
+{
+ int i;
+ Uid *u;
+
+ /* user 'none' cannot be a group leader */
+ if(ui == 0)
+ return 0;
+
+ rlock(&uidgc.uidlock);
+ u = uidtop(gi);
+ if(u == 0) {
+ runlock(&uidgc.uidlock);
+ return 0;
+ }
+ i = u->lead;
+ runlock(&uidgc.uidlock);
+ if(i == ui)
+ return 1;
+ if(i == 0)
+ return ingroup(ui, gi);
+
+ return 0;
+}
+
+int
+byuid(void *a1, void *a2)
+{
+ Uid *u1, *u2;
+
+ u1 = a1;
+ u2 = a2;
+ return u1->uid - u2->uid;
+}
+
+int
+fchar(void)
+{
+ int n;
+
+ n = BUFSIZE;
+ if(n > MAXDAT)
+ n = MAXDAT;
+ if(uidgc.find >= uidgc.flen) {
+ uidgc.find = 0;
+ uidgc.flen = con_read(FID2, uidgc.uidbuf->iobuf, cons.offset, n);
+ if(uidgc.flen <= 0)
+ return -1;
+ cons.offset += uidgc.flen;
+ }
+ return (uchar)uidgc.uidbuf->iobuf[uidgc.find++];
+}
+
+int
+readln(char *p, int len)
+{
+ int n, c;
+
+ n = 0;
+ while(len--) {
+ c = fchar();
+ if(c == -1 || c == '\n')
+ break;
+ n++;
+ *p++ = c;
+ }
+ *p = '\0';
+ return n;
+}