void PDB_deleteUser(int32_t id) { PDB_HANDLE h; PDB_profile r,p; int32_t nextid; pdb_array_off off; h=PDB_db_open(O_RDWR); PDB_readProfile(h, id, &r); if(r.id == 0){ PDB_db_close(h); return; } PDB_deleteProfile(h, &r); /* Remove from groups */ nextid = pdb_array_head(&(r.member_of), &off); while(nextid != 0){ PDB_readProfile(h, nextid, &p); CODA_ASSERT(p.id != 0); pdb_array_del(&(p.groups_or_members), id); PDB_writeProfile(h, &p); PDB_freeProfile(&p); nextid = pdb_array_next(&(r.member_of), &off); } PDB_freeProfile(&r); PDB_db_close(h); }
void PDB_removeFromGroup(int32_t id, int32_t groupId) { PDB_HANDLE h; PDB_profile r; /* sanity check arguments (groupId must be < 0) */ CODA_ASSERT(PDB_ISGROUP(groupId) && (id != 0)); h = PDB_db_open(O_RDWR); /* remove id from the group's member list */ PDB_readProfile(h, groupId, &r); CODA_ASSERT(r.id != 0); pdb_array_del(&(r.groups_or_members), id); PDB_writeProfile(h, &r); PDB_freeProfile(&r); /* remove groupId from user's member_of list */ PDB_readProfile(h, id, &r); CODA_ASSERT(r.id != 0); pdb_array_del(&(r.member_of), groupId); PDB_updateCps(h, &r); PDB_freeProfile(&r); PDB_db_close(h); }
void PDB_deleteGroup(int32_t id) { PDB_HANDLE h; PDB_profile r,p; int32_t nextid; pdb_array_off off; h=PDB_db_open(O_RDWR); PDB_readProfile(h, id, &r); if(r.id == 0){ PDB_db_close(h); return; } PDB_deleteProfile(h, &r); /* remove from owner's list */ PDB_readProfile(h, r.owner_id, &p); CODA_ASSERT(p.id != 0); pdb_array_del(&(p.groups_or_members), id); PDB_writeProfile(h, &p); PDB_freeProfile(&p); /* remove from groups if memberof */ nextid = pdb_array_head(&(r.member_of), &off); while(nextid != 0){ PDB_readProfile(h, nextid, &p); CODA_ASSERT(p.id == 0); pdb_array_del(&(p.groups_or_members), id); PDB_writeProfile(h, &p); PDB_freeProfile(&p); nextid = pdb_array_next(&(r.member_of), &off); } /* remove from members */ nextid = pdb_array_head(&(r.groups_or_members), &off); while(nextid != 0){ PDB_readProfile(h, nextid, &p); CODA_ASSERT(p.id != 0); pdb_array_del(&(p.member_of), id); PDB_updateCps(h, &p); PDB_freeProfile(&p); nextid = pdb_array_next(&(r.groups_or_members), &off); } /* Now fix the owner's cps */ PDB_readProfile(h, r.owner_id, &p); CODA_ASSERT(p.id != 0); PDB_updateCps(h, &p); PDB_freeProfile(&p); PDB_freeProfile(&r); PDB_db_close(h); }
void PDB_cloneUser(char *name, int32_t cloneid, int32_t *newId) { PDB_HANDLE h; int32_t nextid, maxId, minGroupId; PDB_profile r, p; pdb_array_off off; /* sanity check arguments */ CODA_ASSERT(name && (name[0] != '\0') && newId && (cloneid != 0)); /* MAKE SURE NO USER WITH THAT NAME ALREADY EXISTS */ CODA_ASSERT(PDB_nameInUse(name) == 0); h=PDB_db_open(O_RDWR); /* Read the profile we are cloning */ PDB_readProfile(h, cloneid, &r); CODA_ASSERT(r.id != 0); /* add one to the highest user id -- that's our new user's id */ PDB_db_maxids(h, &maxId, &minGroupId); r.id = maxId + 1; PDB_db_update_maxids(h, r.id, minGroupId, PDB_MAXID_SET); /* CREATE A NEW USER WITH SPECIFIED NAME, ALL OTHER FIELDS EMPTY */ /* create the new user's profile */ free(r.name); r.name = strdup(name); /* MAKE THE NEW USER A MEMBER OF THE SAME GROUPS AS THE OLD USER */ nextid = pdb_array_head(&(r.member_of), &off); while(nextid != 0){ PDB_readProfile(h, nextid, &p); CODA_ASSERT(r.id != 0); pdb_array_add(&(p.groups_or_members), r.id); PDB_writeProfile(h, &p); PDB_freeProfile(&p); nextid = pdb_array_next(&(r.member_of), &off); } /* updateCps also writes the new user's information to the databases */ PDB_updateCps(h, &r); PDB_db_close(h); *newId = r.id; PDB_freeProfile(&r); }
void PDB_createGroup(char *name, int32_t owner, int32_t *newGroupId) { PDB_HANDLE h; int32_t maxId, minGroupId; PDB_profile r, p; /* sanity check arguments */ CODA_ASSERT(name && (name[0] != '\0') && newGroupId && PDB_ISUSER(owner)); /* MAKE SURE NO GROUP WITH THAT NAME ALREADY EXISTS */ CODA_ASSERT(PDB_nameInUse(name) == 0); h=PDB_db_open(O_RDWR); PDB_readProfile(h, owner, &p); CODA_ASSERT(p.id != 0); /* subtract one from the lowest group id -- that's new group's id */ PDB_db_maxids(h, &maxId, &minGroupId); r.id = minGroupId - 1; *newGroupId = r.id; PDB_db_update_maxids(h, maxId, r.id, PDB_MAXID_SET); /* CREATE A NEW GROUP WITH SPECIFIED NAME AND OWNER */ /* create the new group's profile */ r.name = strdup(name); r.owner_id = owner; r.owner_name = strdup(p.name); pdb_array_init(&(r.member_of)); pdb_array_init(&(r.cps)); pdb_array_add(&(r.cps),r.id); pdb_array_init(&(r.groups_or_members)); pdb_array_add(&(r.groups_or_members),owner); /* write the new group's information to the databases */ PDB_writeProfile(h, &r); /* add the new group's id to owner's groups_or_members list */ pdb_array_add(&(p.groups_or_members), r.id); pdb_array_add(&(p.member_of), r.id); pdb_array_add(&(p.cps), r.id); PDB_writeProfile(h, &p); PDB_freeProfile(&r); PDB_freeProfile(&p); PDB_db_close(h); }
/* UPDATE USER OR GROUP */ void tool_update(int argc, char *argv[]) { long arg1; PDB_HANDLE h; PDB_profile p; if (check_args_num(argc, 2)) { printf( "Usage: u id/name\n" "id/name\t\tid or name of user/group\n"); return; } h = PDB_db_open(O_RDWR); arg1 = get_id(argv[1]); if (arg1 == 0) { printf("%s not found.\n", argv[1]); return; } PDB_readProfile(h, arg1, &p); if (p.id != 0) { PDB_updateCps(h, &p); PDB_freeProfile(&p); } PDB_db_close(h); }
/* Updates the CPS entries of the given id and the CPS entries of its children*/ void PDB_updateCps(PDB_HANDLE h, PDB_profile *r) { PDB_profile p, c; int32_t nextid; pdb_array_off off; CODA_ASSERT(r != NULL); /* Update the CPS entry of the given id */ pdb_array_free(&(r->cps)); /* Add the CPS of parents into list */ nextid = pdb_array_head(&(r->member_of), &off); while(nextid != 0){ PDB_readProfile(h, nextid, &p); if(p.id != 0) { pdb_array_merge(&(r->cps), &(p.cps)); PDB_freeProfile(&p); } nextid = pdb_array_next(&(r->member_of), &off); } /* Add self to list */ pdb_array_add(&(r->cps), r->id); /* write the updated CPS */ PDB_writeProfile(h, r); /* Update the CPS entries of the given id's children's CPS entries */ if (!PDB_ISGROUP(r->id)) return; /* Add the CPS of parents into list */ nextid = pdb_array_head(&(r->groups_or_members), &off); while(nextid != 0){ PDB_readProfile(h, nextid, &c); if (c.id != 0) { /* Recurse through all children */ PDB_updateCps(h, &c); PDB_freeProfile(&c); } nextid = pdb_array_next(&(r->groups_or_members), &off); } }
void PDB_lookupByName(const char *name, int32_t *id) { PDB_HANDLE h; PDB_profile r; h = PDB_db_open(O_RDONLY); PDB_readProfile_byname(h, name, &r); *id = r.id; PDB_freeProfile(&r); PDB_db_close(h); }
void PDB_changeName(int32_t id, char *name) { PDB_HANDLE h; PDB_profile r,p; pdb_array_off off; int32_t nextid; /* sanity check arguments */ CODA_ASSERT(name); h = PDB_db_open(O_RDWR); /* add id to the group's member list */ PDB_readProfile(h, id, &r); CODA_ASSERT(r.id != 0); PDB_db_delete_xfer(h, r.name); free(r.name); r.name = strdup(name); PDB_writeProfile(h, &r); /* Update everything is an owner of */ if(PDB_ISUSER(id)){ nextid = pdb_array_head(&(r.groups_or_members), &off); while(nextid != 0){ PDB_readProfile(h, nextid, &p); CODA_ASSERT(r.id != 0); if(PDB_ISGROUP(p.id)){ free(p.owner_name); p.owner_name = strdup(name); PDB_writeProfile(h, &p); } PDB_freeProfile(&p); nextid = pdb_array_next(&(r.groups_or_members), &off); } } PDB_freeProfile(&r); PDB_db_close(h); }
void PDB_addToGroup(int32_t id, int32_t groupId) { PDB_HANDLE h; PDB_profile r; int n; /* sanity check arguments */ CODA_ASSERT(PDB_ISGROUP(groupId) && (id != 0)); h = PDB_db_open(O_RDWR); /* add id to the group's member list */ PDB_readProfile(h, groupId, &r); CODA_ASSERT(r.id != 0); /* make sure we don't introduce an infinite loop */ n = pdb_array_search(&(r.cps), id); if (n != -1) { fprintf(stderr, "Cannot add %d, it is already a parent of %d\n", id, groupId); PDB_freeProfile(&r); return; } pdb_array_add(&(r.groups_or_members), id); PDB_writeProfile(h, &r); PDB_freeProfile(&r); /* add groupId to user's member_of list */ PDB_readProfile(h, id, &r); CODA_ASSERT(r.id != 0); pdb_array_add(&(r.member_of), groupId); PDB_updateCps(h, &r); PDB_freeProfile(&r); PDB_db_close(h); }
/* On successful return, ICPS defines a newly-created data structure, corresponding to the internal CPS of Id. Return 0 on success; -1 if Id is not a valid user or group. -2 otherwise */ int AL_GetInternalCPS(IN int Id, OUT PRS_InternalCPS **ICPS){ PDB_HANDLE h; PDB_profile profile; LogMsg(1,AL_DebugLevel,stdout,"in AL_GetInternalCPS(%d, 0x%x)", Id, ICPS); if(Id == 0) { *ICPS = NULL; return -1; } h = PDB_db_open(O_RDONLY); PDB_readProfile(h, Id, &profile); PDB_db_close(h); if(profile.id == 0){ PDB_freeProfile(&profile); *ICPS = NULL; return -1; } if(AL_NewCPS(pdb_array_size(&(profile.cps)),ICPS) != 0){ PDB_freeProfile(&profile); return -2; } if(((*ICPS)->InclEntries=pdb_array_to_array((*ICPS)->IdList, &(profile.cps))) < 0){ AL_FreeCPS(ICPS); PDB_freeProfile(&profile); return -2; } (*ICPS)->ExclEntries=0; PDB_freeProfile(&profile); return 0; }
void PDB_lookupById(int32_t id, char **name) { PDB_HANDLE h; PDB_profile r; h = PDB_db_open(O_RDONLY); PDB_readProfile(h, id, &r); if(r.id != 0) *name = strdup(r.name); else *name = NULL; PDB_freeProfile(&r); PDB_db_close(h); }
/* LOOKUP BY ID */ void tool_byNameOrId(int argc, char *argv[]) { PDB_profile sample; PDB_HANDLE h; int32_t arg1; if (check_args_num(argc, 2)) { printf("Usage: i idnum\nidnum\t\tnumber of user/group\n"); return; } arg1 = get_id(argv[1]); if (arg1 == 0) { printf("'%s' not found.\n", argv[1]); return; } h = PDB_db_open(O_RDONLY); PDB_readProfile(h, arg1, &sample); PDB_printProfile(stdout, &sample); PDB_freeProfile(&sample); PDB_db_close(h); }
/* LIST EVERTHING */ void tool_list(int argc, char *argv[]) { int32_t id; PDB_profile sample; PDB_HANDLE h; int rc; if (check_args_num(argc, 1)) { printf("Usage: list\n"); return; } h = PDB_db_open(O_RDONLY); while ((rc = PDB_db_nextkey(h, &id))) { if (rc == -1) continue; PDB_readProfile(h, id, &sample); PDB_printProfile(stdout, &sample); PDB_freeProfile(&sample); } PDB_db_close(h); }
void PDB_createUser(char *name, int32_t *newId) { PDB_HANDLE h; int32_t maxId, minGroupId; PDB_profile r; /* sanity check arguments */ CODA_ASSERT(name && (name[0] != '\0') && newId); /* MAKE SURE NO USER WITH THAT NAME ALREADY EXISTS */ CODA_ASSERT(PDB_nameInUse(name) == 0); h=PDB_db_open(O_RDWR); /* add one to the highest user id -- that's our new user's id */ PDB_db_maxids(h, &maxId, &minGroupId); r.id = maxId + 1; PDB_db_update_maxids(h, r.id, minGroupId, PDB_MAXID_SET); /* CREATE A NEW USER WITH SPECIFIED NAME, ALL OTHER FIELDS EMPTY */ /* create the new user's profile */ r.name = strdup(name); r.owner_id = 0; r.owner_name = NULL; pdb_array_init(&(r.member_of)); pdb_array_init(&(r.cps)); pdb_array_add(&(r.cps),r.id); pdb_array_init(&(r.groups_or_members)); /* write the new user's information to the databases */ PDB_writeProfile(h, &r); PDB_db_close(h); *newId = r.id; PDB_freeProfile(&r); }
/* dump/restore database contents */ void tool_export(int argc, char *argv[]) { int32_t id, i; PDB_profile rec; PDB_HANDLE h; FILE *userfile, *groupfile; char *s; int rc; if (check_args_num(argc, 3)) { printf("Usage: export <userfile> <groupfile>\n"); return; } userfile = fopen(argv[1], "w"); groupfile = fopen(argv[2], "w"); h = PDB_db_open(O_RDONLY); while ((rc = PDB_db_nextkey(h, &id))) { if (rc == -1) continue; PDB_readProfile(h, id, &rec); { if (rec.id == 0) continue; if (PDB_ISUSER(rec.id)) { /* users are dumped in an /etc/passwd like format * "<username>:x:<userid>:500::/:" */ fprintf(userfile, "%s:*:%d:500::/:\n", rec.name, rec.id); } else { /* groups and group members are dumped in an /etc/group like * format "<groupname>:x:<groupid>:<owner>[,<members>]*" */ /* escape the :'s in the group names */ s = rec.name; while ((s = strchr(s, ':')) != NULL) *s = '%'; PDB_lookupById(rec.owner_id, &s); fprintf(groupfile, "%s:*:%d:%s", rec.name, rec.id, s); free(s); for (i = 0; i < rec.groups_or_members.size; i++) { if (rec.groups_or_members.data[i] == rec.owner_id) continue; PDB_lookupById(rec.groups_or_members.data[i], &s); if (s == NULL) continue; fprintf(groupfile, ",%s", s); free(s); } fprintf(groupfile, "\n"); } } PDB_freeProfile(&rec); } PDB_db_close(h); fclose(userfile); fclose(groupfile); }
void PDB_changeId(int32_t oldId, int32_t newId) { PDB_HANDLE h; PDB_profile r,p; void *tmp; size_t size; int32_t nextid; pdb_array_off off; if (oldId == newId) return; h = PDB_db_open(O_RDWR); PDB_db_read(h, newId, NULL, &tmp, &size); pdb_unpack(&r, tmp, size); CODA_ASSERT(r.id == 0); PDB_readProfile(h, oldId, &r); CODA_ASSERT(r.id != 0); /* Delete the old id */ PDB_deleteProfile(h, &r); /* Change the id */ r.id = newId; PDB_updateCps(h, &r); if(PDB_ISGROUP(oldId)){ /* Need to change owner info */ PDB_readProfile(h, r.owner_id, &p); CODA_ASSERT(p.id != 0); pdb_array_del(&(p.groups_or_members), oldId); pdb_array_add(&(p.groups_or_members), newId); PDB_writeProfile(h, &p); PDB_db_update_maxids(h, 0, newId, PDB_MAXID_SET); PDB_freeProfile(&p); } else PDB_db_update_maxids(h, newId, 0, PDB_MAXID_SET); /* update groups we are a member of */ nextid = pdb_array_head(&(r.member_of), &off); while(nextid != 0){ PDB_readProfile(h, nextid, &p); CODA_ASSERT(p.id != 0); pdb_array_del(&(p.groups_or_members), oldId); pdb_array_add(&(p.groups_or_members), newId); /* Don't need CPS updates */ PDB_writeProfile(h, &p); PDB_freeProfile(&p); nextid = pdb_array_next(&(r.member_of), &off); } /* update members or ownership */ nextid = pdb_array_head(&(r.groups_or_members), &off); while(nextid != 0) { PDB_readProfile(h, nextid, &p); CODA_ASSERT(p.id != 0); if (PDB_ISGROUP(oldId)) { pdb_array_del(&(p.member_of), oldId); pdb_array_add(&(p.member_of), newId); } else { if (PDB_ISGROUP(p.id)) { if(p.owner_id == oldId) p.owner_id = newId; } } PDB_updateCps(h, &p); PDB_freeProfile(&p); nextid = pdb_array_next(&(r.groups_or_members), &off); } PDB_db_close(h); PDB_freeProfile(&r); }
void PDB_bugfixes(void) { PDB_HANDLE h; /* fixups for old bugs */ int32_t id; pdb_array_off off; int rc, n; PDB_profile p, r; h = PDB_db_open(O_RDWR); while ( (rc = PDB_db_nextkey(h, &id)) ) { if ( rc == -1 ) continue; PDB_readProfile(h, id, &p); CODA_ASSERT(p.id != 0); if (PDB_ISGROUP(p.id)) { /* BUG: forgot to update owner_id when changing a user's uid */ PDB_lookupByName(p.owner_name, &id); if (p.owner_id != id) { fprintf(stderr, "Group %d owner name %s didn't match owner id %d, FIXED\n", p.id, p.owner_name, p.owner_id); p.owner_id = id; PDB_writeProfile(h, &p); } /* BUG: we added userid's to a group's member_of list */ again: id = pdb_array_head(&p.member_of, &off); while(id != 0) { if (PDB_ISUSER(id)) { pdb_array_del(&p.member_of, id); PDB_updateCps(h, &p); fprintf(stderr, "Group %d was listed as a member of userid %d, FIXED\n", p.id, id); goto again; } id = pdb_array_next(&p.member_of, &off); } /* BUG: we forgot to change userid's in a group's groups_or_members * list (fix part 1, removes non-existing or non-member * userids) */ again2: id = pdb_array_head(&p.groups_or_members, &off); while(id != 0) { if (PDB_ISUSER(id)) { PDB_readProfile(h, id, &r); CODA_ASSERT(r.id != 0); n = pdb_array_search(&r.member_of, p.id); if (n == -1) { pdb_array_del(&p.groups_or_members, id); PDB_updateCps(h, &p); PDB_freeProfile(&r); fprintf(stderr, "Group %d had nonexisting member %d, FIXED\n", p.id, id); goto again2; } PDB_freeProfile(&r); } id = pdb_array_next(&p.groups_or_members, &off); } } else /* PDB_ISUSER(p.id) */ { /* BUG: we forgot to change userid's in a group's groups_or_members * list (fix part 2, adds missing members to groups)*/ id = pdb_array_head(&p.member_of, &off); while (id != 0) { if (PDB_ISGROUP(id)) { PDB_readProfile(h, id, &r); CODA_ASSERT(r.id != 0); n = pdb_array_search(&r.groups_or_members, p.id); if (n == -1) { pdb_array_add(&r.groups_or_members, p.id); PDB_updateCps(h, &r); fprintf(stderr, "Group %d was missing member %d, FIXED\n", id, p.id); } PDB_freeProfile(&r); } id = pdb_array_next(&p.member_of, &off); } } PDB_freeProfile(&p); } PDB_db_close(h); /* iterate through the whole database again and this time make sure that * all the CPS arrays are consistent. */ h = PDB_db_open(O_RDWR); while ( (rc = PDB_db_nextkey(h, &id)) ) { if ( rc == -1 ) continue; PDB_readProfile(h, id, &p); if (p.id == 0) continue; PDB_updateCps(h, &p); PDB_freeProfile(&p); } PDB_db_close(h); }
/* dump/restore database contents */ void tool_ldif_export(int argc, char *argv[]) { int32_t id, i; PDB_profile rec; PDB_HANDLE h; FILE *ldiffile; char *s, *basedn; int rc, pass = 0; if (check_args_num(argc, 3)) { printf("Usage: ldif_export <ldif-file> <basedn>\n"); return; } ldiffile = fopen(argv[1], "w"); basedn = argv[2]; again: h = PDB_db_open(O_RDONLY); while ((rc = PDB_db_nextkey(h, &id))) { if (rc == -1) continue; PDB_readProfile(h, id, &rec); { if (rec.id == 0) continue; if (PDB_ISUSER(rec.id)) { /* skip users during the second pass */ if (pass == 1) continue; /* users are dumped as: * * dn: cn=<name>,$basedn * objectClass: top * objectClass: person * objectClass: organizationalPerson * objectClass: inetOrgPerson * objectClass: codaAccount * cn: <name> * uid: <username> * uidNumber: <userid> * * And we 'invent' 2 fields that are required by posixAccount, * gidNumber: 65535 * homeDirectory: /coda/<realm>/usr/<username> */ fprintf(ldiffile, "dn: cn=%s,%s\n" "objectClass: top\n" "objectClass: person\n" "objectClass: organizationalPerson\n" "objectClass: inetOrgPerson\n" "objectClass: posixAccount\n" "cn: %s\nuid: %s\nuidNumber: %d\n" "gidNumber: 65535\n" "homeDirectory: /coda/myrealm/usr/%s\n" "#mail: %s@mydomain\n\n", rec.name, basedn, rec.name, rec.name, rec.id, rec.name, rec.name); } else { /* skip groups during the first pass */ if (pass == 0) continue; /* groups and group members are dumped as follows: * * dn: cn=<groupname>,$basedn * objectClass: top * objectClass: groupOfNames * objectClass: posixGroup * cn: <groupname> * gidNumber: -<groupid> * owner: <ownerdn> * member: <member1dn> * member: <member2dn> * ... */ PDB_lookupById(rec.owner_id, &s); CODA_ASSERT(s != NULL); fprintf(ldiffile, "dn: cn=%s,%s\n" "objectClass: top\n" "objectClass: groupOfNames\n" "objectClass: posixGroup\n" "#description:\n" "cn: %s\ngidNumber: %d\nowner: %s,%s\n", rec.name, basedn, rec.name, -rec.id, s, basedn); free(s); for (i = 0; i < rec.groups_or_members.size; i++) { PDB_lookupById(rec.groups_or_members.data[i], &s); if (s == NULL) continue; fprintf(ldiffile, "member: cn=%s,%s\n", s, basedn); free(s); } fprintf(ldiffile, "\n"); } } PDB_freeProfile(&rec); } PDB_db_close(h); /* we make second pass to dump the groups after the users */ if (pass == 0) { pass = 1; goto again; } fclose(ldiffile); }