From ae98617dfec77ea8392c9d44762c5beb26b68f86 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Sat, 8 Dec 2007 00:09:28 +0000 Subject: [PATCH] add -g support for LDAP --- ldap.c | 92 +++++++++++++++++++++++++++++++++++++++---------- schema.OpenLDAP | 14 +++++++- schema.iPlanet | 4 ++- sudoers2ldif | 20 ++++++++--- 4 files changed, 105 insertions(+), 25 deletions(-) diff --git a/ldap.c b/ldap.c index d3fd7bd57..c3d55331b 100644 --- a/ldap.c +++ b/ldap.c @@ -197,29 +197,21 @@ sudo_ldap_check_host(ld, entry) return(ret); } -/* - * Walk through search results and return TRUE if we have a runas match, - * else FALSE. - * Since the runas directive in /etc/sudoers is optional, so is sudoRunAs. - */ int -sudo_ldap_check_runas(ld, entry) +sudo_ldap_check_runas_user(ld, entry) LDAP *ld; LDAPMessage *entry; { char **v = NULL, **p = NULL; int ret = FALSE; - if (!entry) - return(ret); - - /* If no runas user, just check the group. */ - /* XXX - implement runas group checking via sudoRunasGroup */ if (!runas_pw) - return(TRUE); + return(UNSPEC); /* get the values from the entry */ - v = ldap_get_values(ld, entry, "sudoRunAs"); + v = ldap_get_values(ld, entry, "sudoRunAsUser"); + if (v == NULL) + v = ldap_get_values(ld, entry, "sudoRunAs"); /* backwards compat */ /* * BUG: @@ -267,7 +259,7 @@ sudo_ldap_check_runas(ld, entry) ret = TRUE; break; } - DPRINTF(("ldap sudoRunAs '%s' ... %s", *p, + DPRINTF(("ldap sudoRunAsUser '%s' ... %s", *p, ret ? "MATCH!" : "not"), 2); } @@ -277,6 +269,55 @@ sudo_ldap_check_runas(ld, entry) return(ret); } +int +sudo_ldap_check_runas_group(ld, entry) + LDAP *ld; + LDAPMessage *entry; +{ + char **v = NULL, **p = NULL; + int ret = FALSE; + + /* runas_gr is only set if the user specified the -g flag */ + if (!runas_gr) + return(UNSPEC); + + /* get the values from the entry */ + v = ldap_get_values(ld, entry, "sudoRunAsGroup"); + + /* walk through values returned, looking for a match */ + for (p = v; p && *p && !ret; p++) { + if (strcmp(*p, "ALL") == 0 || group_matches(*p, runas_gr)) + ret = TRUE; + DPRINTF(("ldap sudoRunAsGroup '%s' ... %s", *p, + ret ? "MATCH!" : "not"), 2); + } + + if (v) + ldap_value_free(v); /* cleanup */ + + return(ret); +} + +/* + * Walk through search results and return TRUE if we have a runas match, + * else FALSE. RunAs info is optional. + */ +int +sudo_ldap_check_runas(ld, entry) + LDAP *ld; + LDAPMessage *entry; +{ + int ret; + + if (!entry) + return(FALSE); + + ret = sudo_ldap_check_runas_user(ld, entry) != FALSE && + sudo_ldap_check_runas_group(ld, entry) != FALSE; + + return(ret); +} + /* * Walk through search results and return TRUE if we have a command match. */ @@ -812,16 +853,31 @@ sudo_ldap_display_privs(ldv, pw) ldap_value_free(v); } - /* get the RunAs Values from the entry */ - v = ldap_get_values(ld, entry, "sudoRunAs"); + /* get the RunAsUser Values from the entry */ + v = ldap_get_values(ld, entry, "sudoRunAsUser"); + if (v == NULL) + v = ldap_get_values(ld, entry, "sudoRunAs"); if (v != NULL) { - printf(" RunAs: ("); + fputs(" RunAsUsers: ", stdout); for (p = v; *p != NULL; p++) { if (p != v) fputs(", ", stdout); fputs(*p, stdout); } - puts(")"); + putchar('\n'); + ldap_value_free(v); + } + + /* get the RunAsGroup Values from the entry */ + v = ldap_get_values(ld, entry, "sudoRunAsGroup"); + if (v != NULL) { + fputs(" RunAsGroups: ", stdout); + for (p = v; *p != NULL; p++) { + if (p != v) + fputs(", ", stdout); + fputs(*p, stdout); + } + putchar('\n'); ldap_value_free(v); } diff --git a/schema.OpenLDAP b/schema.OpenLDAP index 3e2e6550f..5ae2104c8 100644 --- a/schema.OpenLDAP +++ b/schema.OpenLDAP @@ -35,9 +35,21 @@ attributetype ( 1.3.6.1.4.1.15953.9.1.5 EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) +attributetype ( 1.3.6.1.4.1.15953.9.1.6 + NAME 'sudoRunAsUser' + DESC 'User(s) impersonated by sudo' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.15953.9.1.7 + NAME 'sudoRunAsGroup' + DESC 'Group(s) impersonated by sudo' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + objectclass ( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' SUP top STRUCTURAL DESC 'Sudoer Entries' MUST ( cn ) - MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoOption $ + MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoRunAsUser $ sudoRunAsGroup $ sudoOption $ description ) ) diff --git a/schema.iPlanet b/schema.iPlanet index 879c2e967..a673c01aa 100644 --- a/schema.iPlanet +++ b/schema.iPlanet @@ -4,4 +4,6 @@ attributeTypes: ( 1.3.6.1.4.1.15953.9.1.2 NAME 'sudoHost' DESC 'Host(s) who may attributeTypes: ( 1.3.6.1.4.1.15953.9.1.3 NAME 'sudoCommand' DESC 'Command(s) to be executed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'SUDO' ) attributeTypes: ( 1.3.6.1.4.1.15953.9.1.4 NAME 'sudoRunAs' DESC 'User(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'SUDO' ) attributeTypes: ( 1.3.6.1.4.1.15953.9.1.5 NAME 'sudoOption' DESC 'Options(s) followed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'SUDO' ) -objectClasses: ( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' SUP top STRUCTURAL DESC 'Sudoer Entries' MUST ( cn ) MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoOption $ description ) X-ORIGIN 'SUDO' ) +attributeTypes: ( 1.3.6.1.4.1.15953.9.1.6 NAME 'sudoRunAsUser' DESC 'User(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'SUDO' ) +attributeTypes: ( 1.3.6.1.4.1.15953.9.1.7 NAME 'sudoRunAsGroup' DESC 'Group(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'SUDO' ) +objectClasses: ( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' SUP top STRUCTURAL DESC 'Sudoer Entries' MUST ( cn ) MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoRunAsUser $ sudoRunAsGroup $ sudoOption $ description ) X-ORIGIN 'SUDO' ) diff --git a/sudoers2ldif b/sudoers2ldif index b839235ea..4328cfcd8 100644 --- a/sudoers2ldif +++ b/sudoers2ldif @@ -14,9 +14,12 @@ use strict; # Does not yet escape + at the beginning of a dn # Does not yet handle line wraps correctly # Does not yet handle multiple roles with same name (needs tiebreaker) -# Sudoers entries can have multiple Runas entries that override former ones, -# with LDAP sudoRunas applies to all commands in a sudoRole +# +# CAVEATS: +# Sudoers entries can have multiple RunAs entries that override former ones, +# with LDAP sudoRunAs{Group,User} applies to all commands in a sudoRole +my %RA; my %UA; my %HA; my %CA; @@ -51,8 +54,10 @@ while (<>){ $p2=~s/\s+$//; # remove trailing whitespace $p3=~s/\s+$//; # remove trailing whitespace - if ($p1 eq "User_Alias") { + if ($p1 eq "User_Alias") { $UA{$p2}=$p3; + } elsif ($p1 eq "Runas_Alias") { + $RA{$p2}=$p3; } elsif ($p1 eq "Host_Alias") { $HA{$p2}=$p3; } elsif ($p1 eq "Cmnd_Alias") { @@ -80,10 +85,15 @@ while (<>){ # will clobber options print "sudoUser: $_\n" foreach expand(\%UA,@users); print "sudoHost: $_\n" foreach expand(\%HA,@hosts); - my $runas = undef; foreach (@cmds) { if (s/^\(([^\)]+)\)\s*//) { - print "sudoRunas: $_\n" foreach expand(\%UA, split(/,\s*/, $1)); + my @runas = split(/:\s*/, $1); + if (defined($runas[0])) { + print "sudoRunAsUser: $_\n" foreach expand(\%RA, split(/,\s*/, $runas[0])); + } + if (defined($runas[1])) { + print "sudoRunAsGroup: $_\n" foreach expand(\%RA, split(/,\s*/, $runas[1])); + } } } print "sudoCommand: $_\n" foreach expand(\%CA,@cmds);