mirror of
https://github.com/sudo-project/sudo.git
synced 2025-08-22 01:49:11 +00:00
Add ldif backend to cvtsudoers, to replace sudoers2ldif
This commit is contained in:
parent
7638e71730
commit
681fb2e76e
1
MANIFEST
1
MANIFEST
@ -266,6 +266,7 @@ plugins/sudoers/check.c
|
|||||||
plugins/sudoers/check.h
|
plugins/sudoers/check.h
|
||||||
plugins/sudoers/cvtsudoers.c
|
plugins/sudoers/cvtsudoers.c
|
||||||
plugins/sudoers/cvtsudoers_json.c
|
plugins/sudoers/cvtsudoers_json.c
|
||||||
|
plugins/sudoers/cvtsudoers_ldif.c
|
||||||
plugins/sudoers/def_data.c
|
plugins/sudoers/def_data.c
|
||||||
plugins/sudoers/def_data.h
|
plugins/sudoers/def_data.h
|
||||||
plugins/sudoers/def_data.in
|
plugins/sudoers/def_data.in
|
||||||
|
@ -17,12 +17,18 @@ DDEESSCCRRIIPPTTIIOONN
|
|||||||
The options are as follows:
|
The options are as follows:
|
||||||
|
|
||||||
--ff, ----ffoorrmmaatt
|
--ff, ----ffoorrmmaatt
|
||||||
Specify the output format. Currently, JSON is the only
|
Specify the output format. The following formats are
|
||||||
supported output format. The JSON format is intended to be
|
supported:
|
||||||
easier for third-party applications to parse than the
|
|
||||||
traditional _s_u_d_o_e_r_s format. The various values have explicit
|
JSON JSON (JavaScript Object Notation) files are usually
|
||||||
types which removes much of the ambiguity of the _s_u_d_o_e_r_s
|
easier for third-party applications to consume than
|
||||||
format.
|
the traditional _s_u_d_o_e_r_s format. The various values
|
||||||
|
have explicit types which removes much of the
|
||||||
|
ambiguity of the _s_u_d_o_e_r_s format.
|
||||||
|
|
||||||
|
LDIF LDIF (LDAP Data Interchange Format) files can be
|
||||||
|
imported into an LDAP server for use with
|
||||||
|
sudoers.ldap(4).
|
||||||
|
|
||||||
--hh, ----hheellpp Display a short help message to the standard output and exit.
|
--hh, ----hheellpp Display a short help message to the standard output and exit.
|
||||||
|
|
||||||
@ -35,7 +41,7 @@ DDEESSCCRRIIPPTTIIOONN
|
|||||||
Print the ccvvttssuuddooeerrss and _s_u_d_o_e_r_s grammar versions and exit.
|
Print the ccvvttssuuddooeerrss and _s_u_d_o_e_r_s grammar versions and exit.
|
||||||
|
|
||||||
SSEEEE AALLSSOO
|
SSEEEE AALLSSOO
|
||||||
sudoers(4), sudo(1m)
|
sudoers(4), sudoers.ldap(4), sudo(1m)
|
||||||
|
|
||||||
AAUUTTHHOORRSS
|
AAUUTTHHOORRSS
|
||||||
Many people have worked on ssuuddoo over the years; this version consists of
|
Many people have worked on ssuuddoo over the years; this version consists of
|
||||||
@ -63,4 +69,4 @@ DDIISSCCLLAAIIMMEERR
|
|||||||
file distributed with ssuuddoo or https://www.sudo.ws/license.html for
|
file distributed with ssuuddoo or https://www.sudo.ws/license.html for
|
||||||
complete details.
|
complete details.
|
||||||
|
|
||||||
Sudo 1.8.22 January 25, 2018 Sudo 1.8.22
|
Sudo 1.8.22 January 27, 2018 Sudo 1.8.22
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
.\"
|
.\"
|
||||||
.TH "CVTSUDOERS" "8" "January 25, 2018" "Sudo @PACKAGE_VERSION@" "System Manager's Manual"
|
.TH "CVTSUDOERS" "8" "January 27, 2018" "Sudo @PACKAGE_VERSION@" "System Manager's Manual"
|
||||||
.nh
|
.nh
|
||||||
.if n .ad l
|
.if n .ad l
|
||||||
.SH "NAME"
|
.SH "NAME"
|
||||||
@ -52,15 +52,30 @@ The options are as follows:
|
|||||||
.TP 12n
|
.TP 12n
|
||||||
\fB\-f\fR, \fB\--format\fR
|
\fB\-f\fR, \fB\--format\fR
|
||||||
Specify the output format.
|
Specify the output format.
|
||||||
Currently, JSON is the only supported output format.
|
The following formats are supported:
|
||||||
The JSON format is intended to be easier for third-party
|
.PP
|
||||||
applications to parse than the traditional
|
.RS 12n
|
||||||
|
.PD 0
|
||||||
|
.TP 10n
|
||||||
|
JSON
|
||||||
|
JSON (JavaScript Object Notation) files are usually easier for
|
||||||
|
third-party applications to consume than the traditional
|
||||||
\fIsudoers\fR
|
\fIsudoers\fR
|
||||||
format.
|
format.
|
||||||
The various values have explicit types which removes much of the
|
The various values have explicit types which removes much of the
|
||||||
ambiguity of the
|
ambiguity of the
|
||||||
\fIsudoers\fR
|
\fIsudoers\fR
|
||||||
format.
|
format.
|
||||||
|
.PD
|
||||||
|
.TP 10n
|
||||||
|
LDIF
|
||||||
|
LDIF (LDAP Data Interchange Format) files can be imported into an LDAP
|
||||||
|
server for use with
|
||||||
|
sudoers.ldap(@mansectform@).
|
||||||
|
.PD 0
|
||||||
|
.PP
|
||||||
|
.RE
|
||||||
|
.PD
|
||||||
.TP 12n
|
.TP 12n
|
||||||
\fB\-h\fR, \fB\--help\fR
|
\fB\-h\fR, \fB\--help\fR
|
||||||
Display a short help message to the standard output and exit.
|
Display a short help message to the standard output and exit.
|
||||||
@ -84,6 +99,7 @@ and
|
|||||||
grammar versions and exit.
|
grammar versions and exit.
|
||||||
.SH "SEE ALSO"
|
.SH "SEE ALSO"
|
||||||
sudoers(@mansectform@),
|
sudoers(@mansectform@),
|
||||||
|
sudoers.ldap(@mansectform@),
|
||||||
sudo(@mansectsu@)
|
sudo(@mansectsu@)
|
||||||
.SH "AUTHORS"
|
.SH "AUTHORS"
|
||||||
Many people have worked on
|
Many people have worked on
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
.\"
|
.\"
|
||||||
.Dd January 25, 2018
|
.Dd January 27, 2018
|
||||||
.Dt CVTSUDOERS @mansectsu@
|
.Dt CVTSUDOERS @mansectsu@
|
||||||
.Os Sudo @PACKAGE_VERSION@
|
.Os Sudo @PACKAGE_VERSION@
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -49,15 +49,22 @@ The options are as follows:
|
|||||||
.Bl -tag -width Fl
|
.Bl -tag -width Fl
|
||||||
.It Fl f , -format
|
.It Fl f , -format
|
||||||
Specify the output format.
|
Specify the output format.
|
||||||
Currently, JSON is the only supported output format.
|
The following formats are supported:
|
||||||
The JSON format is intended to be easier for third-party
|
.Bl -tag -width 8n
|
||||||
applications to parse than the traditional
|
.It JSON
|
||||||
|
JSON (JavaScript Object Notation) files are usually easier for
|
||||||
|
third-party applications to consume than the traditional
|
||||||
.Em sudoers
|
.Em sudoers
|
||||||
format.
|
format.
|
||||||
The various values have explicit types which removes much of the
|
The various values have explicit types which removes much of the
|
||||||
ambiguity of the
|
ambiguity of the
|
||||||
.Em sudoers
|
.Em sudoers
|
||||||
format.
|
format.
|
||||||
|
.It LDIF
|
||||||
|
LDIF (LDAP Data Interchange Format) files can be imported into an LDAP
|
||||||
|
server for use with
|
||||||
|
.Xr sudoers.ldap @mansectform@ .
|
||||||
|
.El
|
||||||
.It Fl h , -help
|
.It Fl h , -help
|
||||||
Display a short help message to the standard output and exit.
|
Display a short help message to the standard output and exit.
|
||||||
.It Fl o Ar output_file , Fl -output Ns = Ns Ar output_file
|
.It Fl o Ar output_file , Fl -output Ns = Ns Ar output_file
|
||||||
@ -80,6 +87,7 @@ grammar versions and exit.
|
|||||||
.El
|
.El
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr sudoers @mansectform@ ,
|
.Xr sudoers @mansectform@ ,
|
||||||
|
.Xr sudoers.ldap @mansectform@ ,
|
||||||
.Xr sudo @mansectsu@
|
.Xr sudo @mansectsu@
|
||||||
.Sh AUTHORS
|
.Sh AUTHORS
|
||||||
Many people have worked on
|
Many people have worked on
|
||||||
|
@ -161,7 +161,8 @@ SUDOERS_OBJS = $(AUTH_OBJS) boottime.lo check.lo editor.lo env.lo \
|
|||||||
|
|
||||||
VISUDO_OBJS = editor.o find_path.o goodpath.o locale.o stubs.o sudo_printf.o visudo.o
|
VISUDO_OBJS = editor.o find_path.o goodpath.o locale.o stubs.o sudo_printf.o visudo.o
|
||||||
|
|
||||||
CVTSUDOERS_OBJS = cvtsudoers.o cvtsudoers_json.o locale.o stubs.o sudo_printf.o
|
CVTSUDOERS_OBJS = cvtsudoers.o cvtsudoers_json.o cvtsudoers_ldif.o \
|
||||||
|
locale.o stubs.o sudo_printf.o
|
||||||
|
|
||||||
REPLAY_OBJS = getdate.o sudoreplay.o
|
REPLAY_OBJS = getdate.o sudoreplay.o
|
||||||
|
|
||||||
@ -705,6 +706,17 @@ cvtsudoers_json.o: $(srcdir)/cvtsudoers_json.c $(devdir)/def_data.h \
|
|||||||
$(srcdir)/sudoers_debug.h $(top_builddir)/config.h \
|
$(srcdir)/sudoers_debug.h $(top_builddir)/config.h \
|
||||||
$(top_builddir)/pathnames.h
|
$(top_builddir)/pathnames.h
|
||||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/cvtsudoers_json.c
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/cvtsudoers_json.c
|
||||||
|
cvtsudoers_ldif.o: $(srcdir)/cvtsudoers_ldif.c $(devdir)/def_data.h \
|
||||||
|
$(devdir)/gram.h $(incdir)/compat/stdbool.h \
|
||||||
|
$(incdir)/sudo_compat.h $(incdir)/sudo_conf.h \
|
||||||
|
$(incdir)/sudo_debug.h $(incdir)/sudo_fatal.h \
|
||||||
|
$(incdir)/sudo_gettext.h $(incdir)/sudo_plugin.h \
|
||||||
|
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
|
||||||
|
$(srcdir)/defaults.h $(srcdir)/logging.h $(srcdir)/parse.h \
|
||||||
|
$(srcdir)/sudo_nss.h $(srcdir)/sudoers.h \
|
||||||
|
$(srcdir)/sudoers_debug.h $(top_builddir)/config.h \
|
||||||
|
$(top_builddir)/pathnames.h
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/cvtsudoers_ldif.c
|
||||||
dce.lo: $(authdir)/dce.c $(devdir)/def_data.h $(incdir)/compat/stdbool.h \
|
dce.lo: $(authdir)/dce.c $(devdir)/def_data.h $(incdir)/compat/stdbool.h \
|
||||||
$(incdir)/sudo_compat.h $(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
|
$(incdir)/sudo_compat.h $(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
|
||||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
|
$(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
|
||||||
|
@ -50,6 +50,7 @@
|
|||||||
#endif /* HAVE_GETOPT_LONG */
|
#endif /* HAVE_GETOPT_LONG */
|
||||||
|
|
||||||
extern bool convert_sudoers_json(const char *output_file);
|
extern bool convert_sudoers_json(const char *output_file);
|
||||||
|
extern bool convert_sudoers_ldif(const char *output_file, const char *base);
|
||||||
extern void parse_sudoers_options(void);
|
extern void parse_sudoers_options(void);
|
||||||
extern void get_hostname(void);
|
extern void get_hostname(void);
|
||||||
|
|
||||||
@ -74,13 +75,19 @@ __dso_public int main(int argc, char *argv[]);
|
|||||||
static void help(void) __attribute__((__noreturn__));
|
static void help(void) __attribute__((__noreturn__));
|
||||||
static void usage(int);
|
static void usage(int);
|
||||||
|
|
||||||
|
enum output_formats {
|
||||||
|
output_invalid,
|
||||||
|
output_json,
|
||||||
|
output_ldif
|
||||||
|
};
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int ch, exitcode = EXIT_FAILURE;
|
int ch, exitcode = EXIT_FAILURE;
|
||||||
|
enum output_formats output_format = output_json;
|
||||||
const char *input_file = NULL;
|
const char *input_file = NULL;
|
||||||
const char *output_file = "-";
|
const char *output_file = "-";
|
||||||
const char *output_format = "JSON";
|
|
||||||
debug_decl(main, SUDOERS_DEBUG_MAIN)
|
debug_decl(main, SUDOERS_DEBUG_MAIN)
|
||||||
|
|
||||||
#if defined(SUDO_DEVEL) && defined(__OpenBSD__)
|
#if defined(SUDO_DEVEL) && defined(__OpenBSD__)
|
||||||
@ -119,11 +126,14 @@ main(int argc, char *argv[])
|
|||||||
while ((ch = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
|
while ((ch = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case 'f':
|
case 'f':
|
||||||
if (strcasecmp(optarg, "json") != 0) {
|
if (strcasecmp(optarg, "json") == 0) {
|
||||||
|
output_format = output_json;
|
||||||
|
} else if (strcasecmp(optarg, "ldif") == 0) {
|
||||||
|
output_format = output_ldif;
|
||||||
|
} else {
|
||||||
sudo_warnx("unsupported output format %s", optarg);
|
sudo_warnx("unsupported output format %s", optarg);
|
||||||
usage(1);
|
usage(1);
|
||||||
}
|
}
|
||||||
output_format = optarg;
|
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
help();
|
help();
|
||||||
@ -203,7 +213,16 @@ main(int argc, char *argv[])
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
exitcode = convert_sudoers_json(output_file) ? EXIT_SUCCESS : EXIT_FAILURE;
|
switch (output_format) {
|
||||||
|
case output_json:
|
||||||
|
exitcode = !convert_sudoers_json(output_file);
|
||||||
|
break;
|
||||||
|
case output_ldif:
|
||||||
|
exitcode = !convert_sudoers_ldif(output_file, NULL);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sudo_fatalx("error: unhandled output format %d", output_format);
|
||||||
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, exitcode);
|
sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, exitcode);
|
||||||
|
408
plugins/sudoers/cvtsudoers_ldif.c
Normal file
408
plugins/sudoers/cvtsudoers_ldif.c
Normal file
@ -0,0 +1,408 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Todd C. Miller <Todd.Miller@sudo.ws>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#ifdef HAVE_STRING_H
|
||||||
|
# include <string.h>
|
||||||
|
#endif /* HAVE_STRING_H */
|
||||||
|
#ifdef HAVE_STRINGS_H
|
||||||
|
# include <strings.h>
|
||||||
|
#endif /* HAVE_STRINGS_H */
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include "sudoers.h"
|
||||||
|
#include "parse.h"
|
||||||
|
#include "redblack.h"
|
||||||
|
#include <gram.h>
|
||||||
|
|
||||||
|
struct seen_user {
|
||||||
|
const char *name;
|
||||||
|
long count;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int sudo_order;
|
||||||
|
static struct rbtree *seen_users;
|
||||||
|
|
||||||
|
static int
|
||||||
|
seen_user_compare(const void *aa, const void *bb)
|
||||||
|
{
|
||||||
|
const struct seen_user *a = aa;
|
||||||
|
const struct seen_user *b = bb;
|
||||||
|
|
||||||
|
return strcasecmp(a->name, b->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print global Defaults in a single sudoRole object.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
print_global_defaults_ldif(FILE *fp, const char *base)
|
||||||
|
{
|
||||||
|
struct defaults *def;
|
||||||
|
debug_decl(print_global_defaults_ldif, SUDOERS_DEBUG_UTIL)
|
||||||
|
|
||||||
|
if (TAILQ_EMPTY(&defaults))
|
||||||
|
debug_return_bool(true);
|
||||||
|
|
||||||
|
fprintf(fp, "dn: cn=defaults,%s\n", base);
|
||||||
|
fputs("objectClass: top\n", fp);
|
||||||
|
fputs("objectClass: sudoRole\n", fp);
|
||||||
|
fputs("cn: defaults\n", fp);
|
||||||
|
fputs("description: Default sudoOption's go here\n", fp);
|
||||||
|
|
||||||
|
TAILQ_FOREACH(def, &defaults, entries) {
|
||||||
|
if (def->type != DEFAULTS)
|
||||||
|
continue; /* only want global defaults */
|
||||||
|
|
||||||
|
if (def->val != NULL) {
|
||||||
|
/* There is no need to double quote values here. */
|
||||||
|
fprintf(fp, "sudoOption: %s%s%s\n", def->var,
|
||||||
|
def->op == '+' ? "+=" : def->op == '-' ? "-=" : "=", def->val);
|
||||||
|
} else {
|
||||||
|
/* Boolean flag. */
|
||||||
|
fprintf(fp, "sudoOption: %s%s\n", def->op == false ? "!" : "",
|
||||||
|
def->var);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
putc('\n', fp);
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
print_member_ldif(FILE *fp, char *name, int type, int negated,
|
||||||
|
int alias_type, const char *prefix)
|
||||||
|
{
|
||||||
|
struct alias *a;
|
||||||
|
struct member *m;
|
||||||
|
struct sudo_command *c;
|
||||||
|
debug_decl(print_member_ldif, SUDOERS_DEBUG_UTIL)
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case ALL:
|
||||||
|
fprintf(fp, "%s: %sALL\n", prefix, negated ? "!" : "");
|
||||||
|
break;
|
||||||
|
case MYSELF:
|
||||||
|
/* Only valid for sudoRunasUser */
|
||||||
|
fprintf(fp, "%s:\n", prefix);
|
||||||
|
break;
|
||||||
|
case COMMAND:
|
||||||
|
c = (struct sudo_command *)name;
|
||||||
|
fprintf(fp, "%s: ", prefix);
|
||||||
|
if (c->digest != NULL)
|
||||||
|
fprintf(fp, "%s:", digest_type_to_name(c->digest->digest_type));
|
||||||
|
fprintf(fp, "%s%s", negated ? "!" : "", c->cmnd);
|
||||||
|
if (c->args != NULL)
|
||||||
|
fprintf(fp, " %s", c->args);
|
||||||
|
putc('\n', fp);
|
||||||
|
break;
|
||||||
|
case ALIAS:
|
||||||
|
if ((a = alias_get(name, alias_type)) != NULL) {
|
||||||
|
TAILQ_FOREACH(m, &a->members, entries) {
|
||||||
|
print_member_ldif(fp, m->name, m->type,
|
||||||
|
negated ? !m->negated : m->negated, alias_type, prefix);
|
||||||
|
}
|
||||||
|
alias_put(a);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
default:
|
||||||
|
fprintf(fp, "%s: %s%s\n", prefix, negated ? "!" : "", name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print a Cmnd_Spec in LDIF format.
|
||||||
|
* A pointer to the next Cmnd_Spec is passed in to make it possible to
|
||||||
|
* merge adjacent entries that are identical in all but the command.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
print_cmndspec_ldif(FILE *fp, struct cmndspec *cs, struct cmndspec **nextp)
|
||||||
|
{
|
||||||
|
struct cmndspec *next = *nextp;
|
||||||
|
struct member *m;
|
||||||
|
bool last_one;
|
||||||
|
debug_decl(print_cmndspec_ldif, SUDOERS_DEBUG_UTIL)
|
||||||
|
|
||||||
|
/* Print runasuserlist as sudoRunAsUser attributes */
|
||||||
|
if (cs->runasuserlist != NULL) {
|
||||||
|
TAILQ_FOREACH(m, cs->runasuserlist, entries) {
|
||||||
|
print_member_ldif(fp, m->name, m->type, m->negated,
|
||||||
|
RUNASALIAS, "sudoRunAsUser");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print runasgrouplist as sudoRunAsGroup attributes */
|
||||||
|
if (cs->runasgrouplist != NULL) {
|
||||||
|
TAILQ_FOREACH(m, cs->runasgrouplist, entries) {
|
||||||
|
print_member_ldif(fp, m->name, m->type, m->negated,
|
||||||
|
RUNASALIAS, "sudoRunAsGroup");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print tags as sudoOption attributes */
|
||||||
|
if (cs->timeout > 0 || TAGS_SET(cs->tags)) {
|
||||||
|
struct cmndtag tag = cs->tags;
|
||||||
|
|
||||||
|
if (cs->timeout > 0) {
|
||||||
|
fprintf(fp, "sudoOption: command_timeout=%d\n", cs->timeout);
|
||||||
|
}
|
||||||
|
if (tag.nopasswd != UNSPEC) {
|
||||||
|
fprintf(fp, "sudoOption: %sauthenticate\n", tag.nopasswd ? "!" : "");
|
||||||
|
}
|
||||||
|
if (tag.noexec != UNSPEC) {
|
||||||
|
fprintf(fp, "sudoOption: %snoexec\n", tag.noexec ? "" : "!");
|
||||||
|
}
|
||||||
|
if (tag.send_mail != UNSPEC) {
|
||||||
|
if (tag.send_mail) {
|
||||||
|
fprintf(fp, "sudoOption: mail_all_cmnds\n");
|
||||||
|
} else {
|
||||||
|
fprintf(fp, "sudoOption: !mail_all_cmnds\n");
|
||||||
|
fprintf(fp, "sudoOption: !mail_always\n");
|
||||||
|
fprintf(fp, "sudoOption: !mail_no_perms\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tag.setenv != UNSPEC && tag.setenv != IMPLIED) {
|
||||||
|
fprintf(fp, "sudoOption: %ssetenv\n", tag.setenv ? "" : "!");
|
||||||
|
}
|
||||||
|
if (tag.follow != UNSPEC) {
|
||||||
|
fprintf(fp, "sudoOption: %ssudoedit_follow\n", tag.follow ? "" : "!");
|
||||||
|
}
|
||||||
|
if (tag.log_input != UNSPEC) {
|
||||||
|
fprintf(fp, "sudoOption: %slog_input\n", tag.log_input ? "" : "!");
|
||||||
|
}
|
||||||
|
if (tag.log_output != UNSPEC) {
|
||||||
|
fprintf(fp, "sudoOption: %slog_output\n", tag.log_output ? "" : "!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_SELINUX
|
||||||
|
/* Print SELinux role/type */
|
||||||
|
if (cs->role != NULL && cs->type != NULL) {
|
||||||
|
fprintf(fp, "sudoOption: role=%s\n", cs->role);
|
||||||
|
fprintf(fp, "sudoOption: type=%s\n", cs->type);
|
||||||
|
}
|
||||||
|
#endif /* HAVE_SELINUX */
|
||||||
|
|
||||||
|
#ifdef HAVE_PRIV_SET
|
||||||
|
/* Print Solaris privs/limitprivs */
|
||||||
|
if (cs->privs != NULL || cs->limitprivs != NULL) {
|
||||||
|
if (cs->privs != NULL)
|
||||||
|
fprintf(fp, "sudoOption: privs=%s\n", cs->privs);
|
||||||
|
if (cs->limitprivs != NULL)
|
||||||
|
fprintf(fp, "sudoOption: limitprivs=%s\n", cs->limitprivs);
|
||||||
|
}
|
||||||
|
#endif /* HAVE_PRIV_SET */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Merge adjacent commands with matching tags, runas, SELinux
|
||||||
|
* role/type and Solaris priv settings.
|
||||||
|
*/
|
||||||
|
for (;;) {
|
||||||
|
/* Does the next entry differ only in the command itself? */
|
||||||
|
/* XXX - move into a function that returns bool */
|
||||||
|
/* XXX - TAG_SET does not account for implied SETENV */
|
||||||
|
last_one = next == NULL ||
|
||||||
|
RUNAS_CHANGED(cs, next) || TAGS_CHANGED(cs->tags, next->tags)
|
||||||
|
#ifdef HAVE_PRIV_SET
|
||||||
|
|| cs->privs != next->privs || cs->limitprivs != next->limitprivs
|
||||||
|
#endif /* HAVE_PRIV_SET */
|
||||||
|
#ifdef HAVE_SELINUX
|
||||||
|
|| cs->role != next->role || cs->type != next->type
|
||||||
|
#endif /* HAVE_SELINUX */
|
||||||
|
;
|
||||||
|
|
||||||
|
print_member_ldif(fp, cs->cmnd->name, cs->cmnd->type, cs->cmnd->negated,
|
||||||
|
CMNDALIAS, "sudoCommand");
|
||||||
|
if (last_one)
|
||||||
|
break;
|
||||||
|
cs = next;
|
||||||
|
next = TAILQ_NEXT(cs, entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
*nextp = next;
|
||||||
|
|
||||||
|
debug_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print a single User_Spec.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
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)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Each userspec struct may contain multiple privileges for
|
||||||
|
* the user. We export each privilege as a separate sudoRole
|
||||||
|
* object for simplicity's sake.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
if (cn == NULL) {
|
||||||
|
sudo_fatalx(U_("%s: %s"), __func__,
|
||||||
|
U_("unable to allocate memory"));
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(fp, "dn: cn=%s,%s\n", cn, base);
|
||||||
|
fprintf(fp, "objectClass: top\n");
|
||||||
|
fprintf(fp, "objectClass: sudoRole\n");
|
||||||
|
fprintf(fp, "cn: %s\n", cn);
|
||||||
|
free(cn);
|
||||||
|
|
||||||
|
TAILQ_FOREACH(m, &us->users, entries) {
|
||||||
|
print_member_ldif(fp, m->name, m->type, m->negated,
|
||||||
|
USERALIAS, "sudoUser");
|
||||||
|
}
|
||||||
|
|
||||||
|
TAILQ_FOREACH(m, &priv->hostlist, entries) {
|
||||||
|
print_member_ldif(fp, m->name, m->type, m->negated,
|
||||||
|
HOSTALIAS, "sudoHost");
|
||||||
|
}
|
||||||
|
|
||||||
|
print_cmndspec_ldif(fp, cs, &next);
|
||||||
|
|
||||||
|
fprintf(fp, "sudoOrder: %d\n\n", ++sudo_order);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_return_bool(!ferror(fp));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print User_Specs.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
print_userspecs_ldif(FILE *fp, const char *base)
|
||||||
|
{
|
||||||
|
struct userspec *us;
|
||||||
|
debug_decl(print_userspecs_ldif, SUDOERS_DEBUG_UTIL)
|
||||||
|
|
||||||
|
TAILQ_FOREACH(us, &userspecs, entries) {
|
||||||
|
if (!print_userspec_ldif(fp, us, base))
|
||||||
|
debug_return_bool(false);
|
||||||
|
}
|
||||||
|
debug_return_bool(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Export the parsed sudoers file in LDIF format.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
convert_sudoers_ldif(const char *output_file, const char *base)
|
||||||
|
{
|
||||||
|
bool ret = true;
|
||||||
|
FILE *output_fp = stdout;
|
||||||
|
debug_decl(convert_sudoers_ldif, SUDOERS_DEBUG_UTIL)
|
||||||
|
|
||||||
|
if (base == NULL) {
|
||||||
|
base = getenv("SUDOERS_BASE");
|
||||||
|
if (base == NULL)
|
||||||
|
sudo_fatalx(U_("The SUDOERS_BASE environment variable is not set"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(output_file, "-") != 0) {
|
||||||
|
if ((output_fp = fopen(output_file, "w")) == NULL)
|
||||||
|
sudo_fatal(U_("unable to open %s"), output_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a dictionary of already-seen users. */
|
||||||
|
seen_users = rbcreate(seen_user_compare);
|
||||||
|
|
||||||
|
/* Dump global Defaults in LDIF format. */
|
||||||
|
print_global_defaults_ldif(output_fp, base);
|
||||||
|
|
||||||
|
/* Dump User_Specs in LDIF format, expanding Aliases. */
|
||||||
|
print_userspecs_ldif(output_fp, base);
|
||||||
|
|
||||||
|
/* Warn about non-translatable Defaults entries. */
|
||||||
|
warn_bound_defaults_ldif(output_fp);
|
||||||
|
|
||||||
|
/* Clean up. */
|
||||||
|
rbdestroy(seen_users, free);
|
||||||
|
|
||||||
|
(void)fflush(output_fp);
|
||||||
|
if (ferror(output_fp))
|
||||||
|
ret = false;
|
||||||
|
if (output_fp != stdout)
|
||||||
|
fclose(output_fp);
|
||||||
|
|
||||||
|
debug_return_bool(ret);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user