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`; \
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));
}
#include "parse.h"
#include "redblack.h"
#include "cvtsudoers.h"
+#include "sudo_lbuf.h"
#include <gram.h>
struct seen_user {
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);
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.
/* 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);
/*
* TODO: use cn to create a UserAlias if multiple users in it?
- * TODO: add comment info based on cn?
*/
if (reuse_userspec) {
}
TAILQ_INIT(&us->privileges);
TAILQ_INIT(&us->users);
+ STAILQ_INIT(&us->comments);
STAILQ_FOREACH(ls, role->users, entries) {
char *user = ls->str;
}
}
+ /* 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),
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.
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"));
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))
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);
}
}
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));
+}
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);
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);
}
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)
}
}
break;
-#line 2092 "gram.c"
+#line 2099 "gram.c"
}
yyssp -= yym;
yystate = *yyssp;
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);
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);
}
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. */
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 {
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.
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;
};
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.
/* 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);
+# 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
+# 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
+
+# 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
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. */