From d776b1b67eb1bc1b815426fdf22f38b25ef1e2df Mon Sep 17 00:00:00 2001 From: Ludwig Nussel Date: Mon, 9 Aug 2010 16:03:12 +0200 Subject: [PATCH 5/7] honor settings in /etc/default/su resp /etc/login.defs --- src/Makefile.am | 1 + src/getdef.c | 259 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/getdef.h | 29 ++++++ src/su.c | 13 +++- 4 files changed, 300 insertions(+), 2 deletions(-) create mode 100644 src/getdef.c create mode 100644 src/getdef.h diff --git a/src/Makefile.am b/src/Makefile.am index bc27274..484f6c2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -352,6 +352,7 @@ factor_LDADD += $(LIB_GMP) uptime_LDADD += $(GETLOADAVG_LIBS) # for crypt and pam +su_SOURCES = su.c getdef.c su_LDADD += $(LIB_CRYPT) $(PAM_LIBS) # for various ACL functions diff --git a/src/getdef.c b/src/getdef.c new file mode 100644 index 0000000..e1872cf --- /dev/null +++ b/src/getdef.c @@ -0,0 +1,259 @@ +/* Copyright (C) 2003, 2004, 2005 Thorsten Kukuk + Author: Thorsten Kukuk + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include + +#include "getdef.h" + +struct item { + char *name; /* Name of the option. */ + char *value; /* Value of the option. */ + struct item *next; /* Pointer to next option. */ +}; + +static struct item *list = NULL; + +void +free_getdef_data (void) +{ + struct item *ptr; + + ptr = list; + while (ptr != NULL) + { + struct item *tmp; + tmp = ptr->next; + free (ptr->name); + free (ptr->value); + free (ptr); + ptr = tmp; + } + + list = NULL; +} + +/* Add a new entry to the list. */ +static void +store (const char *name, const char *value) +{ + struct item *new = malloc (sizeof (struct item)); + + if (new == NULL) + abort (); + + if (name == NULL) + abort (); + + new->name = strdup (name); + new->value = strdup (value ?: ""); + new->next = list; + list = new; +} + +/* Search a special entry in the list and return the value. */ +static const char * +search (const char *name) +{ + struct item *ptr; + + ptr = list; + while (ptr != NULL) + { + if (strcasecmp (name, ptr->name) == 0) + return ptr->value; + ptr = ptr->next; + } + + return NULL; +} + +/* Load the login.defs file (/etc/login.defs). */ +static void +load_defaults_internal (const char *filename) +{ + FILE *fp; + char *buf = NULL; + size_t buflen = 0; + + fp = fopen (filename, "r"); + if (NULL == fp) + return; + + while (!feof (fp)) + { + char *tmp, *cp; +#if defined(HAVE_GETLINE) + ssize_t n = getline (&buf, &buflen, fp); +#elif defined (HAVE_GETDELIM) + ssize_t n = getdelim (&buf, &buflen, '\n', fp); +#else + ssize_t n; + + if (buf == NULL) + { + buflen = 8096; + buf = malloc (buflen); + } + buf[0] = '\0'; + fgets (buf, buflen - 1, fp); + if (buf != NULL) + n = strlen (buf); + else + n = 0; +#endif /* HAVE_GETLINE / HAVE_GETDELIM */ + cp = buf; + + if (n < 1) + break; + + tmp = strchr (cp, '#'); /* remove comments */ + if (tmp) + *tmp = '\0'; + while (isspace ((unsigned char) *cp)) /* remove spaces and tabs */ + ++cp; + if (*cp == '\0') /* ignore empty lines */ + continue; + + if (cp[strlen (cp) - 1] == '\n') + cp[strlen (cp) - 1] = '\0'; + + tmp = strsep (&cp, " \t="); + if (cp != NULL) + while (isspace ((unsigned char) *cp) || *cp == '=') + ++cp; + + store (tmp, cp); + } + fclose (fp); + + if (buf) + free (buf); +} + +static void +load_defaults (void) +{ + load_defaults_internal ("/etc/default/su"); + load_defaults_internal ("/etc/login.defs"); +} + +int +getdef_bool (const char *name, int dflt) +{ + const char *val; + + if (list == NULL) + load_defaults (); + + val = search (name); + + if (val == NULL) + return dflt; + + return (strcasecmp (val, "yes") == 0); +} + +long +getdef_num (const char *name, long dflt) +{ + const char *val; + char *cp; + long retval; + + if (list == NULL) + load_defaults (); + + val = search (name); + + if (val == NULL) + return dflt; + + errno = 0; + retval = strtol (val, &cp, 0); + if (*cp != '\0' + || ((retval == LONG_MAX || retval == LONG_MIN) && errno == ERANGE)) + { + fprintf (stderr, + "%s contains invalid numerical value: %s!\n", + name, val); + retval = dflt; + } + return retval; +} + +unsigned long +getdef_unum (const char *name, unsigned long dflt) +{ + const char *val; + char *cp; + unsigned long retval; + + if (list == NULL) + load_defaults (); + + val = search (name); + + if (val == NULL) + return dflt; + + errno = 0; + retval = strtoul (val, &cp, 0); + if (*cp != '\0' || (retval == ULONG_MAX && errno == ERANGE)) + { + fprintf (stderr, + "%s contains invalid numerical value: %s!\n", + name, val); + retval = dflt; + } + return retval; +} + +const char * +getdef_str (const char *name, const char *dflt) +{ + const char *retval; + + if (list == NULL) + load_defaults (); + + retval = search (name); + + return retval ?: dflt; +} + +#if defined(TEST) + +int +main () +{ + printf ("CYPT=%s\n", getdef_str ("cRypt", "no")); + printf ("LOG_UNKFAIL_ENAB=%s\n", getdef_str ("log_unkfail_enab","")); + printf ("DOESNOTEXIST=%s\n", getdef_str ("DOESNOTEXIST","yes")); + return 0; +} + +#endif diff --git a/src/getdef.h b/src/getdef.h new file mode 100644 index 0000000..2e86cf9 --- /dev/null +++ b/src/getdef.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2003, 2005 Thorsten Kukuk + Author: Thorsten Kukuk + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _GETDEF_H_ + +#define _GETDEF_H_ 1 + +extern int getdef_bool (const char *name, int dflt); +extern long getdef_num (const char *name, long dflt); +extern unsigned long getdef_unum (const char *name, unsigned long dflt); +extern const char *getdef_str (const char *name, const char *dflt); + +/* Free all data allocated by getdef_* calls before. */ +extern void free_getdef_data (void); + +#endif /* _GETDEF_H_ */ diff --git a/src/su.c b/src/su.c index 0071622..eaef195 100644 --- a/src/su.c +++ b/src/su.c @@ -111,6 +111,8 @@ # include #endif +#include "getdef.h" + /* The default PATH for simulated logins to non-superuser accounts. */ #define DEFAULT_LOGIN_PATH "/usr/local/bin:/bin:/usr/bin" @@ -475,8 +477,8 @@ modify_environment (const struct passwd *pw, const char *shell) xsetenv ("USER", pw->pw_name); xsetenv ("LOGNAME", pw->pw_name); xsetenv ("PATH", (pw->pw_uid - ? DEFAULT_LOGIN_PATH - : DEFAULT_ROOT_LOGIN_PATH)); + ? getdef_str ("PATH", DEFAULT_LOGIN_PATH) + : getdef_str ("SUPATH", DEFAULT_ROOT_LOGIN_PATH))); } else { @@ -486,6 +488,12 @@ modify_environment (const struct passwd *pw, const char *shell) { xsetenv ("HOME", pw->pw_dir); xsetenv ("SHELL", shell); + if (getdef_bool ("ALWAYS_SET_PATH", 0)) + xsetenv ("PATH", (pw->pw_uid + ? getdef_str ("PATH", + DEFAULT_LOGIN_PATH) + : getdef_str ("SUPATH", + DEFAULT_ROOT_LOGIN_PATH))); if (pw->pw_uid) { xsetenv ("USER", pw->pw_name); @@ -720,6 +728,7 @@ main (int argc, char **argv) #ifdef SYSLOG_FAILURE log_su (pw, false); #endif + sleep (getdef_num ("FAIL_DELAY", 1)); error (EXIT_CANCELED, 0, _("incorrect password")); } #ifdef SYSLOG_SUCCESS -- 1.7.1