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
12*e12a9870SDavid du Colombier 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 */
22*e12a9870SDavid du Colombier };
235e96a66cSDavid du Colombier
245e96a66cSDavid du Colombier #pragma varargck type "U" User*
255e96a66cSDavid du Colombier
26*e12a9870SDavid du Colombier struct Ubox {
275e96a66cSDavid du Colombier User* head;
285e96a66cSDavid du Colombier User* tail;
295e96a66cSDavid du Colombier int nuser;
305e96a66cSDavid du Colombier int len;
315e96a66cSDavid du Colombier
325e96a66cSDavid du Colombier User* ihash[NUserHash]; /* lookup by .uid */
335e96a66cSDavid du Colombier User* nhash[NUserHash]; /* lookup by .uname */
34*e12a9870SDavid du Colombier };
355e96a66cSDavid du Colombier
365e96a66cSDavid du Colombier static struct {
375e96a66cSDavid du Colombier VtLock* lock;
385e96a66cSDavid du Colombier
395e96a66cSDavid du Colombier Ubox* box;
405e96a66cSDavid du Colombier } ubox;
415e96a66cSDavid du Colombier
425e96a66cSDavid du Colombier static char usersDefault[] = {
435e96a66cSDavid du Colombier "adm:adm:adm:sys\n"
445e96a66cSDavid du Colombier "none:none::\n"
455e96a66cSDavid du Colombier "noworld:noworld::\n"
463421e8c4SDavid du Colombier "sys:sys::glenda\n"
47dc5a79c1SDavid du Colombier "glenda:glenda:glenda:\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
userHash(char * s)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*
_userByUid(Ubox * box,char * uid)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*
unameByUid(char * uid)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*
_userByUname(Ubox * box,char * uname)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*
uidByUname(char * uname)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
_groupMember(Ubox * box,char * group,char * member,int whenNoGroup)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
groupWriteMember(char * uname)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
_groupRemMember(Ubox * box,User * g,char * member)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:
224d5dc43e7SDavid du Colombier for(; i < g->ngroup; i++)
2255e96a66cSDavid du Colombier g->group[i] = g->group[i+1];
226d5dc43e7SDavid du Colombier g->group[i] = nil; /* prevent accidents */
227d5dc43e7SDavid du Colombier g->group = vtMemRealloc(g->group, g->ngroup * sizeof(char*));
2285e96a66cSDavid du Colombier break;
2295e96a66cSDavid du Colombier }
2305e96a66cSDavid du Colombier
2315e96a66cSDavid du Colombier return 1;
2325e96a66cSDavid du Colombier }
2335e96a66cSDavid du Colombier
2345e96a66cSDavid du Colombier static int
_groupAddMember(Ubox * box,User * g,char * member)2355e96a66cSDavid du Colombier _groupAddMember(Ubox* box, User* g, char* member)
2365e96a66cSDavid du Colombier {
2375e96a66cSDavid du Colombier User *u;
2385e96a66cSDavid du Colombier
2395e96a66cSDavid du Colombier if((u = _userByUname(box, member)) == nil)
2405e96a66cSDavid du Colombier return 0;
2415e96a66cSDavid du Colombier if(_groupMember(box, g->uid, u->uname, 0)){
2425e96a66cSDavid du Colombier if(strcmp(g->uname, member) == 0)
2435e96a66cSDavid du Colombier vtSetError("uname: '%s' always in own group", member);
2445e96a66cSDavid du Colombier else
2455e96a66cSDavid du Colombier vtSetError("uname: '%s' already in group '%s'",
2465e96a66cSDavid du Colombier member, g->uname);
2475e96a66cSDavid du Colombier return 0;
2485e96a66cSDavid du Colombier }
2495e96a66cSDavid du Colombier
2505e96a66cSDavid du Colombier g->group = vtMemRealloc(g->group, (g->ngroup+1)*sizeof(char*));
2515e96a66cSDavid du Colombier g->group[g->ngroup] = vtStrDup(member);
2525e96a66cSDavid du Colombier box->len += strlen(member);
2535e96a66cSDavid du Colombier g->ngroup++;
2545e96a66cSDavid du Colombier if(g->ngroup > 1)
2555e96a66cSDavid du Colombier box->len++;
2565e96a66cSDavid du Colombier
2575e96a66cSDavid du Colombier return 1;
2585e96a66cSDavid du Colombier }
2595e96a66cSDavid du Colombier
2605e96a66cSDavid du Colombier int
groupMember(char * group,char * member)2615e96a66cSDavid du Colombier groupMember(char* group, char* member)
2625e96a66cSDavid du Colombier {
2635e96a66cSDavid du Colombier int r;
2645e96a66cSDavid du Colombier
2655e96a66cSDavid du Colombier if(group == nil)
2665e96a66cSDavid du Colombier return 0;
2675e96a66cSDavid du Colombier
2685e96a66cSDavid du Colombier vtRLock(ubox.lock);
2695e96a66cSDavid du Colombier r = _groupMember(ubox.box, group, member, 0);
2705e96a66cSDavid du Colombier vtRUnlock(ubox.lock);
2715e96a66cSDavid du Colombier
2725e96a66cSDavid du Colombier return r;
2735e96a66cSDavid du Colombier }
2745e96a66cSDavid du Colombier
2755e96a66cSDavid du Colombier int
groupLeader(char * group,char * member)2765e96a66cSDavid du Colombier groupLeader(char* group, char* member)
2775e96a66cSDavid du Colombier {
2785e96a66cSDavid du Colombier int r;
2795e96a66cSDavid du Colombier User *g;
2805e96a66cSDavid du Colombier
2815e96a66cSDavid du Colombier /*
2825e96a66cSDavid du Colombier * Is 'member' the leader of 'group'?
2835e96a66cSDavid du Colombier * Note that 'group' is a 'uid' and not a 'uname'.
2845e96a66cSDavid du Colombier * Uname 'none' cannot be a group leader.
2855e96a66cSDavid du Colombier */
2865e96a66cSDavid du Colombier if(strcmp(member, unamenone) == 0 || group == nil)
2875e96a66cSDavid du Colombier return 0;
2885e96a66cSDavid du Colombier
2895e96a66cSDavid du Colombier vtRLock(ubox.lock);
2905e96a66cSDavid du Colombier if((g = _userByUid(ubox.box, group)) == nil){
2915e96a66cSDavid du Colombier vtRUnlock(ubox.lock);
2925e96a66cSDavid du Colombier return 0;
2935e96a66cSDavid du Colombier }
2945e96a66cSDavid du Colombier if(g->leader != nil){
2955e96a66cSDavid du Colombier if(strcmp(g->leader, member) == 0){
2965e96a66cSDavid du Colombier vtRUnlock(ubox.lock);
2975e96a66cSDavid du Colombier return 1;
2985e96a66cSDavid du Colombier }
2995e96a66cSDavid du Colombier r = 0;
3005e96a66cSDavid du Colombier }
3015e96a66cSDavid du Colombier else
3025e96a66cSDavid du Colombier r = _groupMember(ubox.box, group, member, 0);
3035e96a66cSDavid du Colombier vtRUnlock(ubox.lock);
3045e96a66cSDavid du Colombier
3055e96a66cSDavid du Colombier return r;
3065e96a66cSDavid du Colombier }
3075e96a66cSDavid du Colombier
3085e96a66cSDavid du Colombier static void
userFree(User * u)3095e96a66cSDavid du Colombier userFree(User* u)
3105e96a66cSDavid du Colombier {
3115e96a66cSDavid du Colombier int i;
3125e96a66cSDavid du Colombier
3135e96a66cSDavid du Colombier vtMemFree(u->uid);
3145e96a66cSDavid du Colombier vtMemFree(u->uname);
3155e96a66cSDavid du Colombier if(u->leader != nil)
3165e96a66cSDavid du Colombier vtMemFree(u->leader);
3175e96a66cSDavid du Colombier if(u->ngroup){
3185e96a66cSDavid du Colombier for(i = 0; i < u->ngroup; i++)
3195e96a66cSDavid du Colombier vtMemFree(u->group[i]);
3205e96a66cSDavid du Colombier vtMemFree(u->group);
3215e96a66cSDavid du Colombier }
3225e96a66cSDavid du Colombier vtMemFree(u);
3235e96a66cSDavid du Colombier }
3245e96a66cSDavid du Colombier
3255e96a66cSDavid du Colombier static User*
userAlloc(char * uid,char * uname)3265e96a66cSDavid du Colombier userAlloc(char* uid, char* uname)
3275e96a66cSDavid du Colombier {
3285e96a66cSDavid du Colombier User *u;
3295e96a66cSDavid du Colombier
3305e96a66cSDavid du Colombier u = vtMemAllocZ(sizeof(User));
3315e96a66cSDavid du Colombier u->uid = vtStrDup(uid);
3325e96a66cSDavid du Colombier u->uname = vtStrDup(uname);
3335e96a66cSDavid du Colombier
3345e96a66cSDavid du Colombier return u;
3355e96a66cSDavid du Colombier }
3365e96a66cSDavid du Colombier
3375e96a66cSDavid du Colombier int
validUserName(char * name)3385e96a66cSDavid du Colombier validUserName(char* name)
3395e96a66cSDavid du Colombier {
3405e96a66cSDavid du Colombier Rune *r;
3415e96a66cSDavid du Colombier static Rune invalid[] = L"#:,()";
3425e96a66cSDavid du Colombier
3435e96a66cSDavid du Colombier for(r = invalid; *r != '\0'; r++){
3445e96a66cSDavid du Colombier if(utfrune(name, *r))
3455e96a66cSDavid du Colombier return 0;
3465e96a66cSDavid du Colombier }
3475e96a66cSDavid du Colombier return 1;
3485e96a66cSDavid du Colombier }
3495e96a66cSDavid du Colombier
3505e96a66cSDavid du Colombier static int
userFmt(Fmt * fmt)3515e96a66cSDavid du Colombier userFmt(Fmt* fmt)
3525e96a66cSDavid du Colombier {
3535e96a66cSDavid du Colombier User *u;
3545e96a66cSDavid du Colombier int i, r;
3555e96a66cSDavid du Colombier
3565e96a66cSDavid du Colombier u = va_arg(fmt->args, User*);
3575e96a66cSDavid du Colombier
3585e96a66cSDavid du Colombier r = fmtprint(fmt, "%s:%s:", u->uid, u->uname);
3595e96a66cSDavid du Colombier if(u->leader != nil)
3605e96a66cSDavid du Colombier r += fmtprint(fmt, u->leader);
3615e96a66cSDavid du Colombier r += fmtprint(fmt, ":");
3625e96a66cSDavid du Colombier if(u->ngroup){
3635e96a66cSDavid du Colombier r += fmtprint(fmt, u->group[0]);
3645e96a66cSDavid du Colombier for(i = 1; i < u->ngroup; i++)
3655e96a66cSDavid du Colombier r += fmtprint(fmt, ",%s", u->group[i]);
3665e96a66cSDavid du Colombier }
3675e96a66cSDavid du Colombier
3685e96a66cSDavid du Colombier return r;
3695e96a66cSDavid du Colombier }
3705e96a66cSDavid du Colombier
3715e96a66cSDavid du Colombier static int
usersFileWrite(Ubox * box)3725e96a66cSDavid du Colombier usersFileWrite(Ubox* box)
3735e96a66cSDavid du Colombier {
3745e96a66cSDavid du Colombier Fs *fs;
3755e96a66cSDavid du Colombier User *u;
3765e96a66cSDavid du Colombier int i, r;
3775e96a66cSDavid du Colombier Fsys *fsys;
3785e96a66cSDavid du Colombier char *p, *q, *s;
3795e96a66cSDavid du Colombier File *dir, *file;
3805e96a66cSDavid du Colombier
3815e96a66cSDavid du Colombier if((fsys = fsysGet("main")) == nil)
3825e96a66cSDavid du Colombier return 0;
3835e96a66cSDavid du Colombier fsysFsRlock(fsys);
3845e96a66cSDavid du Colombier fs = fsysGetFs(fsys);
3855e96a66cSDavid du Colombier
3865e96a66cSDavid du Colombier /*
3875e96a66cSDavid du Colombier * BUG:
3885e96a66cSDavid du Colombier * the owner/group/permissions need to be thought out.
3895e96a66cSDavid du Colombier */
3905e96a66cSDavid du Colombier r = 0;
3915e96a66cSDavid du Colombier if((dir = fileOpen(fs, "/active")) == nil)
3925e96a66cSDavid du Colombier goto tidy0;
3933cb0b4acSDavid du Colombier if((file = fileWalk(dir, uidadm)) == nil)
3943cb0b4acSDavid du Colombier file = fileCreate(dir, uidadm, ModeDir|0775, uidadm);
3955e96a66cSDavid du Colombier fileDecRef(dir);
3965e96a66cSDavid du Colombier if(file == nil)
3975e96a66cSDavid du Colombier goto tidy;
3985e96a66cSDavid du Colombier dir = file;
3995e96a66cSDavid du Colombier if((file = fileWalk(dir, "users")) == nil)
4005e96a66cSDavid du Colombier file = fileCreate(dir, "users", 0664, uidadm);
4015e96a66cSDavid du Colombier fileDecRef(dir);
4025e96a66cSDavid du Colombier if(file == nil)
4035e96a66cSDavid du Colombier goto tidy;
4045e96a66cSDavid du Colombier if(!fileTruncate(file, uidadm))
4055e96a66cSDavid du Colombier goto tidy;
4065e96a66cSDavid du Colombier
4075e96a66cSDavid du Colombier p = s = vtMemAlloc(box->len+1);
4085e96a66cSDavid du Colombier q = p + box->len+1;
4095e96a66cSDavid du Colombier for(u = box->head; u != nil; u = u->next){
4105e96a66cSDavid du Colombier p += snprint(p, q-p, "%s:%s:", u->uid, u->uname);
4115e96a66cSDavid du Colombier if(u->leader != nil)
4125e96a66cSDavid du Colombier p+= snprint(p, q-p, u->leader);
4135e96a66cSDavid du Colombier p += snprint(p, q-p, ":");
4145e96a66cSDavid du Colombier if(u->ngroup){
4155e96a66cSDavid du Colombier p += snprint(p, q-p, u->group[0]);
4165e96a66cSDavid du Colombier for(i = 1; i < u->ngroup; i++)
4175e96a66cSDavid du Colombier p += snprint(p, q-p, ",%s", u->group[i]);
4185e96a66cSDavid du Colombier }
4195e96a66cSDavid du Colombier p += snprint(p, q-p, "\n");
4205e96a66cSDavid du Colombier }
4215e96a66cSDavid du Colombier r = fileWrite(file, s, box->len, 0, uidadm);
4225e96a66cSDavid du Colombier vtMemFree(s);
4235e96a66cSDavid du Colombier
4245e96a66cSDavid du Colombier tidy:
4255e96a66cSDavid du Colombier if(file != nil)
4265e96a66cSDavid du Colombier fileDecRef(file);
4275e96a66cSDavid du Colombier tidy0:
4285e96a66cSDavid du Colombier fsysFsRUnlock(fsys);
4295e96a66cSDavid du Colombier fsysPut(fsys);
4305e96a66cSDavid du Colombier
4315e96a66cSDavid du Colombier return r;
4325e96a66cSDavid du Colombier }
4335e96a66cSDavid du Colombier
4345e96a66cSDavid du Colombier static void
uboxRemUser(Ubox * box,User * u)4355e96a66cSDavid du Colombier uboxRemUser(Ubox* box, User *u)
4365e96a66cSDavid du Colombier {
4375e96a66cSDavid du Colombier User **h, *up;
4385e96a66cSDavid du Colombier
4395e96a66cSDavid du Colombier h = &box->ihash[userHash(u->uid)];
4405e96a66cSDavid du Colombier for(up = *h; up != nil && up != u; up = up->ihash)
4415e96a66cSDavid du Colombier h = &up->ihash;
4425e96a66cSDavid du Colombier assert(up == u);
4435e96a66cSDavid du Colombier *h = up->ihash;
4445e96a66cSDavid du Colombier box->len -= strlen(u->uid);
4455e96a66cSDavid du Colombier
4465e96a66cSDavid du Colombier h = &box->nhash[userHash(u->uname)];
4475e96a66cSDavid du Colombier for(up = *h; up != nil && up != u; up = up->nhash)
4485e96a66cSDavid du Colombier h = &up->nhash;
4495e96a66cSDavid du Colombier assert(up == u);
4505e96a66cSDavid du Colombier *h = up->nhash;
4515e96a66cSDavid du Colombier box->len -= strlen(u->uname);
4525e96a66cSDavid du Colombier
4535e96a66cSDavid du Colombier h = &box->head;
4545e96a66cSDavid du Colombier for(up = *h; up != nil && strcmp(up->uid, u->uid) != 0; up = up->next)
4555e96a66cSDavid du Colombier h = &up->next;
4565e96a66cSDavid du Colombier assert(up == u);
4575e96a66cSDavid du Colombier *h = u->next;
4585e96a66cSDavid du Colombier u->next = nil;
4595e96a66cSDavid du Colombier
4605e96a66cSDavid du Colombier box->len -= 4;
4615e96a66cSDavid du Colombier box->nuser--;
4625e96a66cSDavid du Colombier }
4635e96a66cSDavid du Colombier
4645e96a66cSDavid du Colombier static void
uboxAddUser(Ubox * box,User * u)4655e96a66cSDavid du Colombier uboxAddUser(Ubox* box, User* u)
4665e96a66cSDavid du Colombier {
4675e96a66cSDavid du Colombier User **h, *up;
4685e96a66cSDavid du Colombier
4695e96a66cSDavid du Colombier h = &box->ihash[userHash(u->uid)];
4705e96a66cSDavid du Colombier u->ihash = *h;
4715e96a66cSDavid du Colombier *h = u;
4725e96a66cSDavid du Colombier box->len += strlen(u->uid);
4735e96a66cSDavid du Colombier
4745e96a66cSDavid du Colombier h = &box->nhash[userHash(u->uname)];
4755e96a66cSDavid du Colombier u->nhash = *h;
4765e96a66cSDavid du Colombier *h = u;
4775e96a66cSDavid du Colombier box->len += strlen(u->uname);
4785e96a66cSDavid du Colombier
4795e96a66cSDavid du Colombier h = &box->head;
4805e96a66cSDavid du Colombier for(up = *h; up != nil && strcmp(up->uid, u->uid) < 0; up = up->next)
4815e96a66cSDavid du Colombier h = &up->next;
4825e96a66cSDavid du Colombier u->next = *h;
4835e96a66cSDavid du Colombier *h = u;
4845e96a66cSDavid du Colombier
4855e96a66cSDavid du Colombier box->len += 4;
4865e96a66cSDavid du Colombier box->nuser++;
4875e96a66cSDavid du Colombier }
4885e96a66cSDavid du Colombier
4895e96a66cSDavid du Colombier static void
uboxDump(Ubox * box)4905e96a66cSDavid du Colombier uboxDump(Ubox* box)
4915e96a66cSDavid du Colombier {
4925e96a66cSDavid du Colombier User* u;
4935e96a66cSDavid du Colombier
4945e96a66cSDavid du Colombier consPrint("nuser %d len = %d\n", box->nuser, box->len);
4955e96a66cSDavid du Colombier
4965e96a66cSDavid du Colombier for(u = box->head; u != nil; u = u->next)
4975e96a66cSDavid du Colombier consPrint("%U\n", u);
4985e96a66cSDavid du Colombier }
4995e96a66cSDavid du Colombier
5005e96a66cSDavid du Colombier static void
uboxFree(Ubox * box)5015e96a66cSDavid du Colombier uboxFree(Ubox* box)
5025e96a66cSDavid du Colombier {
5035e96a66cSDavid du Colombier User *next, *u;
5045e96a66cSDavid du Colombier
5055e96a66cSDavid du Colombier for(u = box->head; u != nil; u = next){
5065e96a66cSDavid du Colombier next = u->next;
5075e96a66cSDavid du Colombier userFree(u);
5085e96a66cSDavid du Colombier }
5095e96a66cSDavid du Colombier vtMemFree(box);
5105e96a66cSDavid du Colombier }
5115e96a66cSDavid du Colombier
5125e96a66cSDavid du Colombier static int
uboxInit(char * users,int len)51381cf8742SDavid du Colombier uboxInit(char* users, int len)
5145e96a66cSDavid du Colombier {
5155e96a66cSDavid du Colombier User *g, *u;
5165e96a66cSDavid du Colombier Ubox *box, *obox;
5173cb0b4acSDavid du Colombier int blank, comment, i, nline, nuser;
5185e96a66cSDavid du Colombier char *buf, *f[5], **line, *p, *q, *s;
5195e96a66cSDavid du Colombier
5205e96a66cSDavid du Colombier /*
5215e96a66cSDavid du Colombier * Strip out whitespace and comments.
5225e96a66cSDavid du Colombier * Note that comments are pointless, they disappear
5235e96a66cSDavid du Colombier * when the server writes the database back out.
5245e96a66cSDavid du Colombier */
5255e96a66cSDavid du Colombier blank = 1;
5263cb0b4acSDavid du Colombier comment = nline = 0;
5275e96a66cSDavid du Colombier
5285e96a66cSDavid du Colombier s = p = buf = vtMemAlloc(len+1);
5295e96a66cSDavid du Colombier for(q = users; *q != '\0'; q++){
5305e96a66cSDavid du Colombier if(*q == '\r' || *q == '\t' || *q == ' ')
5315e96a66cSDavid du Colombier continue;
5325e96a66cSDavid du Colombier if(*q == '\n'){
5335e96a66cSDavid du Colombier if(!blank){
5345e96a66cSDavid du Colombier if(p != s){
5355e96a66cSDavid du Colombier *p++ = '\n';
5363cb0b4acSDavid du Colombier nline++;
5375e96a66cSDavid du Colombier s = p;
5385e96a66cSDavid du Colombier }
5395e96a66cSDavid du Colombier blank = 1;
5405e96a66cSDavid du Colombier }
5415e96a66cSDavid du Colombier comment = 0;
5425e96a66cSDavid du Colombier continue;
5435e96a66cSDavid du Colombier }
5445e96a66cSDavid du Colombier if(*q == '#')
5455e96a66cSDavid du Colombier comment = 1;
5465e96a66cSDavid du Colombier blank = 0;
5475e96a66cSDavid du Colombier if(!comment)
5485e96a66cSDavid du Colombier *p++ = *q;
5495e96a66cSDavid du Colombier }
5505e96a66cSDavid du Colombier *p = '\0';
5515e96a66cSDavid du Colombier
5523cb0b4acSDavid du Colombier line = vtMemAllocZ((nline+2)*sizeof(char*));
5533cb0b4acSDavid du Colombier if((i = gettokens(buf, line, nline+2, "\n")) != nline){
5543cb0b4acSDavid du Colombier fprint(2, "nline %d (%d) botch\n", nline, i);
5555e96a66cSDavid du Colombier vtMemFree(line);
5565e96a66cSDavid du Colombier vtMemFree(buf);
5575e96a66cSDavid du Colombier return 0;
5585e96a66cSDavid du Colombier }
5595e96a66cSDavid du Colombier
5605e96a66cSDavid du Colombier /*
56181cf8742SDavid du Colombier * Everything is updated in a local Ubox until verified.
5625e96a66cSDavid du Colombier */
5635e96a66cSDavid du Colombier box = vtMemAllocZ(sizeof(Ubox));
5645e96a66cSDavid du Colombier
5655e96a66cSDavid du Colombier /*
5665e96a66cSDavid du Colombier * First pass - check format, check for duplicates
5675e96a66cSDavid du Colombier * and enter in hash buckets.
5685e96a66cSDavid du Colombier */
5693cb0b4acSDavid du Colombier nuser = 0;
5703cb0b4acSDavid du Colombier for(i = 0; i < nline; i++){
5715e96a66cSDavid du Colombier s = vtStrDup(line[i]);
5725e96a66cSDavid du Colombier if(getfields(s, f, nelem(f), 0, ":") != 4){
5735e96a66cSDavid du Colombier fprint(2, "bad line '%s'\n", line[i]);
5745e96a66cSDavid du Colombier vtMemFree(s);
5755e96a66cSDavid du Colombier continue;
5765e96a66cSDavid du Colombier }
5775e96a66cSDavid du Colombier if(*f[0] == '\0' || *f[1] == '\0'){
5785e96a66cSDavid du Colombier fprint(2, "bad line '%s'\n", line[i]);
5795e96a66cSDavid du Colombier vtMemFree(s);
5805e96a66cSDavid du Colombier continue;
5815e96a66cSDavid du Colombier }
5825e96a66cSDavid du Colombier if(!validUserName(f[0])){
5835e96a66cSDavid du Colombier fprint(2, "invalid uid '%s'\n", f[0]);
5845e96a66cSDavid du Colombier vtMemFree(s);
5855e96a66cSDavid du Colombier continue;
5865e96a66cSDavid du Colombier }
5875e96a66cSDavid du Colombier if(_userByUid(box, f[0]) != nil){
5885e96a66cSDavid du Colombier fprint(2, "duplicate uid '%s'\n", f[0]);
5895e96a66cSDavid du Colombier vtMemFree(s);
5905e96a66cSDavid du Colombier continue;
5915e96a66cSDavid du Colombier }
5925e96a66cSDavid du Colombier if(!validUserName(f[1])){
5935e96a66cSDavid du Colombier fprint(2, "invalid uname '%s'\n", f[0]);
5945e96a66cSDavid du Colombier vtMemFree(s);
5955e96a66cSDavid du Colombier continue;
5965e96a66cSDavid du Colombier }
5975e96a66cSDavid du Colombier if(_userByUname(box, f[1]) != nil){
5985e96a66cSDavid du Colombier fprint(2, "duplicate uname '%s'\n", f[1]);
5995e96a66cSDavid du Colombier vtMemFree(s);
6005e96a66cSDavid du Colombier continue;
6015e96a66cSDavid du Colombier }
6025e96a66cSDavid du Colombier
6035e96a66cSDavid du Colombier u = userAlloc(f[0], f[1]);
6045e96a66cSDavid du Colombier uboxAddUser(box, u);
6053cb0b4acSDavid du Colombier line[nuser] = line[i];
6063cb0b4acSDavid du Colombier nuser++;
6075e96a66cSDavid du Colombier
6085e96a66cSDavid du Colombier vtMemFree(s);
6095e96a66cSDavid du Colombier }
6105e96a66cSDavid du Colombier assert(box->nuser == nuser);
6115e96a66cSDavid du Colombier
6125e96a66cSDavid du Colombier /*
6135e96a66cSDavid du Colombier * Second pass - fill in leader and group information.
6145e96a66cSDavid du Colombier */
6155e96a66cSDavid du Colombier for(i = 0; i < nuser; i++){
6165e96a66cSDavid du Colombier s = vtStrDup(line[i]);
6175e96a66cSDavid du Colombier getfields(s, f, nelem(f), 0, ":");
6185e96a66cSDavid du Colombier
6195e96a66cSDavid du Colombier assert(g = _userByUname(box, f[1]));
6205e96a66cSDavid du Colombier if(*f[2] != '\0'){
6215e96a66cSDavid du Colombier if((u = _userByUname(box, f[2])) == nil)
6225e96a66cSDavid du Colombier g->leader = vtStrDup(g->uname);
6235e96a66cSDavid du Colombier else
6245e96a66cSDavid du Colombier g->leader = vtStrDup(u->uname);
6255e96a66cSDavid du Colombier box->len += strlen(g->leader);
6265e96a66cSDavid du Colombier }
6275e96a66cSDavid du Colombier for(p = f[3]; p != nil; p = q){
6285e96a66cSDavid du Colombier if((q = utfrune(p, L',')) != nil)
6295e96a66cSDavid du Colombier *q++ = '\0';
6305e96a66cSDavid du Colombier if(!_groupAddMember(box, g, p)){
6315e96a66cSDavid du Colombier // print/log error here
6325e96a66cSDavid du Colombier }
6335e96a66cSDavid du Colombier }
6345e96a66cSDavid du Colombier
6355e96a66cSDavid du Colombier vtMemFree(s);
6365e96a66cSDavid du Colombier }
6375e96a66cSDavid du Colombier
6385e96a66cSDavid du Colombier vtMemFree(line);
6395e96a66cSDavid du Colombier vtMemFree(buf);
6405e96a66cSDavid du Colombier
6415e96a66cSDavid du Colombier for(i = 0; usersMandatory[i] != nil; i++){
6425e96a66cSDavid du Colombier if((u = _userByUid(box, usersMandatory[i])) == nil){
6435e96a66cSDavid du Colombier vtSetError("user '%s' is mandatory", usersMandatory[i]);
6445e96a66cSDavid du Colombier uboxFree(box);
6455e96a66cSDavid du Colombier return 0;
6465e96a66cSDavid du Colombier }
6475e96a66cSDavid du Colombier if(strcmp(u->uid, u->uname) != 0){
6485e96a66cSDavid du Colombier vtSetError("uid/uname for user '%s' must match",
6495e96a66cSDavid du Colombier usersMandatory[i]);
6505e96a66cSDavid du Colombier uboxFree(box);
6515e96a66cSDavid du Colombier return 0;
6525e96a66cSDavid du Colombier }
6535e96a66cSDavid du Colombier }
6545e96a66cSDavid du Colombier
6555e96a66cSDavid du Colombier vtLock(ubox.lock);
6565e96a66cSDavid du Colombier obox = ubox.box;
6575e96a66cSDavid du Colombier ubox.box = box;
6585e96a66cSDavid du Colombier vtUnlock(ubox.lock);
6595e96a66cSDavid du Colombier
6605e96a66cSDavid du Colombier if(obox != nil)
6615e96a66cSDavid du Colombier uboxFree(obox);
6625e96a66cSDavid du Colombier
6635e96a66cSDavid du Colombier return 1;
6645e96a66cSDavid du Colombier }
6655e96a66cSDavid du Colombier
66681cf8742SDavid du Colombier int
usersFileRead(char * path)6675e96a66cSDavid du Colombier usersFileRead(char* path)
6685e96a66cSDavid du Colombier {
6695e96a66cSDavid du Colombier char *p;
6705e96a66cSDavid du Colombier File *file;
6715e96a66cSDavid du Colombier Fsys *fsys;
6725e96a66cSDavid du Colombier int len, r;
6735e96a66cSDavid du Colombier uvlong size;
6745e96a66cSDavid du Colombier
6755e96a66cSDavid du Colombier if((fsys = fsysGet("main")) == nil)
6765e96a66cSDavid du Colombier return 0;
6775e96a66cSDavid du Colombier fsysFsRlock(fsys);
6785e96a66cSDavid du Colombier
67981cf8742SDavid du Colombier if(path == nil)
68081cf8742SDavid du Colombier path = "/active/adm/users";
68181cf8742SDavid du Colombier
6825e96a66cSDavid du Colombier r = 0;
6835e96a66cSDavid du Colombier if((file = fileOpen(fsysGetFs(fsys), path)) != nil){
6845e96a66cSDavid du Colombier if(fileGetSize(file, &size)){
6855e96a66cSDavid du Colombier len = size;
6865e96a66cSDavid du Colombier p = vtMemAlloc(size+1);
6875e96a66cSDavid du Colombier if(fileRead(file, p, len, 0) == len){
6885e96a66cSDavid du Colombier p[len] = '\0';
68981cf8742SDavid du Colombier r = uboxInit(p, len);
6905e96a66cSDavid du Colombier }
6915e96a66cSDavid du Colombier }
6925e96a66cSDavid du Colombier fileDecRef(file);
6935e96a66cSDavid du Colombier }
6945e96a66cSDavid du Colombier
6955e96a66cSDavid du Colombier fsysFsRUnlock(fsys);
6965e96a66cSDavid du Colombier fsysPut(fsys);
6975e96a66cSDavid du Colombier
6985e96a66cSDavid du Colombier return r;
6995e96a66cSDavid du Colombier }
7005e96a66cSDavid du Colombier
7015e96a66cSDavid du Colombier static int
cmdUname(int argc,char * argv[])7025e96a66cSDavid du Colombier cmdUname(int argc, char* argv[])
7035e96a66cSDavid du Colombier {
7045e96a66cSDavid du Colombier User *u, *up;
7055e96a66cSDavid du Colombier int d, dflag, i, r;
7065e96a66cSDavid du Colombier char *p, *uid, *uname;
70761201b97SDavid du Colombier char *createfmt = "fsys main create /active/usr/%s %s %s d775";
70834e04225SDavid du Colombier char *usage = "usage: uname [-d] uname [uid|:uid|%%newname|=leader|+member|-member]";
7095e96a66cSDavid du Colombier
7105e96a66cSDavid du Colombier dflag = 0;
7115e96a66cSDavid du Colombier
7125e96a66cSDavid du Colombier ARGBEGIN{
7135e96a66cSDavid du Colombier default:
7145e96a66cSDavid du Colombier return cliError(usage);
7155e96a66cSDavid du Colombier case 'd':
7165e96a66cSDavid du Colombier dflag = 1;
7175e96a66cSDavid du Colombier break;
7185e96a66cSDavid du Colombier }ARGEND
7195e96a66cSDavid du Colombier
7205e96a66cSDavid du Colombier if(argc < 1){
72134e04225SDavid du Colombier if(!dflag)
72234e04225SDavid du Colombier return cliError(usage);
7235e96a66cSDavid du Colombier vtRLock(ubox.lock);
7245e96a66cSDavid du Colombier uboxDump(ubox.box);
7255e96a66cSDavid du Colombier vtRUnlock(ubox.lock);
7265e96a66cSDavid du Colombier return 1;
7275e96a66cSDavid du Colombier }
7285e96a66cSDavid du Colombier
7295e96a66cSDavid du Colombier uname = argv[0];
7305e96a66cSDavid du Colombier argc--; argv++;
7315e96a66cSDavid du Colombier
7325e96a66cSDavid du Colombier if(argc == 0){
7335e96a66cSDavid du Colombier vtRLock(ubox.lock);
7345e96a66cSDavid du Colombier if((u = _userByUname(ubox.box, uname)) == nil){
7355e96a66cSDavid du Colombier vtRUnlock(ubox.lock);
7365e96a66cSDavid du Colombier return 0;
7375e96a66cSDavid du Colombier }
7385e96a66cSDavid du Colombier consPrint("\t%U\n", u);
7395e96a66cSDavid du Colombier vtRUnlock(ubox.lock);
7405e96a66cSDavid du Colombier return 1;
7415e96a66cSDavid du Colombier }
7425e96a66cSDavid du Colombier
7435e96a66cSDavid du Colombier vtLock(ubox.lock);
7445e96a66cSDavid du Colombier u = _userByUname(ubox.box, uname);
7455e96a66cSDavid du Colombier while(argc--){
7465e96a66cSDavid du Colombier if(argv[0][0] == '%'){
7475e96a66cSDavid du Colombier if(u == nil){
7485e96a66cSDavid du Colombier vtUnlock(ubox.lock);
7495e96a66cSDavid du Colombier return 0;
7505e96a66cSDavid du Colombier }
7515e96a66cSDavid du Colombier p = &argv[0][1];
7525e96a66cSDavid du Colombier if((up = _userByUname(ubox.box, p)) != nil){
7535e96a66cSDavid du Colombier vtSetError("uname: uname '%s' already exists",
7545e96a66cSDavid du Colombier up->uname);
7555e96a66cSDavid du Colombier vtUnlock(ubox.lock);
7565e96a66cSDavid du Colombier return 0;
7575e96a66cSDavid du Colombier }
7585e96a66cSDavid du Colombier for(i = 0; usersMandatory[i] != nil; i++){
7595e96a66cSDavid du Colombier if(strcmp(usersMandatory[i], uname) != 0)
7605e96a66cSDavid du Colombier continue;
7615e96a66cSDavid du Colombier vtSetError("uname: uname '%s' is mandatory",
7625e96a66cSDavid du Colombier uname);
7635e96a66cSDavid du Colombier vtUnlock(ubox.lock);
7645e96a66cSDavid du Colombier return 0;
7655e96a66cSDavid du Colombier }
7665e96a66cSDavid du Colombier
7675e96a66cSDavid du Colombier d = strlen(p) - strlen(u->uname);
7685e96a66cSDavid du Colombier for(up = ubox.box->head; up != nil; up = up->next){
7695e96a66cSDavid du Colombier if(up->leader != nil){
7705e96a66cSDavid du Colombier if(strcmp(up->leader, u->uname) == 0){
7715e96a66cSDavid du Colombier vtMemFree(up->leader);
7725e96a66cSDavid du Colombier up->leader = vtStrDup(p);
7735e96a66cSDavid du Colombier ubox.box->len += d;
7745e96a66cSDavid du Colombier }
7755e96a66cSDavid du Colombier }
7765e96a66cSDavid du Colombier for(i = 0; i < up->ngroup; i++){
7775e96a66cSDavid du Colombier if(strcmp(up->group[i], u->uname) != 0)
7785e96a66cSDavid du Colombier continue;
7795e96a66cSDavid du Colombier vtMemFree(up->group[i]);
7805e96a66cSDavid du Colombier up->group[i] = vtStrDup(p);
7815e96a66cSDavid du Colombier ubox.box->len += d;
7825e96a66cSDavid du Colombier break;
7835e96a66cSDavid du Colombier }
7845e96a66cSDavid du Colombier }
7855e96a66cSDavid du Colombier
7865e96a66cSDavid du Colombier uboxRemUser(ubox.box, u);
7875e96a66cSDavid du Colombier vtMemFree(u->uname);
7885e96a66cSDavid du Colombier u->uname = vtStrDup(p);
7895e96a66cSDavid du Colombier uboxAddUser(ubox.box, u);
7905e96a66cSDavid du Colombier }
7915e96a66cSDavid du Colombier else if(argv[0][0] == '='){
7925e96a66cSDavid du Colombier if(u == nil){
7935e96a66cSDavid du Colombier vtUnlock(ubox.lock);
7945e96a66cSDavid du Colombier return 0;
7955e96a66cSDavid du Colombier }
7965e96a66cSDavid du Colombier if((up = _userByUname(ubox.box, &argv[0][1])) == nil){
7975e96a66cSDavid du Colombier if(argv[0][1] != '\0'){
7985e96a66cSDavid du Colombier vtUnlock(ubox.lock);
7995e96a66cSDavid du Colombier return 0;
8005e96a66cSDavid du Colombier }
8015e96a66cSDavid du Colombier }
8025e96a66cSDavid du Colombier if(u->leader != nil){
8035e96a66cSDavid du Colombier ubox.box->len -= strlen(u->leader);
8045e96a66cSDavid du Colombier vtMemFree(u->leader);
8055e96a66cSDavid du Colombier u->leader = nil;
8065e96a66cSDavid du Colombier }
8075e96a66cSDavid du Colombier if(up != nil){
8085e96a66cSDavid du Colombier u->leader = vtStrDup(up->uname);
8095e96a66cSDavid du Colombier ubox.box->len += strlen(u->leader);
8105e96a66cSDavid du Colombier }
8115e96a66cSDavid du Colombier }
8125e96a66cSDavid du Colombier else if(argv[0][0] == '+'){
8135e96a66cSDavid du Colombier if(u == nil){
8145e96a66cSDavid du Colombier vtUnlock(ubox.lock);
8155e96a66cSDavid du Colombier return 0;
8165e96a66cSDavid du Colombier }
8175e96a66cSDavid du Colombier if((up = _userByUname(ubox.box, &argv[0][1])) == nil){
8185e96a66cSDavid du Colombier vtUnlock(ubox.lock);
8195e96a66cSDavid du Colombier return 0;
8205e96a66cSDavid du Colombier }
8215e96a66cSDavid du Colombier if(!_groupAddMember(ubox.box, u, up->uname)){
8225e96a66cSDavid du Colombier vtUnlock(ubox.lock);
8235e96a66cSDavid du Colombier return 0;
8245e96a66cSDavid du Colombier }
8255e96a66cSDavid du Colombier }
8265e96a66cSDavid du Colombier else if(argv[0][0] == '-'){
8275e96a66cSDavid du Colombier if(u == nil){
8285e96a66cSDavid du Colombier vtUnlock(ubox.lock);
8295e96a66cSDavid du Colombier return 0;
8305e96a66cSDavid du Colombier }
8315e96a66cSDavid du Colombier if((up = _userByUname(ubox.box, &argv[0][1])) == nil){
8325e96a66cSDavid du Colombier vtUnlock(ubox.lock);
8335e96a66cSDavid du Colombier return 0;
8345e96a66cSDavid du Colombier }
8355e96a66cSDavid du Colombier if(!_groupRemMember(ubox.box, u, up->uname)){
8365e96a66cSDavid du Colombier vtUnlock(ubox.lock);
8375e96a66cSDavid du Colombier return 0;
8385e96a66cSDavid du Colombier }
8395e96a66cSDavid du Colombier }
8405e96a66cSDavid du Colombier else{
8415e96a66cSDavid du Colombier if(u != nil){
8425e96a66cSDavid du Colombier vtSetError("uname: uname '%s' already exists",
8435e96a66cSDavid du Colombier u->uname);
8445e96a66cSDavid du Colombier vtUnlock(ubox.lock);
8455e96a66cSDavid du Colombier return 0;
8465e96a66cSDavid du Colombier }
8475e96a66cSDavid du Colombier
8485e96a66cSDavid du Colombier uid = argv[0];
8495e96a66cSDavid du Colombier if(*uid == ':')
8505e96a66cSDavid du Colombier uid++;
8515e96a66cSDavid du Colombier if((u = _userByUid(ubox.box, uid)) != nil){
8525e96a66cSDavid du Colombier vtSetError("uname: uid '%s' already exists",
8535e96a66cSDavid du Colombier u->uid);
8545e96a66cSDavid du Colombier vtUnlock(ubox.lock);
8555e96a66cSDavid du Colombier return 0;
8565e96a66cSDavid du Colombier }
8575e96a66cSDavid du Colombier
8585e96a66cSDavid du Colombier u = userAlloc(uid, uname);
8595e96a66cSDavid du Colombier uboxAddUser(ubox.box, u);
8605e96a66cSDavid du Colombier if(argv[0][0] != ':'){
8615e96a66cSDavid du Colombier // should have an option for the mode and gid
8625e96a66cSDavid du Colombier p = smprint(createfmt, uname, uname, uname);
8635e96a66cSDavid du Colombier r = cliExec(p);
8645e96a66cSDavid du Colombier vtMemFree(p);
865d58da526SDavid du Colombier if(r == 0){
8665e96a66cSDavid du Colombier vtUnlock(ubox.lock);
8675e96a66cSDavid du Colombier return 0;
8685e96a66cSDavid du Colombier }
8695e96a66cSDavid du Colombier }
8705e96a66cSDavid du Colombier }
8715e96a66cSDavid du Colombier argv++;
8725e96a66cSDavid du Colombier }
8735e96a66cSDavid du Colombier
8745e96a66cSDavid du Colombier if(usersFileWrite(ubox.box) == 0){
8755e96a66cSDavid du Colombier vtUnlock(ubox.lock);
8765e96a66cSDavid du Colombier return 0;
8775e96a66cSDavid du Colombier }
8785e96a66cSDavid du Colombier if(dflag)
8795e96a66cSDavid du Colombier uboxDump(ubox.box);
8805e96a66cSDavid du Colombier vtUnlock(ubox.lock);
8815e96a66cSDavid du Colombier
8825e96a66cSDavid du Colombier return 1;
8835e96a66cSDavid du Colombier }
8845e96a66cSDavid du Colombier
8855e96a66cSDavid du Colombier static int
cmdUsers(int argc,char * argv[])8865e96a66cSDavid du Colombier cmdUsers(int argc, char* argv[])
8875e96a66cSDavid du Colombier {
8885e96a66cSDavid du Colombier Ubox *box;
8895e96a66cSDavid du Colombier int dflag, r, wflag;
89081cf8742SDavid du Colombier char *file;
89181cf8742SDavid du Colombier char *usage = "usage: users [-d | -r file] [-w]";
8925e96a66cSDavid du Colombier
8935e96a66cSDavid du Colombier dflag = wflag = 0;
89481cf8742SDavid du Colombier file = nil;
8955e96a66cSDavid du Colombier
8965e96a66cSDavid du Colombier ARGBEGIN{
8975e96a66cSDavid du Colombier default:
8985e96a66cSDavid du Colombier return cliError(usage);
8995e96a66cSDavid du Colombier case 'd':
9005e96a66cSDavid du Colombier dflag = 1;
9015e96a66cSDavid du Colombier break;
90281cf8742SDavid du Colombier case 'r':
90381cf8742SDavid du Colombier file = ARGF();
90481cf8742SDavid du Colombier if(file == nil)
90581cf8742SDavid du Colombier return cliError(usage);
90681cf8742SDavid du Colombier break;
9075e96a66cSDavid du Colombier case 'w':
9085e96a66cSDavid du Colombier wflag = 1;
9095e96a66cSDavid du Colombier break;
9105e96a66cSDavid du Colombier }ARGEND
9115e96a66cSDavid du Colombier
91281cf8742SDavid du Colombier if(argc)
9135e96a66cSDavid du Colombier return cliError(usage);
91481cf8742SDavid du Colombier
91581cf8742SDavid du Colombier if(dflag && file)
91681cf8742SDavid du Colombier return cliError("cannot use -d and -r together");
91781cf8742SDavid du Colombier
9185e96a66cSDavid du Colombier if(dflag)
91981cf8742SDavid du Colombier uboxInit(usersDefault, sizeof(usersDefault));
92081cf8742SDavid du Colombier else if(file){
92181cf8742SDavid du Colombier if(usersFileRead(file) == 0)
92281cf8742SDavid du Colombier return 0;
92381cf8742SDavid du Colombier }
92481cf8742SDavid du Colombier
9255e96a66cSDavid du Colombier vtRLock(ubox.lock);
9265e96a66cSDavid du Colombier box = ubox.box;
9275e96a66cSDavid du Colombier consPrint("\tnuser %d len %d\n", box->nuser, box->len);
9285e96a66cSDavid du Colombier
92981cf8742SDavid du Colombier r = 1;
93081cf8742SDavid du Colombier if(wflag)
93181cf8742SDavid du Colombier r = usersFileWrite(box);
9325e96a66cSDavid du Colombier vtRUnlock(ubox.lock);
9335e96a66cSDavid du Colombier return r;
9345e96a66cSDavid du Colombier }
9355e96a66cSDavid du Colombier
9365e96a66cSDavid du Colombier int
usersInit(void)9375e96a66cSDavid du Colombier usersInit(void)
9385e96a66cSDavid du Colombier {
9395e96a66cSDavid du Colombier fmtinstall('U', userFmt);
9405e96a66cSDavid du Colombier
9415e96a66cSDavid du Colombier ubox.lock = vtLockAlloc();
94281cf8742SDavid du Colombier uboxInit(usersDefault, sizeof(usersDefault));
9435e96a66cSDavid du Colombier
9445e96a66cSDavid du Colombier cliAddCmd("users", cmdUsers);
9455e96a66cSDavid du Colombier cliAddCmd("uname", cmdUname);
9465e96a66cSDavid du Colombier
9475e96a66cSDavid du Colombier return 1;
9485e96a66cSDavid du Colombier }
949