Hi,

this patch adds a check the public PAM socket it a socket that belongs
to root for all plattforms and uses a SCM_CREDENTIALS ancillary
message to identify the uid/gid/pid of the peer if these messages are
available.

bye,
Sumit
From b148d1e7276a8e83079ebf735d3bd34f7b690660 Mon Sep 17 00:00:00 2001
From: Sumit Bose <[email protected]>
Date: Tue, 9 Feb 2010 12:39:49 +0100
Subject: [PATCH] Add better checks on PAM socket

- check if the public socket belongs to root and has 0666 permissions
- use a SCM_CREDENTIALS message if available
---
 src/external/platform.m4                |   12 +++
 src/responder/common/responder.h        |    4 +
 src/responder/common/responder_common.c |  133 ++++++++++++++++++++++++++++++-
 src/sss_client/common.c                 |  122 +++++++++++++++++++++++++++-
 4 files changed, 266 insertions(+), 5 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..6391fcf 100644
--- a/src/responder/common/responder.h
+++ b/src/responder/common/responder.h
@@ -101,6 +101,10 @@ 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 f524afb..f4de3a7 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"
@@ -144,12 +148,130 @@ static void client_recv(struct tevent_context *ev, 
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;
+    char buf[CMSG_SPACE(sizeof(struct ucred))];
+    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 = buf;
+    msg.msg_controllen = sizeof(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(ev, cctx);
         return;
@@ -213,6 +335,10 @@ 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);
@@ -265,6 +391,11 @@ 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 6732c24..f1c8d18 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,8 @@
 #include <string.h>
 #include <fcntl.h>
 #include <poll.h>
+
+#include "config.h"
 #include "sss_cli.h"
 
 /* common functions */
@@ -50,6 +55,104 @@ 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';
+    char buf[CMSG_SPACE(sizeof(struct ucred))];
+    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 = buf;
+    msg.msg_controllen = sizeof(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 = buf;
+    msg.msg_controllen = sizeof(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)
@@ -599,9 +702,10 @@ static enum sss_status sss_cli_check_socket(int *errnop, 
const char *socket_name
 
     sss_cli_sd = mysd;
 
-    if (sss_nss_check_version(socket_name) == NSS_STATUS_SUCCESS) {
-        return SSS_STATUS_SUCCESS;
-    }
+    if (exchange_credentials() == SSS_STATUS_SUCCESS)
+        if (sss_nss_check_version(socket_name) == NSS_STATUS_SUCCESS) {
+            return SSS_STATUS_SUCCESS;
+        }
 
     sss_cli_close_socket();
     *errnop = EFAULT;
@@ -653,12 +757,22 @@ 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 )) {
             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

_______________________________________________
sssd-devel mailing list
[email protected]
https://fedorahosted.org/mailman/listinfo/sssd-devel

Reply via email to