Skip to content

Commit

Permalink
Resolve TODO: Return uname and gname overrides
Browse files Browse the repository at this point in the history
Simplify introducing a struct cpio_owner

Co-authored-by: Martin Matuska <[email protected]>
  • Loading branch information
AreaZR and mmatuska committed May 10, 2024
1 parent d517c67 commit 7078929
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 65 deletions.
51 changes: 36 additions & 15 deletions cpio/cmdline.c
Original file line number Diff line number Diff line change
Expand Up @@ -308,17 +308,22 @@ cpio_getopt(struct cpio *cpio)
* Returns NULL if no error, otherwise returns error string for display.
*
*/
const char *
owner_parse(const char *spec, int *uid, int *gid)
int
owner_parse(const char *spec, struct cpio_owner *owner, const char **errmsg)
{
static char errbuff[128];
const char *u, *ue, *g;

*uid = -1;
*gid = -1;
owner->uid = -1;
owner->gid = -1;

owner->uname = NULL;
owner->gname = NULL;

if (spec[0] == '\0')
return ("Invalid empty user/group spec");
if (spec[0] == '\0') {
*errmsg = "Invalid empty user/group spec";
return (-1);
}

/*
* Split spec into [user][:.][group]
Expand Down Expand Up @@ -347,23 +352,29 @@ owner_parse(const char *spec, int *uid, int *gid)

user = (char *)malloc(ue - u + 1);
if (user == NULL)
return ("Couldn't allocate memory");
goto alloc_error;
memcpy(user, u, ue - u);
user[ue - u] = '\0';
if ((pwent = getpwnam(user)) != NULL) {
*uid = pwent->pw_uid;
owner->uid = pwent->pw_uid;
owner->uname = strdup(pwent->pw_name);
if (owner->uname == NULL) {
free(user);
goto alloc_error;
}
if (*ue != '\0')
*gid = pwent->pw_gid;
owner->gid = pwent->pw_gid;
} else {
char *end;
errno = 0;
*uid = (int)strtoul(user, &end, 10);
owner->uid = (int)strtoul(user, &end, 10);
if (errno || *end != '\0') {
snprintf(errbuff, sizeof(errbuff),
"Couldn't lookup user ``%s''", user);
errbuff[sizeof(errbuff) - 1] = '\0';
free(user);
return (errbuff);
*errmsg = errbuff;
return (-1);
}
}
free(user);
Expand All @@ -372,18 +383,28 @@ owner_parse(const char *spec, int *uid, int *gid)
if (*g != '\0') {
struct group *grp;
if ((grp = getgrnam(g)) != NULL) {
*gid = grp->gr_gid;
owner->gid = grp->gr_gid;
owner->gname = strdup(grp->gr_name);
if (owner->gname == NULL) {
free(owner->uname);
owner->uname = NULL;
goto alloc_error;
}
} else {
char *end;
errno = 0;
*gid = (int)strtoul(g, &end, 10);
owner->gid = (int)strtoul(g, &end, 10);
if (errno || *end != '\0') {
snprintf(errbuff, sizeof(errbuff),
"Couldn't lookup group ``%s''", g);
errbuff[sizeof(errbuff) - 1] = '\0';
return (errbuff);
*errmsg = errbuff;
return (-1);
}
}
}
return (NULL);
return (0);
alloc_error:
*errmsg = "Couldn't allocate memory";
return (-1);
}
46 changes: 28 additions & 18 deletions cpio/cpio.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,16 +132,17 @@ main(int argc, char *argv[])
static char buff[16384];
struct cpio _cpio; /* Allocated on stack. */
struct cpio *cpio;
struct cpio_owner owner;
const char *errmsg;
char *tptr;
int uid, gid;
int opt, t;

cpio = &_cpio;
memset(cpio, 0, sizeof(*cpio));
cpio->buff = buff;
cpio->buff_size = sizeof(buff);


#if defined(HAVE_SIGACTION) && defined(SIGPIPE)
{ /* Ignore SIGPIPE signals. */
struct sigaction sa;
Expand All @@ -161,7 +162,9 @@ main(int argc, char *argv[])
#endif

cpio->uid_override = -1;
cpio->uname_override = NULL;
cpio->gid_override = -1;
cpio->gname_override = NULL;
cpio->argv = argv;
cpio->argc = argc;
cpio->mode = '\0';
Expand Down Expand Up @@ -320,21 +323,21 @@ main(int argc, char *argv[])
cpio->quiet = 1;
break;
case 'R': /* GNU cpio, also --owner */
/* TODO: owner_parse should return uname/gname
* also; use that to set [ug]name_override. */
errmsg = owner_parse(cpio->argument, &uid, &gid);
if (errmsg) {
errmsg = NULL;
if (owner_parse(cpio->argument, &owner, &errmsg) != 0) {
if (!errmsg)
errmsg = "Error parsing owner";
lafe_warnc(-1, "%s", errmsg);
usage();
}
if (uid != -1) {
cpio->uid_override = uid;
cpio->uname_override = NULL;
}
if (gid != -1) {
cpio->gid_override = gid;
cpio->gname_override = NULL;
}
if (owner.uid != -1)
cpio->uid_override = owner.uid;
if (owner.uname != NULL)
cpio->uname_override = owner.uname;
if (owner.gid != -1)
cpio->gid_override = owner.gid;
if (owner.gname != NULL)
cpio->gname_override = owner.gname;
break;
case 'r': /* POSIX 1997 */
cpio->option_rename = 1;
Expand Down Expand Up @@ -439,11 +442,14 @@ main(int argc, char *argv[])
}

archive_match_free(cpio->matching);
free_cache(cpio->gname_cache);
free_cache(cpio->uname_cache);
free(cpio->uname_override);
free_cache(cpio->gname_cache);
free(cpio->gname_override);
archive_read_close(cpio->archive_read_disk);
archive_read_free(cpio->archive_read_disk);
free(cpio->destdir);

passphrase_free(cpio->ppbuff);
return (cpio->return_value);
}
Expand Down Expand Up @@ -728,14 +734,14 @@ file_to_archive(struct cpio *cpio, const char *srcpath)
return (r);
}

if (cpio->uid_override >= 0) {
if (cpio->uid_override >= 0)
archive_entry_set_uid(entry, cpio->uid_override);
if (cpio->gname_override != NULL)
archive_entry_set_uname(entry, cpio->uname_override);
}
if (cpio->gid_override >= 0) {
if (cpio->gid_override >= 0)
archive_entry_set_gid(entry, cpio->gid_override);
if (cpio->gname_override != NULL)
archive_entry_set_gname(entry, cpio->gname_override);
}

/*
* Generate a destination path for this entry.
Expand Down Expand Up @@ -1015,8 +1021,12 @@ mode_in(struct cpio *cpio)
fprintf(stderr, ".");
if (cpio->uid_override >= 0)
archive_entry_set_uid(entry, cpio->uid_override);
if (cpio->uname_override != NULL)
archive_entry_set_uname(entry, cpio->uname_override);
if (cpio->gid_override >= 0)
archive_entry_set_gid(entry, cpio->gid_override);
if (cpio->gname_override != NULL)
archive_entry_set_gname(entry, cpio->gname_override);
r = archive_write_header(ext, entry);
if (r != ARCHIVE_OK) {
fprintf(stderr, "%s: %s\n",
Expand Down
8 changes: 7 additions & 1 deletion cpio/cpio.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,14 @@ struct cpio {
char *ppbuff;
};

const char *owner_parse(const char *, int *, int *);
struct cpio_owner {
int uid;
int gid;
char *uname;
char *gname;
};

int owner_parse(const char *, struct cpio_owner *, const char **);

/* Fake short equivalents for long options that otherwise lack them. */
enum {
Expand Down
90 changes: 59 additions & 31 deletions cpio/test/test_owner_parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,66 +55,94 @@ int_in_list(int i, const int *l, size_t n)
failure("%d", i);
return (0);
}

static void
free_cpio_owner(struct cpio_owner *owner) {
owner->uid = -1;
owner->gid = -1;
free(owner->uname);
free(owner->gname);
}
#endif

DEFINE_TEST(test_owner_parse)
{
#if !defined(ROOT)
skipping("No uid/gid configuration for this OS");
#else
int uid, gid;
struct cpio_owner owner;
const char *errstr;

assert(NULL == owner_parse(ROOT, &uid, &gid));
assert(int_in_list(uid, root_uids,
assert(0 == owner_parse(ROOT, &owner, &errstr));
assert(int_in_list(owner.uid, root_uids,
sizeof(root_uids)/sizeof(root_uids[0])));
assertEqualInt(-1, gid);

assertEqualInt(-1, owner.gid);
free_cpio_owner(&owner);

assert(NULL == owner_parse(ROOT ":", &uid, &gid));
assert(int_in_list(uid, root_uids,
assert(0 == owner_parse(ROOT ":", &owner, &errstr));
assert(int_in_list(owner.uid, root_uids,
sizeof(root_uids)/sizeof(root_uids[0])));
assert(int_in_list(gid, root_gids,
assert(int_in_list(owner.gid, root_gids,
sizeof(root_gids)/sizeof(root_gids[0])));
free_cpio_owner(&owner);

assert(NULL == owner_parse(ROOT ".", &uid, &gid));
assert(int_in_list(uid, root_uids,
assert(0 == owner_parse(ROOT ".", &owner, &errstr));
assert(int_in_list(owner.uid, root_uids,
sizeof(root_uids)/sizeof(root_uids[0])));
assert(int_in_list(gid, root_gids,
assert(int_in_list(owner.gid, root_gids,
sizeof(root_gids)/sizeof(root_gids[0])));
free_cpio_owner(&owner);

assert(NULL == owner_parse("111", &uid, &gid));
assertEqualInt(111, uid);
assertEqualInt(-1, gid);
assert(0 == owner_parse("111", &owner, &errstr));
assertEqualInt(111, owner.uid);
assertEqualInt(-1, owner.gid);
free_cpio_owner(&owner);

assert(NULL == owner_parse("112:", &uid, &gid));
assertEqualInt(112, uid);
assert(0 == owner_parse("112:", &owner, &errstr));
assertEqualInt(112, owner.uid);
/* Can't assert gid, since we don't know gid for user #112. */
free_cpio_owner(&owner);

assert(NULL == owner_parse("113.", &uid, &gid));
assertEqualInt(113, uid);
assert(0 == owner_parse("113.", &owner, &errstr));
assertEqualInt(113, owner.uid);
/* Can't assert gid, since we don't know gid for user #113. */
free_cpio_owner(&owner);

assert(NULL == owner_parse(":114", &uid, &gid));
assertEqualInt(-1, uid);
assertEqualInt(114, gid);
assert(0 == owner_parse(":114", &owner, &errstr));
assertEqualInt(-1, owner.uid);
assertEqualInt(114, owner.gid);
free_cpio_owner(&owner);

assert(NULL == owner_parse(".115", &uid, &gid));
assertEqualInt(-1, uid);
assertEqualInt(115, gid);
assert(0 == owner_parse(".115", &owner, &errstr));
assertEqualInt(-1, owner.uid);
assertEqualInt(115, owner.gid);
free_cpio_owner(&owner);

assert(NULL == owner_parse("116:117", &uid, &gid));
assertEqualInt(116, uid);
assertEqualInt(117, gid);
assert(0 == owner_parse("116:117", &owner, &errstr));
assertEqualInt(116, owner.uid);
assertEqualInt(117, owner.gid);
free_cpio_owner(&owner);

/*
* TODO: Lookup current user/group name, build strings and
* use those to verify username/groupname lookups for ordinary
* users.
*/

assert(NULL != owner_parse(":nonexistentgroup", &uid, &gid));
assert(NULL != owner_parse(ROOT ":nonexistentgroup", &uid, &gid));
assert(NULL !=
owner_parse("nonexistentuser:nonexistentgroup", &uid, &gid));
errstr = NULL;
assert(0 != owner_parse(":nonexistentgroup", &owner, &errstr));
assertEqualString(errstr, "Couldn't lookup group ``nonexistentgroup''");
free_cpio_owner(&owner);

errstr = NULL;
assert(0 != owner_parse(ROOT ":nonexistentgroup", &owner, &errstr));
assertEqualString(errstr, "Couldn't lookup group ``nonexistentgroup''");
free_cpio_owner(&owner);

errstr = NULL;
assert(0 != owner_parse("nonexistentuser:nonexistentgroup", &owner,
&errstr));
assertEqualString(errstr, "Couldn't lookup user ``nonexistentuser''");
free_cpio_owner(&owner);
#endif
}

0 comments on commit 7078929

Please sign in to comment.