1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1997-2002 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * gsscred utility 29 * Manages mapping between a security principal name and unix uid 30 */ 31 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <pwd.h> 35 #include <unistd.h> 36 #include <string.h> 37 #include <gssapi/gssapi_ext.h> 38 #include "gsscred.h" 39 40 #define MAX_STR_LEN 1024 41 42 43 /* 44 * Internal Functions 45 */ 46 static void usage(void); 47 static void addUser(const char *name, const char *oid, const char *userUid, 48 const char *userComment, const char *userMech); 49 static int file_listUsers(const gss_OID mechOid, const char *userUid, 50 char **errDetails); 51 static int listUsers(const char *name, const char *nameTypeOid, 52 const char *uid, const char *mechOid); 53 static int file_removeUsers(const gss_OID mechOid, const char *userUid, 54 char **errDetails); 55 static int removeUsers(const char *name, const char *nameTypeOid, 56 const char *uid, const char *mechOid); 57 58 /* 59 * Global variables 60 */ 61 static int tableSource; 62 static char *PROG_NAME = NULL; 63 64 int 65 main(int argc, char *args[]) 66 { 67 char *userName = NULL, *nameTypeOID = NULL, 68 *uid = NULL, *comment = NULL, *mech = NULL, 69 operation = '0'; 70 int c, errflag = 0; 71 extern char *optarg; 72 73 PROG_NAME = *args; 74 75 /* set locale and domain for internationalization */ 76 setlocale(LC_ALL, ""); 77 textdomain(TEXT_DOMAIN); 78 79 if (argc < 2) 80 usage(); 81 82 /* Process the input arguments */ 83 while ((c = getopt(argc, args, "arln:o:u:m:c:")) != EOF) { 84 85 switch (c) { 86 case 'n': 87 userName = optarg; 88 break; 89 90 case 'o': 91 nameTypeOID = optarg; 92 break; 93 94 case 'u': 95 uid = optarg; 96 break; 97 98 case 'm': 99 mech = optarg; 100 break; 101 102 case 'c': 103 comment = optarg; 104 break; 105 106 case 'a': 107 case 'r': 108 case 'l': 109 operation = c; 110 errflag++; 111 if (errflag > 1) 112 usage(); 113 break; 114 115 default: 116 usage(); 117 } 118 } 119 120 /* determine which back-end to use as the gsscred store */ 121 tableSource = gsscred_read_config_file(); 122 123 /* perform the requested operation */ 124 switch (operation) { 125 case 'a': 126 addUser(userName, nameTypeOID, uid, comment, mech); 127 break; 128 129 case 'r': 130 removeUsers(userName, nameTypeOID, uid, mech); 131 break; 132 133 case 'l': 134 listUsers(userName, nameTypeOID, uid, mech); 135 break; 136 137 default: 138 usage(); 139 } 140 fprintf(stdout, "\n"); 141 return (0); 142 } /* main */ 143 144 /* 145 * Handles the addition of users to the gsscred table. 146 */ 147 static void 148 addUser(const char *name, const char *nameOidStr, 149 const char *userUid, const char *userComment, 150 const char *mechOidStr) 151 { 152 gss_OID mechOid; 153 gss_buffer_desc fullName = GSS_C_EMPTY_BUFFER, 154 hexBufDesc = GSS_C_EMPTY_BUFFER, 155 hexMechOid = GSS_C_EMPTY_BUFFER; 156 char comment[MAX_STR_LEN+1], hexBuf[MAX_STR_LEN+MAX_STR_LEN+1], 157 hexMechOidBuf[MAX_STR_LEN+1], *commentPtr = NULL, 158 *errDetail = NULL, uidStr[256], *uidPtr; 159 struct passwd *aUser; 160 OM_uint32 minor; 161 int count = 0, retCode; 162 163 hexMechOid.length = MAX_STR_LEN; 164 hexMechOid.value = (void*)hexMechOidBuf; 165 166 /* addition of users can only be performed by super users */ 167 if (getuid()) { 168 fprintf(stderr, 169 gettext("\nUser addition requires" 170 " root privileges.")); 171 return; 172 } 173 174 /* the mechanism OID is required */ 175 if (mechOidStr == NULL) { 176 fprintf(stderr, gettext("\nUnspecified mechanism.")); 177 usage(); 178 } 179 180 /* Convert from string mechanism Oid to ASN.1 oid and then hex */ 181 if (__gss_mech_to_oid(mechOidStr, &mechOid) != GSS_S_COMPLETE) { 182 fprintf(stderr, 183 gettext("\nInvalid mechanism specified [%s]."), 184 mechOidStr); 185 return; 186 } 187 188 hexBufDesc.length = mechOid->length; 189 hexBufDesc.value = mechOid->elements; 190 191 if (!gsscred_AsHex(&hexBufDesc, &hexMechOid)) { 192 fprintf(stderr, 193 gettext("\nInternal error. " 194 "Conversion to hex failed.")); 195 return; 196 } 197 198 /* 199 * if the name is specified, then do single addition. 200 * Might have to look up the uid. 201 */ 202 if (name != NULL) { 203 hexBufDesc.length = sizeof (hexBuf); 204 hexBufDesc.value = hexBuf; 205 206 /* build the name as needed */ 207 if (!gsscred_MakeName(mechOid, name, nameOidStr, &fullName)) { 208 fprintf(stderr, 209 gettext("\nError adding user [%s]."), name); 210 return; 211 } 212 213 /* convert it to hex */ 214 if (!gsscred_AsHex(&fullName, &hexBufDesc)) { 215 gss_release_buffer(&minor, &fullName); 216 fprintf(stderr, 217 gettext("\nInternal error. " 218 "Conversion to hex failed.")); 219 return; 220 } 221 222 /* might require the lookup of the uid if one not specified */ 223 if (userUid == NULL) { 224 225 if ((aUser = getpwnam(name)) == NULL) { 226 fprintf(stderr, 227 gettext("\nUnable to obtain password" 228 " information for [%s]."), 229 name); 230 gss_release_buffer(&minor, &fullName); 231 return; 232 } 233 sprintf(uidStr, "%ld", aUser->pw_uid); 234 uidPtr = uidStr; 235 } 236 else 237 uidPtr = (char *)userUid; 238 239 if (userComment == NULL) { 240 sprintf(comment, "%s, %s", name, mechOidStr); 241 commentPtr = comment; 242 } else 243 commentPtr = (char *)userComment; 244 245 if (tableSource == GSSCRED_FLAT_FILE) 246 retCode = file_addGssCredEntry(&hexBufDesc, 247 uidPtr, commentPtr, &errDetail); 248 else 249 /* other backends (ldap, dss) coming soon */ 250 retCode = 0; 251 252 if (!retCode) { 253 fprintf(stderr, gettext("\nError adding user [%s]."), 254 commentPtr); 255 256 if (errDetail) { 257 fprintf(stderr, "\n%s\n", errDetail); 258 free(errDetail); 259 errDetail = NULL; 260 } 261 } 262 263 gss_release_buffer(&minor, &fullName); 264 return; 265 } 266 267 /* 268 * since no name specified, then we will load everyone from 269 * password table. This means that -u and -o options are invalid. 270 * We just ignore it, but we could flag it as error. 271 */ 272 setpwent(); 273 274 while ((aUser = getpwent()) != NULL) { 275 hexBufDesc.length = sizeof (hexBuf); 276 hexBufDesc.value = hexBuf; 277 278 if (!gsscred_MakeName(mechOid, aUser->pw_name, 279 nameOidStr, &fullName)) { 280 fprintf(stderr, 281 gettext("\nError adding user [%s]."), 282 aUser->pw_name); 283 continue; 284 } 285 286 if (!gsscred_AsHex(&fullName, &hexBufDesc)) { 287 gss_release_buffer(&minor, &fullName); 288 fprintf(stderr, 289 gettext("\nInternal error. " 290 "Conversion to hex failed.")); 291 continue; 292 } 293 294 sprintf(uidStr, "%ld", aUser->pw_uid); 295 sprintf(comment, "%s, %s", aUser->pw_name, mechOidStr); 296 if (tableSource == GSSCRED_FLAT_FILE) 297 retCode = file_addGssCredEntry(&hexBufDesc, 298 uidStr, comment, &errDetail); 299 else 300 retCode = 0; 301 302 if (!retCode) { 303 fprintf(stderr, 304 gettext("\nError adding user [%s]."), 305 comment); 306 307 if (errDetail) { 308 fprintf(stderr, "\n%s\n", errDetail); 309 free(errDetail); 310 errDetail = NULL; 311 } 312 } else { 313 count++; 314 if ((count % 50) == 0) 315 fprintf(stdout, 316 gettext("\n[%d] users added..."), 317 count); 318 } 319 gss_release_buffer(&minor, &fullName); 320 } 321 endpwent(); 322 } /* addUser */ 323 324 325 /* 326 * Handles the searching of the gsscred table. 327 */ 328 static int listUsers(const char *name, const char *nameOidStr, 329 const char *uidStr, const char *mechOidStr) 330 { 331 GssCredEntry *entryPtr, *entryTmpPtr; 332 char hexMech[256], 333 hexName[(MAX_STR_LEN *2) + 1]; 334 gss_OID anOid = NULL, userMechOid = NULL; 335 gss_OID_set mechSet = NULL; 336 gss_buffer_desc inBufDesc = GSS_C_EMPTY_BUFFER, 337 outBufDesc = GSS_C_EMPTY_BUFFER, 338 searchName = GSS_C_EMPTY_BUFFER; 339 int status = 1, numOfMechs, i; 340 OM_uint32 minor; 341 char *errDetails = NULL; 342 343 /* Do we need to convert the mechanism oid? */ 344 if (mechOidStr != NULL) { 345 346 if (__gss_mech_to_oid(mechOidStr, &userMechOid) != 347 GSS_S_COMPLETE) { 348 fprintf(stderr, 349 gettext("\nInvalid mechanism specified [%s]."), 350 mechOidStr); 351 return (0); 352 } 353 inBufDesc.length = userMechOid->length; 354 inBufDesc.value = userMechOid->elements; 355 outBufDesc.length = sizeof (hexMech); 356 outBufDesc.value = hexMech; 357 358 if (!gsscred_AsHex(&inBufDesc, &outBufDesc)) { 359 fprintf(stderr, 360 gettext("\nInternal error. " 361 "Conversion to hex failed.")); 362 status = 0; 363 goto cleanup; 364 } 365 366 } /* mechOidStr != NULL */ 367 368 /* are we retrieving everyone ? or searching by mech ? */ 369 if ((name == NULL && uidStr == NULL && mechOidStr == NULL) || 370 (name == NULL && uidStr == NULL)) { 371 372 if (tableSource == GSSCRED_FLAT_FILE) { 373 file_listUsers(userMechOid, NULL, &errDetails); 374 375 if (errDetails) { 376 fprintf(stderr, 377 gettext("\nError searching gsscred" 378 " table [%s]."), 379 errDetails); 380 free(errDetails); 381 errDetails = NULL; 382 return (0); 383 } 384 return (1); 385 } 386 387 } 388 389 /* Are we searching by uid or uid and mech? */ 390 if (name == NULL && uidStr != NULL) { 391 392 if (tableSource == GSSCRED_FLAT_FILE) 393 file_listUsers(userMechOid, uidStr, &errDetails); 394 else { 395 entryPtr = NULL; 396 while (entryPtr != NULL) { 397 fprintf(stdout, "\n%s\t%d\t%s", 398 entryPtr->principal_name, 399 entryPtr->unix_uid, entryPtr->comment); 400 free(entryPtr->principal_name); 401 free(entryPtr->comment); 402 entryTmpPtr = entryPtr->next; 403 free(entryPtr); 404 entryPtr = entryTmpPtr; 405 } 406 } 407 408 /* check for any errors */ 409 if (errDetails) { 410 fprintf(stderr, 411 gettext("\nError searching gsscred table " 412 "[%s]."), 413 errDetails); 414 free(errDetails); 415 errDetails = NULL; 416 status = 0; 417 } 418 419 goto cleanup; 420 } 421 422 /* 423 * We are searching by name; 424 * how many mechs must we check? 425 */ 426 if (mechOidStr == NULL) { 427 428 if (gss_indicate_mechs(&minor, &mechSet) != GSS_S_COMPLETE) { 429 fprintf(stderr, 430 gettext("\nInternal error. " 431 "GSS-API call failed.")); 432 return (0); 433 } 434 numOfMechs = mechSet->count; 435 } 436 else 437 numOfMechs = 1; 438 439 /* now look through all the mechs searching */ 440 for (i = 0; i < numOfMechs; i++) { 441 442 if (mechOidStr == NULL) { 443 anOid = &mechSet->elements[i]; 444 inBufDesc.length = anOid->length; 445 inBufDesc.value = anOid->elements; 446 outBufDesc.length = sizeof (hexMech); 447 outBufDesc.value = hexMech; 448 449 if (!gsscred_AsHex(&inBufDesc, &outBufDesc)) 450 continue; 451 } else 452 anOid = userMechOid; 453 454 /* create a gss name */ 455 if (!gsscred_MakeName(anOid, name, nameOidStr, &outBufDesc)) 456 continue; 457 458 /* now convert it to hex, and find it */ 459 searchName.value = hexName; 460 searchName.length = sizeof (hexName); 461 status = gsscred_AsHex(&outBufDesc, &searchName); 462 free(outBufDesc.value); 463 464 if (!status) 465 continue; 466 467 if (tableSource == GSSCRED_FLAT_FILE) 468 file_getGssCredEntry(&searchName, uidStr, &errDetails); 469 else { 470 entryPtr = NULL; /* other backends coming soon */ 471 while (entryPtr != NULL) { 472 fprintf(stdout, "\n%s\t%d\t%s", 473 entryPtr->principal_name, 474 entryPtr->unix_uid, entryPtr->comment); 475 free(entryPtr->principal_name); 476 free(entryPtr->comment); 477 entryTmpPtr = entryPtr->next; 478 free(entryPtr); 479 entryPtr = entryTmpPtr; 480 } 481 } 482 483 /* any errors to display */ 484 if (errDetails) { 485 fprintf(stderr, 486 gettext("\nError searching gsscred table " 487 "[%s]."), 488 errDetails); 489 free(errDetails); 490 errDetails = NULL; 491 status = 0; 492 } 493 } /* for */ 494 495 cleanup: 496 if (mechSet != NULL) 497 gss_release_oid_set(&minor, &mechSet); 498 499 return (status); 500 } /* listUsers */ 501 502 /* 503 * Performs additional handling while searching for users 504 * stored in the flat file table. 505 */ 506 int 507 file_listUsers(const gss_OID mechOid, const char *unixUid, 508 char **errDetails) 509 { 510 gss_buffer_desc mechBufDesc = GSS_C_EMPTY_BUFFER, 511 mechHexBufDesc = GSS_C_EMPTY_BUFFER; 512 char mechBuf[128], mechHexBuf[256]; 513 514 if (mechOid != NULL) { 515 /* must make the name header whic contains mech oid */ 516 mechBufDesc.value = (void *) mechBuf; 517 mechBufDesc.length = sizeof (mechBuf); 518 mechHexBufDesc.value = (void*) mechHexBuf; 519 mechHexBufDesc.length = sizeof (mechHexBuf); 520 521 if ((!gsscred_MakeNameHeader(mechOid, &mechBufDesc)) || 522 (!gsscred_AsHex(&mechBufDesc, &mechHexBufDesc))) { 523 (*errDetails) = strdup( 524 gettext("\nInternal error. " 525 " Conversion to hex failed.")); 526 return (0); 527 } 528 529 return (file_getGssCredEntry(&mechHexBufDesc, 530 unixUid, errDetails)); 531 } 532 533 return (file_getGssCredEntry(NULL, unixUid, errDetails)); 534 } /* file_listUsers */ 535 536 537 /* 538 * Handles the deletion of users. 539 */ 540 static int removeUsers(const char *name, const char *nameOidStr, 541 const char *uidStr, const char *mechOidStr) 542 { 543 char hexMech[256], 544 hexName[(MAX_STR_LEN *2) + 1], 545 *errDetails = NULL; 546 gss_OID anOid = NULL, userMechOid = NULL; 547 gss_OID_set mechSet = NULL; 548 gss_buffer_desc inBufDesc = GSS_C_EMPTY_BUFFER, 549 outBufDesc = GSS_C_EMPTY_BUFFER, 550 searchName = GSS_C_EMPTY_BUFFER; 551 int status = 0, numOfMechs, i; 552 OM_uint32 minor; 553 554 555 /* user deletion can only be performed by super user */ 556 if (getuid()) { 557 558 fprintf(stderr, 559 gettext("\nUser deletion requires" 560 " root privileges.")); 561 return (0); 562 } 563 564 /* do we need to convert the mechanism oid? */ 565 if (mechOidStr != NULL) { 566 if (__gss_mech_to_oid(mechOidStr, &userMechOid) != 567 GSS_S_COMPLETE) { 568 fprintf(stderr, 569 gettext("\nInvalid mechanism specified [%s]."), 570 mechOidStr); 571 return (0); 572 } 573 574 inBufDesc.length = userMechOid->length; 575 inBufDesc.value = userMechOid->elements; 576 outBufDesc.length = sizeof (hexMech); 577 outBufDesc.value = hexMech; 578 579 if (!gsscred_AsHex(&inBufDesc, &outBufDesc)) { 580 fprintf(stderr, 581 gettext("\nInternal error." 582 " Conversion to hex failed.")); 583 status = 0; 584 goto cleanup; 585 } 586 587 } /* mechOidStr != NULL */ 588 589 /* are we deleting the entire table or an entire mech ? */ 590 if (name == NULL && uidStr == NULL) { 591 592 if (tableSource == GSSCRED_FLAT_FILE) 593 status = file_removeUsers(userMechOid, 594 NULL, &errDetails); 595 else 596 status = 0; 597 598 /* display any errors */ 599 if (errDetails) { 600 fprintf(stderr, 601 gettext("\nError deleting gsscred entry " 602 "[%s]."), 603 errDetails); 604 free(errDetails); 605 errDetails = NULL; 606 } 607 goto cleanup; 608 } 609 610 /* are we deleting by uid or uid and mech? */ 611 if (name == NULL && uidStr != NULL) { 612 613 if (tableSource == GSSCRED_FLAT_FILE) 614 status = file_removeUsers(userMechOid, uidStr, 615 &errDetails); 616 else 617 status = 0; 618 619 /* check for any errors */ 620 if (errDetails) { 621 fprintf(stderr, 622 gettext("\nError deleting gsscred entry " 623 "[%s]."), 624 errDetails); 625 free(errDetails); 626 errDetails = NULL; 627 } 628 goto cleanup; 629 } 630 631 /* 632 * We are deleting by name; 633 * how many mechs must we check? 634 */ 635 if (mechOidStr == NULL) { 636 637 if (gss_indicate_mechs(&minor, &mechSet) != GSS_S_COMPLETE) { 638 fprintf(stderr, 639 gettext("\nInternal error. " 640 "GSS-API call failed.")); 641 status = 0; 642 goto cleanup; 643 } 644 numOfMechs = mechSet->count; 645 } 646 else 647 numOfMechs = 1; 648 649 /* now look through all the mechs, deleting */ 650 for (i = 0; i < numOfMechs; i++) { 651 652 if (mechOidStr == NULL) { 653 anOid = &mechSet->elements[i]; 654 inBufDesc.length = anOid->length; 655 inBufDesc.value = anOid->elements; 656 outBufDesc.length = sizeof (hexMech); 657 outBufDesc.value = hexMech; 658 if (!gsscred_AsHex(&inBufDesc, &outBufDesc)) 659 continue; 660 } else 661 anOid = userMechOid; 662 663 /* create a gss name */ 664 if (!gsscred_MakeName(anOid, name, nameOidStr, &outBufDesc)) 665 continue; 666 667 /* now convert it to hex, and delete it */ 668 searchName.value = hexName; 669 searchName.length = sizeof (hexName); 670 status = gsscred_AsHex(&outBufDesc, &searchName); 671 free(outBufDesc.value); 672 673 if (!status) 674 continue; 675 676 if (tableSource == GSSCRED_FLAT_FILE) 677 status = file_deleteGssCredEntry(&searchName, 678 uidStr, &errDetails); 679 else 680 status = 0; 681 682 /* check for any errors */ 683 if (errDetails) { 684 fprintf(stderr, 685 gettext("\nError deleting gsscred entry" 686 " [%s]."), 687 errDetails); 688 free(errDetails); 689 errDetails = NULL; 690 } 691 } /* for */ 692 693 cleanup: 694 if (mechSet != NULL) 695 gss_release_oid_set(&minor, &mechSet); 696 697 return (status); 698 } /* removeUsers */ 699 700 701 /* 702 * Performs additional handling while deleting users 703 * stored in the flat file table. 704 */ 705 int file_removeUsers(const gss_OID mechOid, const char *unixUid, 706 char **errDetails) 707 { 708 gss_buffer_desc mechBufDesc = GSS_C_EMPTY_BUFFER, 709 mechHexBufDesc = GSS_C_EMPTY_BUFFER; 710 char mechBuf[128], mechHexBuf[256]; 711 712 if (mechOid != NULL) { 713 /* 714 * need to create the buffer header which contains 715 * the mechanism oid. 716 */ 717 mechBufDesc.value = (void*) mechBuf; 718 mechBufDesc.length = sizeof (mechBuf); 719 mechHexBufDesc.value = (void *) mechHexBuf; 720 mechHexBufDesc.length = sizeof (mechHexBuf); 721 722 if ((!gsscred_MakeNameHeader(mechOid, &mechBufDesc)) || 723 (!gsscred_AsHex(&mechBufDesc, &mechHexBufDesc))) { 724 (*errDetails) = strdup( 725 gettext("\nInternal error." 726 " Conversion to hex failed.")); 727 return (0); 728 } 729 730 return (file_deleteGssCredEntry(&mechHexBufDesc, unixUid, 731 errDetails)); 732 } 733 734 return (file_deleteGssCredEntry(NULL, unixUid, errDetails)); 735 } /* file_removeUsers */ 736 737 738 /* 739 * Prints the usage string, and terminates. 740 */ 741 static void usage(void) 742 { 743 744 fprintf(stderr, 745 gettext("\nUsage:\t %s [-n user [-o oid] [-u uid]]" 746 " [-c comment] -m mech -a" 747 "\n\t %s [-n user [-o oid]] [-u uid] [-m mech] -r" 748 "\n\t %s [-n user [-o oid]] [-u uid] [-m mech] -l\n"), 749 PROG_NAME, PROG_NAME, PROG_NAME); 750 exit(1); 751 } /* usage */ 752