LCOV - code coverage report
Current view: top level - egg - egg-unix-credentials.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 61.7 % 47 29
Test Date: 2024-12-15 20:37:51 Functions: 75.0 % 4 3

            Line data    Source code
       1              : /*
       2              :  * Copyright (C) 2008 Stefan Walter
       3              :  *
       4              :  * Redistribution and use in source and binary forms, with or without
       5              :  * modification, are permitted provided that the following conditions
       6              :  * are met:
       7              :  *
       8              :  *     * Redistributions of source code must retain the above
       9              :  *       copyright notice, this list of conditions and the
      10              :  *       following disclaimer.
      11              :  *     * Redistributions in binary form must reproduce the
      12              :  *       above copyright notice, this list of conditions and
      13              :  *       the following disclaimer in the documentation and/or
      14              :  *       other materials provided with the distribution.
      15              :  *     * The names of contributors to this software may not be
      16              :  *       used to endorse or promote products derived from this
      17              :  *       software without specific prior written permission.
      18              :  *
      19              :  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      20              :  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      21              :  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
      22              :  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
      23              :  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
      24              :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
      25              :  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
      26              :  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
      27              :  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
      28              :  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
      29              :  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
      30              :  * DAMAGE.
      31              :  *
      32              :  * Author: Stef Walter <stefw@thewalter.net>
      33              :  */
      34              : 
      35              : #include "config.h"
      36              : 
      37              : #include "egg-unix-credentials.h"
      38              : 
      39              : #include <sys/types.h>
      40              : #include <sys/socket.h>
      41              : #include <sys/uio.h>
      42              : #include <sys/un.h>
      43              : #include <errno.h>
      44              : #include <stdio.h>
      45              : #include <string.h>
      46              : 
      47              : #if defined(HAVE_GETPEERUCRED)
      48              : #include <ucred.h>
      49              : #endif
      50              : 
      51              : int
      52            7 : egg_unix_credentials_read (int sock, pid_t *pid, uid_t *uid)
      53              : {
      54              :         struct msghdr msg;
      55              :         struct iovec iov;
      56              :         char buf;
      57              :         int ret;
      58              :         
      59              : #if defined(HAVE_CMSGCRED) || defined(LOCAL_CREDS)
      60              :         /* Prefer CMSGCRED over LOCAL_CREDS because the former provides the
      61              :          * remote PID. */
      62              : #if defined(HAVE_CMSGCRED)
      63              :         struct cmsgcred *cred;
      64              : #else /* defined(LOCAL_CREDS) */
      65              :         struct sockcred *cred;
      66              : #endif
      67              :         union {
      68              :                 struct cmsghdr hdr;
      69              :                 char cred[CMSG_SPACE (sizeof *cred)];
      70              :         } cmsg;
      71              : #endif
      72              :         
      73            7 :         *pid = 0;
      74            7 :         *uid = 0;
      75              :         
      76              :         /* If LOCAL_CREDS are used in this platform, they have already been
      77              :          * initialized by init_connection prior to sending of the credentials
      78              :          * byte we receive below. */
      79              :         
      80            7 :         iov.iov_base = &buf;
      81            7 :         iov.iov_len = 1;
      82              :         
      83            7 :         memset (&msg, 0, sizeof (msg));
      84            7 :         msg.msg_iov = &iov;
      85            7 :         msg.msg_iovlen = 1;
      86              :         
      87              : #if defined(HAVE_CMSGCRED) || defined(LOCAL_CREDS)
      88              :         memset (&cmsg, 0, sizeof (cmsg));
      89              :         msg.msg_control = (caddr_t) &cmsg;
      90              :         msg.msg_controllen = CMSG_SPACE(sizeof *cred);
      91              : #endif
      92              : 
      93            7 :  again:
      94            7 :         ret = recvmsg (sock, &msg, 0);
      95              : 
      96            7 :         if (ret < 0) {
      97            0 :                 if (errno == EINTR)
      98            0 :                         goto again;
      99            0 :                 return -1;
     100              :                 
     101            7 :         } else if (ret == 0) {
     102              :                 /* Disconnected */
     103            0 :                 return -1;
     104              :         }
     105              :         
     106            7 :         if (buf != '\0') {
     107            0 :                 fprintf (stderr, "credentials byte was not nul\n");
     108            0 :                 return -1;
     109              :         }
     110              : 
     111              : #if defined(HAVE_CMSGCRED) || defined(LOCAL_CREDS)
     112              :         if (cmsg.hdr.cmsg_len < CMSG_LEN (sizeof *cred) ||
     113              :             cmsg.hdr.cmsg_type != SCM_CREDS) {
     114              :                 fprintf (stderr, "message from recvmsg() was not SCM_CREDS\n");
     115              :                 return -1;
     116              :         }
     117              : #endif
     118              : 
     119              :         {
     120              : #ifdef SO_PEERCRED
     121              : #ifndef __OpenBSD__
     122              :                 struct ucred cr;   
     123              : #else
     124              :                 struct sockpeercred cr;
     125              : #endif
     126            7 :                 socklen_t cr_len = sizeof (cr);
     127              :                 
     128            7 :                 if (getsockopt (sock, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) == 0 &&
     129            7 :                     cr_len == sizeof (cr)) {
     130            7 :                         *pid = cr.pid;
     131            7 :                         *uid = cr.uid;
     132              :                 } else {
     133            0 :                         fprintf (stderr, "failed to getsockopt() credentials, returned len %d/%d\n",
     134              :                                      cr_len, (int) sizeof (cr));
     135            0 :                         return -1;
     136              :                 }
     137              : #elif defined(HAVE_CMSGCRED)
     138              :                 cred = (struct cmsgcred *) CMSG_DATA (&cmsg.hdr);
     139              :                 *pid = cred->cmcred_pid;
     140              :                 *uid = cred->cmcred_euid;
     141              : #elif defined(LOCAL_CREDS)
     142              :                 cred = (struct sockcred *) CMSG_DATA (&cmsg.hdr);
     143              :                 *pid = 0;
     144              :                 *uid = cred->sc_euid;
     145              :                 set_local_creds(sock, 0);
     146              : #elif defined(HAVE_GETPEEREID) /* OpenBSD */
     147              :                 uid_t euid;
     148              :                 gid_t egid;
     149              :                 *pid = 0;
     150              : 
     151              :                 if (getpeereid (sock, &euid, &egid) == 0) {
     152              :                         *uid = euid;
     153              :                 } else {
     154              :                         fprintf (stderr, "getpeereid() failed: %s\n", strerror (errno)); 
     155              :                         return -1;
     156              :                 }
     157              : #elif defined(HAVE_GETPEERUCRED)
     158              :                 ucred_t *uc = NULL;
     159              : 
     160              :                 if (getpeerucred (sock, &uc) == 0) {
     161              :                         *pid = ucred_getpid (uc);
     162              :                         *uid = ucred_geteuid (uc);
     163              :                         ucred_free (uc);
     164              :                 } else {
     165              :                         fprintf (stderr, "getpeerucred() failed: %s\n", strerror (errno));
     166              :                         return -1;
     167              :                 }
     168              : #else /* !SO_PEERCRED && !HAVE_CMSGCRED */
     169              :                 fprintf (stderr, "socket credentials not supported on this OS\n");
     170              :                 return -1;
     171              : #endif
     172              :         }
     173              : 
     174            7 :         return 0;
     175              : }
     176              : 
     177              : int
     178            7 : egg_unix_credentials_write (int socket)
     179              : {
     180              :         char buf;
     181              :         int bytes_written;
     182              : #if defined(HAVE_CMSGCRED) && (!defined(LOCAL_CREDS) || defined(__FreeBSD__))
     183              :         union {
     184              :                 struct cmsghdr hdr;
     185              :                 char cred[CMSG_SPACE (sizeof (struct cmsgcred))];
     186              :         } cmsg;
     187              :         struct iovec iov;
     188              :         struct msghdr msg;
     189              : #endif
     190              : 
     191            7 :         buf = 0;
     192              : 
     193              : #if defined(HAVE_CMSGCRED) && (!defined(LOCAL_CREDS) || defined(__FreeBSD__))
     194              :         iov.iov_base = &buf;
     195              :         iov.iov_len = 1;
     196              : 
     197              :         memset (&msg, 0, sizeof (msg));
     198              :         msg.msg_iov = &iov;
     199              :         msg.msg_iovlen = 1;
     200              : 
     201              :         msg.msg_control = (caddr_t) &cmsg;
     202              :         msg.msg_controllen = CMSG_SPACE (sizeof (struct cmsgcred));
     203              :         memset (&cmsg, 0, sizeof (cmsg));
     204              :         cmsg.hdr.cmsg_len = CMSG_LEN (sizeof (struct cmsgcred));
     205              :         cmsg.hdr.cmsg_level = SOL_SOCKET;
     206              :         cmsg.hdr.cmsg_type = SCM_CREDS;
     207              : #endif
     208              : 
     209            7 : again:
     210              : 
     211              : #if defined(HAVE_CMSGCRED) && (!defined(LOCAL_CREDS) || defined(__FreeBSD__))
     212              :         bytes_written = sendmsg (socket, &msg, 0);
     213              : #else
     214            7 :         bytes_written = write (socket, &buf, 1);
     215              : #endif
     216              : 
     217            7 :         if (bytes_written < 0 && errno == EINTR)
     218            0 :                 goto again;
     219              : 
     220            7 :         if (bytes_written <= 0)
     221            0 :                 return -1;
     222              :                 
     223            7 :         return 0;
     224              : }
     225              : 
     226              : int
     227           27 : egg_unix_credentials_setup (int sock)
     228              : {
     229           27 :         int retval = 0;
     230              : #if defined(LOCAL_CREDS) && !defined(HAVE_CMSGCRED)
     231              :         int val = 1;
     232              :         if (setsockopt (sock, 0, LOCAL_CREDS, &val, sizeof (val)) < 0) {
     233              :                 fprintf (stderr, "unable to set LOCAL_CREDS socket option on fd %d\n", fd);
     234              :                 retval = -1;
     235              :         }
     236              : #endif
     237           27 :         return retval;
     238              : }
     239              : 
     240              : char*
     241            0 : egg_unix_credentials_executable (pid_t pid)
     242              : {
     243            0 :         char *result = NULL;
     244              : 
     245              :         /* Try and figure out the path from the pid */
     246              : #if defined(__linux__) || defined(__FreeBSD__)
     247              :         char path[1024];
     248              :         char buffer[64];
     249              :         int count;
     250              : 
     251              : #if defined(__linux__)
     252            0 :         snprintf (buffer, sizeof (buffer), "/proc/%d/exe", (int)pid);
     253              : #elif defined(__FreeBSD__)
     254              :         snprintf (buffer, sizeof (buffer), "/proc/%d/file", (int)pid);
     255              : #endif
     256              : 
     257            0 :         count = readlink (buffer, path, sizeof (path));
     258            0 :         if (count < 0)
     259            0 :                 fprintf (stderr, "readlink failed for file: %s", buffer);
     260              :         else
     261            0 :                 result = strndup (path, count);
     262              : #endif
     263              : 
     264            0 :         return result;
     265              : }
        

Generated by: LCOV version 2.0-1