Cleanup gr_add() so it does not leak mem

This is part of ongoing work on sbin/pw

M    libutil.h
M    gr_util.c

Approved by:	theraven
This commit is contained in:
Diane Bruce 2013-03-07 19:00:00 +00:00
parent 34d3281c57
commit 86e2f99d40
2 changed files with 86 additions and 53 deletions

@ -49,6 +49,8 @@ static char group_dir[PATH_MAX];
static char group_file[PATH_MAX]; static char group_file[PATH_MAX];
static char tempname[PATH_MAX]; static char tempname[PATH_MAX];
static int initialized; static int initialized;
static size_t grmemlen(const struct group *, const char *, int *);
static struct group *grcopy(const struct group *gr, struct group *newgr, const char *, int ndx);
/* /*
* Initialize statics * Initialize statics
@ -428,91 +430,122 @@ gr_make(const struct group *gr)
*/ */
struct group * struct group *
gr_dup(const struct group *gr) gr_dup(const struct group *gr)
{
return (gr_add(gr, NULL));
}
/*
* Add a new member name to a struct group.
*/
struct group *
gr_add(const struct group *gr, const char *newmember)
{ {
struct group *newgr; struct group *newgr;
char *dst;
size_t len; size_t len;
int ndx;
int num_mem; int num_mem;
/* Calculate size of the group. */ num_mem = 0;
len = sizeof(*newgr); len = grmemlen(gr, newmember, &num_mem);
if (gr->gr_name != NULL)
len += strlen(gr->gr_name) + 1;
if (gr->gr_passwd != NULL)
len += strlen(gr->gr_passwd) + 1;
if (gr->gr_mem != NULL) {
for (num_mem = 0; gr->gr_mem[num_mem] != NULL; num_mem++)
len += strlen(gr->gr_mem[num_mem]) + 1;
len += (num_mem + 1) * sizeof(*gr->gr_mem);
} else
num_mem = -1;
/* Create new group and copy old group into it. */ /* Create new group and copy old group into it. */
if ((newgr = malloc(len)) == NULL) if ((newgr = malloc(len)) == NULL)
return (NULL); return (NULL);
/* point new gr_mem to end of struct + 1 */ return (grcopy(gr, newgr, newmember, num_mem));
if (gr->gr_mem != NULL) }
/* It is safer to walk the pointers given at gr_mem since there is no
* guarantee the gr_mem + strings are continguous in the given struct group
* but compact the new group into the following form.
*
* The new struct is laid out like this in memory. The example given is
* for a group with two members only.
*
* {
* (char *name)
* (char *passwd)
* (int gid)
* (gr_mem * newgrp + sizeof(struct group) + sizeof(**)) points to gr_mem area
* gr_mem area
* (member1 *)
* (member2 *)
* (NULL)
* (name string)
* (passwd string)
* (member1 string)
* (member2 string)
* }
*/
/*
* Copy the guts of a group plus given name to a preallocated group struct
*/
static struct group *
grcopy(const struct group *gr, struct group *newgr, const char *name, int ndx)
{
char *dst;
int i;
if (name != NULL)
ndx++;
/* point new gr_mem to end of struct + 1 if there are names */
if (ndx != 0)
newgr->gr_mem = (char **)(newgr + 1); newgr->gr_mem = (char **)(newgr + 1);
else else
newgr->gr_mem = NULL; newgr->gr_mem = NULL;
/* point dst after the end of all the gr_mem pointers in newgr */ /* point dst after the end of all the gr_mem pointers in newgr */
dst = (char *)&newgr->gr_mem[num_mem + 1]; dst = (char *)&newgr->gr_mem[ndx + 1];
if (gr->gr_name != NULL) { if (gr->gr_name != NULL) {
newgr->gr_name = dst; newgr->gr_name = dst;
dst = stpcpy(dst, gr->gr_name) + 1; dst = stpcpy(dst, gr->gr_name) + 1;
} else { } else
newgr->gr_name = NULL; newgr->gr_name = NULL;
}
if (gr->gr_passwd != NULL) { if (gr->gr_passwd != NULL) {
newgr->gr_passwd = dst; newgr->gr_passwd = dst;
dst = stpcpy(dst, gr->gr_passwd) + 1; dst = stpcpy(dst, gr->gr_passwd) + 1;
} else { } else
newgr->gr_passwd = NULL; newgr->gr_passwd = NULL;
}
newgr->gr_gid = gr->gr_gid; newgr->gr_gid = gr->gr_gid;
if (gr->gr_mem != NULL) { if (ndx != 0) {
for (ndx = 0; ndx < num_mem; ndx++) { for (i = 0; gr->gr_mem[i] != NULL; i++) {
newgr->gr_mem[ndx] = dst; newgr->gr_mem[i] = dst;
dst = stpcpy(dst, gr->gr_mem[ndx]) + 1; dst = stpcpy(dst, gr->gr_mem[i]) + 1;
} }
newgr->gr_mem[ndx] = NULL; if (name != NULL) {
newgr->gr_mem[i++] = dst;
dst = stpcpy(dst, name) + 1;
}
newgr->gr_mem[i] = NULL;
} }
return (newgr); return (newgr);
} }
/* /*
* Add a new member name to a struct group. * Calculate length of a struct group + given name
*/ */
struct group * static size_t
gr_add(struct group *gr, char *newmember) grmemlen(const struct group *gr, const char *name, int *num_mem)
{ {
size_t mlen; size_t len;
int num_mem=0; int i;
char **members;
struct group *newgr;
if (newmember == NULL)
return(gr_dup(gr));
if (gr == NULL)
return (0);
/* Calculate size of the group. */
len = sizeof(*gr);
if (gr->gr_name != NULL)
len += strlen(gr->gr_name) + 1;
if (gr->gr_passwd != NULL)
len += strlen(gr->gr_passwd) + 1;
if (gr->gr_mem != NULL) { if (gr->gr_mem != NULL) {
for (num_mem = 0; gr->gr_mem[num_mem] != NULL; num_mem++) { for (len = i = 0; gr->gr_mem[i] != NULL; i++) {
if (strcmp(gr->gr_mem[num_mem], newmember) == 0) { len += strlen(gr->gr_mem[i]) + 1;
errno = EEXIST; len += sizeof(*gr->gr_mem);
return (NULL);
}
} }
*num_mem = i;
} }
/* Allocate enough for current pointers + 1 more and NULL marker */ if (name != NULL) {
mlen = (num_mem + 2) * sizeof(*gr->gr_mem); len += strlen(name) + 1;
if ((members = malloc(mlen)) == NULL) if (gr->gr_mem == NULL)
return (NULL); len += sizeof(*gr->gr_mem);
memcpy(members, gr->gr_mem, num_mem * sizeof(*gr->gr_mem)); }
members[num_mem++] = newmember; return(len);
members[num_mem] = NULL;
gr->gr_mem = members;
newgr = gr_dup(gr);
free(members);
return (newgr);
} }
/* /*

@ -167,7 +167,7 @@ int gr_copy(int __ffd, int _tfd, const struct group *_gr,
struct group * struct group *
gr_dup(const struct group *_gr); gr_dup(const struct group *_gr);
struct group * struct group *
gr_add(struct group *_gr, char *_newmember); gr_add(const struct group *_gr, const char *_newmember);
int gr_equal(const struct group *_gr1, const struct group *_gr2); int gr_equal(const struct group *_gr1, const struct group *_gr2);
void gr_fini(void); void gr_fini(void);
int gr_init(const char *_dir, const char *_master); int gr_init(const char *_dir, const char *_master);