diff options
author | Sumit Bose <sbose@redhat.com> | 2009-02-24 19:37:42 -0500 |
---|---|---|
committer | Simo Sorce <ssorce@redhat.com> | 2009-02-24 21:01:02 -0500 |
commit | fcef1231eea30ee9cdc75f3f39f4b9207a84ea1d (patch) | |
tree | 50525e47d7136efe2c7c746edff0de897a8d2b81 | |
parent | 98531e56318b65eb1bb6883fdfe12e771d8a1efe (diff) | |
download | sssd-fcef1231eea30ee9cdc75f3f39f4b9207a84ea1d.tar.gz sssd-fcef1231eea30ee9cdc75f3f39f4b9207a84ea1d.tar.bz2 sssd-fcef1231eea30ee9cdc75f3f39f4b9207a84ea1d.zip |
Add PAM client
Also rename nss_client to sss_client and reuse the same
pipe protocol for both the NSS and PAM client libraries.
Signed-off-by: Simo Sorce <ssorce@redhat.com>
-rw-r--r-- | BUILD.txt | 20 | ||||
-rw-r--r-- | sss_client/Makefile.in (renamed from nss_client/Makefile.in) | 22 | ||||
-rwxr-xr-x | sss_client/autogen.sh (renamed from nss_client/autogen.sh) | 0 | ||||
-rw-r--r-- | sss_client/common.c (renamed from nss_client/common.c) | 130 | ||||
-rwxr-xr-x | sss_client/config.guess (renamed from nss_client/config.guess) | 0 | ||||
-rwxr-xr-x | sss_client/config.sub (renamed from nss_client/config.sub) | 0 | ||||
-rw-r--r-- | sss_client/configure.ac (renamed from nss_client/configure.ac) | 0 | ||||
-rw-r--r-- | sss_client/exports.linux (renamed from nss_client/exports.linux) | 0 | ||||
-rw-r--r-- | sss_client/group.c (renamed from nss_client/group.c) | 10 | ||||
-rwxr-xr-x | sss_client/install-sh (renamed from nss_client/install-sh) | 0 | ||||
-rw-r--r-- | sss_client/pam_sss.c | 324 | ||||
-rw-r--r-- | sss_client/pam_test_client.c | 75 | ||||
-rw-r--r-- | sss_client/passwd.c (renamed from nss_client/passwd.c) | 8 | ||||
-rw-r--r-- | sss_client/protos.h (renamed from nss_client/protos.h) | 0 | ||||
-rw-r--r-- | sss_client/sss_cli.h (renamed from nss_client/sss_nss.h) | 50 | ||||
-rw-r--r-- | sss_client/sss_errno.h (renamed from nss_client/sss_errno.h) | 0 |
16 files changed, 559 insertions, 80 deletions
@@ -19,7 +19,7 @@ I use the following steps to build all pieces. export LD_LIBRARY_PATH=/tmp/foo/lib pushd talloc; ./autogen.sh && ./configure --with-shared-build-dir=/tmp/foo && make shared-build; popd pushd tdb; ./autogen.sh && ./configure --with-shared-build-dir=/tmp/foo && make shared-build; popd -pushd events; ./autogen.sh && ./configure --with-shared-build-dir=/tmp/foo && make shared-build; popd +pushd tevent; ./autogen.sh && ./configure --with-shared-build-dir=/tmp/foo && make shared-build; popd pushd ldb; ./autogen.sh && ./configure --with-shared-build-dir=/tmp/foo && make shared-build; popd pushd server; ./autogen.sh && ./configure --with-shared-build-dir=/tmp/foo && make; popd @@ -32,12 +32,26 @@ export LD_LIBRARY_PATH=/tmp/foo/lib This will start the sssd daemon in interactive mode. -The nss_client doesn't need any dependency nor supports the shared-build option. +The nss and pam client doesn't need any dependency nor supports the +shared-build option. -pushd nss_client; ./autogen.sh && ./configure && make; popd +pushd sss_client; ./autogen.sh && ./configure && make; popd Now you have to copy libnss_sss* into /lib (or /lib64) and add the 'sss' traget to nsswitch.conf passwd database +For pam copy pam_sss.so into /lib/security (or /lib64/security) and add +pam_sss.so to your pam configuration. To use the pam_test_client from +sss_client create the following file: + +/etc/pam.d/sss_test: +auth required pam_sss.so +account required pam_sss.so +password required pam_sss.so +session required pam_sss.so + +Now you can call pam_test_client: +./pam_test_client [auth|chau|acct|setc|open|clos] username@domain + ~~~~~ Simo. diff --git a/nss_client/Makefile.in b/sss_client/Makefile.in index 4b719917..6d80f83c 100644 --- a/nss_client/Makefile.in +++ b/sss_client/Makefile.in @@ -28,6 +28,14 @@ NSS_SSS_SONAME = libnss_sss.$(SHLIBEXT).2 NSS_SSS_OBJS = common.o passwd.o group.o +PAM_SSS_SOLIB = pam_sss.$(SHLIBEXT) +PAM_SSS_OBJS = pam_sss.o common.o +PAM_LIBS = -lpam -lpam_misc +PAM_CFLAGS = -DDEBUG -g -Wall -Werror + +PAM_CLIENT = pam_test_client +PAM_CLIENT_OBJS = pam_test_client.o + default: all showflags: @@ -49,7 +57,17 @@ $(NSS_SSS_SOLIB): $(NSS_SSS_OBJS) $(NSS_SSS_SONAME): $(NSS_SSS_SOLIB) ln -fs $< $@ -all: showflags $(NSS_SSS_OBJS) $(NSS_SSS_SOLIB) $(NSS_SSS_SONAME) +pam_sss.o: pam_sss.c + @echo Compiling $*.c + @$(CC) $(PICFLAG) $(CFLAGS) $(PAM_CFLAGS) -c $< -o $@ + +$(PAM_CLIENT): $(PAM_CLIENT_OBJS) + @$(CC) $(CFLAGS) $(PAM_CFLAGS) $< -o $@ $(PAM_LIBS) + +$(PAM_SSS_SOLIB): $(PAM_SSS_OBJS) + $(SHLD) $(SHLD_FLAGS) -o $@ $(PAM_SSS_OBJS) $(PAM_LIBS) + +all: showflags $(NSS_SSS_OBJS) $(NSS_SSS_SOLIB) $(NSS_SSS_SONAME) $(PAM_SSS_SOLIB) $(PAM_CLIENT) install: all $(INSTALLCMD) -m 755 $(NSS_SSS_SOLIB) /lib @@ -57,7 +75,7 @@ install: all clean: rm -f *.o *.a */*.o - rm -f $(NSS_SSS_SOLIB) $(NSS_SSS_SONAME) + rm -f $(NSS_SSS_SOLIB) $(NSS_SSS_SONAME) $(PAM_SSS_SOLIB) $(PAM_CLIENT) distclean: clean rm -f config.log config.status config.h config.cache diff --git a/nss_client/autogen.sh b/sss_client/autogen.sh index bf84eeee..bf84eeee 100755 --- a/nss_client/autogen.sh +++ b/sss_client/autogen.sh diff --git a/nss_client/common.c b/sss_client/common.c index a79dc660..50aabff2 100644 --- a/nss_client/common.c +++ b/sss_client/common.c @@ -24,6 +24,7 @@ */ #include <nss.h> +#include <security/pam_modules.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> @@ -34,17 +35,17 @@ #include <string.h> #include <fcntl.h> #include <poll.h> -#include "sss_nss.h" +#include "sss_cli.h" /* common functions */ -int sss_nss_sd = -1; /* the nss socket descriptor */ +int sss_cli_sd = -1; /* the sss client socket descriptor */ -static void sss_nss_close_socket(void) +static void sss_cli_close_socket(void) { - if (sss_nss_sd != -1) { - close(sss_nss_sd); - sss_nss_sd = -1; + if (sss_cli_sd != -1) { + close(sss_cli_sd); + sss_cli_sd = -1; } } @@ -56,8 +57,8 @@ static void sss_nss_close_socket(void) * byte 12-15: 32bit unsigned (reserved) * byte 16-X: (optional) request structure associated to the command code used */ -static enum nss_status sss_nss_send_req(enum sss_nss_command cmd, - struct sss_nss_req_data *rd, +static enum nss_status sss_nss_send_req(enum sss_cli_command cmd, + struct sss_cli_req_data *rd, int *errnop) { uint32_t header[4]; @@ -76,10 +77,10 @@ static enum nss_status sss_nss_send_req(enum sss_nss_command cmd, int res; *errnop = 0; - pfd.fd = sss_nss_sd; + pfd.fd = sss_cli_sd; pfd.events = POLLOUT; - res = poll(&pfd, 1, SSS_NSS_SOCKET_TIMEOUT); + res = poll(&pfd, 1, SSS_CLI_SOCKET_TIMEOUT); switch (res) { case -1: *errnop = errno; @@ -100,17 +101,17 @@ static enum nss_status sss_nss_send_req(enum sss_nss_command cmd, break; } if (*errnop) { - sss_nss_close_socket(); + sss_cli_close_socket(); return NSS_STATUS_UNAVAIL; } if (datasent < SSS_NSS_HEADER_SIZE) { - res = write(sss_nss_sd, + res = write(sss_cli_sd, (char *)header + datasent, SSS_NSS_HEADER_SIZE - datasent); } else { rdsent = datasent - SSS_NSS_HEADER_SIZE; - res = write(sss_nss_sd, + res = write(sss_cli_sd, (const char *)rd->data + rdsent, rd->len - rdsent); } @@ -118,7 +119,7 @@ static enum nss_status sss_nss_send_req(enum sss_nss_command cmd, if ((res == -1) || (res == 0)) { /* Write failed */ - sss_nss_close_socket(); + sss_cli_close_socket(); *errnop = errno; return NSS_STATUS_UNAVAIL; } @@ -138,7 +139,7 @@ static enum nss_status sss_nss_send_req(enum sss_nss_command cmd, * byte 16-X: (optional) reply structure associated to the command code used */ -static enum nss_status sss_nss_recv_rep(enum sss_nss_command cmd, +static enum nss_status sss_nss_recv_rep(enum sss_cli_command cmd, uint8_t **buf, int *len, int *errnop) { @@ -160,10 +161,10 @@ static enum nss_status sss_nss_recv_rep(enum sss_nss_command cmd, int res; *errnop = 0; - pfd.fd = sss_nss_sd; + pfd.fd = sss_cli_sd; pfd.events = POLLIN; - res = poll(&pfd, 1, SSS_NSS_SOCKET_TIMEOUT); + res = poll(&pfd, 1, SSS_CLI_SOCKET_TIMEOUT); switch (res) { case -1: *errnop = errno; @@ -184,17 +185,17 @@ static enum nss_status sss_nss_recv_rep(enum sss_nss_command cmd, break; } if (*errnop) { - sss_nss_close_socket(); + sss_cli_close_socket(); return NSS_STATUS_UNAVAIL; } if (datarecv < SSS_NSS_HEADER_SIZE) { - res = read(sss_nss_sd, + res = read(sss_cli_sd, (char *)header + datarecv, SSS_NSS_HEADER_SIZE - datarecv); } else { bufrecv = datarecv - SSS_NSS_HEADER_SIZE; - res = read(sss_nss_sd, + res = read(sss_cli_sd, (char *)(*buf) + bufrecv, header[0] - datarecv); } @@ -206,7 +207,7 @@ static enum nss_status sss_nss_recv_rep(enum sss_nss_command cmd, * since the transaction has failed half way * through. */ - sss_nss_close_socket(); + sss_cli_close_socket(); *errnop = errno; return NSS_STATUS_UNAVAIL; } @@ -219,7 +220,7 @@ static enum nss_status sss_nss_recv_rep(enum sss_nss_command cmd, * been read, do checks and proceed */ if (header[2] != 0) { /* server side error */ - sss_nss_close_socket(); + sss_cli_close_socket(); *errnop = header[2]; if (*errnop == EAGAIN) { return NSS_STATUS_TRYAGAIN; @@ -229,7 +230,7 @@ static enum nss_status sss_nss_recv_rep(enum sss_nss_command cmd, } if (header[1] != cmd) { /* wrong command id */ - sss_nss_close_socket(); + sss_cli_close_socket(); *errnop = EBADMSG; return NSS_STATUS_UNAVAIL; } @@ -237,7 +238,7 @@ static enum nss_status sss_nss_recv_rep(enum sss_nss_command cmd, *len = header[0] - SSS_NSS_HEADER_SIZE; *buf = malloc(*len); if (!*buf) { - sss_nss_close_socket(); + sss_cli_close_socket(); *errnop = ENOMEM; return NSS_STATUS_UNAVAIL; } @@ -251,8 +252,8 @@ static enum nss_status sss_nss_recv_rep(enum sss_nss_command cmd, /* this function will check command codes match and returned length is ok */ /* repbuf and replen report only the data section not the header */ static enum nss_status sss_nss_make_request_nochecks( - enum sss_nss_command cmd, - struct sss_nss_req_data *rd, + enum sss_cli_command cmd, + struct sss_cli_req_data *rd, uint8_t **repbuf, size_t *replen, int *errnop) { @@ -301,7 +302,7 @@ static int sss_nss_check_version(void) int errnop; int res = NSS_STATUS_UNAVAIL; - nret = sss_nss_make_request_nochecks(SSS_NSS_GET_VERSION, NULL, + nret = sss_nss_make_request_nochecks(SSS_GET_VERSION, NULL, &repbuf, &replen, &errnop); if (nret != NSS_STATUS_SUCCESS) { return nret; @@ -311,7 +312,7 @@ static int sss_nss_check_version(void) return res; } - if (((uint32_t *)repbuf)[0] == SSS_NSS_VERSION) { + if (((uint32_t *)repbuf)[0] == SSS_PROTOCOL_VERSION) { res = NSS_STATUS_SUCCESS; } @@ -413,7 +414,7 @@ static int make_safe_fd(int fd) return new_fd; } -static int sss_nss_open_socket(int *errnop) +static int sss_nss_open_socket(int *errnop, const char *socket_name) { struct sockaddr_un nssaddr; int inprogress = 1; @@ -422,8 +423,8 @@ static int sss_nss_open_socket(int *errnop) memset(&nssaddr, 0, sizeof(struct sockaddr_un)); nssaddr.sun_family = AF_UNIX; - strncpy(nssaddr.sun_path, SSS_NSS_SOCKET_NAME, - strlen(SSS_NSS_SOCKET_NAME) + 1); + strncpy(nssaddr.sun_path, socket_name, + strlen(socket_name) + 1); sd = socket(AF_UNIX, SOCK_STREAM, 0); if (sd == -1) { @@ -461,7 +462,7 @@ static int sss_nss_open_socket(int *errnop) case EINPROGRESS: FD_ZERO(&w_fds); FD_SET(sd, &w_fds); - tv.tv_sec = SSS_NSS_SOCKET_TIMEOUT - wait_time; + tv.tv_sec = SSS_CLI_SOCKET_TIMEOUT - wait_time; tv.tv_usec = 0; ret = select(sd + 1, NULL, &w_fds, NULL, &tv); @@ -474,10 +475,10 @@ static int sss_nss_open_socket(int *errnop) return sd; } } - wait_time += SSS_NSS_SOCKET_TIMEOUT; + wait_time += SSS_CLI_SOCKET_TIMEOUT; break; case EAGAIN: - if (wait_time < SSS_NSS_SOCKET_TIMEOUT) { + if (wait_time < SSS_CLI_SOCKET_TIMEOUT) { sleep_time = rand() % 2 + 1; sleep(sleep_time); } @@ -488,7 +489,7 @@ static int sss_nss_open_socket(int *errnop) break; } - if (wait_time >= SSS_NSS_SOCKET_TIMEOUT) { + if (wait_time >= SSS_CLI_SOCKET_TIMEOUT) { inprogress = 0; } } @@ -499,26 +500,26 @@ static int sss_nss_open_socket(int *errnop) return -1; } -static enum nss_status sss_nss_check_socket(int *errnop) +static enum sss_status sss_cli_check_socket(int *errnop, const char *socket_name) { static pid_t mypid; int mysd; if (getpid() != mypid) { - sss_nss_close_socket(); + sss_cli_close_socket(); mypid = getpid(); } /* check if the socket has been closed on the other side */ - if (sss_nss_sd != -1) { + if (sss_cli_sd != -1) { struct pollfd pfd; int res; *errnop = 0; - pfd.fd = sss_nss_sd; + pfd.fd = sss_cli_sd; pfd.events = POLLIN | POLLOUT; - res = poll(&pfd, 1, SSS_NSS_SOCKET_TIMEOUT); + res = poll(&pfd, 1, SSS_CLI_SOCKET_TIMEOUT); switch (res) { case -1: *errnop = errno; @@ -539,33 +540,33 @@ static enum nss_status sss_nss_check_socket(int *errnop) break; } if (*errnop) { - sss_nss_close_socket(); - return NSS_STATUS_UNAVAIL; + sss_cli_close_socket(); + return SSS_STATUS_UNAVAIL; } - return NSS_STATUS_SUCCESS; + return SSS_STATUS_SUCCESS; } - mysd = sss_nss_open_socket(errnop); + mysd = sss_nss_open_socket(errnop, socket_name); if (mysd == -1) { - return NSS_STATUS_UNAVAIL; + return SSS_STATUS_UNAVAIL; } - sss_nss_sd = mysd; + sss_cli_sd = mysd; if (sss_nss_check_version()) { - return NSS_STATUS_SUCCESS; + return SSS_STATUS_SUCCESS; } - sss_nss_close_socket(); + sss_cli_close_socket(); *errnop = EFAULT; - return NSS_STATUS_UNAVAIL; + return SSS_STATUS_UNAVAIL; } /* this function will check command codes match and returned length is ok */ /* repbuf and replen report only the data section not the header */ -enum nss_status sss_nss_make_request(enum sss_nss_command cmd, - struct sss_nss_req_data *rd, +enum nss_status sss_nss_make_request(enum sss_cli_command cmd, + struct sss_cli_req_data *rd, uint8_t **repbuf, size_t *replen, int *errnop) { @@ -578,11 +579,32 @@ enum nss_status sss_nss_make_request(enum sss_nss_command cmd, return NSS_STATUS_NOTFOUND; } - ret = sss_nss_check_socket(errnop); - if (ret != NSS_STATUS_SUCCESS) { - return ret; + ret = sss_cli_check_socket(errnop, SSS_NSS_SOCKET_NAME); + if (ret != SSS_STATUS_SUCCESS) { + return NSS_STATUS_UNAVAIL; } return sss_nss_make_request_nochecks(cmd, rd, repbuf, replen, errnop); } +int sss_pam_make_request(enum sss_cli_command cmd, + struct sss_cli_req_data *rd, + uint8_t **repbuf, size_t *replen, + int *errnop) +{ + int ret; + char *envval; + + /* avoid looping in the pam daemon */ + envval = getenv("_SSS_LOOPS"); + if (envval && strcmp(envval, "NO") == 0) { + return PAM_SERVICE_ERR; + } + + ret = sss_cli_check_socket(errnop, SSS_PAM_SOCKET_NAME); + if (ret != NSS_STATUS_SUCCESS) { + return PAM_SERVICE_ERR; + } + + return sss_nss_make_request_nochecks(cmd, rd, repbuf, replen, errnop); +} diff --git a/nss_client/config.guess b/sss_client/config.guess index 354dbe17..354dbe17 100755 --- a/nss_client/config.guess +++ b/sss_client/config.guess diff --git a/nss_client/config.sub b/sss_client/config.sub index 23cd6fd7..23cd6fd7 100755 --- a/nss_client/config.sub +++ b/sss_client/config.sub diff --git a/nss_client/configure.ac b/sss_client/configure.ac index 9bd4f1f3..9bd4f1f3 100644 --- a/nss_client/configure.ac +++ b/sss_client/configure.ac diff --git a/nss_client/exports.linux b/sss_client/exports.linux index bcc6b10e..bcc6b10e 100644 --- a/nss_client/exports.linux +++ b/sss_client/exports.linux diff --git a/nss_client/group.c b/sss_client/group.c index 74cc7394..c340a2cc 100644 --- a/nss_client/group.c +++ b/sss_client/group.c @@ -27,7 +27,7 @@ #include <stdlib.h> #include <stdint.h> #include <string.h> -#include "sss_nss.h" +#include "sss_cli.h" static struct sss_nss_getgrent_data { size_t len; @@ -174,7 +174,7 @@ enum nss_status _nss_sss_initgroups_dyn(const char *user, gid_t group, gid_t **groups, long int limit, int *errnop) { - struct sss_nss_req_data rd; + struct sss_cli_req_data rd; uint8_t *repbuf; size_t replen; enum nss_status nret; @@ -233,7 +233,7 @@ enum nss_status _nss_sss_initgroups_dyn(const char *user, gid_t group, enum nss_status _nss_sss_getgrnam_r(const char *name, struct group *result, char *buffer, size_t buflen, int *errnop) { - struct sss_nss_req_data rd; + struct sss_cli_req_data rd; struct sss_nss_gr_rep grrep; uint8_t *repbuf; size_t replen, len; @@ -279,7 +279,7 @@ enum nss_status _nss_sss_getgrnam_r(const char *name, struct group *result, enum nss_status _nss_sss_getgrgid_r(gid_t gid, struct group *result, char *buffer, size_t buflen, int *errnop) { - struct sss_nss_req_data rd; + struct sss_cli_req_data rd; struct sss_nss_gr_rep grrep; uint8_t *repbuf; size_t replen, len; @@ -345,7 +345,7 @@ enum nss_status _nss_sss_setgrent(void) enum nss_status _nss_sss_getgrent_r(struct group *result, char *buffer, size_t buflen, int *errnop) { - struct sss_nss_req_data rd; + struct sss_cli_req_data rd; struct sss_nss_gr_rep grrep; uint8_t *repbuf; size_t replen; diff --git a/nss_client/install-sh b/sss_client/install-sh index 58719246..58719246 100755 --- a/nss_client/install-sh +++ b/sss_client/install-sh diff --git a/sss_client/pam_sss.c b/sss_client/pam_sss.c new file mode 100644 index 00000000..25a1d2ca --- /dev/null +++ b/sss_client/pam_sss.c @@ -0,0 +1,324 @@ + +#define PAM_SM_AUTH +#define PAM_SM_ACCOUNT +#define PAM_SM_SESSION +#define PAM_SM_PASSWORD + +#include <sys/types.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdint.h> +#include <security/pam_modules.h> +#include <security/pam_misc.h> + +#include "sss_cli.h" + +struct pam_items { + const char* pam_service; + const char* pam_user; + const char* pam_tty; + const char* pam_ruser; + const char* pam_rhost; + const char* pam_authtok; + const char* pam_newauthtok; + const char* pamstack_authtok; + const char* pamstack_oldauthtok; + int pam_service_size; + int pam_user_size; + int pam_tty_size; + int pam_ruser_size; + int pam_rhost_size; + int pam_authtok_type; + int pam_authtok_size; + int pam_newauthtok_type; + int pam_newauthtok_size; +}; + + +static int get_pam_items(pam_handle_t *pamh, struct pam_items *pi) { + int ret; + + ret = pam_get_item(pamh, PAM_SERVICE, (const void **) &(pi->pam_service)); + if (ret != PAM_SUCCESS) return ret; + if (pi->pam_service == NULL) pi->pam_service=""; + pi->pam_service_size=strlen(pi->pam_service)+1; + + ret = pam_get_item(pamh, PAM_USER, (const void **) &(pi->pam_user)); + if (ret != PAM_SUCCESS) return ret; + if (pi->pam_user == NULL) pi->pam_user=""; + pi->pam_user_size=strlen(pi->pam_user)+1; + + ret = pam_get_item(pamh, PAM_TTY, (const void **) &(pi->pam_tty)); + if (ret != PAM_SUCCESS) return ret; + if (pi->pam_tty == NULL) pi->pam_tty=""; + pi->pam_tty_size=strlen(pi->pam_tty)+1; + + ret = pam_get_item(pamh, PAM_RUSER, (const void **) &(pi->pam_ruser)); + if (ret != PAM_SUCCESS) return ret; + if (pi->pam_ruser == NULL) pi->pam_ruser=""; + pi->pam_ruser_size=strlen(pi->pam_ruser)+1; + + ret = pam_get_item(pamh, PAM_RHOST, (const void **) &(pi->pam_rhost)); + if (ret != PAM_SUCCESS) return ret; + if (pi->pam_rhost == NULL) pi->pam_rhost=""; + pi->pam_rhost_size=strlen(pi->pam_rhost)+1; + + ret = pam_get_item(pamh, PAM_AUTHTOK, (const void **) &(pi->pamstack_authtok)); + if (ret != PAM_SUCCESS) return ret; + if (pi->pamstack_authtok == NULL) pi->pamstack_authtok=""; + + ret = pam_get_item(pamh, PAM_OLDAUTHTOK, (const void **) &(pi->pamstack_oldauthtok)); + if (ret != PAM_SUCCESS) return ret; + if (pi->pamstack_oldauthtok == NULL) pi->pamstack_oldauthtok=""; + + return PAM_SUCCESS; +} + +static void print_pam_items(struct pam_items pi) { + D(("Service: %s", *pi.pam_service!='\0' ? pi.pam_service : "(not available)")); + D(("User: %s", *pi.pam_user!='\0' ? pi.pam_user : "(not available)")); + D(("Tty: %s", *pi.pam_tty!='\0' ? pi.pam_tty : "(not available)")); + D(("Ruser: %s", *pi.pam_ruser!='\0' ? pi.pam_ruser : "(not available)")); + D(("Rhost: %s", *pi.pam_rhost!='\0' ? pi.pam_rhost : "(not available)")); + D(("Authtok: %s", *pi.pamstack_authtok!='\0' ? pi.pamstack_authtok : "(not available)")); + D(("Oldauthtok: %s", *pi.pamstack_oldauthtok!='\0' ? pi.pamstack_oldauthtok : "(not available)")); +} + +static int pam_sss(int task, pam_handle_t *pamh, int flags, int argc, + const char **argv) { + int ret; + int errnop; + struct pam_items pi; + struct sss_cli_req_data rd; + uint8_t *repbuf=NULL; + size_t replen; + size_t rp; + char *buf=NULL; + struct pam_conv *conv; + struct pam_message *mesg[1]; + struct pam_response *resp=NULL; + int pam_status; + char *domain; + + D(("Hello pam_sssd: %d", task)); + + ret = get_pam_items(pamh, &pi); + if (ret != PAM_SUCCESS) { + D(("get items returned error: %s", pam_strerror(pamh,ret))); + return ret; + } + + pi.pam_authtok_type = SSS_AUTHTOK_TYPE_EMPTY; + pi.pam_authtok = NULL; + pi.pam_authtok_size = 0; + pi.pam_newauthtok_type = SSS_AUTHTOK_TYPE_EMPTY; + pi.pam_newauthtok = NULL; + pi.pam_newauthtok_size = 0; +/* according to pam_conv(3) only one message should be requested by conv to + * keep compatibility to Solaris. Therefore we make separate calls to request + * AUTHTOK and OLDAUTHTOK. */ + if (task == SSS_PAM_AUTHENTICATE || task == SSS_PAM_CHAUTHTOK) { + ret=pam_get_item(pamh, PAM_CONV, (const void **) &conv); + if (ret != PAM_SUCCESS) return ret; + + mesg[0] = malloc(sizeof(struct pam_message)); + if (mesg[0] == NULL) { + D(("Malloc failed.\n")); + return PAM_SYSTEM_ERR; + } + mesg[0]->msg_style = PAM_PROMPT_ECHO_OFF; + mesg[0]->msg = strdup("Password: "); + + ret=conv->conv(1, (const struct pam_message **) mesg, &resp, + conv->appdata_ptr); + free((void *)mesg[0]->msg); + free(mesg[0]); + if (ret != PAM_SUCCESS) { + D(("Conversation failure: %s.\n", pam_strerror(pamh,ret))); + pam_status = ret; + goto done; + } + + if (resp[0].resp == NULL) { + D(("Empty password\n")); + pi.pam_authtok = NULL; + pi.pam_authtok_type = SSS_AUTHTOK_TYPE_EMPTY; + } else { + pi.pam_authtok = strdup(resp[0].resp); + pi.pam_authtok_type = SSS_AUTHTOK_TYPE_PASSWORD; + } + pi.pam_authtok_size=strlen(pi.pam_authtok); + } + + if (task == SSS_PAM_CHAUTHTOK) { + ret=pam_get_item(pamh, PAM_CONV, (const void **) &conv); + if (ret != PAM_SUCCESS) return ret; + + mesg[0] = malloc(sizeof(struct pam_message)); + if (mesg[0] == NULL) { + D(("Malloc failed.\n")); + return PAM_SYSTEM_ERR; + } + mesg[0]->msg_style = PAM_PROMPT_ECHO_OFF; + mesg[0]->msg = strdup("New Password: "); + + ret=conv->conv(1, (const struct pam_message **) mesg, &resp, + conv->appdata_ptr); + free((void *)mesg[0]->msg); + free(mesg[0]); + if (ret != PAM_SUCCESS) { + D(("Conversation failure: %s.\n", pam_strerror(pamh,ret))); + pam_status = ret; + goto done; + } + + if (resp[0].resp == NULL) { + D(("Empty password\n")); + pi.pam_newauthtok = NULL; + pi.pam_newauthtok_type = SSS_AUTHTOK_TYPE_EMPTY; + } else { + pi.pam_newauthtok = strdup(resp[0].resp); + pi.pam_newauthtok_type = SSS_AUTHTOK_TYPE_PASSWORD; + } + pi.pam_newauthtok_size=strlen(pi.pam_newauthtok); + } + + print_pam_items(pi); + + if (pi.pam_user) { + rd.len = pi.pam_user_size + + pi.pam_service_size + + pi.pam_tty_size + + pi.pam_ruser_size + + pi.pam_rhost_size + + 2*sizeof(uint32_t) + pi.pam_authtok_size + + 2*sizeof(uint32_t) + pi.pam_newauthtok_size + + sizeof(uint32_t); + buf = malloc(rd.len); + + memcpy(buf, pi.pam_user, pi.pam_user_size); + rp = pi.pam_user_size; + + memcpy(&buf[rp], pi.pam_service, pi.pam_service_size); + rp += pi.pam_service_size; + + memcpy(&buf[rp], pi.pam_tty, pi.pam_tty_size); + rp += pi.pam_tty_size; + + memcpy(&buf[rp], pi.pam_ruser, pi.pam_ruser_size); + rp += pi.pam_ruser_size; + + memcpy(&buf[rp], pi.pam_rhost, pi.pam_rhost_size); + rp += pi.pam_rhost_size; + + ((uint32_t *)(&buf[rp]))[0] = pi.pam_authtok_type; + rp += sizeof(uint32_t); + ((uint32_t *)(&buf[rp]))[0] = pi.pam_authtok_size; + rp += sizeof(uint32_t); + memcpy(&buf[rp], pi.pam_authtok, pi.pam_authtok_size); + rp += pi.pam_authtok_size; + _pam_overwrite((void *)pi.pam_authtok); + free((void *)pi.pam_authtok); + + ((uint32_t *)(&buf[rp]))[0] = pi.pam_newauthtok_type; + rp += sizeof(uint32_t); + ((uint32_t *)(&buf[rp]))[0] = pi.pam_newauthtok_size; + rp += sizeof(uint32_t); + memcpy(&buf[rp], pi.pam_newauthtok, pi.pam_newauthtok_size); + rp += pi.pam_newauthtok_size; + _pam_overwrite((void *)pi.pam_newauthtok); + free((void *)pi.pam_newauthtok); + + ((uint32_t *)(&buf[rp]))[0] = END_OF_PAM_REQUEST; + rp += sizeof(uint32_t); + + if (rp != rd.len) { + D(("error during packet creation.")); + pam_status = PAM_ABORT; + goto done; + } + rd.data = buf; + + ret = sss_pam_make_request(task, &rd, &repbuf, &replen, &errnop); + + if (ret != NSS_STATUS_SUCCESS) { + D(("sss_pam_make_request failed.")); + pam_status = ret; + goto done; + } + + if (replen<sizeof(int) || repbuf[replen-1]!='\0') { + D(("response not in expected format.")); + pam_status=PAM_SYSTEM_ERR; + goto done; + } + + pam_status = ((int32_t *)repbuf)[0]; + domain = (char *)(repbuf + sizeof(uint32_t)); + D(("received: %d (%s)", pam_status, pam_strerror(pamh,pam_status))); + D(("received: %s", domain)); + } else { + D(("no user found, doing nothing")); + return PAM_SUCCESS; + } + +done: + if ( resp != NULL ) { + _pam_overwrite((void *)resp[0].resp); + free(resp[0].resp); + free(resp); + } + if ( buf != NULL && repbuf != NULL) _pam_overwrite_n(buf, rd.len); + free(buf); + free(repbuf); + + return pam_status; +} + +PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, + const char **argv ) { + return pam_sss(SSS_PAM_AUTHENTICATE, pamh, flags, argc, argv); +} + + +PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, + const char **argv ) { + return pam_sss(SSS_PAM_SETCRED, pamh, flags, argc, argv); +} + +PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, + const char **argv ) { + return pam_sss(SSS_PAM_ACCT_MGMT, pamh, flags, argc, argv); +} + +PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, + const char **argv ) { + return pam_sss(SSS_PAM_CHAUTHTOK, pamh, flags, argc, argv); +} + +PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, + const char **argv ) { + return pam_sss(SSS_PAM_OPEN_SESSION, pamh, flags, argc, argv); +} + +PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, + const char **argv ) { + return pam_sss(SSS_PAM_CLOSE_SESSION, pamh, flags, argc, argv); +} + + +#ifdef PAM_STATIC + +/* static module data */ + +struct pam_module _pam_sssd_modstruct = { + "pam_sssd", + pam_sm_authenticate, + pam_sm_setcred, + pam_sm_acct_mgmt, + pam_sm_open_session, + pam_sm_close_session, + pam_sm_chauthtok +}; + +#endif diff --git a/sss_client/pam_test_client.c b/sss_client/pam_test_client.c new file mode 100644 index 00000000..675d7b2b --- /dev/null +++ b/sss_client/pam_test_client.c @@ -0,0 +1,75 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <unistd.h> + +#include <security/pam_appl.h> +#include <security/pam_misc.h> + +static struct pam_conv conv = { + misc_conv, + NULL +}; + +int main(int argc, char *argv[]) { + + pam_handle_t *pamh; + char *user; + char *action; + int ret; + + if (argc == 1) { + fprintf(stderr, "missing action and user name, using default\n"); + action = strdup("auth"); + user = strdup("dummy"); + } else if (argc == 2) { + fprintf(stdout, "using first argument as action and default user name\n"); + action = strdup(argv[1]); + user = strdup("dummy"); + } else { + action = strdup(argv[1]); + user = strdup(argv[2]); + } + + fprintf(stdout, "action: %s\nuser: %s\n", action,user); + + ret = pam_start("sss_test", user, &conv, &pamh); + if (ret != PAM_SUCCESS) { + fprintf(stderr, "pam_start failed: %s\n", pam_strerror(pamh, ret)); + return 1; + } + + if ( strncmp(action, "auth", 4)== 0 ) { + fprintf(stdout, "testing pam_authenticate\n"); + ret = pam_authenticate(pamh, 0); + fprintf(stderr, "pam_authenticate: %s\n", pam_strerror(pamh, ret)); + } else if ( strncmp(action, "chau", 4)== 0 ) { + fprintf(stdout, "testing pam_chauthtok\n"); + ret = pam_chauthtok(pamh, 0); + fprintf(stderr, "pam_chauthtok: %s\n", pam_strerror(pamh, ret)); + } else if ( strncmp(action, "acct", 4)== 0 ) { + fprintf(stdout, "testing pam_acct_mgmt\n"); + ret = pam_acct_mgmt(pamh, 0); + fprintf(stderr, "pam_acct_mgmt: %s\n", pam_strerror(pamh, ret)); + } else if ( strncmp(action, "setc", 4)== 0 ) { + fprintf(stdout, "testing pam_setcred\n"); + ret = pam_setcred(pamh, 0); + fprintf(stderr, "pam_setcred: %d[%s]\n", ret, pam_strerror(pamh, ret)); + } else if ( strncmp(action, "open", 4)== 0 ) { + fprintf(stdout, "testing pam_open_session\n"); + ret = pam_open_session(pamh, 0); + fprintf(stderr, "pam_open_session: %s\n", pam_strerror(pamh, ret)); + } else if ( strncmp(action, "clos", 4)== 0 ) { + fprintf(stdout, "testing pam_close_session\n"); + ret = pam_close_session(pamh, 0); + fprintf(stderr, "pam_close_session: %s\n", pam_strerror(pamh, ret)); + } else { + fprintf(stderr, "unknown action\n"); + } + + pam_end(pamh, ret); + + return 0; +} diff --git a/nss_client/passwd.c b/sss_client/passwd.c index 776e6cea..d02e067f 100644 --- a/nss_client/passwd.c +++ b/sss_client/passwd.c @@ -27,7 +27,7 @@ #include <stdlib.h> #include <stdint.h> #include <string.h> -#include "sss_nss.h" +#include "sss_cli.h" static struct sss_nss_getpwent_data { size_t len; @@ -155,7 +155,7 @@ static int sss_nss_getpw_readrep(struct sss_nss_pw_rep *pr, enum nss_status _nss_sss_getpwnam_r(const char *name, struct passwd *result, char *buffer, size_t buflen, int *errnop) { - struct sss_nss_req_data rd; + struct sss_cli_req_data rd; struct sss_nss_pw_rep pwrep; uint8_t *repbuf; size_t replen, len; @@ -201,7 +201,7 @@ enum nss_status _nss_sss_getpwnam_r(const char *name, struct passwd *result, enum nss_status _nss_sss_getpwuid_r(uid_t uid, struct passwd *result, char *buffer, size_t buflen, int *errnop) { - struct sss_nss_req_data rd; + struct sss_cli_req_data rd; struct sss_nss_pw_rep pwrep; uint8_t *repbuf; size_t replen, len; @@ -268,7 +268,7 @@ enum nss_status _nss_sss_getpwent_r(struct passwd *result, char *buffer, size_t buflen, int *errnop) { - struct sss_nss_req_data rd; + struct sss_cli_req_data rd; struct sss_nss_pw_rep pwrep; uint8_t *repbuf; size_t replen; diff --git a/nss_client/protos.h b/sss_client/protos.h index adb0b7bb..adb0b7bb 100644 --- a/nss_client/protos.h +++ b/sss_client/protos.h diff --git a/nss_client/sss_nss.h b/sss_client/sss_cli.h index b5a92162..5445b5fa 100644 --- a/nss_client/sss_nss.h +++ b/sss_client/sss_cli.h @@ -1,5 +1,5 @@ /* - * System Security Services Daemon. NSS Interface + * System Security Services Daemon. Client Interface for NSS and PAM. * * Copyright (C) Simo Sorce 2007 * @@ -8,8 +8,8 @@ * */ -#ifndef _SSSNSS_H -#define _SSSNSS_H +#ifndef _SSSCLI_H +#define _SSSCLI_H #include <nss.h> #include <pwd.h> @@ -18,15 +18,16 @@ /* SELinux will have a better way to regulate access if they are seprate * Also a change in one of the pipes will not affect the others */ #define SSS_NSS_SOCKET_NAME "/var/lib/sss/pipes/nss" +#define SSS_PAM_SOCKET_NAME "/var/lib/sss/pipes/pam" -#define SSS_NSS_VERSION 0 +#define SSS_PROTOCOL_VERSION 0 -enum sss_nss_command { +enum sss_cli_command { /* null */ - SSS_NSS_NULL = 0x0000, + SSS_CLI_NULL = 0x0000, /* version */ - SSS_NSS_GET_VERSION = 0x0001, + SSS_GET_VERSION = 0x0001, /* passwd */ @@ -118,25 +119,50 @@ enum sss_nss_command { SSS_NSS_GETSPENT = 0x00B4, SSS_NSS_ENDSPENT = 0x00B5, #endif + +/* PAM related calls */ + SSS_PAM_AUTHENTICATE = 0x00F1, + SSS_PAM_SETCRED = 0x00F2, + SSS_PAM_ACCT_MGMT = 0x00F3, + SSS_PAM_OPEN_SESSION = 0x00F4, + SSS_PAM_CLOSE_SESSION = 0x00F5, + SSS_PAM_CHAUTHTOK = 0x00F6, + }; +enum sss_authtok_type { + SSS_AUTHTOK_TYPE_EMPTY = 0x0000, + SSS_AUTHTOK_TYPE_PASSWORD = 0x0001, +}; + +#define END_OF_PAM_REQUEST 0x4950414d + #define SSS_NSS_MAX_ENTRIES 256 #define SSS_NSS_HEADER_SIZE (sizeof(uint32_t) * 4) -struct sss_nss_req_data { +struct sss_cli_req_data { size_t len; const void *data; }; /* this is in milliseconds, wait up to 300 seconds */ -#define SSS_NSS_SOCKET_TIMEOUT 300000 +#define SSS_CLI_SOCKET_TIMEOUT 300000 +enum sss_status { + SSS_STATUS_UNAVAIL, + SSS_STATUS_SUCCESS +}; + +enum nss_status sss_nss_make_request(enum sss_cli_command cmd, + struct sss_cli_req_data *rd, + uint8_t **repbuf, size_t *replen, + int *errnop); -enum nss_status sss_nss_make_request(enum sss_nss_command cmd, - struct sss_nss_req_data *rd, +int sss_pam_make_request(enum sss_cli_command cmd, + struct sss_cli_req_data *rd, uint8_t **repbuf, size_t *replen, int *errnop); -#endif /* _SSSNSS_H */ +#endif /* _SSSCLI_H */ #if 0 diff --git a/nss_client/sss_errno.h b/sss_client/sss_errno.h index 365263f2..365263f2 100644 --- a/nss_client/sss_errno.h +++ b/sss_client/sss_errno.h |