[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[Freeipa-devel] [PATCH] added scm_credentials exchange



Hi,

with this patch client and responder can identify the other side. So far
uid, gid and pid are only exchanged and stored. As a next step I would
include this information to the pam data to, e.g., allow passowrd reset
by root.

bye,
Sumit
>From b0ffe509ce874c6e72fcee3d9ff3d41976b0ffbe Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose redhat com>
Date: Wed, 4 Mar 2009 14:00:50 +0100
Subject: [PATCH] added scm_credentials exchange

---
 server/responder/common/responder_cmd.h    |    4 +
 server/responder/common/responder_common.c |  116 +++++++++++++++++++++++++++-
 server/responder/common/responder_dp.h     |    2 +-
 server/responder/common/responder_packet.h |    2 +
 sss_client/common.c                        |  100 +++++++++++++++++++++++-
 5 files changed, 218 insertions(+), 6 deletions(-)

diff --git a/server/responder/common/responder_cmd.h b/server/responder/common/responder_cmd.h
index 15141a0..9939542 100644
--- a/server/responder/common/responder_cmd.h
+++ b/server/responder/common/responder_cmd.h
@@ -66,6 +66,10 @@ struct cli_ctx {
     struct tevent_context *ev;
     struct nss_ctx *nctx;
     int cfd;
+    int creds_exchange_done;
+    int client_uid;
+    int client_gid;
+    int client_pid;
     struct tevent_fd *cfde;
     struct sockaddr_un addr;
     struct cli_request *creq;
diff --git a/server/responder/common/responder_common.c b/server/responder/common/responder_common.c
index f532102..9d44943 100644
--- a/server/responder/common/responder_common.c
+++ b/server/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>
@@ -31,12 +34,12 @@
 #include <errno.h>
 #include "popt.h"
 #include "util/util.h"
-#include "responder/nss/nsssrv.h"
 #include "db/sysdb.h"
 #include "confdb/confdb.h"
 #include "dbus/dbus.h"
 #include "sbus/sssd_dbus.h"
 #include "util/btreemap.h"
+#include "responder/common/responder_common.h"
 #include "responder/common/responder_packet.h"
 #include "responder/common/responder_cmd.h"
 #include "responder/common/responder_dp.h"
@@ -102,7 +105,7 @@ static void client_recv(struct tevent_context *ev, struct cli_ctx *cctx)
     }
 
     if (!cctx->creq->in) {
-        ret = sss_packet_new(cctx->creq, NSS_PACKET_MAX_RECV_SIZE,
+        ret = sss_packet_new(cctx->creq, SSS_PACKET_MAX_RECV_SIZE,
                              0, &cctx->creq->in);
         if (ret != EOK) {
             DEBUG(0, ("Failed to alloc request, aborting client!\n"));
@@ -148,12 +151,117 @@ static void client_recv(struct tevent_context *ev, struct cli_ctx *cctx)
     return;
 }
 
+static void cred_handler(struct cli_ctx *cctx, char action)
+{
+    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;
+}
+
 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;
@@ -197,6 +305,8 @@ static void accept_fd_handler(struct tevent_context *ev,
         return;
     }
 
+    cctx->creds_exchange_done = 0;
+
     cctx->cfde = tevent_add_fd(ev, cctx, cctx->cfd,
                                TEVENT_FD_READ, client_fd_handler, cctx);
     if (!cctx->cfde) {
@@ -427,7 +537,7 @@ int sss_parse_name(TALLOC_CTX *memctx,
     struct btreemap *node;
     int ret;
 
-    if ((delim = strchr(fullname, NSS_DOMAIN_DELIM)) != NULL) {
+    if ((delim = strchr(fullname, SSS_DOMAIN_DELIM)) != NULL) {
 
         /* Check for registered domain */
         ret = btreemap_search_key(domain_map, (void *)(delim+1), &node);
diff --git a/server/responder/common/responder_dp.h b/server/responder/common/responder_dp.h
index 2eeddf5..b0194f3 100644
--- a/server/responder/common/responder_dp.h
+++ b/server/responder/common/responder_dp.h
@@ -1,4 +1,4 @@
-#include "responder/nss/nsssrv.h"
+#include "responder/common/responder_cmd.h"
 #include "sbus/sssd_dbus.h"
 
 int sss_dp_init(struct nss_ctx *nctx, struct sbus_method dp_methods[]);
diff --git a/server/responder/common/responder_packet.h b/server/responder/common/responder_packet.h
index 1a85294..6ac92b1 100644
--- a/server/responder/common/responder_packet.h
+++ b/server/responder/common/responder_packet.h
@@ -26,6 +26,8 @@
 
 struct sss_packet;
 
+#define SSS_PACKET_MAX_RECV_SIZE 1024
+
 int sss_packet_new(TALLOC_CTX *mem_ctx, size_t size,
                    enum sss_cli_command cmd,
                    struct sss_packet **rpacket);
diff --git a/sss_client/common.c b/sss_client/common.c
index 50aabff..b5aa8fb 100644
--- a/sss_client/common.c
+++ b/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>
@@ -49,6 +52,97 @@ static void sss_cli_close_socket(void)
     }
 }
 
+static int exchange_scm_credentials(void)
+{
+    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;
+}
+
 /* Requests:
  *
  * byte 0-3: 32bit unsigned with length (the complete packet length: 0 to X)
@@ -554,8 +648,10 @@ static enum sss_status sss_cli_check_socket(int *errnop, const char *socket_name
 
     sss_cli_sd = mysd;
 
-    if (sss_nss_check_version()) {
-        return SSS_STATUS_SUCCESS;
+    if (exchange_scm_credentials() == SSS_STATUS_SUCCESS) {
+        if (sss_nss_check_version()) {
+            return SSS_STATUS_SUCCESS;
+        }
     }
 
     sss_cli_close_socket();
-- 
1.6.0.6


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]