1   /*
   2 |  * Copyright (c) 1996,1997, by Sun Microsystems, Inc.
   3 |  * All rights reserved.
   2 |  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
   3 |  * Use is subject to license terms.
   4    */
   5   
   6 | #pragma ident        "@(#)gssd_pname_to_uid.c        1.19        04/09/08 SMI"
   6 | #pragma ident        "@(#)gssd_pname_to_uid.c        1.18        04/02/23 SMI"
   7   
   8   #include <pwd.h>
   9   #include <grp.h>
  10   #include <stdio.h>
  11   #include <stdlib.h>
  12   #include <unistd.h>
  13 + #include <thread.h>
  14 + #include <synch.h>
  15 + #include <syslog.h>
  16 + #include <deflt.h>
  17   #include <mechglueP.h>
  18   #include "../../cmd/gss/gsscred/gsscred.h"
  19   
  20 + static mutex_t uid_map_lock = DEFAULTMUTEX;
  21 + static int uid_map_opt = 0;
  22 + 
  23   extern int _getgroupsbymember(const char *, gid_t[], int, int);
  24   
  25   /* local function used to call a mechanisms pname_to_uid */
  26   static OM_uint32 gss_pname_to_uid(OM_uint32*, const gss_name_t,
  27                           const gss_OID, uid_t *);
  28   
  29   static OM_uint32 private_gsscred_expname_to_unix_cred(const gss_buffer_t,
  30                           uid_t *, gid_t *, gid_t **, int *);
  31   
  32   /*
  33    * The gsscred functions will first attempt to call the
  34    * mechanism'm pname_to_uid function.  In case this function
  35    * returns an error or if it is not provided by a mechanism
  36    * then the functions will attempt to look up the principal
  37    * in the gsscred table.
  38    * It is envisioned that the pname_to_uid function will be
  39    * provided by only a few mechanism, which may have the principal
  40    * name to unix credential mapping inherently present.
  41    */
  42   
  43   /*
  44 +  * Fetch gsscred options from conf file.
  45 +  */
  46 + static void
  47 + get_conf_options(int *uid_map)
  48 + {
  49 +         register int  flags;
  50 +         char *ptr;
  51 +         static char *conffile = "/etc/gss/gsscred.conf";
  52 +         static  mutex_t deflt_lock = DEFAULTMUTEX;
  53 + 
  54 + 
  55 +         *uid_map = 0;
  56 +         /*
  57 +          * hold the lock for the deflt file access as its
  58 +          * interface does not appear to be mt-safe
  59 +          */
  60 +         (void) mutex_lock(&deflt_lock);
  61 +         if (defopen(conffile) == 0) {
  62 +                 flags = defcntl(DC_GETFLAGS, 0);
  63 +                 /* ignore case */
  64 +                 TURNOFF(flags, DC_CASE);
  65 +                 (void) defcntl(DC_SETFLAGS, flags);
  66 + 
  67 +                 if ((ptr = defread("SYSLOG_UID_MAPPING=")) != NULL &&
  68 +                     strcasecmp("yes", ptr) == 0) {
  69 +                         (void) defopen((char *)NULL);
  70 +                         (void) mutex_unlock(&deflt_lock);
  71 +                         *uid_map = 1;
  72 +                         return;
  73 +                 }
  74 +                 (void) defopen((char *)NULL);
  75 +         }
  76 +         (void) mutex_unlock(&deflt_lock);
  77 + }
  78 + 
  79 + void
  80 + gsscred_set_options()
  81 + {
  82 +         int u;
  83 + 
  84 +         get_conf_options(&u);
  85 +         (void) mutex_lock(&uid_map_lock);
  86 +         uid_map_opt = u;
  87 +         (void) mutex_unlock(&uid_map_lock);
  88 + }
  89 + 
  90 + static int
  91 + get_uid_map_opt()
  92 + {
  93 +         int u;
  94 + 
  95 +         (void) mutex_lock(&uid_map_lock);
  96 +         u = uid_map_opt;
  97 +         (void) mutex_unlock(&uid_map_lock);
  98 +         return (u);
  99 + }
 100 + 
 101 + /*
 102    * This routine accepts a name in export name format and retrieves
 103    * unix credentials associated with it.
 104    */
 105 + 
 106   OM_uint32
  41 | gsscred_expname_to_unix_cred(expName, uidOut, gidOut, gids, gidsLen)
  42 | const gss_buffer_t expName;
  43 | uid_t *uidOut;
  44 | gid_t *gidOut;
  45 | gid_t *gids[];
  46 | int *gidsLen;
 107 | gsscred_expname_to_unix_cred_ext(
 108 |         const gss_buffer_t expName,
 109 |         uid_t *uidOut,
 110 |         gid_t *gidOut,
 111 |         gid_t *gids[],
 112 |         int *gidsLen,
 113 +         int try_mech)
 114   {
 115           gss_name_t intName;
 116           OM_uint32 minor, major;
 117 +         const char *mechStr = NULL;
 118 +         char *nameStr = NULL;
 119 +         char *whoami = "gsscred_expname_to_unix_cred";
 120 +         gss_buffer_desc namebuf;
 121 +         int debug = get_uid_map_opt();
 122   
 123           if (uidOut == NULL)
 124                   return (GSS_S_CALL_INACCESSIBLE_WRITE);
 125   
 126           if (expName == NULL)
 127                   return (GSS_S_CALL_INACCESSIBLE_READ);
 128   
 129           /* first check the mechanism for the mapping */
 130           if (gss_import_name(&minor, expName, (gss_OID)GSS_C_NT_EXPORT_NAME,
 131                           &intName) == GSS_S_COMPLETE) {
  60 |                 major = gss_pname_to_uid(&minor, intName, NULL, uidOut);
  61 |                 gss_release_name(&minor, &intName);
 132 | 
 133 |                 if (debug) {
 134 +                         gss_union_name_t uintName = (gss_union_name_t)intName;
 135 + 
 136 +                         if (uintName->mech_type)
 137 +                                 mechStr = __gss_oid_to_mech(
 138 +                                         uintName->mech_type);
 139 + 
 140 +                         major = gss_display_name(&minor, intName,
 141 +                                                 &namebuf, NULL);
 142                           if (major == GSS_S_COMPLETE) {
 143 +                                 nameStr = strdup(namebuf.value);
 144 +                                 (void) gss_release_buffer(&minor, &namebuf);
 145 +                         }
 146 +                 }
 147 + 
 148 +                 if (try_mech) {
 149 +                         major = gss_pname_to_uid(&minor, intName,
 150 +                                                 NULL, uidOut);
 151 +                         if (major == GSS_S_COMPLETE) {
 152 + 
 153 +                                 if (debug) {
 154 +                                         syslog(LOG_AUTH|LOG_DEBUG,
 155 +                                             "%s: mech provided local name"
 156 +                                             " mapping (%s, %s, %d)", whoami,
 157 +                                             mechStr ? mechStr : "<null>",
 158 +                                             nameStr ? nameStr : "<null>",
 159 +                                             *uidOut);
 160 +                                         free(nameStr);
 161 +                                 }
 162 + 
 163 +                                 (void) gss_release_name(&minor, &intName);
 164                                   if (gids && gidsLen && gidOut)
  64 |                                 return (gss_get_group_info(*uidOut, gidOut,
  65 |                                                 gids, gidsLen));
 165 |                                         return (gss_get_group_info(*uidOut,
 166 |                                                                 gidOut,
 167 +                                                                 gids,
 168 +                                                                 gidsLen));
  67 -                                 (void) gss_release_buffer(&minor, &namebuf);
 169                                   return (GSS_S_COMPLETE);
 170                           }
 171 +                 }
 172 + 
  70 -                 (void) gss_release_name(&minor, &intName);
 173                   (void) gss_release_name(&minor, &intName);
 174           }
 175   
 176           /*
 177            * we fall back onto the gsscred table to provide the mapping
 178            * start by making sure that the expName is an export name buffer
 179            */
  77 |         return (private_gsscred_expname_to_unix_cred(expName, uidOut, gidOut,
  78 |                                                 gids, gidsLen));
 180 |         major = private_gsscred_expname_to_unix_cred(expName, uidOut, gidOut,
 181 |                                                 gids, gidsLen);
 182 + 
 183 +         if (debug && major == GSS_S_COMPLETE) {
 184 +                 syslog(LOG_AUTH|LOG_DEBUG,
 185 +                     "%s: gsscred tbl provided"
 186 +                     " local name mapping (%s, %s, %d)",
 187 +                     whoami,
 188 +                     mechStr ? mechStr : "<unknown>",
 189 +                     nameStr ? nameStr : "<unknown>",
 190 +                     *uidOut);
 191 +                 free(nameStr);
 192 +         } else if (debug) {
 193 +                 syslog(LOG_AUTH|LOG_DEBUG,
 194 +                     "%s: gsscred tbl could NOT"
 195 +                     " provide local name mapping (%s, %s)",
 196 +                     whoami,
 197 +                     mechStr ? mechStr : "<unknown>",
 198 +                     nameStr ? nameStr : "<unknown>");
 199 +                 free(nameStr);
 200 +         }
 201 + 
 202 +         return (major);
 203 + 
 204   } /* gsscred_expname_to_unix_cred */
 205   
 206 + OM_uint32
 207 + gsscred_expname_to_unix_cred(
 208 +         const gss_buffer_t expName,
 209 +         uid_t *uidOut,
 210 +         gid_t *gidOut,
 211 +         gid_t *gids[],
 212 +         int *gidsLen)
 213 + {
 214 +         return (gsscred_expname_to_unix_cred_ext(expName, uidOut, gidOut, gids,
 215 +                                                 gidsLen, 1));
 216 + }
 217   
 218 + 
 219   static const char *expNameTokId = "\x04\x01";
 220   static const int expNameTokIdLen = 2;
 221   /*
 222    * private routine added to be called from gsscred_name_to_unix_cred
 223    * and gsscred_expName_to_unix_cred.
 224    */
 225   static OM_uint32
 226   private_gsscred_expname_to_unix_cred(expName, uidOut, gidOut, gids, gidsLen)
 227   const gss_buffer_t expName;
 228   uid_t *uidOut;
 229   gid_t *gidOut;
 230   gid_t *gids[];
 231   int *gidsLen;
 232   {
 233   
 234           if (expName->length < expNameTokIdLen ||
 235                   (memcmp(expName->value, expNameTokId, expNameTokIdLen) != 0))
 236                   return (GSS_S_DEFECTIVE_TOKEN);
 237   
 238           if (!gss_getGssCredEntry(expName, uidOut))
 239                   return (GSS_S_FAILURE);
 240   
 241           /* did caller request group info also ? */
 242           if (gids && gidsLen && gidOut)
 243                   return (gss_get_group_info(*uidOut, gidOut, gids, gidsLen));
 244   
 245           return (GSS_S_COMPLETE);
 246   }
 247   
 248   /*
 249 +  * Return a string of the authenticated name.
 250 +  * It's a bit of hack/workaround/longroad but the current intName
 251 +  * passed to gss_display_name insists on returning an empty string.
 252 +  *
 253 +  * Caller must free string memory.
 254 +  */
 255 + static
 256 + char *make_name_str(
 257 +         const gss_name_t intName,
 258 +         const gss_OID mechType)
 259 + 
 260 + {
 261 +         gss_buffer_desc expName = GSS_C_EMPTY_BUFFER;
 262 +         OM_uint32 major, minor;
 263 +         gss_name_t canonName;
 264 +         gss_name_t iName;
 265 +         gss_buffer_desc namebuf;
 266 + 
 267 +         if (major = gss_canonicalize_name(&minor, intName,
 268 +                                 mechType, &canonName))
 269 +                 return (NULL);
 270 + 
 271 +         major = gss_export_name(&minor, canonName, &expName);
 272           (void) gss_release_name(&minor, &canonName);
 273 +         if (major)
 274 +                 return (NULL);
 275 + 
 276 +         if (gss_import_name(&minor, &expName,
 277 +                             (gss_OID)GSS_C_NT_EXPORT_NAME,
 278 +                             &iName) == GSS_S_COMPLETE) {
 279 + 
 280 +                 major = gss_display_name(&minor, iName, &namebuf, NULL);
 281 +                 if (major == GSS_S_COMPLETE) {
 282 +                         char *s;
 283 + 
 284 +                         if (namebuf.value)
 285 +                                 s = strdup(namebuf.value);
 286 + 
 287                           (void) gss_release_buffer(&minor, &namebuf);
 288                           (void) gss_release_buffer(&minor, &expName);
 289                           (void) gss_release_buffer(&minor, (gss_buffer_t)iName);
 290 +                         return (s);
 291 +                 }
 292                   (void) gss_release_buffer(&minor, (gss_buffer_t)iName);
 293 +         }
 294 + 
 295           (void) gss_release_buffer(&minor, &expName);
 296 +         return (NULL);
 297 + }
 298 + 
 299 + /*
 300    * This routine accepts a name in gss internal name format together with
 301    * a mechanim OID and retrieves a unix credentials for that entity.
 302    */
 303   OM_uint32
 122 | gsscred_name_to_unix_cred(intName, mechType, uidOut, gidOut, gids, gidsLen)
 123 | const gss_name_t intName;
 124 | const gss_OID mechType;
 125 | uid_t *uidOut;
 126 | gid_t *gidOut;
 127 | gid_t *gids[];
 128 | int *gidsLen;
 304 | gsscred_name_to_unix_cred_ext(
 305 |         const gss_name_t intName,
 306 |         const gss_OID mechType,
 307 |         uid_t *uidOut,
 308 |         gid_t *gidOut,
 309 |         gid_t *gids[],
 310 |         int *gidsLen,
 311 +         int try_mech)
 312   {
 313           gss_name_t canonName;
 314           gss_buffer_desc expName = GSS_C_EMPTY_BUFFER;
 315           OM_uint32 major, minor;
 316 +         int debug = get_uid_map_opt();
 317   
 318 +         const char *mechStr;
 319 +         char *whoami = "gsscred_name_to_unix_cred";
 320 +         gss_buffer_desc namebuf;
 321 + 
 322           if (intName == NULL || mechType == NULL)
 323                   return (GSS_S_CALL_INACCESSIBLE_READ);
 324   
 325           if (uidOut == NULL)
 326                   return (GSS_S_CALL_INACCESSIBLE_WRITE);
 327   
 328 +         mechStr = __gss_oid_to_mech(mechType);
 329 + 
 330           /* first try the mechanism provided mapping */
 141 |         if (gss_pname_to_uid(&minor, intName, mechType, uidOut)
 331 |         if (try_mech && gss_pname_to_uid(&minor, intName, mechType, uidOut)
 332                   == GSS_S_COMPLETE) {
 333 + 
 334 +                 if (debug) {
 335 +                         char *s = make_name_str(intName, mechType);
 336 +                         syslog(LOG_AUTH|LOG_DEBUG,
 337 +                             "%s: mech provided local name"
 338 +                             " mapping (%s, %s, %d)", whoami,
 339 +                             mechStr ? mechStr : "<null>",
 340 +                             s ? s : "<null>",
 341 +                             *uidOut);
 342 +                         free(s);
 343 +                 }
 344 + 
 345                   if (gids && gidsLen && gidOut)
 346                           return (gss_get_group_info(*uidOut, gidOut, gids,
 347                                           gidsLen));
 348                   return (GSS_S_COMPLETE);
 148 - 
 149 - 
 349           }
 350           /*
 351            * falling back onto the gsscred table to provide the mapping
 352            * start by canonicalizing the passed in name and then export it
 353            */
 354           if (major = gss_canonicalize_name(&minor, intName,
 355                                   mechType, &canonName))
 356                   return (major);
 357   
 358           major = gss_export_name(&minor, canonName, &expName);
 359           (void) gss_release_name(&minor, &canonName);
 360           if (major)
 361                   return (major);
 362   
 363           major = private_gsscred_expname_to_unix_cred(&expName, uidOut, gidOut,
 364                                           gids, gidsLen);
 365 + 
 366 + 
 367 +         if (debug) {
 368 +                 gss_name_t iName;
 369 +                 OM_uint32 maj;
 370 +                 char *nameStr = NULL;
 371 + 
 372 +                 if (gss_import_name(&minor, &expName,
 373 +                                     (gss_OID)GSS_C_NT_EXPORT_NAME,
 374 +                                     &iName) == GSS_S_COMPLETE) {
 375 + 
 376 +                         maj = gss_display_name(&minor, iName, &namebuf,
 377 +                                             NULL);
 378                           (void) gss_release_buffer(&minor, (gss_buffer_t)iName);
 379 +                         if (maj == GSS_S_COMPLETE) {
 380 +                                 nameStr = strdup(namebuf.value);
 381                                   (void) gss_release_buffer(&minor, &namebuf);
 382 +                         }
 383 +                 }
 384 + 
 385 +                 if (major == GSS_S_COMPLETE)
 386 +                         syslog(LOG_AUTH|LOG_DEBUG,
 387 +                             "%s: gsscred tbl provided"
 388 +                             " local name mapping (%s, %s, %d)",
 389 +                             whoami,
 390 +                             mechStr ? mechStr : "<unknown>",
 391 +                             nameStr ? nameStr : "<unknown>",
 392 +                             *uidOut);
 393 +                 else
 394 +                         syslog(LOG_AUTH|LOG_DEBUG,
 395 +                             "%s: gsscred tbl could NOT"
 396 +                             " provide local name mapping (%s, %s)",
 397 +                             whoami,
 398 +                             mechStr ? mechStr : "<unknown>",
 399 +                             nameStr ? nameStr : "<unknown>");
 400 + 
 401 +                 free(nameStr);
 402 +         }
 403 + 
 404           (void) gss_release_buffer(&minor, &expName);
 405           return (major);
 406   } /* gsscred_name_to_unix_cred */
 407   
 408   
 409 + OM_uint32
 410 + gsscred_name_to_unix_cred(
 411 +         const gss_name_t intName,
 412 +         const gss_OID mechType,
 413 +         uid_t *uidOut,
 414 +         gid_t *gidOut,
 415 +         gid_t *gids[],
 416 +         int *gidsLen)
 417 + {
 418 +         return (gsscred_name_to_unix_cred_ext(intName, mechType,
 419 +                                             uidOut, gidOut,
 420 +                                             gids, gidsLen, 1));
 421 + }
 422 + 
 423 + 
 424 + 
 425   /*
 426    * This routine accepts a unix uid, and retrieves the group id
 427    * and supplamentery group ids for that uid.
 428    * Callers should be aware that the supplamentary group ids
 429    * array may be empty even when this function returns success.
 430    */
 431   OM_uint32
 432   gss_get_group_info(uid, gidOut, gids, gidsLen)
 433   const uid_t uid;
 434   gid_t *gidOut;
 435   gid_t *gids[];
 436   int *gidsLen;
 437   {
 438           struct passwd *pw;
 439           int maxgroups;
 440   
 441           /* check for output parameters */
 442           if (gidOut == NULL || gids == NULL || gidsLen == NULL)
 443                   return (GSS_S_CALL_INACCESSIBLE_WRITE);
 444   
 445           *gids = NULL;
 446           *gidsLen = 0;
 447   
 448           /* determine maximum number of groups possible */
 449           maxgroups = sysconf(_SC_NGROUPS_MAX);
 450           if (maxgroups < 1)
 451               maxgroups = 16;
 452   
 453           if ((pw = getpwuid(uid)) == NULL)
 454               return (GSS_S_FAILURE);
 455   
 456           /*
 457            * we allocate for the maximum number of groups
 458            * we do not reclaim the space when the actual number
 459            * is lower, just set the size approprately.
 460            */
 461           *gids = (gid_t *)calloc(maxgroups, sizeof (gid_t));
 462           if (*gids == NULL)
 463               return (GSS_S_FAILURE);
 464   
 465           *gidOut = pw->pw_gid;
 466           (*gids)[0] = pw->pw_gid;
 467           *gidsLen = _getgroupsbymember(pw->pw_name, *gids, maxgroups, 1);
 468           /*
 469            * we will try to remove the duplicate entry from the groups
 470            * array.  This can cause the group array to be empty.
 471            */
 472           if (*gidsLen < 1)
 473           {
 474                   free(*gids);
 475                   *gids = NULL;
 476                   return (GSS_S_FAILURE);
 477           } else if (*gidsLen == 1) {
 478                   free(*gids);
 479                   *gids = NULL;
 480                   *gidsLen = 0;
 481           } else {
 482                   /* length is atleast 2 */
 483                   *gidsLen = *gidsLen -1;
 484                   (*gids)[0] = (*gids)[*gidsLen];
 485           }
 486   
 487           return (GSS_S_COMPLETE);
 488   } /* gss_get_group_info */

 ----Unchanged portion omitted----