]> andersk Git - nss_nonlocal.git/blobdiff - nonlocal-group.c
Guard one-time initialization with memory barriers
[nss_nonlocal.git] / nonlocal-group.c
index aa9c588a9342073bf6bf337f8d769594ff3eb8b4..9bbe156183ccb6db5bc2e325eb2641e866a0d1d6 100644 (file)
  */
 
 #define _GNU_SOURCE
+
 #include <sys/types.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
 #include <dlfcn.h>
-#include <stdio.h>
-#include <syslog.h>
 #include <errno.h>
 #include <grp.h>
 #include <nss.h>
+#include <pwd.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
 #include "nsswitch-internal.h"
 #include "nonlocal.h"
 
@@ -42,7 +45,8 @@
  * If the MAGIC_NONLOCAL_GROUPNAME local group exists, then nonlocal
  * users will be automatically added to it.  Furthermore, if a local
  * user is added to this group, then that user will inherit any
- * nonlocal supplementary gids from a nonlocal user of the same name.
+ * nonlocal gids from a nonlocal user of the same name, as
+ * supplementary gids.
  */
 #define MAGIC_NONLOCAL_GROUPNAME "nss-nonlocal-users"
 
  */
 #define MAGIC_LOCAL_GROUPNAME "nss-local-users"
 
+/*
+ * If the MAGIC_NONLOCAL_USERNAME local user is added to a local
+ * group, then the local group will inherit the nonlocal membership of
+ * a group of the same gid.
+ */
+#define MAGIC_NONLOCAL_USERNAME "nss-nonlocal-users"
+
 
 enum nss_status
 _nss_nonlocal_getgrnam_r(const char *name, struct group *grp,
@@ -82,7 +93,7 @@ __nss_group_nonlocal_lookup(service_user **ni, const char *fct_name,
 
 
 enum nss_status
-check_nonlocal_gid(const char *user, gid_t gid, int *errnop)
+check_nonlocal_gid(const char *user, const char *group, gid_t gid, int *errnop)
 {
     enum nss_status status;
     struct group gbuf;
@@ -97,15 +108,30 @@ check_nonlocal_gid(const char *user, gid_t gid, int *errnop)
 #include "walk_nss.h"
 #undef args
 
-    if (status == NSS_STATUS_SUCCESS) {
-       syslog(LOG_DEBUG, "nss_nonlocal: removing local group %u (%s) from non-local user %s\n", gbuf.gr_gid, gbuf.gr_name, user);
-       free(buf);
-       status = NSS_STATUS_NOTFOUND;
-    } else if (status != NSS_STATUS_TRYAGAIN) {
-       status = NSS_STATUS_SUCCESS;
+    if (status == NSS_STATUS_TRYAGAIN)
+       return status;
+    else if (status != NSS_STATUS_SUCCESS)
+       return NSS_STATUS_SUCCESS;
+
+    if (group == NULL || strcmp(gbuf.gr_name, group) == 0) {
+       char *const *mem;
+       for (mem = gbuf.gr_mem; *mem != NULL; mem++)
+           if (strcmp(*mem, MAGIC_NONLOCAL_USERNAME) == 0) {
+               status = check_nonlocal_user(*mem, errnop);
+               if (status == NSS_STATUS_TRYAGAIN) {
+                   free(buf);
+                   return status;
+               } else if (status == NSS_STATUS_NOTFOUND) {
+                   free(buf);
+                   return NSS_STATUS_SUCCESS;
+               }
+               break;
+           }
     }
 
-    return status;
+    syslog(LOG_DEBUG, "nss_nonlocal: removing local group %u (%s) from non-local user %s\n", gbuf.gr_gid, gbuf.gr_name, user);
+    free(buf);
+    return NSS_STATUS_NOTFOUND;
 }
 
 enum nss_status
@@ -120,13 +146,13 @@ check_nonlocal_group(const char *user, struct group *grp, int *errnop)
     gid = strtoul(grp->gr_name, &end, 10);
     if (errno == 0 && *end == '\0' && (gid_t)gid == gid) {
        errno = old_errno;
-       status = check_nonlocal_gid(user, gid, errnop);
+       status = check_nonlocal_gid(user, grp->gr_name, gid, errnop);
     } else
        errno = old_errno;
     if (status != NSS_STATUS_SUCCESS)
        return status;
 
-    return check_nonlocal_gid(user, grp->gr_gid, errnop);
+    return check_nonlocal_gid(user, grp->gr_name, grp->gr_gid, errnop);
 }
 
 enum nss_status
@@ -145,6 +171,7 @@ get_local_group(const char *name, struct group *grp, char **buffer, int *errnop)
     return status;
 }
 
+static bool grent_initialized = false;
 static service_user *grent_startp, *grent_nip;
 static void *grent_fct_start;
 static union {
@@ -169,9 +196,12 @@ _nss_nonlocal_setgrent(int stayopen)
     if (status != NSS_STATUS_SUCCESS)
        return status;
 
-    if (grent_fct_start == NULL)
+    if (!grent_initialized) {
        __nss_group_nonlocal_lookup(&grent_startp, grent_fct_name,
                                    &grent_fct_start);
+       __sync_synchronize();
+       grent_initialized = true;
+    }
     grent_nip = grent_startp;
     grent_fct.ptr = grent_fct_start;
     return NSS_STATUS_SUCCESS;
@@ -380,6 +410,29 @@ _nss_nonlocal_initgroups_dyn(const char *user, gid_t group, long int *start,
                    break;
                }
            }
+
+           if (is_nonlocal) {
+               struct passwd pwbuf;
+               char *buf;
+               int nonlocal_errno = *errnop;
+               status = get_nonlocal_passwd(user, &pwbuf, &buf, errnop);
+
+               if (status == NSS_STATUS_SUCCESS) {
+                   nonlocal_errno = *errnop;
+                   status = check_nonlocal_gid(user, NULL, pwbuf.pw_gid,
+                                               &nonlocal_errno);
+                   free(buf);
+               }
+
+               if (status == NSS_STATUS_SUCCESS) {
+                   if (!add_group(pwbuf.pw_gid, start, size, groupsp, limit,
+                                  errnop, &status))
+                       return status;
+               } else if (status == NSS_STATUS_TRYAGAIN) {
+                   *errnop = nonlocal_errno;
+                   return status;
+               }
+           }
        }
     } else if (status == NSS_STATUS_TRYAGAIN) {
        if (is_nonlocal)
@@ -409,7 +462,8 @@ _nss_nonlocal_initgroups_dyn(const char *user, gid_t group, long int *start,
        if (i < out)
            continue;
 
-       status = check_nonlocal_gid(user, (*groupsp)[in], &nonlocal_errno);
+       status = check_nonlocal_gid(user, NULL, (*groupsp)[in],
+                                   &nonlocal_errno);
        if (status == NSS_STATUS_SUCCESS) {
            (*groupsp)[out++] = (*groupsp)[in];
        } else if (status == NSS_STATUS_TRYAGAIN) {
This page took 0.190151 seconds and 4 git commands to generate.