]> granicus.if.org Git - sudo/commitdiff
Initial support for adding comments that will be emitted when
authorTodd C. Miller <Todd.Miller@sudo.ws>
Sun, 4 Mar 2018 14:03:43 +0000 (07:03 -0700)
committerTodd C. Miller <Todd.Miller@sudo.ws>
Sun, 4 Mar 2018 14:03:43 +0000 (07:03 -0700)
sudoers is formatted.  Currently adds a comment for the source
sudoRole when converting from ldif -> sudoers.

13 files changed:
plugins/sudoers/Makefile.in
plugins/sudoers/cvtsudoers.c
plugins/sudoers/cvtsudoers_ldif.c
plugins/sudoers/fmtsudoers.c
plugins/sudoers/gram.c
plugins/sudoers/gram.y
plugins/sudoers/ldap.c
plugins/sudoers/ldap_util.c
plugins/sudoers/parse.h
plugins/sudoers/regress/sudoers/test2.ldif.ok
plugins/sudoers/regress/sudoers/test3.ldif.ok
plugins/sudoers/regress/sudoers/test6.ldif.ok
plugins/sudoers/sssd.c

index 2e650327c0e94ca7cf9a00730cc3ff74beef8b74..14b4dfbbacaeb2b9dea01ed5f84df6c3f9380491 100644 (file)
@@ -461,7 +461,7 @@ check: $(TEST_PROGS) visudo testsudoers
                    diff $$json $(srcdir)/$$json.ok || true; \
                fi; \
                SUDOERS_BASE="ou=SUDOers,dc=sudo,dc=ws" \
-                   ./cvtsudoers -c "" -f ldif $$t >$$ldif 2>/dev/null || true; \
+                   ./cvtsudoers -c "" -f ldif $$t >$$ldif 2>/dev/null || true; \
                total=`expr $$total + 1`; \
                if cmp $$ldif $(srcdir)/$$ldif.ok >/dev/null; then \
                    passed=`expr $$passed + 1`; \
index ecb2614d114fd80691d76aa7c5b058a922d388db..e3fd021539009e4b570193565d463c4902bda265 100644 (file)
@@ -455,51 +455,9 @@ print_defaults_sudoers(struct sudo_lbuf *lbuf, bool expand_aliases)
     struct defaults *def, *next;
     debug_decl(print_defaults_sudoers, SUDOERS_DEBUG_UTIL)
 
-    TAILQ_FOREACH_SAFE(def, &defaults, entries, next) {
-       struct member *m;
-       int alias_type;
-
-       /* Print Defaults type and binding (if present) */
-       switch (def->type) {
-           case DEFAULTS_HOST:
-               sudo_lbuf_append(lbuf, "Defaults@");
-               alias_type = HOSTALIAS;
-               break;
-           case DEFAULTS_USER:
-               sudo_lbuf_append(lbuf, "Defaults:");
-               alias_type = expand_aliases ? USERALIAS : UNSPEC;
-               break;
-           case DEFAULTS_RUNAS:
-               sudo_lbuf_append(lbuf, "Defaults>");
-               alias_type = expand_aliases ? RUNASALIAS : UNSPEC;
-               break;
-           case DEFAULTS_CMND:
-               sudo_lbuf_append(lbuf, "Defaults!");
-               alias_type = expand_aliases ? CMNDALIAS : UNSPEC;
-               break;
-           default:
-               sudo_lbuf_append(lbuf, "Defaults");
-               alias_type = UNSPEC;
-               break;
-       }
-       TAILQ_FOREACH(m, def->binding, entries) {
-           if (m != TAILQ_FIRST(def->binding))
-               sudo_lbuf_append(lbuf, ", ");
-           sudoers_format_member(lbuf, m, ", ", alias_type);
-       }
+    TAILQ_FOREACH_SAFE(def, &defaults, entries, next)
+       sudoers_format_default_line(lbuf, def, &next, expand_aliases);
 
-       /* Print Defaults with the same binding, there may be multiple. */
-       for (;;) {
-           sudo_lbuf_append(lbuf, " ");
-           sudoers_format_default(lbuf, def);
-           next = TAILQ_NEXT(def, entries);
-           if (next == NULL || def->binding != next->binding)
-               break;
-           def = next;
-           sudo_lbuf_append(lbuf, ",");
-       }
-       sudo_lbuf_append(lbuf, "\n");
-    }
     debug_return_bool(!sudo_lbuf_error(lbuf));
 }
 
index 563bde4fbad76eefb49b6ff0e46964f8b78963d9..70488a79722fdb12a4218db1abe99aac1798bf04 100644 (file)
@@ -34,6 +34,7 @@
 #include "parse.h"
 #include "redblack.h"
 #include "cvtsudoers.h"
+#include "sudo_lbuf.h"
 #include <gram.h>
 
 struct seen_user {
@@ -95,14 +96,26 @@ static bool
 print_global_defaults_ldif(FILE *fp, const char *base)
 {
     unsigned int count = 0;
+    struct sudo_lbuf lbuf;
     struct defaults *opt;
     debug_decl(print_global_defaults_ldif, SUDOERS_DEBUG_UTIL)
 
+    sudo_lbuf_init(&lbuf, NULL, 0, NULL, 80);
+
     TAILQ_FOREACH(opt, &defaults, entries) {
        /* Skip bound Defaults (unsupported). */
-       if (opt->type == DEFAULTS)
+       if (opt->type == DEFAULTS) {
            count++;
+       } else {
+           lbuf.len = 0;
+           sudo_lbuf_append(&lbuf, "# ");
+           sudoers_format_default_line(&lbuf, opt, false, true);
+           fprintf(fp, "# Unable to translate %s:%d\n%s\n",
+               opt->file, opt->lineno, lbuf.buf);
+       }
     }
+    sudo_lbuf_destroy(&lbuf);
+
     if (count == 0)
        debug_return_bool(true);
 
@@ -118,24 +131,6 @@ print_global_defaults_ldif(FILE *fp, const char *base)
     debug_return_bool(!ferror(fp));
 }
 
-static void
-warn_bound_defaults_ldif(FILE *fp)
-{
-    struct defaults *def;
-    debug_decl(warn_bound_defaults_ldif, SUDOERS_DEBUG_UTIL)
-
-    TAILQ_FOREACH(def, &defaults, entries) {
-       if (def->type == DEFAULTS)
-           continue;           /* only want bound defaults */
-
-       /* XXX - print Defaults line */
-       sudo_warnx(U_("%s:%d unable to translate Defaults line"),
-           def->file, def->lineno);
-    }
-
-    debug_return;
-}
-
 /*
  * Print struct member in LDIF format, with specified prefix.
  * See print_member_int() in parse.c.
@@ -506,9 +501,6 @@ convert_sudoers_ldif(const char *output_file, struct cvtsudoers_config *conf)
     /* Dump User_Specs in LDIF format, expanding Aliases. */
     print_userspecs_ldif(output_fp, conf);
 
-    /* Warn about non-translatable Defaults entries. */
-    warn_bound_defaults_ldif(output_fp);
-
     /* Clean up. */
     rbdestroy(seen_users, seen_user_free);
 
@@ -812,7 +804,6 @@ role_to_sudoers(struct sudo_role *role, bool store_options,
 
     /*
      * TODO: use cn to create a UserAlias if multiple users in it?
-     * TODO: add comment info based on cn?
      */
 
     if (reuse_userspec) {
@@ -826,6 +817,7 @@ role_to_sudoers(struct sudo_role *role, bool store_options,
        }
        TAILQ_INIT(&us->privileges);
        TAILQ_INIT(&us->users);
+       STAILQ_INIT(&us->comments);
 
        STAILQ_FOREACH(ls, role->users, entries) {
            char *user = ls->str;
@@ -853,6 +845,38 @@ role_to_sudoers(struct sudo_role *role, bool store_options,
        }
     }
 
+    /* Add source role as a comment. */
+    if (role->cn != NULL) {
+       struct comment *comment = NULL;
+       if (reuse_userspec) {
+           /* Try to re-use comment too. */
+           STAILQ_FOREACH(comment, &us->comments, entries) {
+               if (strncmp(comment->str, "sudoRole ", 9) == 0) {
+                   char *tmpstr;
+                   if (asprintf(&tmpstr, "%s, %s", comment->str, role->cn) == -1) {
+                       sudo_fatalx(U_("%s: %s"), __func__,
+                           U_("unable to allocate memory"));
+                   }
+                   free(comment->str);
+                   comment->str = tmpstr;
+                   break;
+               }
+           }
+       }
+       if (comment == NULL) {
+           /* Create a new comment. */
+           if ((comment = malloc(sizeof(*comment))) == NULL) {
+               sudo_fatalx(U_("%s: %s"), __func__,
+                   U_("unable to allocate memory"));
+           }
+           if (asprintf(&comment->str, "sudoRole %s", role->cn) == -1) {
+               sudo_fatalx(U_("%s: %s"), __func__,
+                   U_("unable to allocate memory"));
+           }
+           STAILQ_INSERT_TAIL(&us->comments, comment, entries);
+       }
+    }
+
     /* Convert role to sudoers privilege. */
     priv = sudo_ldap_role_to_priv(role->cn, STAILQ_FIRST(role->hosts),
        STAILQ_FIRST(role->runasusers), STAILQ_FIRST(role->runasgroups),
@@ -966,6 +990,32 @@ ldif_to_sudoers(struct sudo_role_list *roles, unsigned int numroles,
     debug_return;
 }
 
+/*
+ * Given a cn with possible quoted characters, return a copy of
+ * the cn with quote characters ('\\') removed.
+ * The caller is responsible for freeing the returned string.
+ */
+static
+char *unquote_cn(const char *src)
+{
+    char *dst, *new_cn;
+    size_t len;
+    debug_decl(unquote_cn, SUDOERS_DEBUG_UTIL)
+
+    len = strlen(src);
+    if ((new_cn = malloc(len + 1)) == NULL)
+       debug_return_str(NULL);
+
+    for (dst = new_cn; *src != '\0';) {
+       if (src[0] == '\\' && src[1] != '\0')
+           src++;
+       *dst++ = *src++;
+    }
+    *dst = '\0';
+
+    debug_return_str(new_cn);
+}
+
 /*
  * Parse a sudoers file in LDIF format, https://tools.ietf.org/html/rfc2849
  * Parsed sudoRole objects are stored in the global sudoers data structures.
@@ -1136,8 +1186,7 @@ parse_ldif(const char *input_file, struct cvtsudoers_config *conf)
            while (isblank((unsigned char)*cp))
                cp++;
            free(role->cn);
-           /* XXX - unescape chars? */
-           role->cn = strdup(cp);
+           role->cn = unquote_cn(cp);
            if (role->cn == NULL) {
                sudo_fatalx(U_("%s: %s"), __func__,
                    U_("unable to allocate memory"));
index 39372199bfbecbec960bee8d5b3e839f5526fb72..9ae812e440b79f42573c0a39af0da9a41cc3159c 100644 (file)
@@ -256,9 +256,15 @@ sudoers_format_userspec(struct sudo_lbuf *lbuf, struct userspec *us,
     bool expand_aliases)
 {
     struct privilege *priv;
+    struct comment *comment;
     struct member *m;
     debug_decl(sudoers_format_userspec, SUDOERS_DEBUG_UTIL)
 
+    /* Print comments (if any). */
+    STAILQ_FOREACH(comment, &us->comments, entries) {
+       sudo_lbuf_append(lbuf, "# %s\n", comment->str);
+    }
+
     /* Print users list. */
     TAILQ_FOREACH(m, &us->users, entries) {
        if (m != TAILQ_FIRST(&us->users))
@@ -291,9 +297,10 @@ sudoers_format_userspecs(struct sudo_lbuf *lbuf, struct userspec_list *usl,
     debug_decl(sudoers_format_userspecs, SUDOERS_DEBUG_UTIL)
 
     TAILQ_FOREACH(us, usl, entries) {
+       if (us != TAILQ_FIRST(usl))
+           sudo_lbuf_append(lbuf, sep);
        if (!sudoers_format_userspec(lbuf, us, expand_aliases))
            break;
-       sudo_lbuf_append(lbuf, sep);
        sudo_lbuf_print(lbuf);
     }
 
@@ -322,3 +329,64 @@ sudoers_format_default(struct sudo_lbuf *lbuf, struct defaults *d)
     }
     debug_return_bool(!sudo_lbuf_error(lbuf));
 }
+
+/*
+ * Format and append a defaults line to the specified lbuf.
+ * If next, is specified, it must point to the next defaults
+ * entry in the list; this is used to print multiple defaults
+ * entries with the same binding on a single line.
+ */
+bool
+sudoers_format_default_line(struct sudo_lbuf *lbuf, struct defaults *d,
+    struct defaults **next, bool expand_aliases)
+{
+    struct member *m;
+    int alias_type;
+    debug_decl(sudoers_format_default_line, SUDOERS_DEBUG_UTIL)
+
+    /* Print Defaults type and binding (if present) */
+    switch (d->type) {
+       case DEFAULTS_HOST:
+           sudo_lbuf_append(lbuf, "Defaults@");
+           alias_type = HOSTALIAS;
+           break;
+       case DEFAULTS_USER:
+           sudo_lbuf_append(lbuf, "Defaults:");
+           alias_type = expand_aliases ? USERALIAS : UNSPEC;
+           break;
+       case DEFAULTS_RUNAS:
+           sudo_lbuf_append(lbuf, "Defaults>");
+           alias_type = expand_aliases ? RUNASALIAS : UNSPEC;
+           break;
+       case DEFAULTS_CMND:
+           sudo_lbuf_append(lbuf, "Defaults!");
+           alias_type = expand_aliases ? CMNDALIAS : UNSPEC;
+           break;
+       default:
+           sudo_lbuf_append(lbuf, "Defaults");
+           alias_type = UNSPEC;
+           break;
+    }
+    TAILQ_FOREACH(m, d->binding, entries) {
+       if (m != TAILQ_FIRST(d->binding))
+           sudo_lbuf_append(lbuf, ", ");
+       sudoers_format_member(lbuf, m, ", ", alias_type);
+    }
+
+    sudo_lbuf_append(lbuf, " ");
+    sudoers_format_default(lbuf, d);
+
+    if (next != NULL) {
+       /* Merge Defaults with the same binding, there may be multiple. */
+       struct defaults *n = *next;
+       while ((n = TAILQ_NEXT(d, entries)) && d->binding == n->binding) {
+           sudo_lbuf_append(lbuf, ", ");
+           sudoers_format_default(lbuf, n);
+           d = n;
+       }
+       *next = n;
+    }
+    sudo_lbuf_append(lbuf, "\n");
+
+    debug_return_bool(!sudo_lbuf_error(lbuf));
+}
index dca7253ae511b04fca304ee6536ce884ca96afbe..02f95300ff1fe3329571f2b0eeffd0460c88f52b 100644 (file)
@@ -825,6 +825,7 @@ add_userspec(struct member *members, struct privilege *privs)
     u->file = rcstr_addref(sudoers);
     HLTQ_TO_TAILQ(&u->users, members, entries);
     HLTQ_TO_TAILQ(&u->privileges, privs, entries);
+    STAILQ_INIT(&u->comments);
     TAILQ_INSERT_TAIL(&userspecs, u, entries);
 
     debug_return_bool(true);
@@ -929,12 +930,18 @@ void
 free_userspec(struct userspec *us)
 {
     struct privilege *priv;
+    struct comment *comment;
 
     free_members(&us->users);
     while ((priv = TAILQ_FIRST(&us->privileges)) != NULL) {
        TAILQ_REMOVE(&us->privileges, priv, entries);
        free_privilege(priv);
     }
+    while ((comment = STAILQ_FIRST(&us->comments)) != NULL) {
+       STAILQ_REMOVE_HEAD(&us->comments, entries);
+       free(comment->str);
+       free(comment);
+    }
     rcstr_delref(us->file);
     free(us);
 }
@@ -1016,7 +1023,7 @@ init_options(struct command_options *opts)
     opts->limitprivs = NULL;
 #endif
 }
-#line 967 "gram.c"
+#line 974 "gram.c"
 /* allocate initial stack or double stack size, up to YYMAXDEPTH */
 #if defined(__cplusplus) || defined(__STDC__)
 static int yygrowstack(void)
@@ -2141,7 +2148,7 @@ case 116:
                            }
                        }
 break;
-#line 2092 "gram.c"
+#line 2099 "gram.c"
     }
     yyssp -= yym;
     yystate = *yyssp;
index 5bc1003d379793fc6e5a20e46e8abff30acb37c3..cc54e101364fb5ed94b459d4359a420efdb3627f 100644 (file)
@@ -1053,6 +1053,7 @@ add_userspec(struct member *members, struct privilege *privs)
     u->file = rcstr_addref(sudoers);
     HLTQ_TO_TAILQ(&u->users, members, entries);
     HLTQ_TO_TAILQ(&u->privileges, privs, entries);
+    STAILQ_INIT(&u->comments);
     TAILQ_INSERT_TAIL(&userspecs, u, entries);
 
     debug_return_bool(true);
@@ -1157,12 +1158,18 @@ void
 free_userspec(struct userspec *us)
 {
     struct privilege *priv;
+    struct comment *comment;
 
     free_members(&us->users);
     while ((priv = TAILQ_FIRST(&us->privileges)) != NULL) {
        TAILQ_REMOVE(&us->privileges, priv, entries);
        free_privilege(priv);
     }
+    while ((comment = STAILQ_FIRST(&us->comments)) != NULL) {
+       STAILQ_REMOVE_HEAD(&us->comments, entries);
+       free(comment->str);
+       free(comment);
+    }
     rcstr_delref(us->file);
     free(us);
 }
index b35f1ee1b450d59bfe4bc80dd440f617474fea16..8857c0ce37cbbac54c760a6b6061c8402c3f5df1 100644 (file)
@@ -1519,6 +1519,7 @@ ldap_to_sudoers(LDAP *ld, struct ldap_result *lres)
        goto oom;
     TAILQ_INIT(&us->users);
     TAILQ_INIT(&us->privileges);
+    STAILQ_INIT(&us->comments);
     TAILQ_INSERT_TAIL(ldap_userspecs, us, entries);
 
     /* The user has already matched, use ALL as wildcard. */
index e7ace94690417b82cdd91f5e439cc05134492bac..c6d37e186e8274061b7d9e4b94503f0fbcb2c0cb 100644 (file)
@@ -461,6 +461,7 @@ sudo_ldap_role_to_priv(const char *cn, void *hosts, void *runasusers,
                            handled = false;
                        }
                        if (!handled && warnings) {
+                           /* XXX - callback to process unsupported options. */
                            if (val != NULL) {
                                sudo_warnx(U_("unable to convert sudoOption: %s%s%s"), var, op == '+' ? "+=" : op == '-' ? "-=" : "=", val);
                            } else {
index d17886f77e551341dacee5cf4b21ca61933c2c46..31dfc7fac900f6e64ac3c7d435af0f045637707d 100644 (file)
@@ -150,6 +150,7 @@ TAILQ_HEAD(userspec_list, userspec);
 TAILQ_HEAD(member_list, member);
 TAILQ_HEAD(privilege_list, privilege);
 TAILQ_HEAD(cmndspec_list, cmndspec);
+STAILQ_HEAD(comment_list, comment);
 
 /*
  * Structure describing a user specification and list thereof.
@@ -158,6 +159,7 @@ struct userspec {
     TAILQ_ENTRY(userspec) entries;
     struct member_list users;          /* list of users */
     struct privilege_list privileges;  /* list of privileges */
+    struct comment_list comments;      /* optional comments */
     int lineno;
     char *file;
 };
@@ -209,6 +211,11 @@ struct runascontainer {
     struct member *runasgroups;
 };
 
+struct comment {
+    STAILQ_ENTRY(comment) entries;
+    char *str;
+};
+
 /*
  * Generic structure to hold {User,Host,Runas,Cmnd}_Alias
  * Aliases are stored in a red-black tree, sorted by name and type.
@@ -312,6 +319,7 @@ int sudo_display_userspecs(struct userspec_list *usl, struct passwd *pw, struct
 /* fmtsudoers.c */
 bool sudoers_format_cmndspec(struct sudo_lbuf *lbuf, struct cmndspec *cs, struct cmndspec *prev_cs, bool expand_aliases);
 bool sudoers_format_default(struct sudo_lbuf *lbuf, struct defaults *d);
+bool sudoers_format_default_line(struct sudo_lbuf *lbuf, struct defaults *d, struct defaults **next, bool expand_aliases);
 bool sudoers_format_member(struct sudo_lbuf *lbuf, struct member *m, const char *separator, int alias_type);
 bool sudoers_format_privilege(struct sudo_lbuf *lbuf, struct privilege *priv, bool expand_aliases);
 bool sudoers_format_userspec(struct sudo_lbuf *lbuf, struct userspec *us, bool expand_aliases);
index 9823707a9ba06c5667bed3ec87c239be6f8ffc13..94714879757c3e7a3d21acec8caf4be03f768a18 100644 (file)
@@ -1,3 +1,30 @@
+# Unable to translate stdin:26
+# Defaults@somehost set_home
+
+# Unable to translate stdin:27
+# Defaults@quoted\" set_home
+
+# Unable to translate stdin:30
+# Defaults:you set_home
+
+# Unable to translate stdin:31
+# Defaults:us\" set_home
+
+# Unable to translate stdin:32
+# Defaults:%them set_home
+
+# Unable to translate stdin:33
+# Defaults:"%: non UNIX 0 c" set_home
+
+# Unable to translate stdin:34
+# Defaults:+net set_home
+
+# Unable to translate stdin:37
+# Defaults>someone set_home
+
+# Unable to translate stdin:38
+# Defaults>"some one" set_home
+
 dn: cn=foo,ou=SUDOers,dc=sudo,dc=ws
 objectClass: top
 objectClass: sudoRole
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0aa54be860550bed4fe746d3c48a2f3d9346f6af 100644 (file)
@@ -0,0 +1,12 @@
+# Unable to translate stdin:3
+# Defaults:foo, bar env_reset
+
+# Unable to translate stdin:4
+# Defaults:foo, bar env_reset
+
+# Unable to translate stdin:5
+# Defaults:foo, " bar" env_reset
+
+# Unable to translate stdin:6
+# Defaults:foo, bar env_reset
+
index 5ca28d10a94334488c79c82e0070a6b33edefb4d..c4e11e4ff7f18e1a73cb21c1ae0b4c1139a07ac6 100644 (file)
@@ -1,3 +1,15 @@
+# Unable to translate stdin:2
+# Defaults:#123 set_home
+
+# Unable to translate stdin:3
+# Defaults>#123 set_home
+
+# Unable to translate stdin:4
+# Defaults:#123 set_home
+
+# Unable to translate stdin:5
+# Defaults>#123 set_home
+
 dn: cn=\#0,ou=SUDOers,dc=sudo,dc=ws
 objectClass: top
 objectClass: sudoRole
index 8cee7e68436113a7a83efb4afb046dc7b80dc707..1994f9c1c55d6b19897309a8c930099f9ad2ce36 100644 (file)
@@ -1436,6 +1436,7 @@ sss_to_sudoers(struct sudo_sss_handle *handle, struct sss_sudo_result *sss_resul
        goto oom;
     TAILQ_INIT(&us->users);
     TAILQ_INIT(&us->privileges);
+    STAILQ_INIT(&us->comments);
     TAILQ_INSERT_TAIL(sss_userspecs, us, entries);
 
     /* The user has already matched, use ALL as wildcard. */