Back to index

openldap  2.4.31
getpeereid.c
Go to the documentation of this file.
00001 /* getpeereid.c */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 2000-2012 The OpenLDAP Foundation.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted only as authorized by the OpenLDAP
00010  * Public License.
00011  *
00012  * A copy of this license is available in the file LICENSE in the
00013  * top-level directory of the distribution or, alternatively, at
00014  * <http://www.OpenLDAP.org/license.html>.
00015  */
00016 
00017 #ifndef _GNU_SOURCE
00018 #define _GNU_SOURCE 1                     /* Needed for glibc struct ucred */
00019 #endif
00020 
00021 #include "portable.h"
00022 
00023 #ifndef HAVE_GETPEEREID
00024 
00025 #include <sys/types.h>
00026 #include <ac/unistd.h>
00027 
00028 #include <ac/socket.h>
00029 #include <ac/errno.h>
00030 
00031 #ifdef HAVE_GETPEERUCRED
00032 #include <ucred.h>
00033 #endif
00034 
00035 #ifdef LDAP_PF_LOCAL_SENDMSG
00036 #include <lber.h>
00037 #ifdef HAVE_SYS_UIO_H
00038 #include <sys/uio.h>
00039 #endif
00040 #include <sys/stat.h>
00041 #endif
00042 
00043 #ifdef HAVE_SYS_UCRED_H
00044 #ifdef HAVE_GRP_H
00045 #include <grp.h>     /* for NGROUPS on Tru64 5.1 */
00046 #endif
00047 #include <sys/ucred.h>
00048 #endif
00049 
00050 #include <stdlib.h>
00051 
00052 int lutil_getpeereid( int s, uid_t *euid, gid_t *egid
00053 #ifdef LDAP_PF_LOCAL_SENDMSG
00054        , struct berval *peerbv
00055 #endif
00056        )
00057 {
00058 #ifdef LDAP_PF_LOCAL
00059 #if defined( HAVE_GETPEERUCRED )
00060        ucred_t *uc = NULL;
00061        if( getpeerucred( s, &uc ) == 0 )  {
00062               *euid = ucred_geteuid( uc );
00063               *egid = ucred_getegid( uc );
00064               ucred_free( uc );
00065               return 0;
00066        }
00067 
00068 #elif defined( SO_PEERCRED )
00069        struct ucred peercred;
00070        ber_socklen_t peercredlen = sizeof peercred;
00071 
00072        if(( getsockopt( s, SOL_SOCKET, SO_PEERCRED,
00073               (void *)&peercred, &peercredlen ) == 0 )
00074               && ( peercredlen == sizeof peercred ))
00075        {
00076               *euid = peercred.uid;
00077               *egid = peercred.gid;
00078               return 0;
00079        }
00080 
00081 #elif defined( LOCAL_PEERCRED )
00082        struct xucred peercred;
00083        ber_socklen_t peercredlen = sizeof peercred;
00084 
00085        if(( getsockopt( s, LOCAL_PEERCRED, 1,
00086               (void *)&peercred, &peercredlen ) == 0 )
00087               && ( peercred.cr_version == XUCRED_VERSION ))
00088        {
00089               *euid = peercred.cr_uid;
00090               *egid = peercred.cr_gid;
00091               return 0;
00092        }
00093 #elif defined( LDAP_PF_LOCAL_SENDMSG ) && defined( MSG_WAITALL )
00094        int err, fd;
00095        struct iovec iov;
00096        struct msghdr msg = {0};
00097 # ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
00098 # ifndef CMSG_SPACE
00099 # define CMSG_SPACE(len)    (_CMSG_ALIGN(sizeof(struct cmsghdr)) + _CMSG_ALIGN(len))
00100 # endif
00101 # ifndef CMSG_LEN
00102 # define CMSG_LEN(len)             (_CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
00103 # endif
00104        struct {
00105               struct cmsghdr cm;
00106               int fd;
00107        } control_st;
00108        struct cmsghdr *cmsg;
00109 # endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */
00110        struct stat st;
00111        struct sockaddr_un lname, rname;
00112        ber_socklen_t llen, rlen;
00113 
00114        rlen = sizeof(rname);
00115        llen = sizeof(lname);
00116        memset( &lname, 0, sizeof( lname ));
00117        getsockname(s, (struct sockaddr *)&lname, &llen);
00118 
00119        iov.iov_base = peerbv->bv_val;
00120        iov.iov_len = peerbv->bv_len;
00121        msg.msg_iov = &iov;
00122        msg.msg_iovlen = 1;
00123        peerbv->bv_len = 0;
00124 
00125 # ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
00126        msg.msg_control = &control_st;
00127        msg.msg_controllen = sizeof( struct cmsghdr ) + sizeof( int ); /* no padding! */
00128 
00129        cmsg = CMSG_FIRSTHDR( &msg );
00130 # else
00131        msg.msg_accrights = (char *)&fd;
00132        msg.msg_accrightslen = sizeof(fd);
00133 # endif
00134 
00135        /*
00136         * AIX returns a bogus file descriptor if recvmsg() is
00137         * called with MSG_PEEK (is this a bug?). Hence we need
00138         * to receive the Abandon PDU.
00139         */
00140        err = recvmsg( s, &msg, MSG_WAITALL );
00141        if( err >= 0 &&
00142 # ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
00143            cmsg->cmsg_len == CMSG_LEN( sizeof(int) ) &&
00144            cmsg->cmsg_level == SOL_SOCKET &&
00145            cmsg->cmsg_type == SCM_RIGHTS
00146 # else
00147               msg.msg_accrightslen == sizeof(int)
00148 # endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL*/
00149        ) {
00150               int mode = S_IFIFO|S_ISUID|S_IRWXU;
00151 
00152               /* We must receive a valid descriptor, it must be a pipe,
00153                * it must only be accessible by its owner, and it must
00154                * have the name of our socket written on it.
00155                */
00156               peerbv->bv_len = err;
00157 # ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
00158               fd = (*(int *)CMSG_DATA( cmsg ));
00159 # endif
00160               err = fstat( fd, &st );
00161               if ( err == 0 )
00162                      rlen = read(fd, &rname, rlen);
00163               close(fd);
00164               if( err == 0 && st.st_mode == mode &&
00165                      llen == rlen && !memcmp(&lname, &rname, llen))
00166               {
00167                      *euid = st.st_uid;
00168                      *egid = st.st_gid;
00169                      return 0;
00170               }
00171        }
00172 #elif defined(SOCKCREDSIZE)
00173        struct msghdr msg;
00174        ber_socklen_t crmsgsize;
00175        void *crmsg;
00176        struct cmsghdr *cmp;
00177        struct sockcred *sc;
00178 
00179        memset(&msg, 0, sizeof msg);
00180        crmsgsize = CMSG_SPACE(SOCKCREDSIZE(NGROUPS));
00181        if (crmsgsize == 0) goto sc_err;
00182        crmsg = malloc(crmsgsize);
00183        if (crmsg == NULL) goto sc_err;
00184        memset(crmsg, 0, crmsgsize);
00185        
00186        msg.msg_control = crmsg;
00187        msg.msg_controllen = crmsgsize;
00188        
00189        if (recvmsg(s, &msg, 0) < 0) {
00190               free(crmsg);
00191               goto sc_err;
00192        }      
00193 
00194        if (msg.msg_controllen == 0 || (msg.msg_flags & MSG_CTRUNC) != 0) {
00195               free(crmsg);
00196               goto sc_err;
00197        }      
00198        
00199        cmp = CMSG_FIRSTHDR(&msg);
00200        if (cmp->cmsg_level != SOL_SOCKET || cmp->cmsg_type != SCM_CREDS) {
00201               printf("nocreds\n");
00202               goto sc_err;
00203        }      
00204        
00205        sc = (struct sockcred *)(void *)CMSG_DATA(cmp);
00206        
00207        *euid = sc->sc_euid;
00208        *egid = sc->sc_egid;
00209 
00210        free(crmsg);
00211        return 0;
00212 
00213 sc_err:       
00214 #endif
00215 #endif /* LDAP_PF_LOCAL */
00216 
00217        return -1;
00218 }
00219 
00220 #endif /* HAVE_GETPEEREID */