From e430131d25c4404bd4daa6b1b954dbf4c01bc161 Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Fri, 8 Nov 2024 14:51:41 +0100 Subject: [PATCH] mod_authz_unixgroup: Use getgrouplist() instead of gr_mem for sssd compatibility Some services, like sssd, can optimize away grp->gr_mem which makes this module fail group lookup. Use getgrouplist(3) instead and gid_from_group(3bsd) which uses libbsd, link with -lbsd. This avoids the problematic getgrgid()/getgrnam() functions. --- .github/workflows/build.yml | 21 +++--- mod_authz_unixgroup/CONTRIBUTORS | 1 + mod_authz_unixgroup/INSTALL | 15 ++-- mod_authz_unixgroup/Makefile | 12 +++- mod_authz_unixgroup/mod_authz_unixgroup.c | 86 ++++++++++++++++++++++- 5 files changed, 119 insertions(+), 16 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cdbff0d..0807881 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,24 +17,29 @@ jobs: steps: - uses: actions/checkout@v2 - - name: install apache (ubuntu) + - name: install apache and libbsd (ubuntu) if: runner.os == 'Linux' - run: sudo apt-get install apache2 apache2-dev - - - name: install apache (macos) + run: sudo apt-get install apache2 apache2-dev libbsd-dev + + - name: install apache and libbsd (macos) if: runner.os == 'macOS' - run: brew install httpd - + run: | + # use latest master, not stable (until libbsd mac version is in stable) + brew developer on + # grab master version of libbsd with mac support + brew update + brew install httpd libbsd + - name: make mod_authnz_external (POSIX-GCC) if: runner.os != 'Windows' run: make working-directory: ./mod_authnz_external - + - name: make mod_authz_unixgroup (POSIX-GCC) if: runner.os != 'Windows' run: make working-directory: ./mod_authz_unixgroup - + - name: nmake (MSVC) if: runner.os == 'Windows' run: | diff --git a/mod_authz_unixgroup/CONTRIBUTORS b/mod_authz_unixgroup/CONTRIBUTORS index 1121dfd..cf3f2c0 100644 --- a/mod_authz_unixgroup/CONTRIBUTORS +++ b/mod_authz_unixgroup/CONTRIBUTORS @@ -12,3 +12,4 @@ mod_authz_unixgroup is based on code from the following sources: David Homborg klemens/ka7 Micah Andersen/Baptist International Missions, Inc. (micah@bimi.org) + Joakim Tjernlund/joakim-tjernlund (joakim.tjernlund@infinera.com) \ No newline at end of file diff --git a/mod_authz_unixgroup/INSTALL b/mod_authz_unixgroup/INSTALL index 46f1056..491e97f 100644 --- a/mod_authz_unixgroup/INSTALL +++ b/mod_authz_unixgroup/INSTALL @@ -42,12 +42,17 @@ Step 2: Compile the module using the following command in the mod_authz_unixgroup distribution directory: - apxs -c mod_authz_unixgroup.c + apxs -c mod_authz_unixgroup.c -lbsd - 'Apxs' is the Apache extension tool. It is part of the standard - Apache installation. If you don't have it, then your Apache server - is probably not set up for handling dynamically loaded modules. - This should create a file named 'mod_authz_unixgroup.so'. + * Build using just POSIX group interfaces: + apxs -c mod_authz_unixgroup.c -DUSE_POSIX_GRP + NOTE that some group providers (e.g sssd) can optionally omit gr_mem + in struct grp which will break POSIX API (in addition to being slower) + + * 'Apxs' is the Apache extension tool. It is part of the standard + Apache installation. If you don't have it, then your Apache server + is probably not set up for handling dynamically loaded modules. + This should create a file named 'mod_authz_unixgroup.so'. Step 3: Install the module. Apxs can do this for you too. Do the following diff --git a/mod_authz_unixgroup/Makefile b/mod_authz_unixgroup/Makefile index d4d08e7..4921f25 100644 --- a/mod_authz_unixgroup/Makefile +++ b/mod_authz_unixgroup/Makefile @@ -2,6 +2,10 @@ #APXS=apxs2 APXS=apxs +ifneq ($(OS),Windows_NT) + OS := $(shell uname -s) +endif + TAR= README INSTALL NOTICE CHANGES CONTRIBUTORS LICENSE \ mod_authz_unixgroup.c Makefile Makefile.win @@ -14,13 +18,17 @@ install: mod_authz_unixgroup.la build: mod_authz_unixgroup.la mod_authz_unixgroup.la: mod_authz_unixgroup.c - $(APXS) -c mod_authz_unixgroup.c + $(info REMINDER: This project requires libbsd and associated headers to compile and run. Please install any necessary development packages for your platform if you have not already. macOS users should install libbsd via homebrew.) +ifeq ($(OS),Darwin) + $(APXS) -I/opt/homebrew/opt/libbsd/include -c mod_authz_unixgroup.c +else + $(APXS) -c mod_authz_unixgroup.c -lbsd +endif clean: rm -rf mod_authz_unixgroup.so mod_authz_unixgroup.o \ mod_authz_unixgroup.la mod_authz_unixgroup.slo \ mod_authz_unixgroup.lo .libs - -ls -a .*.swp tar: mod_authz_unixgroup.tar diff --git a/mod_authz_unixgroup/mod_authz_unixgroup.c b/mod_authz_unixgroup/mod_authz_unixgroup.c index 43c9a0c..12630ec 100644 --- a/mod_authz_unixgroup/mod_authz_unixgroup.c +++ b/mod_authz_unixgroup/mod_authz_unixgroup.c @@ -20,7 +20,11 @@ #include #endif #if HAVE_GRP_H +#ifdef USE_POSIX_GRP #include +#else +#include +#endif #endif #if APR_HAVE_UNISTD_H #include @@ -41,7 +45,7 @@ APR_DECLARE_OPTIONAL_FN(char*, authz_owner_get_file_group, (request_rec *r)); * can either be unix group names or numeric group id numbers. There must * be a unix login corresponding to the named user. */ - +#ifdef USE_POSIX_GRP static int check_unix_group(request_rec *r, const char *grouplist) { char **p; @@ -112,6 +116,86 @@ static int check_unix_group(request_rec *r, const char *grouplist) if (at != NULL) *at= '@'; return 0; } +#else +#define MAX_USER_GRPS (4*1024) +static int check_unix_group(request_rec *r, const char *grouplist) +{ + char *user = r->user; + char *w, *at; + static gid_t groups[MAX_USER_GRPS], gid; + int ngroups = MAX_USER_GRPS, i; + + /* Strip @ sign and anything following it from the username. Some + * authentication modules, like mod_auth_kerb like appending such + * stuff to user names, but an @ sign is never legal in a unix login + * name, so it should be safe to always discard such stuff. + */ + if ((at = strchr(user, '@')) != NULL) *at = '\0'; + + /* Get info about login */ + struct passwd *pwd = getpwnam(user); + if (pwd == NULL) + { + /* No such user - forget it */ + if (at != NULL) *at = '@'; + return 0; + } + + if (getgrouplist(user, pwd->pw_gid, groups, &ngroups) < 0) + { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "Authorization of user %s to access %s failed. " + " getgrouplist(errno:%s).", + r->user, r->uri, strerror(errno)); + if (at != NULL) *at = '@'; + return 0; + } + /* Loop through list of allowed groups passed in */ + while (*grouplist != '\0') + { + w = ap_getword_conf(r->pool, &grouplist); + if (apr_isdigit(w[0])) + { + /* Numeric group id */ + gid = atoi(w); + } + else + { + /* Get gid and list of group members for group name */ + /* from libbsd */ + if (gid_from_group(w, &gid) < 0) + { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "Authorization of user %s to access %s failed. " + " gid_from_group(errno:%s).", + r->user, r->uri, strerror(errno)); + if (at != NULL) *at = '@'; + return 0; + } + } + /* Check if the user's primary group matches allowed group(s) */ + if (gid == pwd->pw_gid) + { + if (at != NULL) *at = '@'; + return 1; + } + + /* Walk through list of user's group(s), seeing if any match allowed group(s) */ + for (i = 0; i < ngroups; i++) + { + if (gid == groups[i]) + { + if (at != NULL) *at = '@'; + return 1; + } + } + } + + /* Didn't find any matches, flunk him */ + if (at != NULL) *at = '@'; + return 0; +} +#endif static authz_status unixgroup_check_authorization(request_rec *r, const char *require_args, const void *parsed_require_args)