15e96a66cSDavid du Colombier #include "stdinc.h" 25e96a66cSDavid du Colombier 35e96a66cSDavid du Colombier #include "9.h" 45e96a66cSDavid du Colombier 55e96a66cSDavid du Colombier enum { 65e96a66cSDavid du Colombier NUserHash = 1009, 75e96a66cSDavid du Colombier }; 85e96a66cSDavid du Colombier 95e96a66cSDavid du Colombier typedef struct Ubox Ubox; 105e96a66cSDavid du Colombier typedef struct User User; 115e96a66cSDavid du Colombier 125e96a66cSDavid du Colombier typedef struct User { 135e96a66cSDavid du Colombier char* uid; 145e96a66cSDavid du Colombier char* uname; 155e96a66cSDavid du Colombier char* leader; 165e96a66cSDavid du Colombier char** group; 175e96a66cSDavid du Colombier int ngroup; 185e96a66cSDavid du Colombier 195e96a66cSDavid du Colombier User* next; /* */ 205e96a66cSDavid du Colombier User* ihash; /* lookup by .uid */ 215e96a66cSDavid du Colombier User* nhash; /* lookup by .uname */ 225e96a66cSDavid du Colombier } User; 235e96a66cSDavid du Colombier 245e96a66cSDavid du Colombier #pragma varargck type "U" User* 255e96a66cSDavid du Colombier 265e96a66cSDavid du Colombier typedef struct Ubox { 275e96a66cSDavid du Colombier User* head; 285e96a66cSDavid du Colombier User* tail; 295e96a66cSDavid du Colombier char* name; 305e96a66cSDavid du Colombier int nuser; 315e96a66cSDavid du Colombier int len; 325e96a66cSDavid du Colombier 335e96a66cSDavid du Colombier User* ihash[NUserHash]; /* lookup by .uid */ 345e96a66cSDavid du Colombier User* nhash[NUserHash]; /* lookup by .uname */ 355e96a66cSDavid du Colombier } Ubox; 365e96a66cSDavid du Colombier 375e96a66cSDavid du Colombier static struct { 385e96a66cSDavid du Colombier VtLock* lock; 395e96a66cSDavid du Colombier 405e96a66cSDavid du Colombier Ubox* box; 415e96a66cSDavid du Colombier } ubox; 425e96a66cSDavid du Colombier 435e96a66cSDavid du Colombier static char usersDefault[] = { 445e96a66cSDavid du Colombier "adm:adm:adm:sys\n" 455e96a66cSDavid du Colombier "none:none::\n" 465e96a66cSDavid du Colombier "noworld:noworld::\n" 475e96a66cSDavid du Colombier "sys:sys::\n" 485e96a66cSDavid du Colombier }; 495e96a66cSDavid du Colombier 505e96a66cSDavid du Colombier static char* usersMandatory[] = { 515e96a66cSDavid du Colombier "adm", 525e96a66cSDavid du Colombier "none", 535e96a66cSDavid du Colombier "noworld", 545e96a66cSDavid du Colombier "sys", 555e96a66cSDavid du Colombier nil, 565e96a66cSDavid du Colombier }; 575e96a66cSDavid du Colombier 585e96a66cSDavid du Colombier char* uidadm = "adm"; 595e96a66cSDavid du Colombier char* unamenone = "none"; 605e96a66cSDavid du Colombier char* uidnoworld = "noworld"; 615e96a66cSDavid du Colombier 625e96a66cSDavid du Colombier static u32int 635e96a66cSDavid du Colombier userHash(char* s) 645e96a66cSDavid du Colombier { 655e96a66cSDavid du Colombier uchar *p; 665e96a66cSDavid du Colombier u32int hash; 675e96a66cSDavid du Colombier 685e96a66cSDavid du Colombier hash = 0; 695e96a66cSDavid du Colombier for(p = (uchar*)s; *p != '\0'; p++) 705e96a66cSDavid du Colombier hash = hash*7 + *p; 715e96a66cSDavid du Colombier 725e96a66cSDavid du Colombier return hash % NUserHash; 735e96a66cSDavid du Colombier } 745e96a66cSDavid du Colombier 755e96a66cSDavid du Colombier static User* 765e96a66cSDavid du Colombier _userByUid(Ubox* box, char* uid) 775e96a66cSDavid du Colombier { 785e96a66cSDavid du Colombier User *u; 795e96a66cSDavid du Colombier 805e96a66cSDavid du Colombier if(box != nil){ 815e96a66cSDavid du Colombier for(u = box->ihash[userHash(uid)]; u != nil; u = u->ihash){ 825e96a66cSDavid du Colombier if(strcmp(u->uid, uid) == 0) 835e96a66cSDavid du Colombier return u; 845e96a66cSDavid du Colombier } 855e96a66cSDavid du Colombier } 865e96a66cSDavid du Colombier vtSetError("uname: uid '%s' not found", uid); 875e96a66cSDavid du Colombier return nil; 885e96a66cSDavid du Colombier } 895e96a66cSDavid du Colombier 905e96a66cSDavid du Colombier char* 915e96a66cSDavid du Colombier unameByUid(char* uid) 925e96a66cSDavid du Colombier { 935e96a66cSDavid du Colombier User *u; 945e96a66cSDavid du Colombier char *uname; 955e96a66cSDavid du Colombier 965e96a66cSDavid du Colombier vtRLock(ubox.lock); 975e96a66cSDavid du Colombier if((u = _userByUid(ubox.box, uid)) == nil){ 985e96a66cSDavid du Colombier vtRUnlock(ubox.lock); 995e96a66cSDavid du Colombier return nil; 1005e96a66cSDavid du Colombier } 1015e96a66cSDavid du Colombier uname = vtStrDup(u->uname); 1025e96a66cSDavid du Colombier vtRUnlock(ubox.lock); 1035e96a66cSDavid du Colombier 1045e96a66cSDavid du Colombier return uname; 1055e96a66cSDavid du Colombier } 1065e96a66cSDavid du Colombier 1075e96a66cSDavid du Colombier static User* 1085e96a66cSDavid du Colombier _userByUname(Ubox* box, char* uname) 1095e96a66cSDavid du Colombier { 1105e96a66cSDavid du Colombier User *u; 1115e96a66cSDavid du Colombier 1125e96a66cSDavid du Colombier if(box != nil){ 1135e96a66cSDavid du Colombier for(u = box->nhash[userHash(uname)]; u != nil; u = u->nhash){ 1145e96a66cSDavid du Colombier if(strcmp(u->uname, uname) == 0) 1155e96a66cSDavid du Colombier return u; 1165e96a66cSDavid du Colombier } 1175e96a66cSDavid du Colombier } 1185e96a66cSDavid du Colombier vtSetError("uname: uname '%s' not found", uname); 1195e96a66cSDavid du Colombier return nil; 1205e96a66cSDavid du Colombier } 1215e96a66cSDavid du Colombier 1225e96a66cSDavid du Colombier char* 1235e96a66cSDavid du Colombier uidByUname(char* uname) 1245e96a66cSDavid du Colombier { 1255e96a66cSDavid du Colombier User *u; 1265e96a66cSDavid du Colombier char *uid; 1275e96a66cSDavid du Colombier 1285e96a66cSDavid du Colombier vtRLock(ubox.lock); 1295e96a66cSDavid du Colombier if((u = _userByUname(ubox.box, uname)) == nil){ 1305e96a66cSDavid du Colombier vtRUnlock(ubox.lock); 1315e96a66cSDavid du Colombier return nil; 1325e96a66cSDavid du Colombier } 1335e96a66cSDavid du Colombier uid = vtStrDup(u->uid); 1345e96a66cSDavid du Colombier vtRUnlock(ubox.lock); 1355e96a66cSDavid du Colombier 1365e96a66cSDavid du Colombier return uid; 1375e96a66cSDavid du Colombier } 1385e96a66cSDavid du Colombier 1395e96a66cSDavid du Colombier static int 1405e96a66cSDavid du Colombier _groupMember(Ubox* box, char* group, char* member, int whenNoGroup) 1415e96a66cSDavid du Colombier { 1425e96a66cSDavid du Colombier int i; 1435e96a66cSDavid du Colombier User *g, *m; 1445e96a66cSDavid du Colombier 1455e96a66cSDavid du Colombier /* 1465e96a66cSDavid du Colombier * Is 'member' a member of 'group'? 1475e96a66cSDavid du Colombier * Note that 'group' is a 'uid' and not a 'uname'. 1485e96a66cSDavid du Colombier * A 'member' is automatically in their own group. 1495e96a66cSDavid du Colombier */ 1505e96a66cSDavid du Colombier if((g = _userByUid(box, group)) == nil) 1515e96a66cSDavid du Colombier return whenNoGroup; 1525e96a66cSDavid du Colombier if((m = _userByUname(box, member)) == nil) 1535e96a66cSDavid du Colombier return 0; 1545e96a66cSDavid du Colombier if(m == g) 1555e96a66cSDavid du Colombier return 1; 1565e96a66cSDavid du Colombier for(i = 0; i < g->ngroup; i++){ 1575e96a66cSDavid du Colombier if(strcmp(g->group[i], member) == 0) 1585e96a66cSDavid du Colombier return 1; 1595e96a66cSDavid du Colombier } 1605e96a66cSDavid du Colombier return 0; 1615e96a66cSDavid du Colombier } 1625e96a66cSDavid du Colombier 1635e96a66cSDavid du Colombier int 1645e96a66cSDavid du Colombier groupWriteMember(char* uname) 1655e96a66cSDavid du Colombier { 1665e96a66cSDavid du Colombier int ret; 1675e96a66cSDavid du Colombier 1685e96a66cSDavid du Colombier /* 1695e96a66cSDavid du Colombier * If there is a ``write'' group, then only its members can write 1705e96a66cSDavid du Colombier * to the file system, no matter what the permission bits say. 1715e96a66cSDavid du Colombier * 1725e96a66cSDavid du Colombier * To users not in the ``write'' group, the file system appears 1735e96a66cSDavid du Colombier * read only. This is used to serve sources.cs.bell-labs.com 1745e96a66cSDavid du Colombier * to the world. 1755e96a66cSDavid du Colombier * 1765e96a66cSDavid du Colombier * Note that if there is no ``write'' group, then this routine 1775e96a66cSDavid du Colombier * makes it look like everyone is a member -- the opposite 1785e96a66cSDavid du Colombier * of what groupMember does. 1795e96a66cSDavid du Colombier * 1805e96a66cSDavid du Colombier * We use this for sources.cs.bell-labs.com. 1815e96a66cSDavid du Colombier * If this slows things down too much on systems that don't 1825e96a66cSDavid du Colombier * use this functionality, we could cache the write group lookup. 1835e96a66cSDavid du Colombier */ 1845e96a66cSDavid du Colombier 1855e96a66cSDavid du Colombier vtRLock(ubox.lock); 1865e96a66cSDavid du Colombier ret = _groupMember(ubox.box, "write", uname, 1); 1875e96a66cSDavid du Colombier vtRUnlock(ubox.lock); 1885e96a66cSDavid du Colombier return ret; 1895e96a66cSDavid du Colombier } 1905e96a66cSDavid du Colombier 1915e96a66cSDavid du Colombier static int 1925e96a66cSDavid du Colombier _groupRemMember(Ubox* box, User* g, char* member) 1935e96a66cSDavid du Colombier { 1945e96a66cSDavid du Colombier int i; 1955e96a66cSDavid du Colombier 1965e96a66cSDavid du Colombier if(_userByUname(box, member) == nil) 1975e96a66cSDavid du Colombier return 0; 1985e96a66cSDavid du Colombier 1995e96a66cSDavid du Colombier for(i = 0; i < g->ngroup; i++){ 2005e96a66cSDavid du Colombier if(strcmp(g->group[i], member) == 0) 2015e96a66cSDavid du Colombier break; 2025e96a66cSDavid du Colombier } 2035e96a66cSDavid du Colombier if(i >= g->ngroup){ 2045e96a66cSDavid du Colombier if(strcmp(g->uname, member) == 0) 2055e96a66cSDavid du Colombier vtSetError("uname: '%s' always in own group", member); 2065e96a66cSDavid du Colombier else 2075e96a66cSDavid du Colombier vtSetError("uname: '%s' not in group '%s'", 2085e96a66cSDavid du Colombier member, g->uname); 2095e96a66cSDavid du Colombier return 0; 2105e96a66cSDavid du Colombier } 2115e96a66cSDavid du Colombier 2125e96a66cSDavid du Colombier vtMemFree(g->group[i]); 2135e96a66cSDavid du Colombier 2145e96a66cSDavid du Colombier box->len -= strlen(member); 2155e96a66cSDavid du Colombier if(g->ngroup > 1) 2165e96a66cSDavid du Colombier box->len--; 2175e96a66cSDavid du Colombier g->ngroup--; 2185e96a66cSDavid du Colombier switch(g->ngroup){ 2195e96a66cSDavid du Colombier case 0: 2205e96a66cSDavid du Colombier vtMemFree(g->group); 2215e96a66cSDavid du Colombier g->group = nil; 2225e96a66cSDavid du Colombier break; 2235e96a66cSDavid du Colombier default: 2245e96a66cSDavid du Colombier while(i < g->ngroup){ 2255e96a66cSDavid du Colombier g->group[i] = g->group[i+1]; 2265e96a66cSDavid du Colombier i++; 2275e96a66cSDavid du Colombier } 2285e96a66cSDavid du Colombier /*FALLTHROUGH*/ 2295e96a66cSDavid du Colombier case 1: 2305e96a66cSDavid du Colombier g->group = vtMemRealloc(g->group, (g->ngroup)*sizeof(char*)); 2315e96a66cSDavid du Colombier break; 2325e96a66cSDavid du Colombier } 2335e96a66cSDavid du Colombier 2345e96a66cSDavid du Colombier return 1; 2355e96a66cSDavid du Colombier } 2365e96a66cSDavid du Colombier 2375e96a66cSDavid du Colombier static int 2385e96a66cSDavid du Colombier _groupAddMember(Ubox* box, User* g, char* member) 2395e96a66cSDavid du Colombier { 2405e96a66cSDavid du Colombier User *u; 2415e96a66cSDavid du Colombier 2425e96a66cSDavid du Colombier if((u = _userByUname(box, member)) == nil) 2435e96a66cSDavid du Colombier return 0; 2445e96a66cSDavid du Colombier if(_groupMember(box, g->uid, u->uname, 0)){ 2455e96a66cSDavid du Colombier if(strcmp(g->uname, member) == 0) 2465e96a66cSDavid du Colombier vtSetError("uname: '%s' always in own group", member); 2475e96a66cSDavid du Colombier else 2485e96a66cSDavid du Colombier vtSetError("uname: '%s' already in group '%s'", 2495e96a66cSDavid du Colombier member, g->uname); 2505e96a66cSDavid du Colombier return 0; 2515e96a66cSDavid du Colombier } 2525e96a66cSDavid du Colombier 2535e96a66cSDavid du Colombier g->group = vtMemRealloc(g->group, (g->ngroup+1)*sizeof(char*)); 2545e96a66cSDavid du Colombier g->group[g->ngroup] = vtStrDup(member); 2555e96a66cSDavid du Colombier box->len += strlen(member); 2565e96a66cSDavid du Colombier g->ngroup++; 2575e96a66cSDavid du Colombier if(g->ngroup > 1) 2585e96a66cSDavid du Colombier box->len++; 2595e96a66cSDavid du Colombier 2605e96a66cSDavid du Colombier return 1; 2615e96a66cSDavid du Colombier } 2625e96a66cSDavid du Colombier 2635e96a66cSDavid du Colombier int 2645e96a66cSDavid du Colombier groupMember(char* group, char* member) 2655e96a66cSDavid du Colombier { 2665e96a66cSDavid du Colombier int r; 2675e96a66cSDavid du Colombier 2685e96a66cSDavid du Colombier if(group == nil) 2695e96a66cSDavid du Colombier return 0; 2705e96a66cSDavid du Colombier 2715e96a66cSDavid du Colombier vtRLock(ubox.lock); 2725e96a66cSDavid du Colombier r = _groupMember(ubox.box, group, member, 0); 2735e96a66cSDavid du Colombier vtRUnlock(ubox.lock); 2745e96a66cSDavid du Colombier 2755e96a66cSDavid du Colombier return r; 2765e96a66cSDavid du Colombier } 2775e96a66cSDavid du Colombier 2785e96a66cSDavid du Colombier int 2795e96a66cSDavid du Colombier groupLeader(char* group, char* member) 2805e96a66cSDavid du Colombier { 2815e96a66cSDavid du Colombier int r; 2825e96a66cSDavid du Colombier User *g; 2835e96a66cSDavid du Colombier 2845e96a66cSDavid du Colombier /* 2855e96a66cSDavid du Colombier * Is 'member' the leader of 'group'? 2865e96a66cSDavid du Colombier * Note that 'group' is a 'uid' and not a 'uname'. 2875e96a66cSDavid du Colombier * Uname 'none' cannot be a group leader. 2885e96a66cSDavid du Colombier */ 2895e96a66cSDavid du Colombier if(strcmp(member, unamenone) == 0 || group == nil) 2905e96a66cSDavid du Colombier return 0; 2915e96a66cSDavid du Colombier 2925e96a66cSDavid du Colombier vtRLock(ubox.lock); 2935e96a66cSDavid du Colombier if((g = _userByUid(ubox.box, group)) == nil){ 2945e96a66cSDavid du Colombier vtRUnlock(ubox.lock); 2955e96a66cSDavid du Colombier return 0; 2965e96a66cSDavid du Colombier } 2975e96a66cSDavid du Colombier if(g->leader != nil){ 2985e96a66cSDavid du Colombier if(strcmp(g->leader, member) == 0){ 2995e96a66cSDavid du Colombier vtRUnlock(ubox.lock); 3005e96a66cSDavid du Colombier return 1; 3015e96a66cSDavid du Colombier } 3025e96a66cSDavid du Colombier r = 0; 3035e96a66cSDavid du Colombier } 3045e96a66cSDavid du Colombier else 3055e96a66cSDavid du Colombier r = _groupMember(ubox.box, group, member, 0); 3065e96a66cSDavid du Colombier vtRUnlock(ubox.lock); 3075e96a66cSDavid du Colombier 3085e96a66cSDavid du Colombier return r; 3095e96a66cSDavid du Colombier } 3105e96a66cSDavid du Colombier 3115e96a66cSDavid du Colombier static void 3125e96a66cSDavid du Colombier userFree(User* u) 3135e96a66cSDavid du Colombier { 3145e96a66cSDavid du Colombier int i; 3155e96a66cSDavid du Colombier 3165e96a66cSDavid du Colombier vtMemFree(u->uid); 3175e96a66cSDavid du Colombier vtMemFree(u->uname); 3185e96a66cSDavid du Colombier if(u->leader != nil) 3195e96a66cSDavid du Colombier vtMemFree(u->leader); 3205e96a66cSDavid du Colombier if(u->ngroup){ 3215e96a66cSDavid du Colombier for(i = 0; i < u->ngroup; i++) 3225e96a66cSDavid du Colombier vtMemFree(u->group[i]); 3235e96a66cSDavid du Colombier vtMemFree(u->group); 3245e96a66cSDavid du Colombier } 3255e96a66cSDavid du Colombier vtMemFree(u); 3265e96a66cSDavid du Colombier } 3275e96a66cSDavid du Colombier 3285e96a66cSDavid du Colombier static User* 3295e96a66cSDavid du Colombier userAlloc(char* uid, char* uname) 3305e96a66cSDavid du Colombier { 3315e96a66cSDavid du Colombier User *u; 3325e96a66cSDavid du Colombier 3335e96a66cSDavid du Colombier u = vtMemAllocZ(sizeof(User)); 3345e96a66cSDavid du Colombier u->uid = vtStrDup(uid); 3355e96a66cSDavid du Colombier u->uname = vtStrDup(uname); 3365e96a66cSDavid du Colombier 3375e96a66cSDavid du Colombier return u; 3385e96a66cSDavid du Colombier } 3395e96a66cSDavid du Colombier 3405e96a66cSDavid du Colombier int 3415e96a66cSDavid du Colombier validUserName(char* name) 3425e96a66cSDavid du Colombier { 3435e96a66cSDavid du Colombier Rune *r; 3445e96a66cSDavid du Colombier static Rune invalid[] = L"#:,()"; 3455e96a66cSDavid du Colombier 3465e96a66cSDavid du Colombier for(r = invalid; *r != '\0'; r++){ 3475e96a66cSDavid du Colombier if(utfrune(name, *r)) 3485e96a66cSDavid du Colombier return 0; 3495e96a66cSDavid du Colombier } 3505e96a66cSDavid du Colombier return 1; 3515e96a66cSDavid du Colombier } 3525e96a66cSDavid du Colombier 3535e96a66cSDavid du Colombier static int 3545e96a66cSDavid du Colombier userFmt(Fmt* fmt) 3555e96a66cSDavid du Colombier { 3565e96a66cSDavid du Colombier User *u; 3575e96a66cSDavid du Colombier int i, r; 3585e96a66cSDavid du Colombier 3595e96a66cSDavid du Colombier u = va_arg(fmt->args, User*); 3605e96a66cSDavid du Colombier 3615e96a66cSDavid du Colombier r = fmtprint(fmt, "%s:%s:", u->uid, u->uname); 3625e96a66cSDavid du Colombier if(u->leader != nil) 3635e96a66cSDavid du Colombier r += fmtprint(fmt, u->leader); 3645e96a66cSDavid du Colombier r += fmtprint(fmt, ":"); 3655e96a66cSDavid du Colombier if(u->ngroup){ 3665e96a66cSDavid du Colombier r += fmtprint(fmt, u->group[0]); 3675e96a66cSDavid du Colombier for(i = 1; i < u->ngroup; i++) 3685e96a66cSDavid du Colombier r += fmtprint(fmt, ",%s", u->group[i]); 3695e96a66cSDavid du Colombier } 3705e96a66cSDavid du Colombier 3715e96a66cSDavid du Colombier return r; 3725e96a66cSDavid du Colombier } 3735e96a66cSDavid du Colombier 3745e96a66cSDavid du Colombier static int 3755e96a66cSDavid du Colombier usersFileWrite(Ubox* box) 3765e96a66cSDavid du Colombier { 3775e96a66cSDavid du Colombier Fs *fs; 3785e96a66cSDavid du Colombier User *u; 3795e96a66cSDavid du Colombier int i, r; 3805e96a66cSDavid du Colombier Fsys *fsys; 3815e96a66cSDavid du Colombier char *p, *q, *s; 3825e96a66cSDavid du Colombier File *dir, *file; 3835e96a66cSDavid du Colombier 3845e96a66cSDavid du Colombier if((fsys = fsysGet("main")) == nil) 3855e96a66cSDavid du Colombier return 0; 3865e96a66cSDavid du Colombier fsysFsRlock(fsys); 3875e96a66cSDavid du Colombier fs = fsysGetFs(fsys); 3885e96a66cSDavid du Colombier 3895e96a66cSDavid du Colombier /* 3905e96a66cSDavid du Colombier * BUG: 3915e96a66cSDavid du Colombier * the owner/group/permissions need to be thought out. 3925e96a66cSDavid du Colombier */ 3935e96a66cSDavid du Colombier r = 0; 3945e96a66cSDavid du Colombier if((dir = fileOpen(fs, "/active")) == nil) 3955e96a66cSDavid du Colombier goto tidy0; 3965e96a66cSDavid du Colombier if((file = fileWalk(dir, "adm")) == nil) 3975e96a66cSDavid du Colombier file = fileCreate(dir, "adm", ModeDir|0775, uidadm); 3985e96a66cSDavid du Colombier fileDecRef(dir); 3995e96a66cSDavid du Colombier if(file == nil) 4005e96a66cSDavid du Colombier goto tidy; 4015e96a66cSDavid du Colombier dir = file; 4025e96a66cSDavid du Colombier if((file = fileWalk(dir, "users")) == nil) 4035e96a66cSDavid du Colombier file = fileCreate(dir, "users", 0664, uidadm); 4045e96a66cSDavid du Colombier fileDecRef(dir); 4055e96a66cSDavid du Colombier if(file == nil) 4065e96a66cSDavid du Colombier goto tidy; 4075e96a66cSDavid du Colombier if(!fileTruncate(file, uidadm)) 4085e96a66cSDavid du Colombier goto tidy; 4095e96a66cSDavid du Colombier 4105e96a66cSDavid du Colombier p = s = vtMemAlloc(box->len+1); 4115e96a66cSDavid du Colombier q = p + box->len+1; 4125e96a66cSDavid du Colombier for(u = box->head; u != nil; u = u->next){ 4135e96a66cSDavid du Colombier p += snprint(p, q-p, "%s:%s:", u->uid, u->uname); 4145e96a66cSDavid du Colombier if(u->leader != nil) 4155e96a66cSDavid du Colombier p+= snprint(p, q-p, u->leader); 4165e96a66cSDavid du Colombier p += snprint(p, q-p, ":"); 4175e96a66cSDavid du Colombier if(u->ngroup){ 4185e96a66cSDavid du Colombier p += snprint(p, q-p, u->group[0]); 4195e96a66cSDavid du Colombier for(i = 1; i < u->ngroup; i++) 4205e96a66cSDavid du Colombier p += snprint(p, q-p, ",%s", u->group[i]); 4215e96a66cSDavid du Colombier } 4225e96a66cSDavid du Colombier p += snprint(p, q-p, "\n"); 4235e96a66cSDavid du Colombier } 4245e96a66cSDavid du Colombier r = fileWrite(file, s, box->len, 0, uidadm); 4255e96a66cSDavid du Colombier vtMemFree(s); 4265e96a66cSDavid du Colombier 4275e96a66cSDavid du Colombier tidy: 4285e96a66cSDavid du Colombier if(file != nil) 4295e96a66cSDavid du Colombier fileDecRef(file); 4305e96a66cSDavid du Colombier tidy0: 4315e96a66cSDavid du Colombier fsysFsRUnlock(fsys); 4325e96a66cSDavid du Colombier fsysPut(fsys); 4335e96a66cSDavid du Colombier 4345e96a66cSDavid du Colombier return r; 4355e96a66cSDavid du Colombier } 4365e96a66cSDavid du Colombier 4375e96a66cSDavid du Colombier static void 4385e96a66cSDavid du Colombier uboxRemUser(Ubox* box, User *u) 4395e96a66cSDavid du Colombier { 4405e96a66cSDavid du Colombier User **h, *up; 4415e96a66cSDavid du Colombier 4425e96a66cSDavid du Colombier h = &box->ihash[userHash(u->uid)]; 4435e96a66cSDavid du Colombier for(up = *h; up != nil && up != u; up = up->ihash) 4445e96a66cSDavid du Colombier h = &up->ihash; 4455e96a66cSDavid du Colombier assert(up == u); 4465e96a66cSDavid du Colombier *h = up->ihash; 4475e96a66cSDavid du Colombier box->len -= strlen(u->uid); 4485e96a66cSDavid du Colombier 4495e96a66cSDavid du Colombier h = &box->nhash[userHash(u->uname)]; 4505e96a66cSDavid du Colombier for(up = *h; up != nil && up != u; up = up->nhash) 4515e96a66cSDavid du Colombier h = &up->nhash; 4525e96a66cSDavid du Colombier assert(up == u); 4535e96a66cSDavid du Colombier *h = up->nhash; 4545e96a66cSDavid du Colombier box->len -= strlen(u->uname); 4555e96a66cSDavid du Colombier 4565e96a66cSDavid du Colombier h = &box->head; 4575e96a66cSDavid du Colombier for(up = *h; up != nil && strcmp(up->uid, u->uid) != 0; up = up->next) 4585e96a66cSDavid du Colombier h = &up->next; 4595e96a66cSDavid du Colombier assert(up == u); 4605e96a66cSDavid du Colombier *h = u->next; 4615e96a66cSDavid du Colombier u->next = nil; 4625e96a66cSDavid du Colombier 4635e96a66cSDavid du Colombier box->len -= 4; 4645e96a66cSDavid du Colombier box->nuser--; 4655e96a66cSDavid du Colombier } 4665e96a66cSDavid du Colombier 4675e96a66cSDavid du Colombier static void 4685e96a66cSDavid du Colombier uboxAddUser(Ubox* box, User* u) 4695e96a66cSDavid du Colombier { 4705e96a66cSDavid du Colombier User **h, *up; 4715e96a66cSDavid du Colombier 4725e96a66cSDavid du Colombier h = &box->ihash[userHash(u->uid)]; 4735e96a66cSDavid du Colombier u->ihash = *h; 4745e96a66cSDavid du Colombier *h = u; 4755e96a66cSDavid du Colombier box->len += strlen(u->uid); 4765e96a66cSDavid du Colombier 4775e96a66cSDavid du Colombier h = &box->nhash[userHash(u->uname)]; 4785e96a66cSDavid du Colombier u->nhash = *h; 4795e96a66cSDavid du Colombier *h = u; 4805e96a66cSDavid du Colombier box->len += strlen(u->uname); 4815e96a66cSDavid du Colombier 4825e96a66cSDavid du Colombier h = &box->head; 4835e96a66cSDavid du Colombier for(up = *h; up != nil && strcmp(up->uid, u->uid) < 0; up = up->next) 4845e96a66cSDavid du Colombier h = &up->next; 4855e96a66cSDavid du Colombier u->next = *h; 4865e96a66cSDavid du Colombier *h = u; 4875e96a66cSDavid du Colombier 4885e96a66cSDavid du Colombier box->len += 4; 4895e96a66cSDavid du Colombier box->nuser++; 4905e96a66cSDavid du Colombier } 4915e96a66cSDavid du Colombier 4925e96a66cSDavid du Colombier static void 4935e96a66cSDavid du Colombier uboxDump(Ubox* box) 4945e96a66cSDavid du Colombier { 4955e96a66cSDavid du Colombier User* u; 4965e96a66cSDavid du Colombier 4975e96a66cSDavid du Colombier consPrint("nuser %d len = %d\n", box->nuser, box->len); 4985e96a66cSDavid du Colombier 4995e96a66cSDavid du Colombier for(u = box->head; u != nil; u = u->next) 5005e96a66cSDavid du Colombier consPrint("%U\n", u); 5015e96a66cSDavid du Colombier } 5025e96a66cSDavid du Colombier 5035e96a66cSDavid du Colombier static void 5045e96a66cSDavid du Colombier uboxFree(Ubox* box) 5055e96a66cSDavid du Colombier { 5065e96a66cSDavid du Colombier User *next, *u; 5075e96a66cSDavid du Colombier 5085e96a66cSDavid du Colombier for(u = box->head; u != nil; u = next){ 5095e96a66cSDavid du Colombier next = u->next; 5105e96a66cSDavid du Colombier userFree(u); 5115e96a66cSDavid du Colombier } 5125e96a66cSDavid du Colombier if(box->name != nil) 5135e96a66cSDavid du Colombier vtMemFree(box->name); 5145e96a66cSDavid du Colombier vtMemFree(box); 5155e96a66cSDavid du Colombier } 5165e96a66cSDavid du Colombier 5175e96a66cSDavid du Colombier static int 5185e96a66cSDavid du Colombier uboxInit(char* name, char* users, int len) 5195e96a66cSDavid du Colombier { 5205e96a66cSDavid du Colombier User *g, *u; 5215e96a66cSDavid du Colombier Ubox *box, *obox; 5225e96a66cSDavid du Colombier int blank, comment, i, nuser; 5235e96a66cSDavid du Colombier char *buf, *f[5], **line, *p, *q, *s; 5245e96a66cSDavid du Colombier 5255e96a66cSDavid du Colombier /* 5265e96a66cSDavid du Colombier * Strip out whitespace and comments. 5275e96a66cSDavid du Colombier * Note that comments are pointless, they disappear 5285e96a66cSDavid du Colombier * when the server writes the database back out. 5295e96a66cSDavid du Colombier */ 5305e96a66cSDavid du Colombier blank = 1; 5315e96a66cSDavid du Colombier comment = nuser = 0; 5325e96a66cSDavid du Colombier 5335e96a66cSDavid du Colombier s = p = buf = vtMemAlloc(len+1); 5345e96a66cSDavid du Colombier for(q = users; *q != '\0'; q++){ 5355e96a66cSDavid du Colombier if(*q == '\r' || *q == '\t' || *q == ' ') 5365e96a66cSDavid du Colombier continue; 5375e96a66cSDavid du Colombier if(*q == '\n'){ 5385e96a66cSDavid du Colombier if(!blank){ 5395e96a66cSDavid du Colombier if(p != s){ 5405e96a66cSDavid du Colombier *p++ = '\n'; 5415e96a66cSDavid du Colombier nuser++; 5425e96a66cSDavid du Colombier s = p; 5435e96a66cSDavid du Colombier } 5445e96a66cSDavid du Colombier blank = 1; 5455e96a66cSDavid du Colombier } 5465e96a66cSDavid du Colombier comment = 0; 5475e96a66cSDavid du Colombier continue; 5485e96a66cSDavid du Colombier } 5495e96a66cSDavid du Colombier if(*q == '#') 5505e96a66cSDavid du Colombier comment = 1; 5515e96a66cSDavid du Colombier blank = 0; 5525e96a66cSDavid du Colombier if(!comment) 5535e96a66cSDavid du Colombier *p++ = *q; 5545e96a66cSDavid du Colombier } 5555e96a66cSDavid du Colombier *p = '\0'; 5565e96a66cSDavid du Colombier 5575e96a66cSDavid du Colombier line = vtMemAllocZ((nuser+2)*sizeof(char*)); 5585e96a66cSDavid du Colombier if((i = gettokens(buf, line, nuser+2, "\n")) != nuser){ 5595e96a66cSDavid du Colombier fprint(2, "nuser %d (%d) botch\n", nuser, i); 5605e96a66cSDavid du Colombier vtMemFree(line); 5615e96a66cSDavid du Colombier vtMemFree(buf); 5625e96a66cSDavid du Colombier return 0; 5635e96a66cSDavid du Colombier } 5645e96a66cSDavid du Colombier 5655e96a66cSDavid du Colombier fprint(2, "nuser %d\n", nuser); 5665e96a66cSDavid du Colombier 5675e96a66cSDavid du Colombier /* 5685e96a66cSDavid du Colombier * Everything us updated in a local Ubox until verified. 5695e96a66cSDavid du Colombier */ 5705e96a66cSDavid du Colombier box = vtMemAllocZ(sizeof(Ubox)); 5715e96a66cSDavid du Colombier if(name != nil) 5725e96a66cSDavid du Colombier box->name = vtStrDup(name); 5735e96a66cSDavid du Colombier 5745e96a66cSDavid du Colombier /* 5755e96a66cSDavid du Colombier * First pass - check format, check for duplicates 5765e96a66cSDavid du Colombier * and enter in hash buckets. 5775e96a66cSDavid du Colombier */ 5785e96a66cSDavid du Colombier for(i = 0; i < nuser; i++){ 5795e96a66cSDavid du Colombier s = vtStrDup(line[i]); 5805e96a66cSDavid du Colombier if(getfields(s, f, nelem(f), 0, ":") != 4){ 5815e96a66cSDavid du Colombier fprint(2, "bad line '%s'\n", line[i]); 5825e96a66cSDavid du Colombier vtMemFree(s); 5835e96a66cSDavid du Colombier continue; 5845e96a66cSDavid du Colombier } 5855e96a66cSDavid du Colombier if(*f[0] == '\0' || *f[1] == '\0'){ 5865e96a66cSDavid du Colombier fprint(2, "bad line '%s'\n", line[i]); 5875e96a66cSDavid du Colombier vtMemFree(s); 5885e96a66cSDavid du Colombier continue; 5895e96a66cSDavid du Colombier } 5905e96a66cSDavid du Colombier if(!validUserName(f[0])){ 5915e96a66cSDavid du Colombier fprint(2, "invalid uid '%s'\n", f[0]); 5925e96a66cSDavid du Colombier vtMemFree(s); 5935e96a66cSDavid du Colombier continue; 5945e96a66cSDavid du Colombier } 5955e96a66cSDavid du Colombier if(_userByUid(box, f[0]) != nil){ 5965e96a66cSDavid du Colombier fprint(2, "duplicate uid '%s'\n", f[0]); 5975e96a66cSDavid du Colombier vtMemFree(s); 5985e96a66cSDavid du Colombier continue; 5995e96a66cSDavid du Colombier } 6005e96a66cSDavid du Colombier if(!validUserName(f[1])){ 6015e96a66cSDavid du Colombier fprint(2, "invalid uname '%s'\n", f[0]); 6025e96a66cSDavid du Colombier vtMemFree(s); 6035e96a66cSDavid du Colombier continue; 6045e96a66cSDavid du Colombier } 6055e96a66cSDavid du Colombier if(_userByUname(box, f[1]) != nil){ 6065e96a66cSDavid du Colombier fprint(2, "duplicate uname '%s'\n", f[1]); 6075e96a66cSDavid du Colombier vtMemFree(s); 6085e96a66cSDavid du Colombier continue; 6095e96a66cSDavid du Colombier } 6105e96a66cSDavid du Colombier 6115e96a66cSDavid du Colombier u = userAlloc(f[0], f[1]); 6125e96a66cSDavid du Colombier uboxAddUser(box, u); 6135e96a66cSDavid du Colombier 6145e96a66cSDavid du Colombier vtMemFree(s); 6155e96a66cSDavid du Colombier } 6165e96a66cSDavid du Colombier assert(box->nuser == nuser); 6175e96a66cSDavid du Colombier 6185e96a66cSDavid du Colombier /* 6195e96a66cSDavid du Colombier * Second pass - fill in leader and group information. 6205e96a66cSDavid du Colombier */ 6215e96a66cSDavid du Colombier for(i = 0; i < nuser; i++){ 6225e96a66cSDavid du Colombier s = vtStrDup(line[i]); 6235e96a66cSDavid du Colombier getfields(s, f, nelem(f), 0, ":"); 6245e96a66cSDavid du Colombier 6255e96a66cSDavid du Colombier assert(g = _userByUname(box, f[1])); 6265e96a66cSDavid du Colombier if(*f[2] != '\0'){ 6275e96a66cSDavid du Colombier if((u = _userByUname(box, f[2])) == nil) 6285e96a66cSDavid du Colombier g->leader = vtStrDup(g->uname); 6295e96a66cSDavid du Colombier else 6305e96a66cSDavid du Colombier g->leader = vtStrDup(u->uname); 6315e96a66cSDavid du Colombier box->len += strlen(g->leader); 6325e96a66cSDavid du Colombier } 6335e96a66cSDavid du Colombier for(p = f[3]; p != nil; p = q){ 6345e96a66cSDavid du Colombier if((q = utfrune(p, L',')) != nil) 6355e96a66cSDavid du Colombier *q++ = '\0'; 6365e96a66cSDavid du Colombier if(!_groupAddMember(box, g, p)){ 6375e96a66cSDavid du Colombier // print/log error here 6385e96a66cSDavid du Colombier } 6395e96a66cSDavid du Colombier } 6405e96a66cSDavid du Colombier 6415e96a66cSDavid du Colombier vtMemFree(s); 6425e96a66cSDavid du Colombier } 6435e96a66cSDavid du Colombier 6445e96a66cSDavid du Colombier vtMemFree(line); 6455e96a66cSDavid du Colombier vtMemFree(buf); 6465e96a66cSDavid du Colombier 6475e96a66cSDavid du Colombier for(i = 0; usersMandatory[i] != nil; i++){ 6485e96a66cSDavid du Colombier if((u = _userByUid(box, usersMandatory[i])) == nil){ 6495e96a66cSDavid du Colombier vtSetError("user '%s' is mandatory", usersMandatory[i]); 6505e96a66cSDavid du Colombier uboxFree(box); 6515e96a66cSDavid du Colombier return 0; 6525e96a66cSDavid du Colombier } 6535e96a66cSDavid du Colombier if(strcmp(u->uid, u->uname) != 0){ 6545e96a66cSDavid du Colombier vtSetError("uid/uname for user '%s' must match", 6555e96a66cSDavid du Colombier usersMandatory[i]); 6565e96a66cSDavid du Colombier uboxFree(box); 6575e96a66cSDavid du Colombier return 0; 6585e96a66cSDavid du Colombier } 6595e96a66cSDavid du Colombier } 6605e96a66cSDavid du Colombier 6615e96a66cSDavid du Colombier vtLock(ubox.lock); 6625e96a66cSDavid du Colombier if(name != nil && usersFileWrite(box) == 0){ 6635e96a66cSDavid du Colombier /* 6645e96a66cSDavid du Colombier * What to do here? How much whining? 6655e96a66cSDavid du Colombier */ 6665e96a66cSDavid du Colombier } 6675e96a66cSDavid du Colombier obox = ubox.box; 6685e96a66cSDavid du Colombier ubox.box = box; 6695e96a66cSDavid du Colombier vtUnlock(ubox.lock); 6705e96a66cSDavid du Colombier 6715e96a66cSDavid du Colombier if(obox != nil) 6725e96a66cSDavid du Colombier uboxFree(obox); 6735e96a66cSDavid du Colombier 6745e96a66cSDavid du Colombier return 1; 6755e96a66cSDavid du Colombier } 6765e96a66cSDavid du Colombier 6775e96a66cSDavid du Colombier static int 6785e96a66cSDavid du Colombier usersFileRead(char* path) 6795e96a66cSDavid du Colombier { 6805e96a66cSDavid du Colombier char *p; 6815e96a66cSDavid du Colombier File *file; 6825e96a66cSDavid du Colombier Fsys *fsys; 6835e96a66cSDavid du Colombier int len, r; 6845e96a66cSDavid du Colombier uvlong size; 6855e96a66cSDavid du Colombier 6865e96a66cSDavid du Colombier if((fsys = fsysGet("main")) == nil) 6875e96a66cSDavid du Colombier return 0; 6885e96a66cSDavid du Colombier fsysFsRlock(fsys); 6895e96a66cSDavid du Colombier 6905e96a66cSDavid du Colombier r = 0; 6915e96a66cSDavid du Colombier if((file = fileOpen(fsysGetFs(fsys), path)) != nil){ 6925e96a66cSDavid du Colombier if(fileGetSize(file, &size)){ 6935e96a66cSDavid du Colombier len = size; 6945e96a66cSDavid du Colombier p = vtMemAlloc(size+1); 6955e96a66cSDavid du Colombier if(fileRead(file, p, len, 0) == len){ 6965e96a66cSDavid du Colombier p[len] = '\0'; 6975e96a66cSDavid du Colombier r = uboxInit(path, p, len); 6985e96a66cSDavid du Colombier } 6995e96a66cSDavid du Colombier } 7005e96a66cSDavid du Colombier fileDecRef(file); 7015e96a66cSDavid du Colombier } 7025e96a66cSDavid du Colombier 7035e96a66cSDavid du Colombier fsysFsRUnlock(fsys); 7045e96a66cSDavid du Colombier fsysPut(fsys); 7055e96a66cSDavid du Colombier 7065e96a66cSDavid du Colombier return r; 7075e96a66cSDavid du Colombier } 7085e96a66cSDavid du Colombier 7095e96a66cSDavid du Colombier static int 7105e96a66cSDavid du Colombier cmdUname(int argc, char* argv[]) 7115e96a66cSDavid du Colombier { 7125e96a66cSDavid du Colombier User *u, *up; 7135e96a66cSDavid du Colombier int d, dflag, i, r; 7145e96a66cSDavid du Colombier char *p, *uid, *uname; 71561201b97SDavid du Colombier char *createfmt = "fsys main create /active/usr/%s %s %s d775"; 716*34e04225SDavid du Colombier char *usage = "usage: uname [-d] uname [uid|:uid|%%newname|=leader|+member|-member]"; 7175e96a66cSDavid du Colombier 7185e96a66cSDavid du Colombier dflag = 0; 7195e96a66cSDavid du Colombier 7205e96a66cSDavid du Colombier ARGBEGIN{ 7215e96a66cSDavid du Colombier default: 7225e96a66cSDavid du Colombier return cliError(usage); 7235e96a66cSDavid du Colombier case 'd': 7245e96a66cSDavid du Colombier dflag = 1; 7255e96a66cSDavid du Colombier break; 7265e96a66cSDavid du Colombier }ARGEND 7275e96a66cSDavid du Colombier 7285e96a66cSDavid du Colombier if(argc < 1){ 729*34e04225SDavid du Colombier if(!dflag) 730*34e04225SDavid du Colombier return cliError(usage); 7315e96a66cSDavid du Colombier vtRLock(ubox.lock); 7325e96a66cSDavid du Colombier uboxDump(ubox.box); 7335e96a66cSDavid du Colombier vtRUnlock(ubox.lock); 7345e96a66cSDavid du Colombier return 1; 7355e96a66cSDavid du Colombier } 7365e96a66cSDavid du Colombier 7375e96a66cSDavid du Colombier uname = argv[0]; 7385e96a66cSDavid du Colombier argc--; argv++; 7395e96a66cSDavid du Colombier 7405e96a66cSDavid du Colombier if(argc == 0){ 7415e96a66cSDavid du Colombier vtRLock(ubox.lock); 7425e96a66cSDavid du Colombier if((u = _userByUname(ubox.box, uname)) == nil){ 7435e96a66cSDavid du Colombier vtRUnlock(ubox.lock); 7445e96a66cSDavid du Colombier return 0; 7455e96a66cSDavid du Colombier } 7465e96a66cSDavid du Colombier consPrint("\t%U\n", u); 7475e96a66cSDavid du Colombier vtRUnlock(ubox.lock); 7485e96a66cSDavid du Colombier return 1; 7495e96a66cSDavid du Colombier } 7505e96a66cSDavid du Colombier 7515e96a66cSDavid du Colombier vtLock(ubox.lock); 7525e96a66cSDavid du Colombier u = _userByUname(ubox.box, uname); 7535e96a66cSDavid du Colombier while(argc--){ 7545e96a66cSDavid du Colombier if(argv[0][0] == '%'){ 7555e96a66cSDavid du Colombier if(u == nil){ 7565e96a66cSDavid du Colombier vtUnlock(ubox.lock); 7575e96a66cSDavid du Colombier return 0; 7585e96a66cSDavid du Colombier } 7595e96a66cSDavid du Colombier p = &argv[0][1]; 7605e96a66cSDavid du Colombier if((up = _userByUname(ubox.box, p)) != nil){ 7615e96a66cSDavid du Colombier vtSetError("uname: uname '%s' already exists", 7625e96a66cSDavid du Colombier up->uname); 7635e96a66cSDavid du Colombier vtUnlock(ubox.lock); 7645e96a66cSDavid du Colombier return 0; 7655e96a66cSDavid du Colombier } 7665e96a66cSDavid du Colombier for(i = 0; usersMandatory[i] != nil; i++){ 7675e96a66cSDavid du Colombier if(strcmp(usersMandatory[i], uname) != 0) 7685e96a66cSDavid du Colombier continue; 7695e96a66cSDavid du Colombier vtSetError("uname: uname '%s' is mandatory", 7705e96a66cSDavid du Colombier uname); 7715e96a66cSDavid du Colombier vtUnlock(ubox.lock); 7725e96a66cSDavid du Colombier return 0; 7735e96a66cSDavid du Colombier } 7745e96a66cSDavid du Colombier 7755e96a66cSDavid du Colombier d = strlen(p) - strlen(u->uname); 7765e96a66cSDavid du Colombier for(up = ubox.box->head; up != nil; up = up->next){ 7775e96a66cSDavid du Colombier if(up->leader != nil){ 7785e96a66cSDavid du Colombier if(strcmp(up->leader, u->uname) == 0){ 7795e96a66cSDavid du Colombier vtMemFree(up->leader); 7805e96a66cSDavid du Colombier up->leader = vtStrDup(p); 7815e96a66cSDavid du Colombier ubox.box->len += d; 7825e96a66cSDavid du Colombier } 7835e96a66cSDavid du Colombier } 7845e96a66cSDavid du Colombier for(i = 0; i < up->ngroup; i++){ 7855e96a66cSDavid du Colombier if(strcmp(up->group[i], u->uname) != 0) 7865e96a66cSDavid du Colombier continue; 7875e96a66cSDavid du Colombier vtMemFree(up->group[i]); 7885e96a66cSDavid du Colombier up->group[i] = vtStrDup(p); 7895e96a66cSDavid du Colombier ubox.box->len += d; 7905e96a66cSDavid du Colombier break; 7915e96a66cSDavid du Colombier } 7925e96a66cSDavid du Colombier } 7935e96a66cSDavid du Colombier 7945e96a66cSDavid du Colombier uboxRemUser(ubox.box, u); 7955e96a66cSDavid du Colombier vtMemFree(u->uname); 7965e96a66cSDavid du Colombier u->uname = vtStrDup(p); 7975e96a66cSDavid du Colombier uboxAddUser(ubox.box, u); 7985e96a66cSDavid du Colombier } 7995e96a66cSDavid du Colombier else if(argv[0][0] == '='){ 8005e96a66cSDavid du Colombier if(u == nil){ 8015e96a66cSDavid du Colombier vtUnlock(ubox.lock); 8025e96a66cSDavid du Colombier return 0; 8035e96a66cSDavid du Colombier } 8045e96a66cSDavid du Colombier if((up = _userByUname(ubox.box, &argv[0][1])) == nil){ 8055e96a66cSDavid du Colombier if(argv[0][1] != '\0'){ 8065e96a66cSDavid du Colombier vtUnlock(ubox.lock); 8075e96a66cSDavid du Colombier return 0; 8085e96a66cSDavid du Colombier } 8095e96a66cSDavid du Colombier } 8105e96a66cSDavid du Colombier if(u->leader != nil){ 8115e96a66cSDavid du Colombier ubox.box->len -= strlen(u->leader); 8125e96a66cSDavid du Colombier vtMemFree(u->leader); 8135e96a66cSDavid du Colombier u->leader = nil; 8145e96a66cSDavid du Colombier } 8155e96a66cSDavid du Colombier if(up != nil){ 8165e96a66cSDavid du Colombier u->leader = vtStrDup(up->uname); 8175e96a66cSDavid du Colombier ubox.box->len += strlen(u->leader); 8185e96a66cSDavid du Colombier } 8195e96a66cSDavid du Colombier } 8205e96a66cSDavid du Colombier else if(argv[0][0] == '+'){ 8215e96a66cSDavid du Colombier if(u == nil){ 8225e96a66cSDavid du Colombier vtUnlock(ubox.lock); 8235e96a66cSDavid du Colombier return 0; 8245e96a66cSDavid du Colombier } 8255e96a66cSDavid du Colombier if((up = _userByUname(ubox.box, &argv[0][1])) == nil){ 8265e96a66cSDavid du Colombier vtUnlock(ubox.lock); 8275e96a66cSDavid du Colombier return 0; 8285e96a66cSDavid du Colombier } 8295e96a66cSDavid du Colombier if(!_groupAddMember(ubox.box, u, up->uname)){ 8305e96a66cSDavid du Colombier vtUnlock(ubox.lock); 8315e96a66cSDavid du Colombier return 0; 8325e96a66cSDavid du Colombier } 8335e96a66cSDavid du Colombier } 8345e96a66cSDavid du Colombier else if(argv[0][0] == '-'){ 8355e96a66cSDavid du Colombier if(u == nil){ 8365e96a66cSDavid du Colombier vtUnlock(ubox.lock); 8375e96a66cSDavid du Colombier return 0; 8385e96a66cSDavid du Colombier } 8395e96a66cSDavid du Colombier if((up = _userByUname(ubox.box, &argv[0][1])) == nil){ 8405e96a66cSDavid du Colombier vtUnlock(ubox.lock); 8415e96a66cSDavid du Colombier return 0; 8425e96a66cSDavid du Colombier } 8435e96a66cSDavid du Colombier if(!_groupRemMember(ubox.box, u, up->uname)){ 8445e96a66cSDavid du Colombier vtUnlock(ubox.lock); 8455e96a66cSDavid du Colombier return 0; 8465e96a66cSDavid du Colombier } 8475e96a66cSDavid du Colombier } 8485e96a66cSDavid du Colombier else{ 8495e96a66cSDavid du Colombier if(u != nil){ 8505e96a66cSDavid du Colombier vtSetError("uname: uname '%s' already exists", 8515e96a66cSDavid du Colombier u->uname); 8525e96a66cSDavid du Colombier vtUnlock(ubox.lock); 8535e96a66cSDavid du Colombier return 0; 8545e96a66cSDavid du Colombier } 8555e96a66cSDavid du Colombier 8565e96a66cSDavid du Colombier uid = argv[0]; 8575e96a66cSDavid du Colombier if(*uid == ':') 8585e96a66cSDavid du Colombier uid++; 8595e96a66cSDavid du Colombier if((u = _userByUid(ubox.box, uid)) != nil){ 8605e96a66cSDavid du Colombier vtSetError("uname: uid '%s' already exists", 8615e96a66cSDavid du Colombier u->uid); 8625e96a66cSDavid du Colombier vtUnlock(ubox.lock); 8635e96a66cSDavid du Colombier return 0; 8645e96a66cSDavid du Colombier } 8655e96a66cSDavid du Colombier 8665e96a66cSDavid du Colombier u = userAlloc(uid, uname); 8675e96a66cSDavid du Colombier uboxAddUser(ubox.box, u); 8685e96a66cSDavid du Colombier if(argv[0][0] != ':'){ 8695e96a66cSDavid du Colombier // should have an option for the mode and gid 8705e96a66cSDavid du Colombier p = smprint(createfmt, uname, uname, uname); 8715e96a66cSDavid du Colombier r = cliExec(p); 8725e96a66cSDavid du Colombier vtMemFree(p); 8735e96a66cSDavid du Colombier if(r != 0){ 8745e96a66cSDavid du Colombier vtUnlock(ubox.lock); 8755e96a66cSDavid du Colombier return 0; 8765e96a66cSDavid du Colombier } 8775e96a66cSDavid du Colombier } 8785e96a66cSDavid du Colombier } 8795e96a66cSDavid du Colombier argv++; 8805e96a66cSDavid du Colombier } 8815e96a66cSDavid du Colombier 8825e96a66cSDavid du Colombier if(usersFileWrite(ubox.box) == 0){ 8835e96a66cSDavid du Colombier vtUnlock(ubox.lock); 8845e96a66cSDavid du Colombier return 0; 8855e96a66cSDavid du Colombier } 8865e96a66cSDavid du Colombier if(dflag) 8875e96a66cSDavid du Colombier uboxDump(ubox.box); 8885e96a66cSDavid du Colombier vtUnlock(ubox.lock); 8895e96a66cSDavid du Colombier 8905e96a66cSDavid du Colombier return 1; 8915e96a66cSDavid du Colombier } 8925e96a66cSDavid du Colombier 8935e96a66cSDavid du Colombier static int 8945e96a66cSDavid du Colombier cmdUsers(int argc, char* argv[]) 8955e96a66cSDavid du Colombier { 8965e96a66cSDavid du Colombier Ubox *box; 8975e96a66cSDavid du Colombier int dflag, r, wflag; 8985e96a66cSDavid du Colombier char *usage = "usage: users [-dw] [file]"; 8995e96a66cSDavid du Colombier 9005e96a66cSDavid du Colombier dflag = wflag = 0; 9015e96a66cSDavid du Colombier 9025e96a66cSDavid du Colombier ARGBEGIN{ 9035e96a66cSDavid du Colombier default: 9045e96a66cSDavid du Colombier return cliError(usage); 9055e96a66cSDavid du Colombier case 'd': 9065e96a66cSDavid du Colombier dflag = 1; 9075e96a66cSDavid du Colombier break; 9085e96a66cSDavid du Colombier case 'w': 9095e96a66cSDavid du Colombier wflag = 1; 9105e96a66cSDavid du Colombier break; 9115e96a66cSDavid du Colombier }ARGEND 9125e96a66cSDavid du Colombier 9135e96a66cSDavid du Colombier switch(argc){ 9145e96a66cSDavid du Colombier default: 9155e96a66cSDavid du Colombier return cliError(usage); 9165e96a66cSDavid du Colombier case 0: 9175e96a66cSDavid du Colombier if(dflag) 9185e96a66cSDavid du Colombier uboxInit(nil, usersDefault, sizeof(usersDefault)); 9195e96a66cSDavid du Colombier vtRLock(ubox.lock); 9205e96a66cSDavid du Colombier box = ubox.box; 9215e96a66cSDavid du Colombier if(box->name != nil) 9225e96a66cSDavid du Colombier consPrint("\tfile %s\n", box->name); 9235e96a66cSDavid du Colombier else 9245e96a66cSDavid du Colombier consPrint("\tno file\n"); 9255e96a66cSDavid du Colombier consPrint("\tnuser %d len %d\n", box->nuser, box->len); 9265e96a66cSDavid du Colombier vtRUnlock(ubox.lock); 9275e96a66cSDavid du Colombier break; 9285e96a66cSDavid du Colombier case 1: 9295e96a66cSDavid du Colombier if(dflag) 9305e96a66cSDavid du Colombier return cliError(usage); 9315e96a66cSDavid du Colombier if(usersFileRead(argv[0]) == 0) 9325e96a66cSDavid du Colombier return 0; 9335e96a66cSDavid du Colombier break; 9345e96a66cSDavid du Colombier } 9355e96a66cSDavid du Colombier 9365e96a66cSDavid du Colombier if(wflag){ 9375e96a66cSDavid du Colombier vtRLock(ubox.lock); 9385e96a66cSDavid du Colombier r = usersFileWrite(ubox.box); 9395e96a66cSDavid du Colombier vtRUnlock(ubox.lock); 9405e96a66cSDavid du Colombier return r; 9415e96a66cSDavid du Colombier } 9425e96a66cSDavid du Colombier 9435e96a66cSDavid du Colombier return 1; 9445e96a66cSDavid du Colombier } 9455e96a66cSDavid du Colombier 9465e96a66cSDavid du Colombier int 9475e96a66cSDavid du Colombier usersInit(void) 9485e96a66cSDavid du Colombier { 9495e96a66cSDavid du Colombier fmtinstall('U', userFmt); 9505e96a66cSDavid du Colombier 9515e96a66cSDavid du Colombier ubox.lock = vtLockAlloc(); 9525e96a66cSDavid du Colombier uboxInit(nil, usersDefault, sizeof(usersDefault)); 9535e96a66cSDavid du Colombier 9545e96a66cSDavid du Colombier cliAddCmd("users", cmdUsers); 9555e96a66cSDavid du Colombier cliAddCmd("uname", cmdUname); 9565e96a66cSDavid du Colombier 9575e96a66cSDavid du Colombier return 1; 9585e96a66cSDavid du Colombier } 959