update changelog
[debian/sudo] / sudo_nss.c
index 7d7061758791166c99e1abc8942e5d117b1f6435..e21aaae495681dc3612092b4470ed06c2ed26913 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2008 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 2007-2010 Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
 #endif /* STDC_HEADERS */
 #ifdef HAVE_STRING_H
 # include <string.h>
-#else
-# ifdef HAVE_STRINGS_H
-#  include <strings.h>
-# endif
 #endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif /* HAVE_UNISTD_H */
 #include <pwd.h>
 #include <grp.h>
+#include <ctype.h>
 
 #include "sudo.h"
 #include "lbuf.h"
 
-#ifndef lint
-__unused static const char rcsid[] = "$Sudo: sudo_nss.c,v 1.6 2008/02/08 13:18:12 millert Exp $";
-#endif /* lint */
-
 extern struct sudo_nss sudo_nss_file;
 #ifdef HAVE_LDAP
 extern struct sudo_nss sudo_nss_ldap;
@@ -89,7 +85,7 @@ sudo_read_nss()
                got_match = TRUE;
            } else if (strcasecmp(cp, "[NOTFOUND=return]") == 0 && got_match) {
                /* NOTFOUND affects the most recent entry */
-               tq_last(&snl)->ret_notfound = TRUE;
+               tq_last(&snl)->ret_if_notfound = TRUE;
                got_match = FALSE;
            } else
                got_match = FALSE;
@@ -109,6 +105,85 @@ nomatch:
 
 #else /* HAVE_LDAP && _PATH_NSSWITCH_CONF */
 
+# if defined(HAVE_LDAP) && defined(_PATH_NETSVC_CONF)
+
+/*
+ * Read in /etc/netsvc.conf (like nsswitch.conf on AIX)
+ * Returns a tail queue of matches.
+ */
+struct sudo_nss_list *
+sudo_read_nss()
+{
+    FILE *fp;
+    char *cp, *ep;
+    int saw_files = FALSE;
+    int saw_ldap = FALSE;
+    int got_match = FALSE;
+    static struct sudo_nss_list snl;
+
+    if ((fp = fopen(_PATH_NETSVC_CONF, "r")) == NULL)
+       goto nomatch;
+
+    while ((cp = sudo_parseln(fp)) != NULL) {
+       /* Skip blank or comment lines */
+       if (*cp == '\0')
+           continue;
+
+       /* Look for a line starting with "sudoers = " */
+       if (strncasecmp(cp, "sudoers", 7) != 0)
+           continue;
+       cp += 7;
+       while (isspace((unsigned char)*cp))
+           cp++;
+       if (*cp++ != '=')
+           continue;
+
+       /* Parse line */
+       for ((cp = strtok(cp, ",")); cp != NULL; (cp = strtok(NULL, ","))) {
+           /* Trim leading whitespace. */
+           while (isspace((unsigned char)*cp))
+               cp++;
+
+           if (!saw_files && strncasecmp(cp, "files", 5) == 0 &&
+               (isspace((unsigned char)cp[5]) || cp[5] == '\0')) {
+               tq_append(&snl, &sudo_nss_file);
+               got_match = TRUE;
+               ep = &cp[5];
+           } else if (!saw_ldap && strncasecmp(cp, "ldap", 4) == 0 &&
+               (isspace((unsigned char)cp[4]) || cp[4] == '\0')) {
+               tq_append(&snl, &sudo_nss_ldap);
+               got_match = TRUE;
+               ep = &cp[4];
+           } else {
+               got_match = FALSE;
+           }
+
+           /* check for = auth qualifier */
+           if (got_match && *ep) {
+               cp = ep;
+               while (isspace((unsigned char)*cp) || *cp == '=')
+                   cp++;
+               if (strncasecmp(cp, "auth", 4) == 0 &&
+                   (isspace((unsigned char)cp[4]) || cp[4] == '\0')) {
+                   tq_last(&snl)->ret_if_found = TRUE;
+               }
+           }
+       }
+       /* Only parse the first "sudoers" line */
+       break;
+    }
+    fclose(fp);
+
+nomatch:
+    /* Default to files only if no matches */
+    if (tq_empty(&snl))
+       tq_append(&snl, &sudo_nss_file);
+
+    return(&snl);
+}
+
+# else /* !_PATH_NETSVC_CONF && !_PATH_NSSWITCH_CONF */
+
 /*
  * Non-nsswitch.conf version with hard-coded order.
  */
@@ -117,14 +192,16 @@ sudo_read_nss()
 {
     static struct sudo_nss_list snl;
 
-# ifdef HAVE_LDAP
+#  ifdef HAVE_LDAP
     tq_append(&snl, &sudo_nss_ldap);
-# endif
+#  endif
     tq_append(&snl, &sudo_nss_file);
 
     return(&snl);
 }
 
+# endif /* !HAVE_LDAP || !_PATH_NETSVC_CONF */
+
 #endif /* HAVE_LDAP && _PATH_NSSWITCH_CONF */
 
 /* Reset user_groups based on passwd entry. */
@@ -134,18 +211,29 @@ reset_groups(pw)
 {
 #if defined(HAVE_INITGROUPS) && defined(HAVE_GETGROUPS)
     if (pw != sudo_user.pw) {
+# ifdef HAVE_SETAUTHDB
+        aix_setauthdb(pw->pw_name);
+# endif
        (void) initgroups(pw->pw_name, pw->pw_gid);
+       efree(user_groups);
+       user_groups = NULL;
        if ((user_ngroups = getgroups(0, NULL)) > 0) {
-           user_groups = erealloc3(user_groups, user_ngroups,
-               sizeof(GETGROUPS_T));
+           user_groups = emalloc2(user_ngroups, sizeof(GETGROUPS_T));
            if (getgroups(user_ngroups, user_groups) < 0)
                log_error(USE_ERRNO|MSG_ONLY, "can't get group vector");
-       } else {
-           user_ngroups = 0;
-           efree(user_groups);
        }
+# ifdef HAVE_SETAUTHDB
+        aix_restoreauthdb();
+# endif
     }
-#endif
+#endif /* HAVE_INITGROUPS && HAVE_GETGROUPS */
+}
+
+static int
+output(buf)
+    const char *buf;
+{
+    return fputs(buf, stdout);
 }
 
 /*
@@ -164,35 +252,45 @@ display_privs(snl, pw)
     /* Reset group vector so group matching works correctly. */
     reset_groups(pw);
 
-    lbuf_init(&lbuf, NULL, 4, 0);
+    lbuf_init(&lbuf, output, 4, NULL);
 
     /* Display defaults from all sources. */
+    lbuf_append(&lbuf, "Matching Defaults entries for ", pw->pw_name,
+       " on this host:\n", NULL);
     count = 0;
-    tq_foreach_fwd(snl, nss)
+    tq_foreach_fwd(snl, nss) {
        count += nss->display_defaults(nss, pw, &lbuf);
+    }
     if (count) {
-       printf("Matching Defaults entries for %s on this host:\n", pw->pw_name);
+       lbuf_append(&lbuf, "\n\n", NULL);
        lbuf_print(&lbuf);
-       putchar('\n');
     }
 
     /* Display Runas and Cmnd-specific defaults from all sources. */
+    lbuf.len = 0;
+    lbuf_append(&lbuf, "Runas and Command-specific defaults for ", pw->pw_name,
+       ":\n", NULL);
     count = 0;
-    tq_foreach_fwd(snl, nss)
+    tq_foreach_fwd(snl, nss) {
        count += nss->display_bound_defaults(nss, pw, &lbuf);
+    }
     if (count) {
-       printf("Runas and Command-specific defaults for %s:\n", pw->pw_name);
+       lbuf_append(&lbuf, "\n\n", NULL);
        lbuf_print(&lbuf);
-       putchar('\n');
     }
 
     /* Display privileges from all sources. */
-    printf("User %s may run the following commands on this host:\n",
-       pw->pw_name);
-    tq_foreach_fwd(snl, nss)
-       (void) nss->display_privs(nss, pw, &lbuf);
-    if (lbuf.len != 0)
-       lbuf_print(&lbuf);              /* print remainder, if any */
+    lbuf.len = 0;
+    lbuf_append(&lbuf, "User ", pw->pw_name,
+       " may run the following commands on this host:\n", NULL);
+    count = 0;
+    tq_foreach_fwd(snl, nss) {
+       count += nss->display_privs(nss, pw, &lbuf);
+    }
+    if (count) {
+       lbuf_print(&lbuf);
+    }
+
     lbuf_destroy(&lbuf);
 }