summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSumit Bose <sbose@redhat.com>2009-02-24 19:37:42 -0500
committerSimo Sorce <ssorce@redhat.com>2009-02-24 21:01:02 -0500
commitfcef1231eea30ee9cdc75f3f39f4b9207a84ea1d (patch)
tree50525e47d7136efe2c7c746edff0de897a8d2b81
parent98531e56318b65eb1bb6883fdfe12e771d8a1efe (diff)
downloadsssd-fcef1231eea30ee9cdc75f3f39f4b9207a84ea1d.tar.gz
sssd-fcef1231eea30ee9cdc75f3f39f4b9207a84ea1d.tar.xz
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.txt20
-rw-r--r--sss_client/Makefile.in (renamed from nss_client/Makefile.in)22
-rwxr-xr-xsss_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-xsss_client/config.guess (renamed from nss_client/config.guess)0
-rwxr-xr-xsss_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-xsss_client/install-sh (renamed from nss_client/install-sh)0
-rw-r--r--sss_client/pam_sss.c324
-rw-r--r--sss_client/pam_test_client.c75
-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
diff --git a/BUILD.txt b/BUILD.txt
index ac66ed4b3..6034e7b45 100644
--- a/BUILD.txt
+++ b/BUILD.txt
@@ -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 4b7199178..6d80f83c3 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 bf84eeee1..bf84eeee1 100755
--- a/nss_client/autogen.sh
+++ b/sss_client/autogen.sh
diff --git a/nss_client/common.c b/sss_client/common.c
index a79dc660b..50aabff27 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 354dbe175..354dbe175 100755
--- a/nss_client/config.guess
+++ b/sss_client/config.guess
diff --git a/nss_client/config.sub b/sss_client/config.sub
index 23cd6fd75..23cd6fd75 100755
--- a/nss_client/config.sub
+++ b/sss_client/config.sub
diff --git a/nss_client/configure.ac b/sss_client/configure.ac
index 9bd4f1f33..9bd4f1f33 100644
--- a/nss_client/configure.ac
+++ b/sss_client/configure.ac
diff --git a/nss_client/exports.linux b/sss_client/exports.linux
index bcc6b10e1..bcc6b10e1 100644
--- a/nss_client/exports.linux
+++ b/sss_client/exports.linux
diff --git a/nss_client/group.c b/sss_client/group.c
index 74cc73944..c340a2cc3 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 58719246f..58719246f 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 000000000..25a1d2caf
--- /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 000000000..675d7b2b2
--- /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 776e6cea0..d02e067f1 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 adb0b7bb7..adb0b7bb7 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 b5a921628..5445b5fa6 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 365263f2f..365263f2f 100644
--- a/nss_client/sss_errno.h
+++ b/sss_client/sss_errno.h