Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ldap netgroup issues #251

Closed
mintyhippoxyz opened this issue Mar 6, 2023 · 12 comments
Closed

ldap netgroup issues #251

mintyhippoxyz opened this issue Mar 6, 2023 · 12 comments

Comments

@mintyhippoxyz
Copy link

I've been trying to get sudo setup on Alpine Linux with ldap auth.
I got it working for the most part but I'm having issues getting it to use netgroups.

Netgroups & sudoers are setup like this in ldap, which works with my Gentoo systems.

dn: cn=assist,ou=Netgroup,dc=example,dc=com
objectClass: nisNetgroup
objectClass: top
cn: assist
nisNetgroupTriple: (alpine-test,-,)
dn: cn=assist,ou=sudoers,dc=example,dc=com
objectClass: top
objectClass: sudoRole
cn: assist
sudoUser: %assist
sudoHost: +assist
sudoCommand: ALL

I've been compiling with these args
--with-pam --with-ldap --with-ldap-conf-file=/etc/ldap.conf.sudo

And I've tried both with and without nsswitch
--with-nsswitch=no
--with-nsswitch=/etc/nsswitch.conf.sudo (I didn't use the standard nsswitch.conf because musl-nscd gets a syntax error with sudoers: ldap)

ldap.conf.sudo

suffix dc=example,dc=com
host ldap.example.com
uri ldap://ldap.example.com
tls_cacertfile /etc/openldap/cacert.pem
tls_checkpeer no
port 389
ssl on
ssl start_tls
# tried w/ and w/o the netgroup_* options, see below
netgroup_base ou=Netgroup,dc=example,dc=com
netgroup_search_filter (objectClass=nisNetgroup)
sudoers_base ou=sudoers,dc=example,dc=com
sudoers_search_filter (objectClass=sudoRole)
sudoers_debug 1

nsswitch.conf.sudo

hosts: files dns
passwd: ldap
group: ldap
shadow: ldap
sudoers: ldap
netgroup: ldap

The filter in the "ldap search" debug output '(&(objectClass=sudoRole)(|(sudoUser=matta)... does get cn=assist,ou=sudoers,dc=example,dc=com in it's results, if that's helpful at all.

I do see this one debug difference on Gentoo

sudo: searching from base 'ou=sudoers,dc=example,dc=com'
sudo: adding search result
sudo: result now has 7 entries
sudo: ldap search '(&(objectClass=sudoRole)(|(sudoUser=+*)(sudoUser=!+*)))'
sudo: searching from base 'ou=sudoers,dc=example,dc=com'
sudo: adding search result
sudo: result now has 7 entries
sudo: sorting remaining 7 entries

Compared to Alpine

sudo: searching from base 'ou=sudoers,dc=example,dc=com'
sudo: adding search result
sudo: result now has 7 entries
sudo: sorting remaining 7 entries

Then this may be sending me in the wrong direction since I've never set it on Gentoo but I've noticed that when I set netgroup_base in ldap.conf.sudo I get some additional debug output that I don't see w/o it. It appears to append a filter that would only match if I set a username in the nisNetgroupTriple. I actually tried that to no avail as well.

sudo: Looking up netgroups for matta
sudo: ldap netgroup search filter: '(&(objectClass=nisNetgroup)(|(nisNetgroupTriple=\28*,matta,*\29)))'
sudo: searching from netgroup_base 'ou=Netgroup,dc=example,dc=com'
@millert
Copy link
Collaborator

millert commented Mar 7, 2023

There are two ways sudo's LDAP code can support netgroups for users.

  1. If netgroup_base is not set, sudo will perform an extra query for (&(objectClass=sudoRole)(|(sudoUser=+*)(sudoUser=!+*))) to get all the rules containing netgroups and iterate over the result using innetgr(3) to match the results to the user.
  2. If netgroup_base is set, sudo will do its own netgroup query to determine all the netgroups the user belongs to and include those in the main query. This only works for user netgroups, not host netgroups.

The matching of a host to a netgroup always uses the innetgr(3) C library function. That matching happens outside the LDAP code so you will need to configure a debug file in the /etc/sudo.conf file. For example:

Debug sudoers.so /var/log/sudoers_debug match@debug

would log debug info about user and host matches. The debug info you are looking for should be in the netgr_matches() function that looks like:

netgroup alpine-test matches (alpine-test|alpine-test.example.com, , example.com): true

or

netgroup alpine-test matches (alpine-test|alpine-test.example.com, , example.com): false

However, it doesn't look to me like musl libc supports the innetgr() function. If that is the case you won't see that output for netgr_matches().

@mintyhippoxyz
Copy link
Author

In both cases I get the same debug output when it comes across +assist

Mar  7 03:22:11.206 sudo[8979] host alpine-test (alpine-test) matches sudoers host +assist: false
Mar  7 03:22:11.206 sudo[8979] <- host_matches @ ./match.c:364 := -1
Mar  7 03:22:11.206 sudo[8979] <- hostlist_matches_int @ ./match.c:301 := -1
Mar  7 03:22:11.206 sudo[8979] -> hostlist_matches_int @ ./match.c:294
Mar  7 03:22:11.206 sudo[8979] -> host_matches @ ./match.c:328
Mar  7 03:22:11.206 sudo[8979] -> netgr_matches @ ./match.c:641
Mar  7 03:22:11.206 sudo[8979] netgroups are disabled
Mar  7 03:22:11.206 sudo[8979] <- netgr_matches @ ./match.c:645 := false

I think as far as I'm following things (knowing very little about c) I can see why without netgroup_base I don't see the (&(objectClass=sudoRole)(|(sudoUser=+*)(sudoUser=!+*))) query.

I should say, I do have a Buildroot system that I'm pretty sure uses musl libc and has sudo working with netgroups.

sudo: searching from base 'ou=sudoers,dc=example,dc=com'
sudo: adding search result
sudo: result now has 1 entries
sudo: ldap search '(&(objectClass=sudoRole)(sudoUser=*)(sudoUser=+*))'
sudo: searching from base 'ou=sudoers,dc=example,dc=com'
sudo: adding search result
sudo: result now has 1 entries
sudo: sorting remaining 1 entries
sudo: searching LDAP for sudoers entries
sudo: Command allowed
sudo: LDAP entry: 0x903ae10
sudo: done with LDAP searches
sudo: user_matches=true
sudo: host_matches=true
sudo: sudo_ldap_lookup(0)=0x02
Mar  6 22:16:43 sudo[11258] netgroup all matches (buildroot-host.example.com|buildroot-host, , ): true @ netgr_matches() ./match.c:998
Mar  6 22:16:43 sudo[11258] <- netgr_matches @ ./match.c:1001 := true
Mar  6 22:16:43 sudo[11258] -> addr_matches @ ./match_addr.c:195
Mar  6 22:16:43 sudo[11258] -> addr_matches_if @ ./match_addr.c:56
Mar  6 22:16:43 sudo[11258] <- addr_matches_if @ ./match_addr.c:66 := false

It's not using netgroup_base and I can see it running a slight variation of that query (&(objectClass=sudoRole)(sudoUser=*)(sudoUser=+*)), maybe due to being an older version (1.9.8p2)
Is there anything useful I could maybe gather from that system?

@millert
Copy link
Collaborator

millert commented Mar 7, 2023

I just checked my alpine build log:

checking for innetgr... no

So I don't think you can use host netgroups on that system.

@mintyhippoxyz
Copy link
Author

Alright, thanks for the clarification. At least it's not a deal breaking issue.

@mintyhippoxyz mintyhippoxyz closed this as not planned Won't fix, can't repro, duplicate, stale Mar 7, 2023
millert added a commit that referenced this issue Mar 10, 2023
Wheh netgroup_base is set we now do out own netgroup lookups using
LDAP.  Previously, LDAP was queried directly to get a list of the
netgroups the user belongs to but other netgroups queries went
through innetgr(3).  This makes it possible to use netgroups
in LDAP sudoers on systems that don't have an innetgr() function.
GitHub issue #251.
@mintyhippoxyz
Copy link
Author

Just noticed you've been putting in some work on supporting this. Wasn't expecting that but it's very much appreciated!
Maybe jumping the gun here but doesn't seem to be working yet compiling from git/main.
host alpine-test.example.com (alpine-test) matches sudoers host +assist: false
If there's any value I can add testing/debugging let me know.

@millert
Copy link
Collaborator

millert commented Mar 17, 2023

It should work if netgroup_base is set in sudo's ldap.conf file. If that doesn't work, you can enable debugging in either sudo.conf or ldap.conf to see the exact query sudo is using and try that with, e.g. the ldapsearch utility. For example, in my testing I get debug output like the following with sudoers_debug set to 2 in ldap.conf:

sudo: searching from netgroup_base 'ou=netgroup,dc=sudo,dc=ws'
sudo: ldap netgroup search filter: '(&(objectClass=nisNetgroup)(cn=sudo-hosts))'

With sudo.conf debugging there are more details (date strings removed for readability):

sudo[17435] -> sudo_ldap_innetgr_base @ ../../../trunk/plugins/sudoers/ldap_innetgr.c:148
sudo[17435] ldap netgroup search filter: '(&(objectClass=nisNetgroup)(cn=sudo-test-hosts))'
sudo[17435] searching from netgroup_base 'ou=netgroup,dc=sudo,dc=ws'
sudo[17435] -> sudo_ldap_innetgr_base @ ../../../trunk/plugins/sudoers/ldap_innetgr.c:148
sudo[17435] ldap netgroup search filter: '(&(objectClass=nisNetgroup)(cn=sudo-hosts))'
sudo[17435] searching from netgroup_base 'ou=netgroup,dc=sudo,dc=ws'
sudo[17435] -> sudo_ldap_match_netgroup @ ../../../trunk/plugins/sudoers/ldap_innetgr.c:98
sudo[17435] sudo_ldap_match_netgroup: matching (xerxes,,sudo.ws) against (xerxes,,)
sudo[17435] -> sudo_ldap_netgroup_match_str @ ../../../trunk/plugins/sudoers/ldap_innetgr.c:55
sudo[17435] sudo_ldap_netgroup_match_str: compare "xerxes" to "xerxes"
sudo[17435] <- sudo_ldap_netgroup_match_str @ ../../../trunk/plugins/sudoers/ldap_innetgr.c:80 := true
sudo[17435] -> sudo_ldap_netgroup_match_str @ ../../../trunk/plugins/sudoers/ldap_innetgr.c:55
sudo[17435] sudo_ldap_netgroup_match_str: compare "" to ""
sudo[17435] <- sudo_ldap_netgroup_match_str @ ../../../trunk/plugins/sudoers/ldap_innetgr.c:72 := true
sudo[17435] -> sudo_ldap_netgroup_match_str @ ../../../trunk/plugins/sudoers/ldap_innetgr.c:55
sudo[17435] sudo_ldap_netgroup_match_str: compare "sudo.ws" to ""
sudo[17435] <- sudo_ldap_netgroup_match_str @ ../../../trunk/plugins/sudoers/ldap_innetgr.c:72 := true
sudo[17435] <- sudo_ldap_match_netgroup @ ../../../trunk/plugins/sudoers/ldap_innetgr.c:130 := 1
sudo[17435] <- sudo_ldap_innetgr_base @ ../../../trunk/plugins/sudoers/ldap_innetgr.c:229 := 1

@mintyhippoxyz
Copy link
Author

Got netgroup_base defined.

It's still looking for a triple containing my username.

sudo: sudo_ldap_query: ldap search user matta, host alpine-test.example.com
sudo: Looking up netgroups for matta
sudo: ldap netgroup search filter: '(&(objectClass=nisNetgroup)(|(nisNetgroupTriple=\28*,matta,*\29)))'
sudo: searching from netgroup_base 'ou=Netgroup,dc=example,dc=com'

And I don't see any of the sudo_ldap_innetgr_base output in the sudoers_debug log like you have there.

@millert
Copy link
Collaborator

millert commented Mar 17, 2023

Your LDAP server may not support querying nisNetgroupTriple. OpenLDAP's slapd, for example, does not support that in their nis schema. The sudoers.ldap man page talk about this in the section on NETGROUP_BASE.

@mintyhippoxyz
Copy link
Author

Oh, yes, that does appear to be the case... I'm using OpenLDAP

attributetype ( 1.3.6.1.1.1.1.14 NAME 'nisNetgroupTriple'
        DESC 'Netgroup triple'
        SYNTAX 1.3.6.1.1.1.0.0 )

I'll look into changing that but does make me curious why it's never been a problem on Gentoo.

@millert
Copy link
Collaborator

millert commented Mar 17, 2023

If you are not using netgroup_base sudo will query all sudoRole objects where sudoUser starts with a '+' and then use the system innetgr() to determine whether the invoking user is a member. So it is just a different mechanism. It would be possible for sudo to do this itself but there would need to be another ldap.conf (or perhaps sudoOption) setting to enable it.

@mintyhippoxyz
Copy link
Author

Sadly the schema change seems to have made no difference. Must be some other weirdness with my setup or I'm just missing something.

Not sure if this is useful but out of curiosity I tried setting my username in the triple (alpine-test,matta,) and even that doesn't work. With that I do see something different sudo: ldap netgroup search filter: '(&(objectClass=nisNetgroup)(|(memberNisNetgroup=assist)))' but none of the sudo_ldap_innetgr_base debug info. From what you shared it looks like I should be seeing '(&(objectClass=nisNetgroup)(cn=assist))' instead.

@millert
Copy link
Collaborator

millert commented Jun 27, 2023

FYI, I think I found the issue with this on Alpine. The problem is that sudo checks for the innetgr() function and, if it doesn't exist, avoids compiling some of sudo's netgroup support. I changed that in 6fddb28 and have been able to do netgroup queries on Alpine using sudo's own LDAP netgroup code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants