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