root/opal/mca/pmix/pmix4x/pmix/src/mca/psec/native/psec_native.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. native_init
  2. native_finalize
  3. create_cred
  4. validate_cred

   1 /*
   2  * Copyright (c) 2015-2019 Intel, Inc.  All rights reserved.
   3  * Copyright (c) 2016      IBM Corporation.  All rights reserved.
   4  * Copyright (c) 2017      Research Organization for Information Science
   5  *                         and Technology (RIST). All rights reserved.
   6  * $COPYRIGHT$
   7  *
   8  * Additional copyrights may follow
   9  *
  10  * $HEADER$
  11  */
  12 
  13 #include <src/include/pmix_config.h>
  14 
  15 #include <unistd.h>
  16 #ifdef HAVE_SYS_TYPES_H
  17 #include <sys/types.h>
  18 #endif
  19 
  20 #include <pmix_common.h>
  21 
  22 #include "src/include/pmix_socket_errno.h"
  23 #include "src/include/pmix_globals.h"
  24 #include "src/util/argv.h"
  25 #include "src/util/error.h"
  26 #include "src/util/output.h"
  27 
  28 #include "src/mca/psec/base/base.h"
  29 #include "psec_native.h"
  30 
  31 static pmix_status_t native_init(void);
  32 static void native_finalize(void);
  33 static pmix_status_t create_cred(struct pmix_peer_t *peer,
  34                                  const pmix_info_t directives[], size_t ndirs,
  35                                  pmix_info_t **info, size_t *ninfo,
  36                                  pmix_byte_object_t *cred);
  37 static pmix_status_t validate_cred(struct pmix_peer_t *peer,
  38                                    const pmix_info_t directives[], size_t ndirs,
  39                                    pmix_info_t **info, size_t *ninfo,
  40                                    const pmix_byte_object_t *cred);
  41 
  42 pmix_psec_module_t pmix_native_module = {
  43     .name = "native",
  44     .init = native_init,
  45     .finalize = native_finalize,
  46     .create_cred = create_cred,
  47     .validate_cred = validate_cred
  48 };
  49 
  50 static pmix_status_t native_init(void)
  51 {
  52     pmix_output_verbose(2, pmix_psec_base_framework.framework_output,
  53                         "psec: native init");
  54     return PMIX_SUCCESS;
  55 }
  56 
  57 static void native_finalize(void)
  58 {
  59     pmix_output_verbose(2, pmix_psec_base_framework.framework_output,
  60                         "psec: native finalize");
  61 }
  62 
  63 static pmix_status_t create_cred(struct pmix_peer_t *peer,
  64                                  const pmix_info_t directives[], size_t ndirs,
  65                                  pmix_info_t **info, size_t *ninfo,
  66                                  pmix_byte_object_t *cred)
  67 {
  68     pmix_peer_t *pr = (pmix_peer_t*)peer;
  69     char **types;
  70     size_t n, m;
  71     bool takeus;
  72     uid_t euid;
  73     gid_t egid;
  74     char *tmp, *ptr;
  75 
  76     /* ensure initialization */
  77     PMIX_BYTE_OBJECT_CONSTRUCT(cred);
  78 
  79     /* we may be responding to a local request for a credential, so
  80      * see if they specified a mechanism */
  81     if (NULL != directives && 0 < ndirs) {
  82         /* cycle across the provided info and see if they specified
  83          * any desired credential types */
  84         takeus = true;
  85         for (n=0; n < ndirs; n++) {
  86             if (0 == strncmp(directives[n].key, PMIX_CRED_TYPE, PMIX_MAX_KEYLEN)) {
  87                 /* see if we are included */
  88                 types = pmix_argv_split(directives[n].value.data.string, ',');
  89                 /* start by assuming they don't want us */
  90                 takeus = false;
  91                 for (m=0; NULL != types[m]; m++) {
  92                     if (0 == strcmp(types[m], "native")) {
  93                         /* it's us! */
  94                         takeus = true;
  95                         break;
  96                     }
  97                 }
  98                 pmix_argv_free(types);
  99                 break;
 100             }
 101         }
 102         if (!takeus) {
 103             PMIX_ERROR_LOG(PMIX_ERR_NOT_SUPPORTED);
 104             return PMIX_ERR_NOT_SUPPORTED;
 105         }
 106     }
 107 
 108     if (PMIX_PROTOCOL_V1 == pr->protocol) {
 109         /* usock protocol - nothing to do */
 110         goto complete;
 111     } else if (PMIX_PROTOCOL_V2 == pr->protocol) {
 112         /* tcp protocol - need to provide our effective
 113          * uid and gid for validation on remote end */
 114         tmp = (char*)malloc(sizeof(uid_t) + sizeof(gid_t));
 115         if (NULL == tmp) {
 116             return PMIX_ERR_NOMEM;
 117         }
 118         euid = geteuid();
 119         memcpy(tmp, &euid, sizeof(uid_t));
 120         ptr = tmp + sizeof(uid_t);
 121         egid = getegid();
 122         memcpy(ptr, &egid, sizeof(gid_t));
 123         cred->bytes = tmp;
 124         cred->size = sizeof(uid_t) + sizeof(gid_t);
 125         goto complete;
 126     } else {
 127         /* unrecognized protocol */
 128         PMIX_ERROR_LOG(PMIX_ERR_NOT_SUPPORTED);
 129         return PMIX_ERR_NOT_SUPPORTED;
 130     }
 131 
 132   complete:
 133     if (NULL != info) {
 134         /* mark that this came from us */
 135         PMIX_INFO_CREATE(*info, 1);
 136         if (NULL == *info) {
 137             return PMIX_ERR_NOMEM;
 138         }
 139         *ninfo = 1;
 140         PMIX_INFO_LOAD(info[0], PMIX_CRED_TYPE, "native", PMIX_STRING);
 141     }
 142     return PMIX_SUCCESS;
 143 }
 144 
 145 static pmix_status_t validate_cred(struct pmix_peer_t *peer,
 146                                    const pmix_info_t directives[], size_t ndirs,
 147                                    pmix_info_t **info, size_t *ninfo,
 148                                    const pmix_byte_object_t *cred)
 149 {
 150     pmix_peer_t *pr = (pmix_peer_t*)peer;
 151 
 152 #if defined(SO_PEERCRED)
 153 #ifdef HAVE_STRUCT_SOCKPEERCRED_UID
 154 #define HAVE_STRUCT_UCRED_UID
 155     struct sockpeercred ucred;
 156 #else
 157     struct ucred ucred;
 158 #endif
 159     socklen_t crlen = sizeof (ucred);
 160 #endif
 161     uid_t euid = -1;
 162     gid_t egid = -1;
 163     char *ptr;
 164     size_t ln;
 165     bool takeus;
 166     char **types;
 167     size_t n, m;
 168     uint32_t u32;
 169 
 170     pmix_output_verbose(2, pmix_psec_base_framework.framework_output,
 171                         "psec: native validate_cred %s",
 172                         (NULL == cred) ? "NULL" : "NON-NULL");
 173 
 174     if (PMIX_PROTOCOL_V1 == pr->protocol) {
 175         /* usock protocol - get the remote side's uid/gid */
 176 #if defined(SO_PEERCRED) && (defined(HAVE_STRUCT_UCRED_UID) || defined(HAVE_STRUCT_UCRED_CR_UID))
 177         /* Ignore received 'cred' and validate ucred for socket instead. */
 178         pmix_output_verbose(2, pmix_psec_base_framework.framework_output,
 179                             "psec:native checking getsockopt on socket %d for peer credentials", pr->sd);
 180         if (getsockopt(pr->sd, SOL_SOCKET, SO_PEERCRED, &ucred, &crlen) < 0) {
 181             pmix_output_verbose(2, pmix_psec_base_framework.framework_output,
 182                                 "psec: getsockopt SO_PEERCRED failed: %s",
 183                                 strerror (pmix_socket_errno));
 184             return PMIX_ERR_INVALID_CRED;
 185         }
 186 #if defined(HAVE_STRUCT_UCRED_UID)
 187         euid = ucred.uid;
 188         egid = ucred.gid;
 189 #else
 190         euid = ucred.cr_uid;
 191         egid = ucred.cr_gid;
 192 #endif
 193 
 194 #elif defined(HAVE_GETPEEREID)
 195         pmix_output_verbose(2, pmix_psec_base_framework.framework_output,
 196                             "psec:native checking getpeereid on socket %d for peer credentials", pr->sd);
 197         if (0 != getpeereid(pr->sd, &euid, &egid)) {
 198             pmix_output_verbose(2, pmix_psec_base_framework.framework_output,
 199                                 "psec: getsockopt getpeereid failed: %s",
 200                                 strerror (pmix_socket_errno));
 201             return PMIX_ERR_INVALID_CRED;
 202     }
 203 #else
 204         return PMIX_ERR_NOT_SUPPORTED;
 205 #endif
 206     } else if (PMIX_PROTOCOL_V2 == pr->protocol) {
 207         /* this is a tcp protocol, so the cred is actually the uid/gid
 208          * passed upwards from the client */
 209         if (NULL == cred) {
 210             /* not allowed */
 211             return PMIX_ERR_INVALID_CRED;
 212         }
 213         ln = cred->size;
 214         euid = 0;
 215         egid = 0;
 216         if (sizeof(uid_t) <= ln) {
 217             memcpy(&euid, cred->bytes, sizeof(uid_t));
 218             ln -= sizeof(uid_t);
 219             ptr = cred->bytes + sizeof(uid_t);
 220         } else {
 221             return PMIX_ERR_INVALID_CRED;
 222         }
 223         if (sizeof(gid_t) <= ln) {
 224             memcpy(&egid, ptr, sizeof(gid_t));
 225         } else {
 226             return PMIX_ERR_INVALID_CRED;
 227         }
 228     } else if (PMIX_PROTOCOL_UNDEF != pr->protocol) {
 229         /* don't recognize the protocol */
 230         return PMIX_ERR_NOT_SUPPORTED;
 231     }
 232 
 233     /* if we are responding to a local request to validate a credential,
 234      * then see if they specified a mechanism */
 235     if (NULL != directives && 0 < ndirs) {
 236         for (n=0; n < ndirs; n++) {
 237             if (0 == strncmp(directives[n].key, PMIX_CRED_TYPE, PMIX_MAX_KEYLEN)) {
 238                 /* split the specified string */
 239                 types = pmix_argv_split(directives[n].value.data.string, ',');
 240                 takeus = false;
 241                 for (m=0; NULL != types[m]; m++) {
 242                     if (0 == strcmp(types[m], "native")) {
 243                         /* it's us! */
 244                         takeus = true;
 245                         break;
 246                     }
 247                 }
 248                 pmix_argv_free(types);
 249                 if (!takeus) {
 250                     return PMIX_ERR_NOT_SUPPORTED;
 251                 }
 252             }
 253         }
 254     }
 255 
 256     /* check uid */
 257     if (euid != pr->info->uid) {
 258         pmix_output_verbose(2, pmix_psec_base_framework.framework_output,
 259                             "psec: socket cred contains invalid uid %u", euid);
 260         return PMIX_ERR_INVALID_CRED;
 261     }
 262 
 263     /* check gid */
 264     if (egid != pr->info->gid) {
 265         pmix_output_verbose(2, pmix_psec_base_framework.framework_output,
 266                             "psec: socket cred contains invalid gid %u", egid);
 267         return PMIX_ERR_INVALID_CRED;
 268     }
 269 
 270     /* validated - mark that we did it */
 271     if (NULL != info) {
 272         PMIX_INFO_CREATE(*info, 3);
 273         if (NULL == *info) {
 274             return PMIX_ERR_NOMEM;
 275         }
 276         *ninfo = 3;
 277         /* mark that this came from us */
 278         PMIX_INFO_LOAD(info[0], PMIX_CRED_TYPE, "munge", PMIX_STRING);
 279         /* provide the uid it contained */
 280         u32 = euid;
 281         PMIX_INFO_LOAD(info[1], PMIX_USERID, &u32, PMIX_UINT32);
 282         /* provide the gid it contained */
 283         u32 = egid;
 284         PMIX_INFO_LOAD(info[2], PMIX_GRPID, &u32, PMIX_UINT32);
 285     }
 286     return PMIX_SUCCESS;
 287 
 288 }

/* [<][>][^][v][top][bottom][index][help] */