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