summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNalin Dahyabhai <nalin@dahyabhai.net>2013-08-08 15:16:26 -0400
committerNalin Dahyabhai <nalin@dahyabhai.net>2013-08-12 15:43:32 -0400
commit542b845f4b8b477251d26af6f857de5bfeb2c90e (patch)
treeee85bae9aeb8db247d2885dc96c416b4ede59de6
parentd9dd2ee29fd5430e73ce12d62291ae75abdcedca (diff)
downloadslapi-nis-542b845f4b8b477251d26af6f857de5bfeb2c90e.tar.gz
slapi-nis-542b845f4b8b477251d26af6f857de5bfeb2c90e.tar.xz
slapi-nis-542b845f4b8b477251d26af6f857de5bfeb2c90e.zip
Shoehorn in some nsswitch wrappers
-rw-r--r--tests/Makefile.am8
-rw-r--r--tests/wrap-nsswitch.c366
-rw-r--r--tests/wrap-pam.c210
3 files changed, 584 insertions, 0 deletions
diff --git a/tests/Makefile.am b/tests/Makefile.am
index f2d7638..9264902 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,4 +1,12 @@
SUBDIRS = clients
+
+noinst_PROGRAMS = wrappers.so
+wrappers_so_SOURCES = wrap-nsswitch.c wrap-pam.c
+wrappers_so_CFLAGS = $(AM_CFLAGS) -fPIC
+wrappers_so_LDADD = -ldl
+wrappers_so_LDFLAGS = -shared
+wrappers_so_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(wrappers_so_LDFLAGS) $(LDFLAGS) -o $@
+
EXTRA_DIST = run-tests.sh test*/*.ldif test*/*.sh test*/*.txt config/slapd-collations.conf config/userRoot.ldif config/schema *.supp
if CAN_TEST
check:
diff --git a/tests/wrap-nsswitch.c b/tests/wrap-nsswitch.c
new file mode 100644
index 0000000..23ce89a
--- /dev/null
+++ b/tests/wrap-nsswitch.c
@@ -0,0 +1,366 @@
+/*
+ * Copyright 2013 Red Hat, Inc.
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this Program; if not, write to the
+ *
+ * Free Software Foundation, Inc.
+ * 59 Temple Place, Suite 330
+ * Boston, MA 02111-1307 USA
+ *
+ */
+#define _GNU_SOURCE
+
+#include <sys/types.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <grp.h>
+#include <nss.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+int
+getpwnam_r(const char *name,
+ struct passwd *resultbuf,
+ char *buffer, size_t buflen,
+ struct passwd **result)
+{
+ FILE *fp;
+ static int (*next)(const char *, struct passwd *,
+ char *, size_t,
+ struct passwd **);
+ int error;
+
+ if (next == NULL) {
+ next = dlsym(RTLD_NEXT, "getpwnam_r");
+ }
+ if ((getenv("WRAPPERS_PASSWD") != NULL) &&
+ ((fp = fopen(getenv("WRAPPERS_PASSWD"), "r")) != NULL)) {
+ while ((error = fgetpwent_r(fp, resultbuf,
+ buffer, buflen, result)) == 0) {
+ if (strcmp(name, resultbuf->pw_name) == 0) {
+ fclose(fp);
+ return 0;
+ }
+ }
+ fclose(fp);
+ if ((error != 0) && (error != ENOENT)) {
+ return error;
+ }
+ }
+ return (*next)(name, resultbuf, buffer, buflen, result);
+}
+
+struct passwd *
+getpwnam(const char *name)
+{
+ static struct passwd * (*next)(const char *);
+ static struct passwd pwd, *pwdp;
+ static char *buffer;
+ static size_t buflen = 16;
+
+ if (next == NULL) {
+ next = dlsym(RTLD_NEXT, "getpwnam");
+ }
+ if (buffer == NULL) {
+ buffer = malloc(buflen);
+ }
+ if (buffer != NULL) {
+ retry:
+ switch (getpwnam_r(name, &pwd, buffer, buflen, &pwdp)) {
+ case 0:
+ return &pwd;
+ break;
+ case ERANGE:
+ free(buffer);
+ buffer = malloc((buflen + 1) * 2);
+ if (buffer != NULL) {
+ buflen = ((buflen + 1) * 2);
+ goto retry;
+ }
+ errno = ERANGE;
+ return NULL;
+ break;
+ }
+ }
+ if (next == NULL) {
+ errno = ENOSYS;
+ return NULL;
+ }
+ return (*next)(name);
+}
+
+int
+getpwuid_r(uid_t uid,
+ struct passwd *resultbuf,
+ char *buffer, size_t buflen,
+ struct passwd **result)
+{
+ FILE *fp;
+ static int (*next)(uid_t, struct passwd *,
+ char *, size_t,
+ struct passwd **);
+ int error;
+
+ if (next == NULL) {
+ next = dlsym(RTLD_NEXT, "getpwuid_r");
+ }
+ if ((getenv("WRAPPERS_PASSWD") != NULL) &&
+ ((fp = fopen(getenv("WRAPPERS_PASSWD"), "r")) != NULL)) {
+ while ((error = fgetpwent_r(fp, resultbuf,
+ buffer, buflen, result)) == 0) {
+ if (resultbuf->pw_uid == uid) {
+ fclose(fp);
+ return 0;
+ }
+ }
+ fclose(fp);
+ if ((error != 0) && (error != ENOENT)) {
+ return error;
+ }
+ }
+ return (*next)(uid, resultbuf, buffer, buflen, result);
+}
+
+struct passwd *
+getpwuid(uid_t uid)
+{
+ static struct passwd * (*next)(uid_t);
+ static struct passwd pwd, *pwdp;
+ static char *buffer;
+ static size_t buflen = 16;
+
+ if (next == NULL) {
+ next = dlsym(RTLD_NEXT, "getpwuid");
+ }
+ if (buffer == NULL) {
+ buffer = malloc(buflen);
+ }
+ if (buffer != NULL) {
+ retry:
+ switch (getpwuid_r(uid, &pwd, buffer, buflen, &pwdp)) {
+ case 0:
+ return &pwd;
+ break;
+ case ERANGE:
+ free(buffer);
+ buffer = malloc((buflen + 1) * 2);
+ if (buffer != NULL) {
+ buflen = ((buflen + 1) * 2);
+ goto retry;
+ }
+ errno = ERANGE;
+ return NULL;
+ break;
+ }
+ }
+ if (next == NULL) {
+ errno = ENOSYS;
+ return NULL;
+ }
+ return (*next)(uid);
+}
+
+int
+getgrnam_r(const char *name,
+ struct group *resultbuf,
+ char *buffer, size_t buflen,
+ struct group **result)
+{
+ FILE *fp;
+ static int (*next)(const char *, struct group *,
+ char *, size_t,
+ struct group **);
+ int error;
+
+ if (next == NULL) {
+ next = dlsym(RTLD_NEXT, "getgrnam_r");
+ }
+ if ((getenv("WRAPPERS_GROUP") != NULL) &&
+ ((fp = fopen(getenv("WRAPPERS_GROUP"), "r")) != NULL)) {
+ while ((error = fgetgrent_r(fp, resultbuf,
+ buffer, buflen, result)) == 0) {
+ if (strcmp(name, resultbuf->gr_name) == 0) {
+ fclose(fp);
+ return 0;
+ }
+ }
+ fclose(fp);
+ if ((error != 0) && (error != ENOENT)) {
+ return error;
+ }
+ }
+ return (*next)(name, resultbuf, buffer, buflen, result);
+}
+
+struct group *
+getgrnam(const char *name)
+{
+ static struct group * (*next)(const char *);
+ static struct group grp, *grpp;
+ static char *buffer;
+ static size_t buflen = 16;
+
+ if (next == NULL) {
+ next = dlsym(RTLD_NEXT, "getgrnam");
+ }
+ if (buffer == NULL) {
+ buffer = malloc(buflen);
+ }
+ if (buffer != NULL) {
+ retry:
+ switch (getgrnam_r(name, &grp, buffer, buflen, &grpp)) {
+ case 0:
+ return &grp;
+ break;
+ case ERANGE:
+ free(buffer);
+ buffer = malloc((buflen + 1) * 2);
+ if (buffer != NULL) {
+ buflen = ((buflen + 1) * 2);
+ goto retry;
+ }
+ errno = ERANGE;
+ return NULL;
+ break;
+ }
+ }
+ if (next == NULL) {
+ errno = ENOSYS;
+ return NULL;
+ }
+ return (*next)(name);
+}
+
+int
+getgrgid_r(gid_t gid,
+ struct group *resultbuf,
+ char *buffer, size_t buflen,
+ struct group **result)
+{
+ FILE *fp;
+ static int (*next)(gid_t, struct group *,
+ char *, size_t,
+ struct group **);
+ int error;
+
+ if (next == NULL) {
+ next = dlsym(RTLD_NEXT, "getgrgid_r");
+ }
+ if ((getenv("WRAPPERS_GROUP") != NULL) &&
+ ((fp = fopen(getenv("WRAPPERS_GROUP"), "r")) != NULL)) {
+ while ((error = fgetgrent_r(fp, resultbuf,
+ buffer, buflen, result)) == 0) {
+ if (resultbuf->gr_gid == gid) {
+ fclose(fp);
+ return 0;
+ }
+ }
+ fclose(fp);
+ if ((error != 0) && (error != ENOENT)) {
+ return error;
+ }
+ }
+ return (*next)(gid, resultbuf, buffer, buflen, result);
+}
+
+struct group *
+getgrgid(gid_t gid)
+{
+ static struct group * (*next)(gid_t);
+ static struct group grp, *grpp;
+ static char *buffer;
+ static size_t buflen = 16;
+
+ if (next == NULL) {
+ next = dlsym(RTLD_NEXT, "getgrgid");
+ }
+ if (buffer == NULL) {
+ buffer = malloc(buflen);
+ }
+ if (buffer != NULL) {
+ retry:
+ switch (getgrgid_r(gid, &grp, buffer, buflen, &grpp)) {
+ case 0:
+ return &grp;
+ break;
+ case ERANGE:
+ free(buffer);
+ buffer = malloc((buflen + 1) * 2);
+ if (buffer != NULL) {
+ buflen = ((buflen + 1) * 2);
+ goto retry;
+ }
+ errno = ERANGE;
+ return NULL;
+ break;
+ }
+ }
+ if (next == NULL) {
+ errno = ENOSYS;
+ return NULL;
+ }
+ return (*next)(gid);
+}
+
+
+
+int
+getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups)
+{
+ FILE *fp;
+ static int (*next)(const char *, gid_t, gid_t *, int *);
+ static char *buffer;
+ static size_t buflen = 16;
+ struct group grp, *grpp;
+ int error, i, count = 0;
+
+ if (next == NULL) {
+ next = dlsym(RTLD_NEXT, "getgrouplist");
+ }
+
+ if ((getenv("WRAPPERS_GROUP") != NULL) &&
+ ((fp = fopen(getenv("WRAPPERS_GROUP"), "r")) != NULL)) {
+ while ((error = fgetgrent_r(fp, &grp,
+ buffer, buflen, &grpp)) == 0) {
+ for (i = 0;
+ (grp.gr_mem != NULL) && (grp.gr_mem[i] != NULL);
+ i++) {
+ if (strcmp(grp.gr_mem[i], user) == 0) {
+ if (count >= *ngroups) {
+ *ngroups = count + 1;
+ fclose(fp);
+ errno = ERANGE;
+ return -1;
+ break;
+ }
+ groups[count++] = grp.gr_gid;
+ }
+ }
+ }
+ fclose(fp);
+ if ((error != 0) && (error != ENOENT)) {
+ return error;
+ }
+ if (count > 0) {
+ *ngroups = count;
+ return count;
+ }
+ }
+ if (next == NULL) {
+ errno = ENOSYS;
+ return -1;
+ }
+ return (*next)(user, group, groups, ngroups);
+}
diff --git a/tests/wrap-pam.c b/tests/wrap-pam.c
new file mode 100644
index 0000000..bd728ac
--- /dev/null
+++ b/tests/wrap-pam.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2013 Red Hat, Inc.
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this Program; if not, write to the
+ *
+ * Free Software Foundation, Inc.
+ * 59 Temple Place, Suite 330
+ * Boston, MA 02111-1307 USA
+ *
+ */
+#define _GNU_SOURCE
+
+#include <sys/types.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <security/pam_appl.h>
+
+static const struct {
+ int value;
+ const char *name;
+} pam_errors[] = {
+ {PAM_SUCCESS, "SUCCESS"},
+ {PAM_SUCCESS, "0"},
+ {PAM_OPEN_ERR, "OPEN_ERR"},
+ {PAM_SYMBOL_ERR, "SYMBOL_ERR"},
+ {PAM_SERVICE_ERR, "SERVICE_ERR"},
+ {PAM_SYSTEM_ERR, "SYSTEM_ERR"},
+ {PAM_BUF_ERR, "BUF_ERR"},
+ {PAM_PERM_DENIED, "PERM_DENIED"},
+ {PAM_AUTH_ERR, "AUTH_ERR"},
+ {PAM_CRED_INSUFFICIENT, "CRED_INSUFFICIENT"},
+ {PAM_AUTHINFO_UNAVAIL, "AUTHINFO_UNAVAIL"},
+ {PAM_USER_UNKNOWN, "USER_UNKNOWN"},
+ {PAM_MAXTRIES, "MAXTRIES"},
+ {PAM_NEW_AUTHTOK_REQD, "NEW_AUTHTOK_REQD"},
+ {PAM_ACCT_EXPIRED, "ACCT_EXPIRED"},
+ {PAM_SESSION_ERR, "SESSION_ERR"},
+ {PAM_CRED_UNAVAIL, "CRED_UNAVAIL"},
+ {PAM_CRED_EXPIRED, "CRED_EXPIRED"},
+ {PAM_CRED_ERR, "CRED_ERR"},
+ {PAM_NO_MODULE_DATA, "NO_MODULE_DATA"},
+ {PAM_CONV_ERR, "CONV_ERR"},
+ {PAM_AUTHTOK_ERR, "AUTHTOK_ERR"},
+ {PAM_AUTHTOK_RECOVERY_ERR, "AUTHTOK_RECOVERY_ERR"},
+ {PAM_AUTHTOK_LOCK_BUSY, "AUTHTOK_LOCK_BUSY"},
+ {PAM_AUTHTOK_DISABLE_AGING, "AUTHTOK_DISABLE_AGING"},
+ {PAM_TRY_AGAIN, "TRY_AGAIN"},
+ {PAM_IGNORE, "IGNORE"},
+ {PAM_ABORT, "ABORT"},
+ {PAM_AUTHTOK_EXPIRED, "AUTHTOK_EXPIRED"},
+ {PAM_MODULE_UNKNOWN, "UNKNOWN"},
+ {PAM_BAD_ITEM, "BAD_ITEM"},
+ {PAM_CONV_AGAIN, "CONV_AGAIN"},
+ {PAM_INCOMPLETE, "INCOMPLETE"},
+};
+
+typedef struct pam_handle {
+ char *authtok, errbuf[LINE_MAX];
+ struct pam_conv conv;
+ int auth, acct;
+} pam_handle_t;
+
+static int
+pam_numerror(const char *name)
+{
+ unsigned int i, l;
+
+ for (i = 0; i < sizeof(pam_errors) / sizeof(pam_errors[0]); i++) {
+ l = strlen(pam_errors[i].name);
+ if (strncasecmp(pam_errors[i].name, name, l) == 0) {
+ return pam_errors[i].value;
+ }
+ }
+ return -1;
+}
+
+const char *
+pam_strerror(pam_handle_t *pamh, int errnum)
+{
+ unsigned int i;
+
+ for (i = 0; i < sizeof(pam_errors) / sizeof(pam_errors[0]); i++) {
+ if (pam_errors[i].value == errnum) {
+ return pam_errors[i].name;
+ }
+ }
+ snprintf(pamh->errbuf, sizeof(pamh->errbuf), "PAM error %d", errnum);
+ return pamh->errbuf;
+}
+
+int
+pam_start(const char *service_name, const char *user,
+ const struct pam_conv *pam_conversation, pam_handle_t **pamh)
+{
+ FILE *fp;
+ char buf[LINE_MAX], *p, *q;
+ pam_handle_t *ret;
+
+ ret = calloc(1, sizeof(*ret));
+ if (ret == NULL) {
+ return PAM_BUF_ERR;
+ }
+ ret->conv = *pam_conversation;
+ if (getenv("WRAPPERS_PAM_CREDS") == NULL) {
+ return PAM_ABORT;
+ }
+ fp = fopen(getenv("WRAPPERS_PAM_CREDS"), "r");
+ if (fp == NULL) {
+ return PAM_ABORT;
+ }
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ buf[strcspn(buf, "\r\n")] = '\0';
+ if ((strlen(buf) > strlen(user)) &&
+ (strncmp(user, buf, strlen(user)) == 0) &&
+ (buf[strlen(user)] == ':')) {
+ p = buf + strcspn(buf, ":");
+ if (*p != '\0') {
+ p++;
+ q = p + strcspn(p, ":");
+ ret->authtok = strndup(p, q - p);
+ p = q;
+ }
+ if (*p != '\0') {
+ p++;
+ q = p + strcspn(p, ":");
+ ret->auth = pam_numerror(p);
+ p = q;
+ }
+ if (*p != '\0') {
+ p++;
+ q = p + strcspn(p, ":");
+ ret->acct = pam_numerror(p);
+ p = q;
+ }
+ break;
+ }
+ }
+ fclose(fp);
+ *pamh = ret;
+ return PAM_SUCCESS;
+}
+
+int
+pam_end(pam_handle_t *pamh, int pam_status)
+{
+ if (pamh == NULL) {
+ return PAM_SYSTEM_ERR;
+ }
+ free(pamh->authtok);
+ free(pamh);
+ return PAM_SUCCESS;
+}
+
+int
+pam_authenticate(pam_handle_t *pamh, int flags)
+{
+ struct pam_response *resp;
+ struct pam_message messages[] = {
+ {.msg_style = PAM_PROMPT_ECHO_OFF, .msg = "Password: "},
+ };
+ const struct pam_message *msgs = &messages[0];
+ int ret;
+
+ resp = NULL;
+ if (pamh == NULL) {
+ return PAM_SYSTEM_ERR;
+ }
+ if (pamh->authtok == NULL) {
+ return pamh->auth ? pamh->auth : PAM_USER_UNKNOWN;
+ }
+ if (pamh->conv.conv == NULL) {
+ return PAM_CONV_ERR;
+ }
+ ret = pamh->conv.conv(1, &msgs, &resp, pamh->conv.appdata_ptr);
+ if (ret != PAM_SUCCESS) {
+ return ret;
+ }
+ if (strcmp(pamh->authtok, resp->resp) == 0) {
+ ret = pamh->auth;
+ } else {
+ ret = PAM_AUTH_ERR;
+ }
+ free(resp->resp);
+ free(resp);
+ return ret;
+}
+
+int
+pam_acct_mgmt(pam_handle_t *pamh, int flags)
+{
+ if (pamh == NULL) {
+ return PAM_SYSTEM_ERR;
+ }
+ return pamh->acct;
+}