LCOV - code coverage report
Current view: top level - egg - egg-unix-credentials.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 0 47 0.0 %
Date: 2024-02-08 14:44:34 Functions: 0 4 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 0 -

           Branch data     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                 :          0 : 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                 :          0 :         *pid = 0;
      74                 :          0 :         *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                 :          0 :         iov.iov_base = &buf;
      81                 :          0 :         iov.iov_len = 1;
      82                 :            :         
      83                 :          0 :         memset (&msg, 0, sizeof (msg));
      84                 :          0 :         msg.msg_iov = &iov;
      85                 :          0 :         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                 :          0 :  again:
      94                 :          0 :         ret = recvmsg (sock, &msg, 0);
      95                 :            : 
      96                 :          0 :         if (ret < 0) {
      97                 :          0 :                 if (errno == EINTR)
      98                 :          0 :                         goto again;
      99                 :          0 :                 return -1;
     100                 :            :                 
     101                 :          0 :         } else if (ret == 0) {
     102                 :            :                 /* Disconnected */
     103                 :          0 :                 return -1;
     104                 :            :         }
     105                 :            :         
     106                 :          0 :         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                 :          0 :                 socklen_t cr_len = sizeof (cr);
     127                 :            :                 
     128                 :          0 :                 if (getsockopt (sock, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) == 0 &&
     129                 :          0 :                     cr_len == sizeof (cr)) {
     130                 :          0 :                         *pid = cr.pid;
     131                 :          0 :                         *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                 :          0 :         return 0;
     175                 :            : }
     176                 :            : 
     177                 :            : int
     178                 :          0 : 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                 :          0 :         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                 :          0 : again:
     210                 :            : 
     211                 :            : #if defined(HAVE_CMSGCRED) && (!defined(LOCAL_CREDS) || defined(__FreeBSD__))
     212                 :            :         bytes_written = sendmsg (socket, &msg, 0);
     213                 :            : #else
     214                 :          0 :         bytes_written = write (socket, &buf, 1);
     215                 :            : #endif
     216                 :            : 
     217                 :          0 :         if (bytes_written < 0 && errno == EINTR)
     218                 :          0 :                 goto again;
     219                 :            : 
     220                 :          0 :         if (bytes_written <= 0)
     221                 :          0 :                 return -1;
     222                 :            :                 
     223                 :          0 :         return 0;
     224                 :            : }
     225                 :            : 
     226                 :            : int
     227                 :          0 : egg_unix_credentials_setup (int sock)
     228                 :            : {
     229                 :          0 :         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                 :          0 :         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 1.14