]> andersk Git - nss_nonlocal.git/blobdiff - nonlocal-passwd.c
Replace recursive nss calls with explicit iteration over the nss chain.
[nss_nonlocal.git] / nonlocal-passwd.c
index 6d70ea2d287a871a46e938608c7646f5292600e4..2810e1676841406fe4dd1b5b7059d696bec1792c 100644 (file)
@@ -60,10 +60,17 @@ nss_passwd_nonlocal_database(void)
 enum nss_status
 check_nonlocal_uid(const char *user, uid_t uid, int *errnop)
 {
-    enum nss_status status = NSS_STATUS_SUCCESS;
+    static const char *fct_name = "getpwuid_r";
+    static service_user *startp = NULL;
+    static void *fct_start = NULL;
+    enum nss_status status;
+    service_user *nip;
+    union {
+       enum nss_status (*l)(uid_t uid, struct passwd *pwd,
+                            char *buffer, size_t buflen, int *errnop);
+       void *ptr;
+    } fct;
     struct passwd pwbuf;
-    struct passwd *pwbufp = &pwbuf;
-    int ret;
     int old_errno = errno;
     int buflen = MAGIC_LOCAL_PW_BUFLEN;
     char *buf = malloc(buflen);
@@ -72,26 +79,45 @@ check_nonlocal_uid(const char *user, uid_t uid, int *errnop)
        errno = old_errno;
        return NSS_STATUS_TRYAGAIN;
     }
-    ret = getpwuid_r(uid, pwbufp, buf, buflen, &pwbufp);
-    if (ret != 0) {
-       *errnop = errno;
-       status = NSS_STATUS_TRYAGAIN;
-    } else if (pwbufp != NULL) {
+
+    if (fct_start == NULL &&
+       __nss_passwd_lookup(&startp, fct_name, &fct_start) != 0) {
+       free(buf);
+       return NSS_STATUS_UNAVAIL;
+    }
+    nip = startp;
+    fct.ptr = fct_start;
+    do {
+       status = DL_CALL_FCT(fct.l, (uid, &pwbuf, buf, buflen, errnop));
+       if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
+           break;
+    } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
+
+    if (status == NSS_STATUS_SUCCESS) {
        syslog(LOG_ERR, "nss_nonlocal: possible spoofing attack: non-local user %s has same UID as local user %s!\n", user, pwbuf.pw_name);
        status = NSS_STATUS_NOTFOUND;
+    } else if (status != NSS_STATUS_TRYAGAIN) {
+       status = NSS_STATUS_SUCCESS;
     }
+
     free(buf);
-    errno = old_errno;
     return status;
 }
 
 enum nss_status
 check_nonlocal_user(const char *user, int *errnop)
 {
-    enum nss_status status = NSS_STATUS_SUCCESS;
+    static const char *fct_name = "getpwnam_r";
+    static service_user *startp = NULL;
+    static void *fct_start = NULL;
+    enum nss_status status;
+    service_user *nip;
+    union {
+       enum nss_status (*l)(const char *name, struct passwd *pwd,
+                            char *buffer, size_t buflen, int *errnop);
+       void *ptr;
+    } fct;
     struct passwd pwbuf;
-    struct passwd *pwbufp = &pwbuf;
-    int ret;
     int old_errno = errno;
     int buflen = MAGIC_LOCAL_PW_BUFLEN;
     char *buf = malloc(buflen);
@@ -100,15 +126,26 @@ check_nonlocal_user(const char *user, int *errnop)
        errno = old_errno;
        return NSS_STATUS_TRYAGAIN;
     }
-    ret = getpwnam_r(user, pwbufp, buf, buflen, &pwbufp);
-    if (ret != 0) {
-       *errnop = errno;
-       status = NSS_STATUS_TRYAGAIN;
-    } else if (pwbufp != NULL) {
-       status = NSS_STATUS_NOTFOUND;
+
+    if (fct_start == NULL &&
+       __nss_passwd_lookup(&startp, fct_name, &fct_start) != 0) {
+       free(buf);
+       return NSS_STATUS_UNAVAIL;
     }
+    nip = startp;
+    fct.ptr = fct_start;
+    do {
+       status = DL_CALL_FCT(fct.l, (user, &pwbuf, buf, buflen, errnop));
+       if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
+           break;
+    } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
+
+    if (status == NSS_STATUS_SUCCESS)
+       status = NSS_STATUS_NOTFOUND;
+    else if (status != NSS_STATUS_TRYAGAIN)
+       status = NSS_STATUS_SUCCESS;
+
     free(buf);
-    errno = old_errno;
     return status;
 }
 
This page took 0.086323 seconds and 4 git commands to generate.