Example #1
0
File: pdb.c Project: chutzimir/coda
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);
}
Example #2
0
File: pdb.c Project: chutzimir/coda
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);
}
Example #3
0
File: pdb.c Project: chutzimir/coda
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);
}
Example #4
0
File: pdb.c Project: chutzimir/coda
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);
}
Example #5
0
/* 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);
}
Example #6
0
/* 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);
	}
}
Example #7
0
File: pdb.c Project: chutzimir/coda
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);
}
Example #8
0
File: pdb.c Project: chutzimir/coda
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);
}
Example #9
0
File: pdb.c Project: chutzimir/coda
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);
}
Example #10
0
File: pdb.c Project: chutzimir/coda
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);
}
Example #11
0
/* 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);
}
Example #12
0
/* 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);
}
Example #13
0
/* 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;
}
Example #14
0
/* 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);
}
Example #15
0
File: pdb.c Project: chutzimir/coda
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);
}
Example #16
0
File: pdb.c Project: chutzimir/coda
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);
}
Example #17
0
/* 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);
}