From: Werner Fink Date: 2013-06-06 08:27:43+0000 Subject: let `su' handle /sbin and /usr/sbin in path Index: util-linux-2.31/login-utils/su-common.c =================================================================== --- util-linux-2.31.orig/login-utils/su-common.c +++ util-linux-2.31/login-utils/su-common.c @@ -944,6 +944,117 @@ static void setenv_path(const struct pas err(EXIT_FAILURE, _("failed to set the PATH environment variable")); } +/* Add or clear /sbin and /usr/sbin for the su command + used without `-'. */ + +/* Set if /sbin is found in path. */ +#define SBIN_MASK 0x01 +/* Set if /usr/sbin is found in path. */ +#define USBIN_MASK 0x02 + +static char * +addsbin (const char *const path) +{ + unsigned char smask = 0; + char *ptr, *tmp, *cur, *ret = NULL; + size_t len; + + if (!path || *path == 0) + return NULL; + + tmp = xstrdup (path); + cur = tmp; + for (ptr = strsep (&cur, ":"); ptr != NULL; ptr = strsep (&cur, ":")) + { + if (!strcmp (ptr, "/sbin")) + smask |= SBIN_MASK; + if (!strcmp (ptr, "/usr/sbin")) + smask |= USBIN_MASK; + } + + if ((smask & (USBIN_MASK|SBIN_MASK)) == (USBIN_MASK|SBIN_MASK)) + { + free (tmp); + return NULL; + } + + len = strlen (path); + if (!(smask & USBIN_MASK)) + len += strlen ("/usr/sbin:"); + + if (!(smask & SBIN_MASK)) + len += strlen (":/sbin"); + + ret = xmalloc (len + 1); + strcpy (tmp, path); + + *ret = 0; + cur = tmp; + for (ptr = strsep (&cur, ":"); ptr; ptr = strsep (&cur, ":")) + { + if (!strcmp (ptr, ".")) + continue; + if (*ret) + strcat (ret, ":"); + if (!(smask & USBIN_MASK) && !strcmp (ptr, "/bin")) + { + strcat (ret, "/usr/sbin:"); + strcat (ret, ptr); + smask |= USBIN_MASK; + continue; + } + if (!(smask & SBIN_MASK) && !strcmp (ptr, "/usr/bin")) + { + strcat (ret, ptr); + strcat (ret, ":/sbin"); + smask |= SBIN_MASK; + continue; + } + strcat (ret, ptr); + } + free (tmp); + + if (!(smask & USBIN_MASK)) + strcat (ret, ":/usr/sbin"); + + if (!(smask & SBIN_MASK)) + strcat (ret, ":/sbin"); + + return ret; +} + +static char * +clearsbin (const char *const path) +{ + char *ptr, *tmp, *cur, *ret = NULL; + + if (!path || *path == 0) + return NULL; + + tmp = strdup (path); + if (!tmp) + return NULL; + + ret = xmalloc (strlen (path) + 1); + *ret = 0; + cur = tmp; + for (ptr = strsep (&cur, ":"); ptr; ptr = strsep (&cur, ":")) + { + if (!strcmp (ptr, "/sbin")) + continue; + if (!strcmp (ptr, "/usr/sbin")) + continue; + if (!strcmp (ptr, "/usr/local/sbin")) + continue; + if (*ret) + strcat (ret, ":"); + strcat (ret, ptr); + } + free (tmp); + + return ret; +} + static void modify_environment(struct su_context *su, const char *shell) { const struct passwd *pw = su->pwd; @@ -982,6 +1093,22 @@ static void modify_environment(struct su if (getlogindefs_bool("ALWAYS_SET_PATH", 0)) setenv_path(pw); + else + { + char const *path = getenv ("PATH"); + char *new = NULL; + + if (pw->pw_uid) + new = clearsbin (path); + else + new = addsbin (path); + + if (new) + { + xsetenv ("PATH", new, 1); + free (new); + } + } if (pw->pw_uid) { xsetenv("USER", pw->pw_name, 1);