From b374effcb447af1ee08df9b76f332e7758236462 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Mon, 29 Jan 2018 11:00:43 -0700 Subject: [PATCH] Quote special characters when creating the cn as per RFC2253 --- plugins/sudoers/cvtsudoers_ldif.c | 109 ++++++++++++++---- plugins/sudoers/regress/sudoers/test2.ldif.ok | 12 +- plugins/sudoers/regress/sudoers/test6.ldif.ok | 24 ++-- 3 files changed, 103 insertions(+), 42 deletions(-) diff --git a/plugins/sudoers/cvtsudoers_ldif.c b/plugins/sudoers/cvtsudoers_ldif.c index 0d8c77dc0..d2ca2e494 100644 --- a/plugins/sudoers/cvtsudoers_ldif.c +++ b/plugins/sudoers/cvtsudoers_ldif.c @@ -36,7 +36,7 @@ struct seen_user { const char *name; - long count; + unsigned long count; }; static int sudo_order; @@ -51,6 +51,15 @@ seen_user_compare(const void *aa, const void *bb) return strcasecmp(a->name, b->name); } +static void +seen_user_free(void *v) +{ + struct seen_user *su = v; + + free((void *)su->name); + free(su); +} + /* * Print global Defaults in a single sudoRole object. */ @@ -295,6 +304,79 @@ print_cmndspec_ldif(FILE *fp, struct cmndspec *cs, struct cmndspec **nextp) debug_return; } +/* + * Convert user name to cn, avoiding duplicates and quoting as needed. + */ +static char * +user_to_cn(const char *user) +{ + struct seen_user key, *su = NULL; + struct rbnode *node; + const char *src; + char *cn, *dst; + size_t size; + debug_decl(user_to_cn, SUDOERS_DEBUG_UTIL) + + /* Allocate as much as we could possibly need. */ + size = (2 * strlen(user)) + 64 + 1; + if ((cn = malloc(size)) == NULL) + goto bad; + + /* + * Increment the number of times we have seen this user. + */ + key.name = user; + node = rbfind(seen_users, &key); + if (node != NULL) { + su = node->data; + } else { + if ((su = malloc(sizeof(*su))) == NULL) + goto bad; + su->count = 0; + if ((su->name = strdup(user)) == NULL) + goto bad; + if (rbinsert(seen_users, su, NULL) != 0) + goto bad; + } + + /* Build cn, quoting special chars as needed (we allocated 2 x len). */ + for (src = user, dst = cn; *src != '\0'; src++) { + switch (*src) { + case ',': + case '\\': + case '#': + case '+': + case '<': + case '>': + case ';': + *dst++ = '\\'; + *dst++ = *src; + break; + default: + *dst++ = *src; + break; + } + } + *dst = '\0'; + + /* Append count if there are duplicate users (cn must be unique). */ + if (su->count != 0) { + size -= (size_t)(dst - cn); + if ((size_t)snprintf(dst, size, "_%lu", su->count) >= size) { + sudo_warnx(U_("internal error, %s overflow"), __func__); + goto bad; + } + } + su->count++; + + debug_return_str(cn); +bad: + if (su != NULL && su->count == 1) + seen_user_free(su); + free(cn); + debug_return_str(NULL); +} + /* * Print a single User_Spec. */ @@ -304,7 +386,6 @@ print_userspec_ldif(FILE *fp, struct userspec *us, const char *base) struct privilege *priv; struct member *m; struct cmndspec *cs, *next; - struct rbnode *node; debug_decl(print_userspec_ldif, SUDOERS_DEBUG_UTIL) /* @@ -315,33 +396,13 @@ print_userspec_ldif(FILE *fp, struct userspec *us, const char *base) TAILQ_FOREACH(priv, &us->privileges, entries) { TAILQ_FOREACH_SAFE(cs, &priv->cmndlist, entries, next) { char *cn; - struct seen_user *su, key; /* * Increment the number of times we have seen this user. * If more than one user is listed, just use the first one. */ m = TAILQ_FIRST(&us->users); - key.name = m->name ? m->name : "ALL"; - node = rbfind(seen_users, &key); - if (node != NULL) { - su = node->data; - if (asprintf(&cn, "%s_%ld", key.name, su->count) == -1) - cn = NULL; - su->count++; - } else { - if ((su = malloc(sizeof(*su))) == NULL) { - sudo_fatalx(U_("%s: %s"), __func__, - U_("unable to allocate memory")); - } - su->name = key.name; - su->count = 1; - if (rbinsert(seen_users, su, NULL) != 0) { - sudo_fatalx(U_("%s: %s"), __func__, - U_("unable to allocate memory")); - } - cn = strdup(key.name); - } + cn = user_to_cn(m->name ? m->name : "ALL"); if (cn == NULL) { sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory")); @@ -422,7 +483,7 @@ convert_sudoers_ldif(const char *output_file, const char *base) warn_bound_defaults_ldif(output_fp); /* Clean up. */ - rbdestroy(seen_users, free); + rbdestroy(seen_users, seen_user_free); (void)fflush(output_fp); if (ferror(output_fp)) diff --git a/plugins/sudoers/regress/sudoers/test2.ldif.ok b/plugins/sudoers/regress/sudoers/test2.ldif.ok index 7550acc83..4c47b478e 100644 --- a/plugins/sudoers/regress/sudoers/test2.ldif.ok +++ b/plugins/sudoers/regress/sudoers/test2.ldif.ok @@ -84,10 +84,10 @@ sudoRunAsUser: root sudoCommand: ALL sudoOrder: 8 -dn: cn=%:C/non\'UNIX\'1 c,ou=SUDOers,dc=sudo,dc=ws +dn: cn=%:C/non\\'UNIX\\'1 c,ou=SUDOers,dc=sudo,dc=ws objectClass: top objectClass: sudoRole -cn: %:C/non\'UNIX\'1 c +cn: %:C/non\\'UNIX\\'1 c sudoUser: %:C/non\'UNIX\'1 c sudoHost: hostd sudoRunAsUser: root @@ -114,20 +114,20 @@ sudoRunAsUser: root sudoCommand: ALL sudoOrder: 11 -dn: cn=%:C/non\'UNIX_3 c,ou=SUDOers,dc=sudo,dc=ws +dn: cn=%:C/non\\'UNIX_3 c,ou=SUDOers,dc=sudo,dc=ws objectClass: top objectClass: sudoRole -cn: %:C/non\'UNIX_3 c +cn: %:C/non\\'UNIX_3 c sudoUser: %:C/non\'UNIX_3 c sudoHost: hostg sudoRunAsUser: root sudoCommand: ALL sudoOrder: 12 -dn: cn=+netgr,ou=SUDOers,dc=sudo,dc=ws +dn: cn=\+netgr,ou=SUDOers,dc=sudo,dc=ws objectClass: top objectClass: sudoRole -cn: +netgr +cn: \+netgr sudoUser: +netgr sudoHost: hosth sudoRunAsUser: root diff --git a/plugins/sudoers/regress/sudoers/test6.ldif.ok b/plugins/sudoers/regress/sudoers/test6.ldif.ok index b28159573..6703fa2a1 100644 --- a/plugins/sudoers/regress/sudoers/test6.ldif.ok +++ b/plugins/sudoers/regress/sudoers/test6.ldif.ok @@ -4,19 +4,19 @@ objectClass: sudoRole cn: defaults description: Default sudoOption's go here -dn: cn=#0,ou=SUDOers,dc=sudo,dc=ws +dn: cn=\#0,ou=SUDOers,dc=sudo,dc=ws objectClass: top objectClass: sudoRole -cn: #0 +cn: \#0 sudoUser: #0 sudoHost: ALL sudoCommand: ALL sudoOrder: 1 -dn: cn=#0_1,ou=SUDOers,dc=sudo,dc=ws +dn: cn=\#0_1,ou=SUDOers,dc=sudo,dc=ws objectClass: top objectClass: sudoRole -cn: #0_1 +cn: \#0_1 sudoUser: #0 sudoHost: ALL sudoRunAsUser: #0 @@ -24,19 +24,19 @@ sudoRunAsGroup: #0 sudoCommand: ALL sudoOrder: 2 -dn: cn=#0_2,ou=SUDOers,dc=sudo,dc=ws +dn: cn=\#0_2,ou=SUDOers,dc=sudo,dc=ws objectClass: top objectClass: sudoRole -cn: #0_2 +cn: \#0_2 sudoUser: #0 sudoHost: ALL sudoCommand: ALL sudoOrder: 3 -dn: cn=#0_3,ou=SUDOers,dc=sudo,dc=ws +dn: cn=\#0_3,ou=SUDOers,dc=sudo,dc=ws objectClass: top objectClass: sudoRole -cn: #0_3 +cn: \#0_3 sudoUser: #0 sudoHost: ALL sudoRunAsUser: #0 @@ -44,19 +44,19 @@ sudoRunAsGroup: #0 sudoCommand: ALL sudoOrder: 4 -dn: cn=%#0,ou=SUDOers,dc=sudo,dc=ws +dn: cn=%\#0,ou=SUDOers,dc=sudo,dc=ws objectClass: top objectClass: sudoRole -cn: %#0 +cn: %\#0 sudoUser: %#0 sudoHost: ALL sudoCommand: ALL sudoOrder: 5 -dn: cn=%#0_1,ou=SUDOers,dc=sudo,dc=ws +dn: cn=%\#0_1,ou=SUDOers,dc=sudo,dc=ws objectClass: top objectClass: sudoRole -cn: %#0_1 +cn: %\#0_1 sudoUser: %#0 sudoHost: ALL sudoCommand: ALL -- 2.40.0