[SSSD] [PATCH] Use SO_PEERCRED on the PAM socket

Sumit Bose sbose at redhat.com
Thu Apr 15 13:06:34 UTC 2010


On Thu, Apr 15, 2010 at 08:24:59AM -0400, Stephen Gallagher wrote:
> On 04/15/2010 07:49 AM, Sumit Bose wrote:
> >
> > New version attached.
> >
> > bye,
> > Sumit
> 
> Nack.
> 
> Warnings seen while compiling on Fedora 13:
> 
> ../../src/responder/common/responder_common.c: In function 
> ‘get_client_cred’:
> ../../src/responder/common/responder_common.c:80: warning: passing 
> argument 5 of ‘getsockopt’ from incompatible pointer type
> /usr/include/sys/socket.h:190: note: expected ‘socklen_t * __restrict__’ 
> but argument is of type ‘size_t *’
> ../../src/sss_client/common.c: In function ‘check_server_cred’:
> ../../src/sss_client/common.c:650: warning: passing argument 5 of 
> ‘getsockopt’ from incompatible pointer type
> /usr/include/sys/socket.h:190: note: expected ‘socklen_t * __restrict__’ 
> but argument is of type ‘size_t *’
> 

ah, sorry, looks like it is time to upgrade :-)

New version attached.

bye,
Sumit

> 
> -- 
> Stephen Gallagher
> RHCE 804006346421761
> 
> Delivering value year after year.
> Red Hat ranks #1 in value among software vendors.
> http://www.redhat.com/promo/vendor/
> _______________________________________________
> sssd-devel mailing list
> sssd-devel at lists.fedorahosted.org
> https://fedorahosted.org/mailman/listinfo/sssd-devel
-------------- next part --------------
From 0be18996d1c72be1a8f4bd7954b6412124986029 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Fri, 26 Mar 2010 10:11:22 +0100
Subject: [PATCH 1/2] Revert "Add better checks on PAM socket"

This reverts commit 5a88e963744e5da453e88b5c36499f04712df097.
---
 src/external/platform.m4                |   12 ---
 src/responder/common/responder.h        |    4 -
 src/responder/common/responder_common.c |  137 +------------------------------
 src/sss_client/common.c                 |  126 +---------------------------
 4 files changed, 5 insertions(+), 274 deletions(-)

diff --git a/src/external/platform.m4 b/src/external/platform.m4
index ee00937..71b4f2c 100644
--- a/src/external/platform.m4
+++ b/src/external/platform.m4
@@ -27,15 +27,3 @@ fi
 AM_CONDITIONAL([HAVE_FEDORA], [test x"$osname" == xfedora])
 AM_CONDITIONAL([HAVE_REDHAT], [test x"$osname" == xredhat])
 AM_CONDITIONAL([HAVE_SUSE], [test x"$osname" == xsuse])
-
-AC_CHECK_MEMBERS([struct ucred.pid, struct ucred.uid, struct ucred.gid], , ,
-                 [[#define _GNU_SOURCE
-                   #include <sys/socket.h>]])
-
-if test x"$ac_cv_member_struct_ucred_pid" = xyes -a \
-        x"$ac_cv_member_struct_ucred_uid" = xyes -a \
-        x"$ac_cv_member_struct_ucred_gid" = xyes ; then
-    AC_DEFINE([HAVE_UCRED], [1], [Define if struct ucred is available])
-else
-    AC_MSG_WARN([struct ucred is not available])
-fi
diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h
index 6391fcf..ea6ba58 100644
--- a/src/responder/common/responder.h
+++ b/src/responder/common/responder.h
@@ -101,10 +101,6 @@ struct cli_ctx {
     struct cli_request *creq;
     struct cli_protocol_version *cli_protocol_version;
     int priv;
-    int creds_exchange_done;
-    int client_uid;
-    int client_gid;
-    int client_pid;
 };
 
 struct sss_cmd_table {
diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c
index 315eb73..48ec4bd 100644
--- a/src/responder/common/responder_common.c
+++ b/src/responder/common/responder_common.c
@@ -19,9 +19,6 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-/* for struct ucred */
-#define _GNU_SOURCE
-
 #include <stdio.h>
 #include <unistd.h>
 #include <fcntl.h>
@@ -32,8 +29,7 @@
 #include <string.h>
 #include <sys/time.h>
 #include <errno.h>
-#include <popt.h>
-#include "config.h"
+#include "popt.h"
 #include "util/util.h"
 #include "db/sysdb.h"
 #include "confdb/confdb.h"
@@ -148,134 +144,12 @@ static void client_recv(struct cli_ctx *cctx)
     return;
 }
 
-static void cred_handler(struct cli_ctx *cctx, char action)
-{
-#ifdef HAVE_UCRED
-    int ret;
-    int fd;
-    struct msghdr msg;
-    struct iovec iov;
-    struct cmsghdr *cmsg;
-    struct ucred *creds;
-    /* buf must be aligned on some architectures. */
-    union ubuf {
-        int align;
-        char buf[CMSG_SPACE(sizeof(struct ucred))];
-    } u;
-    char dummy='s';
-    int enable=1;
-
-    if (cctx->creds_exchange_done != 0) {
-        DEBUG(1, ("cred_handler called, but creds are already exchanged.\n"));
-        goto failed;
-    }
-
-    fd = cctx->cfd;
-
-    iov.iov_base = &dummy;
-    iov.iov_len = 1;
-
-    memset (&msg, 0, sizeof(msg));
-
-    msg.msg_name = NULL;
-    msg.msg_namelen = 0;
-    msg.msg_iov = &iov;
-    msg.msg_iovlen = 1;
-
-    msg.msg_control = u.buf;
-    msg.msg_controllen = sizeof(u.buf);
-
-    switch (action) {
-        case 'r':
-            ret = setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &enable, sizeof(int));
-            if (ret == -1) {
-                DEBUG(1, ("setsockopt failed: [%d][%s].\n", errno,
-                                                            strerror(errno)));
-                goto failed;
-            }
-
-            ret = recvmsg(fd, &msg, 0);
-            if (ret == -1) {
-                DEBUG(1, ("recvmsg failed.[%d][%s]\n", errno, strerror(errno)));
-                goto failed;
-            }
-
-            cmsg = CMSG_FIRSTHDR(&msg);
-
-            if (cmsg->cmsg_level == SOL_SOCKET &&
-                cmsg->cmsg_type == SCM_CREDENTIALS) {
-                creds = (struct ucred *) CMSG_DATA(cmsg);
-                DEBUG(1, ("creds: [%d][%d][%d]\n",creds->uid, creds->gid,
-                                                  creds->pid));
-                cctx->client_uid = creds->uid;
-                cctx->client_gid = creds->gid;
-                cctx->client_pid = creds->pid;
-            }
-
-            TEVENT_FD_WRITEABLE(cctx->cfde);
-
-            return;
-            break;
-        case 's':
-            cmsg = CMSG_FIRSTHDR(&msg);
-            cmsg->cmsg_level = SOL_SOCKET;
-            cmsg->cmsg_type = SCM_CREDENTIALS;
-            cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
-
-            creds = (struct ucred *) CMSG_DATA(cmsg);
-
-            creds->uid = geteuid();
-            creds->gid = getegid();
-            creds->pid = getpid();
-
-            msg.msg_controllen = cmsg->cmsg_len;
-
-            ret = sendmsg(fd, &msg, 0);
-            if (ret == -1) {
-                DEBUG(1, ("sendmsg failed.[%d][%s]\n", errno, strerror(errno)));
-                goto failed;
-            }
-            DEBUG(4, ("Send creds to the client succesfully.\n"));
-            cctx->creds_exchange_done = 1;
-
-            TEVENT_FD_NOT_WRITEABLE(cctx->cfde);
-            return;
-        default:
-            DEBUG(1, ("Unknown action [%c].\n", action));
-            goto failed;
-    }
-
-failed:
-    talloc_free(cctx);
-    return;
-
-#else
-
-    DEBUG(9, ("Credential exchange not available over socket, "
-              "continuing without.\n"));
-    cctx->creds_exchange_done = 1;
-    return;
-
-#endif
-}
-
 static void client_fd_handler(struct tevent_context *ev,
                               struct tevent_fd *fde,
                               uint16_t flags, void *ptr)
 {
     struct cli_ctx *cctx = talloc_get_type(ptr, struct cli_ctx);
 
-    if (cctx->creds_exchange_done == 0) {
-        if (flags & TEVENT_FD_READ) {
-            cred_handler(cctx, 'r');
-            return;
-        }
-        if (flags & TEVENT_FD_WRITE) {
-            cred_handler(cctx, 's');
-            return;
-        }
-    }
-
     if (flags & TEVENT_FD_READ) {
         client_recv(cctx);
         return;
@@ -339,10 +213,6 @@ static void accept_priv_fd_handler(struct tevent_context *ev,
     }
 
     cctx->priv = 1;
-    cctx->creds_exchange_done = 0;
-    cctx->client_uid = -1;
-    cctx->client_gid = -1;
-    cctx->client_pid = -1;
 
     cctx->cfde = tevent_add_fd(ev, cctx, cctx->cfd,
                                TEVENT_FD_READ, client_fd_handler, cctx);
@@ -395,11 +265,6 @@ static void accept_fd_handler(struct tevent_context *ev,
         return;
     }
 
-    cctx->creds_exchange_done = 0;
-    cctx->client_uid = -1;
-    cctx->client_gid = -1;
-    cctx->client_pid = -1;
-
     cctx->cfde = tevent_add_fd(ev, cctx, cctx->cfd,
                                TEVENT_FD_READ, client_fd_handler, cctx);
     if (!cctx->cfde) {
diff --git a/src/sss_client/common.c b/src/sss_client/common.c
index 07b9d0d..6732c24 100644
--- a/src/sss_client/common.c
+++ b/src/sss_client/common.c
@@ -23,9 +23,6 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-/* for struct ucred */
-#define _GNU_SOURCE
-
 #include <nss.h>
 #include <security/pam_modules.h>
 #include <errno.h>
@@ -39,8 +36,6 @@
 #include <string.h>
 #include <fcntl.h>
 #include <poll.h>
-
-#include "config.h"
 #include "sss_cli.h"
 
 /* common functions */
@@ -55,108 +50,6 @@ static void sss_cli_close_socket(void)
     }
 }
 
-static int exchange_credentials(void)
-{
-#ifdef HAVE_UCRED
-    int ret;
-    struct msghdr msg;
-    struct cmsghdr *cmsg;
-    struct iovec iov;
-    char dummy='a';
-    /* buf must be aligned on some architectures. */
-    union ubuf {
-        int align;
-        char buf[CMSG_SPACE(sizeof(struct ucred))];
-    } u;
-    struct ucred *creds;
-    int enable = 1;
-    struct pollfd pfd;
-
-    ret = setsockopt(sss_cli_sd, SOL_SOCKET, SO_PASSCRED, &enable, sizeof(int));
-    if (ret == -1) {
-        return errno;
-    }
-
-    iov.iov_base = &dummy;
-    iov.iov_len = 1;
-
-    memset(&msg, 0, sizeof(msg));
-
-    msg.msg_name = NULL;
-    msg.msg_namelen = 0;
-    msg.msg_iov = &iov;
-    msg.msg_iovlen = 1;
-
-    msg.msg_control = u.buf;
-    msg.msg_controllen = sizeof(u.buf);
-
-    cmsg = CMSG_FIRSTHDR(&msg);
-    cmsg->cmsg_level = SOL_SOCKET;
-    cmsg->cmsg_type = SCM_CREDENTIALS;
-    cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
-
-    creds = (struct ucred *) CMSG_DATA(cmsg);
-
-    creds->uid = geteuid();
-    creds->gid = getegid();
-    creds->pid = getpid();
-
-    msg.msg_controllen = cmsg->cmsg_len;
-
-    pfd.fd = sss_cli_sd;
-    pfd.events = POLLOUT;
-    ret = poll(&pfd, 1, SSS_CLI_SOCKET_TIMEOUT);
-    if (ret != 1 || !(pfd.revents & POLLOUT) ) {
-        return errno;
-    }
-
-    ret = sendmsg(sss_cli_sd, &msg, 0);
-    if (ret == -1) {
-        return errno;
-    }
-
-    memset(&msg, 0, sizeof(msg));
-
-    msg.msg_name = NULL;
-    msg.msg_namelen = 0;
-    msg.msg_iov = &iov;
-    msg.msg_iovlen = 1;
-
-    msg.msg_control = u.buf;
-    msg.msg_controllen = sizeof(u.buf);
-
-    pfd.fd = sss_cli_sd;
-    pfd.events = POLLIN;
-    ret = poll(&pfd, 1, SSS_CLI_SOCKET_TIMEOUT);
-
-    if (ret != 1 || !(pfd.revents & POLLIN) ) {
-        return errno;
-    }
-
-    ret = recvmsg(sss_cli_sd, &msg, 0);
-    if (ret == -1) {
-        return errno;
-    }
-
-    cmsg = CMSG_FIRSTHDR(&msg);
-
-    if (msg.msg_controllen != 0 && cmsg->cmsg_level == SOL_SOCKET &&
-                                   cmsg->cmsg_type == SCM_CREDENTIALS) {
-        creds = (struct ucred *) CMSG_DATA(cmsg);
-        if (creds->uid != 0 || creds->gid!= 0) {
-            return SSS_STATUS_UNAVAIL;
-        }
-    }
-
-    return SSS_STATUS_SUCCESS;
-
-#else
-
-    return SSS_STATUS_SUCCESS;
-
-#endif
-}
-
 /* Requests:
  *
  * byte 0-3: 32bit unsigned with length (the complete packet length: 0 to X)
@@ -706,10 +599,9 @@ static enum sss_status sss_cli_check_socket(int *errnop, const char *socket_name
 
     sss_cli_sd = mysd;
 
-    if (exchange_credentials() == SSS_STATUS_SUCCESS)
-        if (sss_nss_check_version(socket_name) == NSS_STATUS_SUCCESS) {
-            return SSS_STATUS_SUCCESS;
-        }
+    if (sss_nss_check_version(socket_name) == NSS_STATUS_SUCCESS) {
+        return SSS_STATUS_SUCCESS;
+    }
 
     sss_cli_close_socket();
     *errnop = EFAULT;
@@ -761,22 +653,12 @@ int sss_pam_make_request(enum sss_cli_command cmd,
         if (ret != 0) return PAM_SERVICE_ERR;
         if ( ! (stat_buf.st_uid == 0 &&
                 stat_buf.st_gid == 0 &&
-                S_ISSOCK(stat_buf.st_mode) &&
-                (stat_buf.st_mode & ~S_IFMT) == 0600 )) {
+                (stat_buf.st_mode&(S_IFSOCK|S_IRUSR|S_IWUSR)) == stat_buf.st_mode)) {
             return PAM_SERVICE_ERR;
         }
 
         ret = sss_cli_check_socket(errnop, SSS_PAM_PRIV_SOCKET_NAME);
     } else {
-        ret = stat(SSS_PAM_SOCKET_NAME, &stat_buf);
-        if (ret != 0) return PAM_SERVICE_ERR;
-        if ( ! (stat_buf.st_uid == 0 &&
-                stat_buf.st_gid == 0 &&
-                S_ISSOCK(stat_buf.st_mode) &&
-                (stat_buf.st_mode & ~S_IFMT) == 0666 )) {
-            return PAM_SERVICE_ERR;
-        }
-
         ret = sss_cli_check_socket(errnop, SSS_PAM_SOCKET_NAME);
     }
     if (ret != NSS_STATUS_SUCCESS) {
-- 
1.6.6.1

-------------- next part --------------
From 5cc9ed97b68925b505c01c2032442f0e449e0d3e Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Mon, 29 Mar 2010 10:13:55 +0200
Subject: [PATCH 2/2] Use SO_PEERCRED on the PAM socket

This is the second attempt to let the PAM client and the PAM responder
exchange their credentials, i.e. uid, gid and pid. Because this approach
does not require any message interchange between the client and the
server the protocol version number is not changed.

On the client side the connection is terminated it the responder is not
run by root. On the server side the effective uid and gid and the pid of
the client are available for future use.

The following additional changes are made by this patch:
- the checks of the ownership and the permissions on the PAM sockets are
  enhanced
- internal error codes are introduced on the client side to generate
  more specific log messages if an error occurs
---
 src/external/platform.m4                |   12 +++++
 src/responder/common/responder.h        |    3 +
 src/responder/common/responder_common.c |   53 ++++++++++++++++++++-
 src/sss_client/common.c                 |   81 ++++++++++++++++++++++++++++++-
 src/sss_client/pam_sss.c                |    5 ++-
 src/sss_client/sss_cli.h                |   11 ++++
 6 files changed, 162 insertions(+), 3 deletions(-)

diff --git a/src/external/platform.m4 b/src/external/platform.m4
index 71b4f2c..ee00937 100644
--- a/src/external/platform.m4
+++ b/src/external/platform.m4
@@ -27,3 +27,15 @@ fi
 AM_CONDITIONAL([HAVE_FEDORA], [test x"$osname" == xfedora])
 AM_CONDITIONAL([HAVE_REDHAT], [test x"$osname" == xredhat])
 AM_CONDITIONAL([HAVE_SUSE], [test x"$osname" == xsuse])
+
+AC_CHECK_MEMBERS([struct ucred.pid, struct ucred.uid, struct ucred.gid], , ,
+                 [[#define _GNU_SOURCE
+                   #include <sys/socket.h>]])
+
+if test x"$ac_cv_member_struct_ucred_pid" = xyes -a \
+        x"$ac_cv_member_struct_ucred_uid" = xyes -a \
+        x"$ac_cv_member_struct_ucred_gid" = xyes ; then
+    AC_DEFINE([HAVE_UCRED], [1], [Define if struct ucred is available])
+else
+    AC_MSG_WARN([struct ucred is not available])
+fi
diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h
index ea6ba58..deb1e5a 100644
--- a/src/responder/common/responder.h
+++ b/src/responder/common/responder.h
@@ -101,6 +101,9 @@ struct cli_ctx {
     struct cli_request *creq;
     struct cli_protocol_version *cli_protocol_version;
     int priv;
+    int32_t client_euid;
+    int32_t client_egid;
+    int32_t client_pid;
 };
 
 struct sss_cmd_table {
diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c
index 48ec4bd..e39063b 100644
--- a/src/responder/common/responder_common.c
+++ b/src/responder/common/responder_common.c
@@ -19,6 +19,9 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+/* for struct ucred */
+#define _GNU_SOURCE
+
 #include <stdio.h>
 #include <unistd.h>
 #include <fcntl.h>
@@ -29,7 +32,8 @@
 #include <string.h>
 #include <sys/time.h>
 #include <errno.h>
-#include "popt.h"
+#include <popt.h>
+#include "config.h"
 #include "util/util.h"
 #include "db/sysdb.h"
 #include "confdb/confdb.h"
@@ -61,6 +65,40 @@ static int client_destructor(struct cli_ctx *ctx)
     return 0;
 }
 
+static errno_t get_client_cred(struct cli_ctx *cctx)
+{
+#ifdef HAVE_UCRED
+    int ret;
+    struct ucred client_cred;
+    socklen_t client_cred_len = sizeof(client_cred);
+
+    cctx->client_euid = -1;
+    cctx->client_egid = -1;
+    cctx->client_pid = -1;
+
+    ret = getsockopt(cctx->cfd, SOL_SOCKET, SO_PEERCRED, &client_cred,
+                     &client_cred_len);
+    if (ret != EOK) {
+        ret = errno;
+        DEBUG(1, ("getsock failed [%d][%s].\n", ret, strerror(ret)));
+        return ret;
+    }
+    if (client_cred_len != sizeof(struct ucred)) {
+        DEBUG(1, ("getsockopt returned unexpected message size.\n"));
+        return ENOMSG;
+    }
+
+    cctx->client_euid = client_cred.uid;
+    cctx->client_egid = client_cred.gid;
+    cctx->client_pid = client_cred.pid;
+
+    DEBUG(9, ("Client creds: euid[%d] egid[%d] pid[%d].\n",
+              cctx->client_euid, cctx->client_egid, cctx->client_pid));
+#endif
+
+    return EOK;
+}
+
 static void client_send(struct cli_ctx *cctx)
 {
     int ret;
@@ -214,6 +252,12 @@ static void accept_priv_fd_handler(struct tevent_context *ev,
 
     cctx->priv = 1;
 
+    ret = get_client_cred(cctx);
+    if (ret != EOK) {
+        DEBUG(2, ("get_client_cred failed, "
+                  "client cred may not be available.\n"));
+    }
+
     cctx->cfde = tevent_add_fd(ev, cctx, cctx->cfd,
                                TEVENT_FD_READ, client_fd_handler, cctx);
     if (!cctx->cfde) {
@@ -240,6 +284,7 @@ static void accept_fd_handler(struct tevent_context *ev,
     struct resp_ctx *rctx = talloc_get_type(ptr, struct resp_ctx);
     struct cli_ctx *cctx;
     socklen_t len;
+    int ret;
 
     cctx = talloc_zero(rctx, struct cli_ctx);
     if (!cctx) {
@@ -265,6 +310,12 @@ static void accept_fd_handler(struct tevent_context *ev,
         return;
     }
 
+    ret = get_client_cred(cctx);
+    if (ret != EOK) {
+        DEBUG(2, ("get_client_cred failed, "
+                  "client cred may not be available.\n"));
+    }
+
     cctx->cfde = tevent_add_fd(ev, cctx, cctx->cfd,
                                TEVENT_FD_READ, client_fd_handler, cctx);
     if (!cctx->cfde) {
diff --git a/src/sss_client/common.c b/src/sss_client/common.c
index 6732c24..237b90a 100644
--- a/src/sss_client/common.c
+++ b/src/sss_client/common.c
@@ -23,6 +23,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+/* for struct ucred */
+#define _GNU_SOURCE
+
 #include <nss.h>
 #include <security/pam_modules.h>
 #include <errno.h>
@@ -36,6 +39,10 @@
 #include <string.h>
 #include <fcntl.h>
 #include <poll.h>
+
+#include <libintl.h>
+#define _(STRING) dgettext (PACKAGE, STRING)
+#include "config.h"
 #include "sss_cli.h"
 
 /* common functions */
@@ -632,6 +639,29 @@ enum nss_status sss_nss_make_request(enum sss_cli_command cmd,
     return sss_nss_make_request_nochecks(cmd, rd, repbuf, replen, errnop);
 }
 
+errno_t check_server_cred(int sockfd)
+{
+#ifdef HAVE_UCRED
+    int ret;
+    struct ucred server_cred;
+    socklen_t server_cred_len = sizeof(server_cred);
+
+    ret = getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &server_cred,
+                     &server_cred_len);
+    if (ret != 0) {
+        return errno;
+    }
+
+    if (server_cred_len != sizeof(struct ucred)) {
+        return ESSS_BAD_CRED_MSG;
+    }
+
+    if (server_cred.uid != 0 || server_cred.gid != 0) {
+        return ESSS_SERVER_NOT_TRUSTED;
+    }
+#endif
+    return 0;
+}
 int sss_pam_make_request(enum sss_cli_command cmd,
                       struct sss_cli_req_data *rd,
                       uint8_t **repbuf, size_t *replen,
@@ -653,17 +683,66 @@ int sss_pam_make_request(enum sss_cli_command cmd,
         if (ret != 0) return PAM_SERVICE_ERR;
         if ( ! (stat_buf.st_uid == 0 &&
                 stat_buf.st_gid == 0 &&
-                (stat_buf.st_mode&(S_IFSOCK|S_IRUSR|S_IWUSR)) == stat_buf.st_mode)) {
+                S_ISSOCK(stat_buf.st_mode) &&
+                (stat_buf.st_mode & ~S_IFMT) == 0600 )) {
+            *errnop = ESSS_BAD_PRIV_SOCKET;
             return PAM_SERVICE_ERR;
         }
 
         ret = sss_cli_check_socket(errnop, SSS_PAM_PRIV_SOCKET_NAME);
     } else {
+        ret = stat(SSS_PAM_SOCKET_NAME, &stat_buf);
+        if (ret != 0) return PAM_SERVICE_ERR;
+        if ( ! (stat_buf.st_uid == 0 &&
+                stat_buf.st_gid == 0 &&
+                S_ISSOCK(stat_buf.st_mode) &&
+                (stat_buf.st_mode & ~S_IFMT) == 0666 )) {
+            *errnop = ESSS_BAD_PUB_SOCKET;
+            return PAM_SERVICE_ERR;
+        }
+
         ret = sss_cli_check_socket(errnop, SSS_PAM_SOCKET_NAME);
     }
     if (ret != NSS_STATUS_SUCCESS) {
         return PAM_SERVICE_ERR;
     }
 
+    ret = check_server_cred(sss_cli_sd);
+    if (ret != 0) {
+        sss_cli_close_socket();
+        *errnop = ret;
+        return PAM_SERVICE_ERR;
+    }
+
     return sss_nss_make_request_nochecks(cmd, rd, repbuf, replen, errnop);
 }
+
+
+const char *ssscli_err2string(int err)
+{
+    const char *m;
+
+    switch(err) {
+        case ESSS_BAD_PRIV_SOCKET:
+            return _("Privileged socket has wrong ownership or permissions.");
+            break;
+        case ESSS_BAD_PUB_SOCKET:
+            return _("Public socket has wrong ownership or permissions.");
+            break;
+        case ESSS_BAD_CRED_MSG:
+            return _("Unexpected format of the server credential message.");
+            break;
+        case ESSS_SERVER_NOT_TRUSTED:
+            return _("SSSD is not run by root.");
+            break;
+        default:
+            m = strerror(err);
+            if (m == NULL) {
+                return _("An error occurred, but no description can be found.");
+            }
+            return m;
+            break;
+    }
+
+    return _("Unexpected error while looking for an error description");
+}
diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c
index 6059dfa..4208faa 100644
--- a/src/sss_client/pam_sss.c
+++ b/src/sss_client/pam_sss.c
@@ -877,10 +877,13 @@ static int send_and_receive(pam_handle_t *pamh, struct pam_items *pi,
     }
     rd.data = buf;
 
+    errnop = 0;
     ret = sss_pam_make_request(task, &rd, &repbuf, &replen, &errnop);
 
     if (ret != NSS_STATUS_SUCCESS) {
-        logger(pamh, LOG_ERR, "Request to sssd failed.");
+        if (errnop != 0) {
+            logger(pamh, LOG_ERR, "Request to sssd failed. %s", ssscli_err2string(errnop));
+        }
         pam_status = PAM_SYSTEM_ERR;
         goto done;
     }
diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h
index f387265..f7e58fe 100644
--- a/src/sss_client/sss_cli.h
+++ b/src/sss_client/sss_cli.h
@@ -406,6 +406,17 @@ enum user_info_type {
  * @}
  */ /* end of group sss_pam_cli */
 
+enum sss_cli_error_codes {
+    ESSS_SSS_CLI_ERROR_START = 0x1000,
+    ESSS_BAD_PRIV_SOCKET,
+    ESSS_BAD_PUB_SOCKET,
+    ESSS_BAD_CRED_MSG,
+    ESSS_SERVER_NOT_TRUSTED,
+
+    ESS_SSS_CLI_ERROR_MAX
+};
+
+const char *ssscli_err2string(int err);
 
 enum nss_status sss_nss_make_request(enum sss_cli_command cmd,
                                      struct sss_cli_req_data *rd,
-- 
1.6.6.1



More information about the sssd-devel mailing list