From 71b7ddcdd5c473f9eaf6035b96acc68c14cb379e Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 20 Nov 2011 14:08:33 -0800 Subject: [PATCH] port to GNU hosts, where getuid and friends can fail * src/groups.c (main): * src/install.c (need_copy): * src/su.c (log_su): * src/test.c (unary_operator): * src/whoami.c (main): Don't assume that getuid and friends always succeed. This fixes the same problem that we recently fixed with 'id'. --- src/groups.c | 14 ++++++++++++++ src/install.c | 24 +++++++++++++++++++++--- src/su.c | 5 ++++- src/test.c | 16 ++++++++++++---- src/whoami.c | 4 +++- 5 files changed, 54 insertions(+), 9 deletions(-) diff --git a/src/groups.c b/src/groups.c index abb7bc7..279b831 100644 --- a/src/groups.c +++ b/src/groups.c @@ -97,9 +97,23 @@ main (int argc, char **argv) if (optind == argc) { /* No arguments. Divulge the details of the current process. */ + uid_t NO_UID = -1; + gid_t NO_GID = -1; + + errno = 0; ruid = getuid (); + if (ruid == NO_UID && errno) + error (EXIT_FAILURE, errno, _("cannot get real UID")); + + errno = 0; egid = getegid (); + if (egid == NO_GID && errno) + error (EXIT_FAILURE, errno, _("cannot get effective GID")); + + errno = 0; rgid = getgid (); + if (rgid == NO_GID && errno) + error (EXIT_FAILURE, errno, _("cannot get real GID")); if (!print_group_list (NULL, ruid, rgid, egid, true)) ok = false; diff --git a/src/install.c b/src/install.c index dbff9c9..94534f8 100644 --- a/src/install.c +++ b/src/install.c @@ -192,9 +192,27 @@ need_copy (const char *src_name, const char *dest_name, return true; if (src_sb.st_size != dest_sb.st_size - || (dest_sb.st_mode & CHMOD_MODE_BITS) != mode - || dest_sb.st_uid != (owner_id == (uid_t) -1 ? getuid () : owner_id) - || dest_sb.st_gid != (group_id == (gid_t) -1 ? getgid () : group_id)) + || (dest_sb.st_mode & CHMOD_MODE_BITS) != mode) + return true; + + if (owner_id == (uid_t) -1) + { + errno = 0; + uid_t ruid = getuid (); + if ((ruid == (uid_t) -1 && errno) || dest_sb.st_uid != ruid) + return true; + } + else if (dest_sb.st_uid != owner_id) + return true; + + if (group_id == (uid_t) -1) + { + errno = 0; + gid_t rgid = getgid (); + if ((rgid == (uid_t) -1 && errno) || dest_sb.st_gid != rgid) + return true; + } + else if (dest_sb.st_gid != group_id) return true; /* compare SELinux context if preserving */ diff --git a/src/su.c b/src/su.c index 081ecb2..b1ba2a7 100644 --- a/src/su.c +++ b/src/su.c @@ -173,7 +173,10 @@ log_su (struct passwd const *pw, bool successful) { /* getlogin can fail -- usually due to lack of utmp entry. Resort to getpwuid. */ - struct passwd *pwd = getpwuid (getuid ()); + errno = 0; + uid_t ruid = getuid (); + uid_t NO_UID = -1; + struct passwd *pwd = (ruid == NO_UID && errno ? NULL : getpwuid (ruid)); old_user = (pwd ? pwd->pw_name : ""); } tty = ttyname (STDERR_FILENO); diff --git a/src/test.c b/src/test.c index 362df65..1b06ca8 100644 --- a/src/test.c +++ b/src/test.c @@ -414,13 +414,21 @@ unary_operator (void) case 'O': /* File is owned by you? */ unary_advance (); - return (stat (argv[pos - 1], &stat_buf) == 0 - && (geteuid () == stat_buf.st_uid)); + if (stat (argv[pos - 1], &stat_buf) != 0) + return false; + errno = 0; + uid_t euid = geteuid (); + uid_t NO_UID = -1; + return ! (euid == NO_UID && errno) && euid == stat_buf.st_uid; case 'G': /* File is owned by your group? */ unary_advance (); - return (stat (argv[pos - 1], &stat_buf) == 0 - && (getegid () == stat_buf.st_gid)); + if (stat (argv[pos - 1], &stat_buf) != 0) + return false; + errno = 0; + gid_t egid = getegid (); + gid_t NO_GID = -1; + return ! (egid == NO_GID && errno) && egid == stat_buf.st_gid; case 'f': /* File is a file? */ unary_advance (); diff --git a/src/whoami.c b/src/whoami.c index e563dcf..1b0c3cd 100644 --- a/src/whoami.c +++ b/src/whoami.c @@ -61,6 +61,7 @@ main (int argc, char **argv) { struct passwd *pw; uid_t uid; + uid_t NO_UID = -1; initialize_main (&argc, &argv); set_program_name (argv[0]); @@ -81,8 +82,9 @@ main (int argc, char **argv) usage (EXIT_FAILURE); } + errno = 0; uid = geteuid (); - pw = getpwuid (uid); + pw = (uid == NO_UID && errno ? NULL : getpwuid (uid)); if (pw) { puts (pw->pw_name); -- 2.7.4