1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-11-29 08:08:37 +00:00

This addresses some issues with my earlier -R fix that

were pointed out by Brooks Davis and Alexey Dokuchaev:
* It now tries to lookup arguments as names first, then tries
   to parse them as numbers.  In particular, this makes the
   behavior consistent with POSIX conventions when usernames
   consist entirely of digits.
* It now uses strtoul() for the numeric parsing.

Finally, I've included an update to the test harness
to exercise the new numeric cases for -R.

Approved by:	re (kib)
This commit is contained in:
Tim Kientzle 2009-07-06 02:02:45 +00:00
parent 0e18ab26d0
commit 3e0fc6d3f3
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=195389
2 changed files with 74 additions and 66 deletions

View File

@ -275,29 +275,14 @@ cpio_getopt(struct cpio *cpio)
* :<groupname|gid> - Override group but not user
*
* Where uid/gid are decimal representations and groupname/username
* are names to be looked up in system database. Note that
* uid/gid parsing takes priority over username/groupname lookup,
* so this won't do a lookup for usernames or group names that
* consist entirely of digits.
* are names to be looked up in system database. Note that we try
* to look up an argument as a name first, then try numeric parsing.
*
* A period can be used instead of the colon.
*
* Sets uid/gid return as appropriate, -1 indicates uid/gid not specified.
*
*/
static int
decimal_parse(const char *p)
{
/* TODO: guard against overflow. */
int n = 0;
for (; *p != '\0'; ++p) {
if (*p < '0' || *p > '9')
return (-1);
n = n * 10 + *p - '0';
}
return (n);
}
int
owner_parse(const char *spec, int *uid, int *gid)
{
@ -306,6 +291,9 @@ owner_parse(const char *spec, int *uid, int *gid)
*uid = -1;
*gid = -1;
if (spec[0] == '\0')
return (1);
/*
* Split spec into [user][:.][group]
* u -> first char of username, NULL if no username
@ -338,32 +326,34 @@ owner_parse(const char *spec, int *uid, int *gid)
}
memcpy(user, u, ue - u);
user[ue - u] = '\0';
*uid = decimal_parse(user);
if (*uid < 0) {
/* Couldn't parse as integer, try username lookup. */
pwent = getpwnam(user);
if (pwent == NULL) {
if ((pwent = getpwnam(user)) != NULL) {
*uid = pwent->pw_uid;
if (*ue != '\0')
*gid = pwent->pw_gid;
} else {
char *end;
errno = 0;
*uid = strtoul(user, &end, 10);
if (errno || *end != '\0') {
cpio_warnc(errno,
"Couldn't lookup user ``%s''", user);
return (1);
}
*uid = pwent->pw_uid;
if (*ue != '\0' && *g == '\0')
*gid = pwent->pw_gid;
}
free(user);
}
if (*g != '\0') {
*gid = decimal_parse(g);
if (*gid < 0) {
/* Couldn't parse int, try group name lookup. */
struct group *grp;
grp = getgrnam(g);
if (grp != NULL)
*gid = grp->gr_gid;
else {
struct group *grp;
if ((grp = getgrnam(g)) != NULL) {
*gid = grp->gr_gid;
} else {
char *end;
errno = 0;
*gid = strtoul(g, &end, 10);
if (errno || *end != '\0') {
cpio_warnc(errno,
"Couldn't look up group ``%s''", g);
"Couldn't lookup group ``%s''", g);
return (1);
}
}

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* Copyright (c) 2003-2009 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -26,6 +26,7 @@
__FBSDID("$FreeBSD$");
#include "../cpio.h"
#include "err.h"
#if defined(__CYGWIN__)
/* On cygwin, the Administrator user most likely exists (unless
@ -37,16 +38,23 @@ __FBSDID("$FreeBSD$");
* Use CreateWellKnownSID() and LookupAccountName()?
*/
#define ROOT "Administrator"
#define ROOT_UID 500
#define ROOT_GID1 513
#define ROOT_GID2 545
#define ROOT_GID3 544
static int root_uids[] = { 500 };
static int root_gids[] = { 513, 545, 544 };
#else
#define ROOT "root"
#define ROOT_UID 0
#define ROOT_GID 0
static int root_uids[] = { 0 };
static int root_gids[] = { 0 };
#endif
static int
int_in_list(int i, int *l, size_t n)
{
while (n-- > 0)
if (*l++ == i)
return (1);
failure("%d", i);
return (0);
}
DEFINE_TEST(test_owner_parse)
{
@ -56,38 +64,47 @@ DEFINE_TEST(test_owner_parse)
#else
int uid, gid;
cpio_progname = "Ignore this message";
assertEqualInt(0, owner_parse(ROOT, &uid, &gid));
assertEqualInt(ROOT_UID, uid);
assert(int_in_list(uid, root_uids,
sizeof(root_uids)/sizeof(root_uids[0])));
assertEqualInt(-1, gid);
assertEqualInt(0, owner_parse(ROOT ":", &uid, &gid));
assertEqualInt(ROOT_UID, uid);
#if defined(__CYGWIN__)
{
int gidIsOneOf = (ROOT_GID1 == gid)
|| (ROOT_GID2 == gid)
|| (ROOT_GID3 == gid);
assertEqualInt(1, gidIsOneOf);
}
#else
assertEqualInt(ROOT_GID, gid);
#endif
assert(int_in_list(uid, root_uids,
sizeof(root_uids)/sizeof(root_uids[0])));
assert(int_in_list(gid, root_gids,
sizeof(root_gids)/sizeof(root_gids[0])));
assertEqualInt(0, owner_parse(ROOT ".", &uid, &gid));
assertEqualInt(ROOT_UID, uid);
#if defined(__CYGWIN__)
{
int gidIsOneOf = (ROOT_GID1 == gid)
|| (ROOT_GID2 == gid)
|| (ROOT_GID3 == gid);
assertEqualInt(1, gidIsOneOf);
}
#else
assertEqualInt(ROOT_GID, gid);
#endif
assert(int_in_list(uid, root_uids,
sizeof(root_uids)/sizeof(root_uids[0])));
assert(int_in_list(gid, root_gids,
sizeof(root_gids)/sizeof(root_gids[0])));
assertEqualInt(0, owner_parse("111", &uid, &gid));
assertEqualInt(111, uid);
assertEqualInt(-1, gid);
assertEqualInt(0, owner_parse("112:", &uid, &gid));
assertEqualInt(112, uid);
/* Can't assert gid, since we don't know gid for user #112. */
assertEqualInt(0, owner_parse("113.", &uid, &gid));
assertEqualInt(113, uid);
/* Can't assert gid, since we don't know gid for user #113. */
assertEqualInt(0, owner_parse(":114", &uid, &gid));
assertEqualInt(-1, uid);
assertEqualInt(114, gid);
assertEqualInt(0, owner_parse(".115", &uid, &gid));
assertEqualInt(-1, uid);
assertEqualInt(115, gid);
assertEqualInt(0, owner_parse("116:117", &uid, &gid));
assertEqualInt(116, uid);
assertEqualInt(117, gid);
/*
* TODO: Lookup current user/group name, build strings and
@ -104,6 +121,7 @@ DEFINE_TEST(test_owner_parse)
* Alternatively, redirect stderr temporarily to suppress the output.
*/
cpio_progname = "Ignore this message";
assertEqualInt(1, owner_parse(":nonexistentgroup", &uid, &gid));
assertEqualInt(1, owner_parse(ROOT ":nonexistentgroup", &uid, &gid));
assertEqualInt(1,