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----