1 /* 2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * kadmin/ldap_util/kdb5_ldap_services.c 8 */ 9 10 /* Copyright (c) 2004-2005, Novell, Inc. 11 * All rights reserved. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions are met: 15 * 16 * * Redistributions of source code must retain the above copyright notice, 17 * this list of conditions and the following disclaimer. 18 * * Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * * The copyright holder's name is not used to endorse or promote products 22 * derived from this software without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 * POSSIBILITY OF SUCH DAMAGE. 35 */ 36 37 /* 38 * Create / Delete / Modify / View / List service objects. 39 */ 40 41 /* 42 * Service objects have rights over realm objects and principals. The following 43 * functions manage the service objects. 44 */ 45 46 #include <stdio.h> 47 #include <k5-int.h> 48 #include <libintl.h> /* Solaris Kerberos */ 49 #include <locale.h> /* Solaris Kerberos */ 50 #include "kdb5_ldap_util.h" 51 #include "kdb5_ldap_list.h" 52 53 #ifdef HAVE_EDIRECTORY 54 55 krb5_error_code 56 rem_service_entry_from_file(int argc, 57 char *argv[], 58 char *file_name, 59 char *service_object); 60 61 extern char *yes; 62 extern krb5_boolean db_inited; 63 64 static int process_host_list(char **host_list, int servicetype) 65 { 66 krb5_error_code retval = 0; 67 char *pchr = NULL; 68 char host_str[MAX_LEN_LIST_ENTRY] = "", proto_str[PROTOCOL_STR_LEN + 1] = "", port_str[PORT_STR_LEN + 1] = ""; 69 int j = 0; 70 71 /* Protocol and port number processing */ 72 for (j = 0; host_list[j]; j++) { 73 /* Look for one hash */ 74 if ((pchr = strchr(host_list[j], HOST_INFO_DELIMITER))) { 75 unsigned int hostname_len = pchr - host_list[j]; 76 77 /* Check input for buffer overflow */ 78 if (hostname_len >= MAX_LEN_LIST_ENTRY) { 79 retval = EINVAL; 80 goto cleanup; 81 } 82 83 /* First copy off the host name portion */ 84 strncpy (host_str, host_list[j], hostname_len); 85 86 /* Parse for the protocol string and translate to number */ 87 strncpy (proto_str, pchr + 1, PROTOCOL_STR_LEN); 88 if (!strcmp(proto_str, "udp")) 89 sprintf (proto_str, "%d", PROTOCOL_NUM_UDP); 90 else if (!strcmp(proto_str, "tcp")) 91 sprintf (proto_str, "%d", PROTOCOL_NUM_TCP); 92 else 93 proto_str[0] = '\0'; /* Make the string null if invalid */ 94 95 /* Look for one more hash */ 96 if ((pchr = strchr(pchr + 1, HOST_INFO_DELIMITER))) { 97 /* Parse for the port string and check if it is numeric */ 98 strncpy (port_str, pchr + 1, PORT_STR_LEN); 99 if (!strtol(port_str, NULL, 10)) /* Not a valid number */ 100 port_str[0] = '\0'; 101 } else 102 port_str[0] = '\0'; 103 } else { /* We have only host name */ 104 strncpy (host_str, host_list[j], MAX_LEN_LIST_ENTRY - 1); 105 proto_str[0] = '\0'; 106 port_str[0] = '\0'; 107 } 108 109 /* Now, based on service type, fill in suitable protocol 110 and port values if they are absent or not matching */ 111 if (servicetype == LDAP_KDC_SERVICE) { 112 if (proto_str[0] == '\0') 113 sprintf (proto_str, "%d", PROTOCOL_DEFAULT_KDC); 114 115 if (port_str[0] == '\0') 116 sprintf (port_str, "%d", PORT_DEFAULT_KDC); 117 } else if (servicetype == LDAP_ADMIN_SERVICE) { 118 if (proto_str[0] == '\0') 119 sprintf (proto_str, "%d", PROTOCOL_DEFAULT_ADM); 120 else if (strcmp(proto_str, "1")) { 121 sprintf (proto_str, "%d", PROTOCOL_DEFAULT_ADM); 122 123 /* Print warning message */ 124 printf (gettext("Admin Server supports only TCP protocol, hence setting that\n")); 125 } 126 127 if (port_str[0] == '\0') 128 sprintf (port_str, "%d", PORT_DEFAULT_ADM); 129 } else if (servicetype == LDAP_PASSWD_SERVICE) { 130 if (proto_str[0] == '\0') 131 sprintf (proto_str, "%d", PROTOCOL_DEFAULT_PWD); 132 else if (strcmp(proto_str, "0")) { 133 sprintf (proto_str, "%d", PROTOCOL_DEFAULT_PWD); 134 135 /* Print warning message */ 136 printf (gettext("Password Server supports only UDP protocol, hence setting that\n")); 137 } 138 139 if (port_str[0] == '\0') 140 sprintf (port_str, "%d", PORT_DEFAULT_PWD); 141 } 142 143 /* Finally form back the string */ 144 free (host_list[j]); 145 host_list[j] = (char*) malloc(sizeof(char) * 146 (strlen(host_str) + strlen(proto_str) + strlen(port_str) + 2 + 1)); 147 if (host_list[j] == NULL) { 148 retval = ENOMEM; 149 goto cleanup; 150 } 151 snprintf (host_list[j], strlen(host_str) + strlen(proto_str) + strlen(port_str) + 2 + 1, 152 "%s#%s#%s", host_str, proto_str, port_str); 153 } 154 155 cleanup: 156 return retval; 157 } 158 159 160 /* 161 * Given a realm name, this function will convert it to a DN by appending the 162 * Kerberos container location. 163 */ 164 static krb5_error_code 165 convert_realm_name2dn_list(list, krbcontainer_loc) 166 char **list; 167 const char *krbcontainer_loc; 168 { 169 krb5_error_code retval = 0; 170 char temp_str[MAX_DN_CHARS] = "\0"; 171 char *temp_node = NULL; 172 int i = 0; 173 174 if (list == NULL) { 175 return EINVAL; 176 } 177 178 for (i = 0; (list[i] != NULL) && (i < MAX_LIST_ENTRIES); i++) { 179 /* Restrict copying to max. length to avoid buffer overflow */ 180 snprintf (temp_str, MAX_DN_CHARS, "cn=%s,%s", list[i], krbcontainer_loc); 181 182 /* Make copy of string to temporary node */ 183 temp_node = strdup(temp_str); 184 if (list[i] == NULL) { 185 retval = ENOMEM; 186 goto cleanup; 187 } 188 189 /* On success, free list node and attach new one */ 190 free (list[i]); 191 list[i] = temp_node; 192 temp_node = NULL; 193 } 194 195 cleanup: 196 return retval; 197 } 198 199 200 /* 201 * This function will create a service object on the LDAP Server, with the 202 * specified attributes. 203 */ 204 void kdb5_ldap_create_service(argc, argv) 205 int argc; 206 char *argv[]; 207 { 208 /* Solaris Kerberos */ 209 char *me = progname; 210 krb5_error_code retval = 0; 211 krb5_ldap_service_params *srvparams = NULL; 212 krb5_boolean print_usage = FALSE; 213 krb5_boolean no_msg = FALSE; 214 int mask = 0; 215 char **extra_argv = NULL; 216 int extra_argc = 0; 217 int i = 0; 218 krb5_ldap_realm_params *rparams = NULL; 219 int rmask = 0; 220 int rightsmask =0; 221 char **temprdns = NULL; 222 char *realmName = NULL; 223 kdb5_dal_handle *dal_handle = NULL; 224 krb5_ldap_context *ldap_context=NULL; 225 krb5_boolean service_obj_created = FALSE; 226 227 /* Check for number of arguments */ 228 if ((argc < 3) || (argc > 10)) { 229 exit_status++; 230 goto err_usage; 231 } 232 233 /* Allocate memory for service parameters structure */ 234 srvparams = (krb5_ldap_service_params*) calloc(1, sizeof(krb5_ldap_service_params)); 235 if (srvparams == NULL) { 236 retval = ENOMEM; 237 goto cleanup; 238 } 239 240 dal_handle = (kdb5_dal_handle *) util_context->db_context; 241 ldap_context = (krb5_ldap_context *) dal_handle->db_context; 242 243 /* Allocate memory for extra arguments to be used for setting 244 password -- it's OK to allocate as much as the total number 245 of arguments */ 246 extra_argv = (char **) calloc((unsigned int)argc, sizeof(char*)); 247 if (extra_argv == NULL) { 248 retval = ENOMEM; 249 goto cleanup; 250 } 251 252 /* Set first of the extra arguments as the program name */ 253 extra_argv[0] = me; 254 extra_argc++; 255 256 /* Read Kerberos container info, to construct realm DN from name 257 * and for assigning rights 258 */ 259 if ((retval = krb5_ldap_read_krbcontainer_params(util_context, 260 &(ldap_context->krbcontainer)))) { 261 com_err(me, retval, gettext("while reading Kerberos container information")); 262 goto cleanup; 263 } 264 265 /* Parse all arguments */ 266 for (i = 1; i < argc; i++) { 267 if (!strcmp(argv[i], "-kdc")) { 268 srvparams->servicetype = LDAP_KDC_SERVICE; 269 } else if (!strcmp(argv[i], "-admin")) { 270 srvparams->servicetype = LDAP_ADMIN_SERVICE; 271 } else if (!strcmp(argv[i], "-pwd")) { 272 srvparams->servicetype = LDAP_PASSWD_SERVICE; 273 } else if (!strcmp(argv[i], "-servicehost")) { 274 if (++i > argc - 1) 275 goto err_usage; 276 277 srvparams->krbhostservers = (char **)calloc(MAX_LIST_ENTRIES, 278 sizeof(char *)); 279 if (srvparams->krbhostservers == NULL) { 280 retval = ENOMEM; 281 goto cleanup; 282 } 283 284 if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, 285 srvparams->krbhostservers))) { 286 goto cleanup; 287 } 288 289 if ((retval = process_host_list (srvparams->krbhostservers, 290 srvparams->servicetype))) { 291 goto cleanup; 292 } 293 294 mask |= LDAP_SERVICE_HOSTSERVER; 295 } else if (!strcmp(argv[i], "-realm")) { 296 if (++i > argc - 1) 297 goto err_usage; 298 299 srvparams->krbrealmreferences = (char **)calloc(MAX_LIST_ENTRIES, 300 sizeof(char *)); 301 if (srvparams->krbrealmreferences == NULL) { 302 retval = ENOMEM; 303 goto cleanup; 304 } 305 306 if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, 307 srvparams->krbrealmreferences))) { 308 goto cleanup; 309 } 310 311 /* Convert realm names to realm DNs */ 312 if ((retval = convert_realm_name2dn_list( 313 srvparams->krbrealmreferences, 314 ldap_context->krbcontainer->DN))) { 315 goto cleanup; 316 } 317 318 mask |= LDAP_SERVICE_REALMREFERENCE; 319 } 320 /* If argument is none of the above and beginning with '-', 321 * it must be related to password -- collect it 322 * to pass onto kdb5_ldap_set_service_password() 323 */ 324 else if (*(argv[i]) == '-') { 325 /* Checking for options of setting the password for the 326 * service (by using 'setsrvpw') is not modular. --need to 327 * have a common function that can be shared with 'setsrvpw' 328 */ 329 if (!strcmp(argv[i], "-randpw")) { 330 extra_argv[extra_argc] = argv[i]; 331 extra_argc++; 332 } else if (!strcmp(argv[i], "-fileonly")) { 333 extra_argv[extra_argc] = argv[i]; 334 extra_argc++; 335 } 336 /* For '-f' option alone, pick up the following argument too */ 337 else if (!strcmp(argv[i], "-f")) { 338 extra_argv[extra_argc] = argv[i]; 339 extra_argc++; 340 341 if (++i > argc - 1) 342 goto err_usage; 343 344 extra_argv[extra_argc] = argv[i]; 345 extra_argc++; 346 } else { /* Any other option is invalid */ 347 exit_status++; 348 goto err_usage; 349 } 350 } else { /* Any other argument must be service DN */ 351 /* First check if service DN is already provided -- 352 * if so, there's a usage error 353 */ 354 if (srvparams->servicedn != NULL) { 355 com_err(me, EINVAL, gettext("while creating service object")); 356 goto err_usage; 357 } 358 359 /* If not present already, fill up service DN */ 360 srvparams->servicedn = strdup(argv[i]); 361 if (srvparams->servicedn == NULL) { 362 com_err(me, ENOMEM, gettext("while creating service object")); 363 goto err_nomsg; 364 } 365 } 366 } 367 368 /* No point in proceeding further if service DN value is not available */ 369 if (srvparams->servicedn == NULL) { 370 com_err(me, EINVAL, gettext("while creating service object")); 371 goto err_usage; 372 } 373 374 if (srvparams->servicetype == 0) { /* Not provided and hence not set */ 375 com_err(me, EINVAL, gettext("while creating service object")); 376 goto err_usage; 377 } 378 379 /* Create object with all attributes provided */ 380 if ((retval = krb5_ldap_create_service(util_context, srvparams, mask))) 381 goto cleanup; 382 383 service_obj_created = TRUE; 384 385 /* ** NOTE ** srvparams structure should not be modified, as it is 386 * used for deletion of the service object in case of any failures 387 * from now on. 388 */ 389 390 /* Set password too */ 391 if (extra_argc >= 1) { 392 /* Set service DN as the last argument */ 393 extra_argv[extra_argc] = strdup(srvparams->servicedn); 394 if (extra_argv[extra_argc] == NULL) { 395 retval = ENOMEM; 396 goto cleanup; 397 } 398 extra_argc++; 399 400 if ((retval = kdb5_ldap_set_service_password(extra_argc, extra_argv)) != 0) { 401 goto err_nomsg; 402 } 403 } 404 /* Rights assignment */ 405 if (mask & LDAP_SERVICE_REALMREFERENCE) { 406 407 printf("%s", gettext("Changing rights for the service object. Please wait ... ")); 408 fflush(stdout); 409 410 rightsmask =0; 411 rightsmask |= LDAP_REALM_RIGHTS; 412 rightsmask |= LDAP_SUBTREE_RIGHTS; 413 414 if ((srvparams != NULL) && (srvparams->krbrealmreferences != NULL)) { 415 for (i=0; (srvparams->krbrealmreferences[i] != NULL); i++) { 416 417 /* Get the realm name, not the dn */ 418 temprdns = ldap_explode_dn(srvparams->krbrealmreferences[i], 1); 419 420 if (temprdns[0] == NULL) { 421 retval = EINVAL; 422 goto cleanup; 423 } 424 425 realmName = strdup(temprdns[0]); 426 if (realmName == NULL) { 427 retval = ENOMEM; 428 goto cleanup; 429 } 430 431 if ((retval = krb5_ldap_read_realm_params(util_context, 432 realmName, &rparams, &rmask))) { 433 com_err(me, retval, gettext("while reading information of realm '%s'"), 434 realmName); 435 goto cleanup; 436 } 437 438 if ((retval = krb5_ldap_add_service_rights(util_context, 439 srvparams->servicetype, srvparams->servicedn, 440 realmName, rparams->subtree, rightsmask))) { 441 printf(gettext("failed\n")); 442 com_err(me, retval, gettext("while assigning rights '%s'"), 443 srvparams->servicedn); 444 goto cleanup; 445 } 446 447 if (rparams) 448 krb5_ldap_free_realm_params(rparams); 449 } 450 } 451 printf(gettext("done\n")); 452 } 453 goto cleanup; 454 455 err_usage: 456 print_usage = TRUE; 457 458 err_nomsg: 459 no_msg = TRUE; 460 461 cleanup: 462 463 if ((retval != 0) && (service_obj_created == TRUE)) { 464 /* This is for deleting the service object if something goes 465 * wrong in creating the service object 466 */ 467 468 /* srvparams is populated from the user input and should be correct as 469 * we were successful in creating a service object. Reusing the same 470 */ 471 krb5_ldap_delete_service(util_context, srvparams, srvparams->servicedn); 472 } 473 474 /* Clean-up structure */ 475 krb5_ldap_free_service (util_context, srvparams); 476 477 if (extra_argv) { 478 free (extra_argv); 479 extra_argv = NULL; 480 } 481 if (realmName) { 482 free(realmName); 483 realmName = NULL; 484 } 485 if (print_usage) 486 db_usage (CREATE_SERVICE); 487 488 if (retval) { 489 if (!no_msg) 490 com_err(me, retval, gettext("while creating service object")); 491 492 exit_status++; 493 } 494 495 return; 496 } 497 498 499 /* 500 * This function will modify the attributes of a given service 501 * object on the LDAP Server 502 */ 503 void kdb5_ldap_modify_service(argc, argv) 504 int argc; 505 char *argv[]; 506 { 507 /* Solaris Kerberos */ 508 char *me = progname; 509 krb5_error_code retval = 0; 510 krb5_ldap_service_params *srvparams = NULL; 511 krb5_boolean print_usage = FALSE; 512 krb5_boolean no_msg = FALSE; 513 char *servicedn = NULL; 514 int i = 0; 515 int in_mask = 0, out_mask = 0; 516 int srvhost_flag = 0, realmdn_flag = 0; 517 char **list = NULL; 518 int existing_entries = 0, new_entries = 0; 519 char **temp_ptr = NULL; 520 krb5_ldap_realm_params *rparams = NULL; 521 int j = 0; 522 int rmask = 0; 523 int rightsmask =0; 524 char **oldrealmrefs = NULL; 525 char **newrealmrefs = NULL; 526 char **temprdns = NULL; 527 char *realmName = NULL; 528 kdb5_dal_handle *dal_handle = NULL; 529 krb5_ldap_context *ldap_context=NULL; 530 531 /* Check for number of arguments */ 532 if ((argc < 3) || (argc > 10)) { 533 exit_status++; 534 goto err_usage; 535 } 536 537 dal_handle = (kdb5_dal_handle *) util_context->db_context; 538 ldap_context = (krb5_ldap_context *) dal_handle->db_context; 539 540 /* Parse all arguments, only to pick up service DN (Pass 1) */ 541 for (i = 1; i < argc; i++) { 542 /* Skip arguments next to 'servicehost' 543 and 'realmdn' arguments */ 544 if (!strcmp(argv[i], "-servicehost")) { 545 ++i; 546 } else if (!strcmp(argv[i], "-clearservicehost")) { 547 ++i; 548 } else if (!strcmp(argv[i], "-addservicehost")) { 549 ++i; 550 } else if (!strcmp(argv[i], "-realm")) { 551 ++i; 552 } else if (!strcmp(argv[i], "-clearrealm")) { 553 ++i; 554 } else if (!strcmp(argv[i], "-addrealm")) { 555 ++i; 556 } else { /* Any other argument must be service DN */ 557 /* First check if service DN is already provided -- 558 if so, there's a usage error */ 559 if (servicedn != NULL) { 560 com_err(me, EINVAL, gettext("while modifying service object")); 561 goto err_usage; 562 } 563 564 /* If not present already, fill up service DN */ 565 servicedn = strdup(argv[i]); 566 if (servicedn == NULL) { 567 com_err(me, ENOMEM, gettext("while modifying service object")); 568 goto err_nomsg; 569 } 570 } 571 } 572 573 /* No point in proceeding further if service DN value is not available */ 574 if (servicedn == NULL) { 575 com_err(me, EINVAL, gettext("while modifying service object")); 576 goto err_usage; 577 } 578 579 retval = krb5_ldap_read_service(util_context, servicedn, &srvparams, &in_mask); 580 if (retval) { 581 /* Solaris Kerberos */ 582 com_err(me, retval, gettext("while reading information of service '%s'"), 583 servicedn); 584 goto err_nomsg; 585 } 586 587 /* Read Kerberos container info, to construct realm DN from name 588 * and for assigning rights 589 */ 590 if ((retval = krb5_ldap_read_krbcontainer_params(util_context, 591 &(ldap_context->krbcontainer)))) { 592 com_err(me, retval, gettext("while reading Kerberos container information")); 593 goto cleanup; 594 } 595 596 /* Parse all arguments, but skip the service DN (Pass 2) */ 597 for (i = 1; i < argc; i++) { 598 if (!strcmp(argv[i], "-servicehost")) { 599 if (++i > argc - 1) 600 goto err_usage; 601 602 /* Free the old list if available */ 603 if (srvparams->krbhostservers) { 604 krb5_free_list_entries (srvparams->krbhostservers); 605 free (srvparams->krbhostservers); 606 } 607 608 srvparams->krbhostservers = (char **)calloc(MAX_LIST_ENTRIES, 609 sizeof(char *)); 610 if (srvparams->krbhostservers == NULL) { 611 retval = ENOMEM; 612 goto cleanup; 613 } 614 615 if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, 616 srvparams->krbhostservers))) { 617 goto cleanup; 618 } 619 620 if ((retval = process_host_list (srvparams->krbhostservers, 621 srvparams->servicetype))) { 622 goto cleanup; 623 } 624 625 out_mask |= LDAP_SERVICE_HOSTSERVER; 626 627 /* Set flag to ignore 'add' and 'clear' */ 628 srvhost_flag = 1; 629 } else if (!strcmp(argv[i], "-clearservicehost")) { 630 if (++i > argc - 1) 631 goto err_usage; 632 633 if (!srvhost_flag) { 634 /* If attribute doesn't exist, don't permit 'clear' option */ 635 if ((in_mask & LDAP_SERVICE_HOSTSERVER) == 0) { 636 /* Send out some proper error message here */ 637 com_err(me, EINVAL, gettext("service host list is empty\n")); 638 goto err_nomsg; 639 } 640 641 /* Allocate list for processing */ 642 list = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); 643 if (list == NULL) { 644 retval = ENOMEM; 645 goto cleanup; 646 } 647 648 if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) 649 goto cleanup; 650 651 if ((retval = process_host_list (list, srvparams->servicetype))) { 652 goto cleanup; 653 } 654 655 list_modify_str_array(&(srvparams->krbhostservers), 656 (const char**)list, LIST_MODE_DELETE); 657 658 out_mask |= LDAP_SERVICE_HOSTSERVER; 659 660 /* Clean up */ 661 free (list); 662 list = NULL; 663 } 664 } else if (!strcmp(argv[i], "-addservicehost")) { 665 if (++i > argc - 1) 666 goto err_usage; 667 668 if (!srvhost_flag) { 669 /* Allocate list for processing */ 670 list = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); 671 if (list == NULL) { 672 retval = ENOMEM; 673 goto cleanup; 674 } 675 676 if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) 677 goto cleanup; 678 679 if ((retval = process_host_list (list, srvparams->servicetype))) { 680 goto cleanup; 681 } 682 683 /* Call list_modify_str_array() only if host server attribute 684 * exists already --Actually, it's better to handle this 685 * within list_modify_str_array() 686 */ 687 if (in_mask & LDAP_SERVICE_HOSTSERVER) { 688 /* Re-size existing list */ 689 existing_entries = list_count_str_array(srvparams->krbhostservers); 690 new_entries = list_count_str_array(list); 691 temp_ptr = (char **) realloc(srvparams->krbhostservers, 692 sizeof(char *) * (existing_entries + new_entries + 1)); 693 if (temp_ptr == NULL) { 694 retval = ENOMEM; 695 goto cleanup; 696 } 697 srvparams->krbhostservers = temp_ptr; 698 699 list_modify_str_array(&(srvparams->krbhostservers), 700 (const char**)list, LIST_MODE_ADD); 701 702 /* Clean up */ 703 free (list); 704 list = NULL; 705 } else 706 srvparams->krbhostservers = list; 707 708 out_mask |= LDAP_SERVICE_HOSTSERVER; 709 } 710 } else if (!strcmp(argv[i], "-realm")) { 711 if (++i > argc - 1) 712 goto err_usage; 713 714 if ((in_mask & LDAP_SERVICE_REALMREFERENCE) && (srvparams->krbrealmreferences)) { 715 if (!oldrealmrefs) { 716 /* Store the old realm list for removing rights */ 717 oldrealmrefs = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); 718 if (oldrealmrefs == NULL) { 719 retval = ENOMEM; 720 goto cleanup; 721 } 722 723 for (j = 0; srvparams->krbrealmreferences[j] != NULL; j++) { 724 oldrealmrefs[j] = strdup(srvparams->krbrealmreferences[j]); 725 if (oldrealmrefs[j] == NULL) { 726 retval = ENOMEM; 727 goto cleanup; 728 } 729 } 730 oldrealmrefs[j] = NULL; 731 } 732 733 /* Free the old list if available */ 734 krb5_free_list_entries (srvparams->krbrealmreferences); 735 free (srvparams->krbrealmreferences); 736 } 737 738 srvparams->krbrealmreferences = (char **)calloc(MAX_LIST_ENTRIES, 739 sizeof(char *)); 740 if (srvparams->krbrealmreferences == NULL) { 741 retval = ENOMEM; 742 goto cleanup; 743 } 744 745 if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, 746 srvparams->krbrealmreferences))) { 747 goto cleanup; 748 } 749 750 /* Convert realm names to realm DNs */ 751 if ((retval = convert_realm_name2dn_list( 752 srvparams->krbrealmreferences, 753 ldap_context->krbcontainer->DN))) { 754 goto cleanup; 755 } 756 757 out_mask |= LDAP_SERVICE_REALMREFERENCE; 758 759 /* Set flag to ignore 'add' and 'clear' */ 760 realmdn_flag = 1; 761 } else if (!strcmp(argv[i], "-clearrealm")) { 762 if (++i > argc - 1) 763 goto err_usage; 764 765 if (!realmdn_flag) { 766 /* If attribute doesn't exist, don't permit 'clear' option */ 767 if (((in_mask & LDAP_SERVICE_REALMREFERENCE) == 0) || (srvparams->krbrealmreferences == NULL)) { 768 /* Send out some proper error message here */ 769 goto err_nomsg; 770 } 771 772 if (!oldrealmrefs) { 773 /* Store the old realm list for removing rights */ 774 oldrealmrefs = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); 775 if (oldrealmrefs == NULL) { 776 retval = ENOMEM; 777 goto cleanup; 778 } 779 780 for (j = 0; srvparams->krbrealmreferences[j] != NULL; j++) { 781 oldrealmrefs[j] = strdup(srvparams->krbrealmreferences[j]); 782 if (oldrealmrefs[j] == NULL) { 783 retval = ENOMEM; 784 goto cleanup; 785 } 786 } 787 oldrealmrefs[j] = NULL; 788 } 789 790 /* Allocate list for processing */ 791 list = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); 792 if (list == NULL) { 793 retval = ENOMEM; 794 goto cleanup; 795 } 796 797 if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) 798 goto cleanup; 799 800 /* Convert realm names to realm DNs */ 801 if ((retval = convert_realm_name2dn_list(list, 802 ldap_context->krbcontainer->DN))) { 803 goto cleanup; 804 } 805 806 list_modify_str_array(&(srvparams->krbrealmreferences), 807 (const char**)list, LIST_MODE_DELETE); 808 809 out_mask |= LDAP_SERVICE_REALMREFERENCE; 810 811 /* Clean up */ 812 free (list); 813 list = NULL; 814 } 815 } else if (!strcmp(argv[i], "-addrealm")) { 816 if (++i > argc - 1) 817 goto err_usage; 818 819 if (!realmdn_flag) { 820 /* Allocate list for processing */ 821 list = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); 822 if (list == NULL) { 823 retval = ENOMEM; 824 goto cleanup; 825 } 826 827 if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) 828 goto cleanup; 829 830 /* Convert realm names to realm DNs */ 831 if ((retval = convert_realm_name2dn_list(list, 832 ldap_context->krbcontainer->DN))) { 833 goto cleanup; 834 } 835 836 if ((in_mask & LDAP_SERVICE_REALMREFERENCE) && (srvparams->krbrealmreferences) && (!oldrealmrefs)) { 837 /* Store the old realm list for removing rights */ 838 oldrealmrefs = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); 839 if (oldrealmrefs == NULL) { 840 retval = ENOMEM; 841 goto cleanup; 842 } 843 844 for (j = 0; srvparams->krbrealmreferences[j] != NULL; j++) { 845 oldrealmrefs[j] = strdup(srvparams->krbrealmreferences[j]); 846 if (oldrealmrefs[j] == NULL) { 847 retval = ENOMEM; 848 goto cleanup; 849 } 850 } 851 oldrealmrefs[j] = NULL; 852 } 853 854 /* Call list_modify_str_array() only if realm DN attribute 855 * exists already -- Actually, it's better to handle this 856 * within list_modify_str_array() */ 857 if (in_mask & LDAP_SERVICE_REALMREFERENCE) { 858 /* Re-size existing list */ 859 existing_entries = list_count_str_array( 860 srvparams->krbrealmreferences); 861 new_entries = list_count_str_array(list); 862 temp_ptr = (char **) realloc(srvparams->krbrealmreferences, 863 sizeof(char *) * (existing_entries + new_entries + 1)); 864 if (temp_ptr == NULL) { 865 retval = ENOMEM; 866 goto cleanup; 867 } 868 srvparams->krbrealmreferences = temp_ptr; 869 870 list_modify_str_array(&(srvparams->krbrealmreferences), 871 (const char**)list, LIST_MODE_ADD); 872 873 /* Clean up */ 874 free (list); 875 list = NULL; 876 } else 877 srvparams->krbrealmreferences = list; 878 879 out_mask |= LDAP_SERVICE_REALMREFERENCE; 880 } 881 } else { 882 /* Any other argument must be service DN 883 -- skip it */ 884 } 885 } 886 887 /* Modify attributes of object */ 888 if ((retval = krb5_ldap_modify_service(util_context, srvparams, out_mask))) 889 goto cleanup; 890 891 /* Service rights modification code */ 892 if (out_mask & LDAP_SERVICE_REALMREFERENCE) { 893 894 printf("%s", gettext("Changing rights for the service object. Please wait ... ")); 895 fflush(stdout); 896 897 newrealmrefs = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); 898 if (newrealmrefs == NULL) { 899 retval = ENOMEM; 900 goto cleanup; 901 } 902 903 if ((srvparams != NULL) && (srvparams->krbrealmreferences != NULL)) { 904 for (j = 0; srvparams->krbrealmreferences[j] != NULL; j++) { 905 newrealmrefs[j] = strdup(srvparams->krbrealmreferences[j]); 906 if (newrealmrefs[j] == NULL) { 907 retval = ENOMEM; 908 goto cleanup; 909 } 910 } 911 newrealmrefs[j] = NULL; 912 } 913 disjoint_members(oldrealmrefs, newrealmrefs); 914 915 /* Delete the rights for the given service, on each of the realm 916 * container & subtree in the old realm reference list. 917 */ 918 if (oldrealmrefs) { 919 rightsmask = 0; 920 rightsmask |= LDAP_REALM_RIGHTS; 921 rightsmask |= LDAP_SUBTREE_RIGHTS; 922 923 for (i = 0; (oldrealmrefs[i] != NULL); i++) { 924 /* Get the realm name, not the dn */ 925 temprdns = ldap_explode_dn(oldrealmrefs[i], 1); 926 927 if (temprdns[0] == NULL) { 928 retval = EINVAL; 929 goto cleanup; 930 } 931 932 realmName = strdup(temprdns[0]); 933 if (realmName == NULL) { 934 retval = ENOMEM; 935 goto cleanup; 936 } 937 938 if ((retval = krb5_ldap_read_realm_params(util_context, 939 realmName, &rparams, &rmask))) { 940 com_err(me, retval, gettext("while reading information of realm '%s'"), 941 realmName); 942 goto err_nomsg; 943 } 944 945 if ((retval = krb5_ldap_delete_service_rights(util_context, 946 srvparams->servicetype, srvparams->servicedn, 947 realmName, rparams->subtree, rightsmask))) { 948 printf(gettext("failed\n")); 949 com_err(me, retval, gettext("while assigning rights '%s'"), 950 srvparams->servicedn); 951 goto err_nomsg; 952 } 953 954 if (rparams) 955 krb5_ldap_free_realm_params(rparams); 956 } 957 } 958 959 /* Add the rights for the given service, on each of the realm 960 * container & subtree in the new realm reference list. 961 */ 962 if (newrealmrefs) { 963 rightsmask = 0; 964 rightsmask |= LDAP_REALM_RIGHTS; 965 rightsmask |= LDAP_SUBTREE_RIGHTS; 966 967 for (i = 0; (newrealmrefs[i] != NULL); i++) { 968 /* Get the realm name, not the dn */ 969 temprdns = ldap_explode_dn(newrealmrefs[i], 1); 970 971 if (temprdns[0] == NULL) { 972 retval = EINVAL; 973 goto cleanup; 974 } 975 976 realmName = strdup(temprdns[0]); 977 if (realmName == NULL) { 978 retval = ENOMEM; 979 goto cleanup; 980 } 981 982 if ((retval = krb5_ldap_read_krbcontainer_params(util_context, 983 &(ldap_context->krbcontainer)))) { 984 com_err(me, retval, 985 gettext("while reading Kerberos container information")); 986 goto cleanup; 987 } 988 989 if ((retval = krb5_ldap_read_realm_params(util_context, 990 realmName, &rparams, &rmask))) { 991 com_err(me, retval, gettext("while reading information of realm '%s'"), 992 realmName); 993 goto err_nomsg; 994 } 995 996 if ((retval = krb5_ldap_add_service_rights(util_context, 997 srvparams->servicetype, srvparams->servicedn, 998 realmName, rparams->subtree, rightsmask))) { 999 printf(gettext("failed\n")); 1000 com_err(me, retval, gettext("while assigning rights '%s'"), 1001 srvparams->servicedn); 1002 goto err_nomsg; 1003 } 1004 1005 if (rparams) { 1006 krb5_ldap_free_realm_params(rparams); 1007 rparams = NULL; 1008 } 1009 } 1010 printf(gettext("done\n")); 1011 } 1012 } 1013 goto cleanup; 1014 1015 err_usage: 1016 print_usage = TRUE; 1017 1018 err_nomsg: 1019 no_msg = TRUE; 1020 1021 cleanup: 1022 /* Clean-up structure */ 1023 krb5_ldap_free_service(util_context, srvparams); 1024 1025 if (servicedn) 1026 free(servicedn); 1027 1028 if (list) { 1029 free(list); 1030 list = NULL; 1031 } 1032 1033 if (oldrealmrefs) { 1034 for (i = 0; oldrealmrefs[i] != NULL; i++) 1035 free(oldrealmrefs[i]); 1036 free(oldrealmrefs); 1037 } 1038 1039 if (newrealmrefs) { 1040 for (i = 0; newrealmrefs[i] != NULL; i++) 1041 free(newrealmrefs[i]); 1042 free(newrealmrefs); 1043 } 1044 if (realmName) { 1045 free(realmName); 1046 realmName = NULL; 1047 } 1048 1049 if (print_usage) 1050 db_usage(MODIFY_SERVICE); 1051 1052 if (retval) { 1053 if (!no_msg) 1054 com_err(me, retval, gettext("while modifying service object")); 1055 exit_status++; 1056 } 1057 1058 return; 1059 } 1060 1061 1062 /* 1063 * This function will delete the entry corresponding to the service object 1064 * from the service password file. 1065 */ 1066 static krb5_error_code 1067 rem_service_entry_from_file(argc, argv, file_name, service_object) 1068 int argc; 1069 char *argv[]; 1070 char *file_name; 1071 char *service_object; 1072 { 1073 int st = EINVAL; 1074 /* Solaris Kerberos */ 1075 char *me = progname; 1076 char *tmp_file = NULL; 1077 int tmpfd = -1; 1078 FILE *pfile = NULL; 1079 unsigned int len = 0; 1080 char line[MAX_LEN]={0}; 1081 mode_t omask = umask(077); 1082 1083 /* Check for permissions on the password file */ 1084 if (access(file_name, W_OK) == -1) { 1085 /* If the specified file itself is not there, no need to show error */ 1086 if (errno == ENOENT) { 1087 st=0; 1088 goto cleanup; 1089 } else { 1090 com_err(me, errno, gettext("while deleting entry from file %s", file_name)); 1091 goto cleanup; 1092 } 1093 } 1094 1095 /* Create a temporary file which contains all the entries except the 1096 entry for the given service dn */ 1097 pfile = fopen(file_name, "r+F"); 1098 if (pfile == NULL) { 1099 com_err(me, errno, gettext("while deleting entry from file %s"), file_name); 1100 goto cleanup; 1101 } 1102 1103 /* Create a new file with the extension .tmp */ 1104 tmp_file = (char *)malloc(strlen(file_name) + 4 + 1); 1105 if (tmp_file == NULL) { 1106 com_err(me, ENOMEM, gettext("while deleting entry from file")); 1107 fclose(pfile); 1108 goto cleanup; 1109 } 1110 snprintf (tmp_file, strlen(file_name) + 4 + 1, "%s%s", file_name, ".tmp"); 1111 1112 1113 tmpfd = creat(tmp_file, S_IRUSR|S_IWUSR); 1114 umask(omask); 1115 if (tmpfd == -1) { 1116 com_err(me, errno, gettext("while deleting entry from file\n")); 1117 fclose(pfile); 1118 goto cleanup; 1119 } 1120 1121 /* Copy only those lines which donot have the specified service dn */ 1122 while (fgets(line, MAX_LEN, pfile) != NULL) { 1123 if ((strstr(line, service_object) != NULL) && 1124 (line[strlen(service_object)] == '#')) { 1125 continue; 1126 } else { 1127 len = strlen(line); 1128 if (write(tmpfd, line, len) != len) { 1129 com_err(me, errno, gettext("while deleting entry from file\n")); 1130 close(tmpfd); 1131 unlink(tmp_file); 1132 fclose(pfile); 1133 goto cleanup; 1134 } 1135 } 1136 } 1137 1138 fclose(pfile); 1139 if (unlink(file_name) == 0) { 1140 link(tmp_file, file_name); 1141 } else { 1142 com_err(me, errno, gettext("while deleting entry from file\n")); 1143 } 1144 unlink(tmp_file); 1145 1146 st=0; 1147 1148 cleanup: 1149 1150 if (tmp_file) 1151 free(tmp_file); 1152 1153 return st; 1154 } 1155 1156 1157 /* 1158 * This function will delete the service object from the LDAP Server 1159 * and unlink the references to the Realm objects (if any) 1160 */ 1161 void 1162 kdb5_ldap_destroy_service(argc, argv) 1163 int argc; 1164 char *argv[]; 1165 { 1166 int i = 0; 1167 char buf[5] = {0}; 1168 krb5_error_code retval = EINVAL; 1169 int force = 0; 1170 char *servicedn = NULL; 1171 char *stashfilename = NULL; 1172 int mask = 0; 1173 krb5_ldap_service_params *lserparams = NULL; 1174 krb5_boolean print_usage = FALSE; 1175 1176 if ((argc < 2) || (argc > 5)) { 1177 exit_status++; 1178 goto err_usage; 1179 } 1180 1181 for (i=1; i < argc; i++) { 1182 1183 if (strcmp(argv[i],"-force")==0) { 1184 force++; 1185 } else if (strcmp(argv[i],"-f")==0) { 1186 if (argv[i+1]) { 1187 stashfilename=strdup(argv[i+1]); 1188 if (stashfilename == NULL) { 1189 /* Solaris Kerberos */ 1190 com_err(progname, ENOMEM, gettext("while destroying service")); 1191 exit_status++; 1192 goto cleanup; 1193 } 1194 i++; 1195 } else { 1196 exit_status++; 1197 goto err_usage; 1198 } 1199 } else { 1200 if ((argv[i]) && (servicedn == NULL)) { 1201 servicedn=strdup(argv[i]); 1202 if (servicedn == NULL) { 1203 /* Solaris Kerberos */ 1204 com_err(progname, ENOMEM, gettext("while destroying service")); 1205 exit_status++; 1206 goto cleanup; 1207 } 1208 } else { 1209 exit_status++; 1210 goto err_usage; 1211 } 1212 } 1213 } 1214 1215 if (!servicedn) { 1216 exit_status++; 1217 goto err_usage; 1218 } 1219 1220 if (!force) { 1221 printf(gettext("This will delete the service object '%s', are you sure?\n"), servicedn); 1222 printf(gettext("(type 'yes' to confirm)? ")); 1223 if (fgets(buf, sizeof(buf), stdin) == NULL) { 1224 exit_status++; 1225 goto cleanup;; 1226 } 1227 if (strcmp(buf, yes)) { 1228 exit_status++; 1229 goto cleanup; 1230 } 1231 } 1232 1233 if ((retval = krb5_ldap_read_service(util_context, servicedn, 1234 &lserparams, &mask))) { 1235 /* Solaris Kerberos */ 1236 com_err(progname, retval, gettext("while destroying service '%s'"), servicedn); 1237 exit_status++; 1238 goto cleanup; 1239 } 1240 1241 retval = krb5_ldap_delete_service(util_context, lserparams, servicedn); 1242 1243 if (retval) { 1244 /* Solaris Kerberos */ 1245 com_err(progname, retval, gettext("while destroying service '%s'"), servicedn); 1246 exit_status++; 1247 goto cleanup; 1248 } 1249 1250 if (stashfilename == NULL) { 1251 stashfilename = strdup(DEF_SERVICE_PASSWD_FILE); 1252 if (stashfilename == NULL) { 1253 /* Solaris Kerberos */ 1254 com_err(progname, ENOMEM, gettext("while destroying service")); 1255 exit_status++; 1256 goto cleanup; 1257 } 1258 } 1259 printf(gettext("** service object '%s' deleted.\n"), servicedn); 1260 retval = rem_service_entry_from_file(argc, argv, stashfilename, servicedn); 1261 1262 if (retval) 1263 printf(gettext("** error removing service object entry '%s' from password file.\n"), 1264 servicedn); 1265 1266 goto cleanup; 1267 1268 1269 err_usage: 1270 print_usage = TRUE; 1271 1272 cleanup: 1273 1274 if (lserparams) { 1275 krb5_ldap_free_service(util_context, lserparams); 1276 } 1277 1278 if (servicedn) { 1279 free(servicedn); 1280 } 1281 1282 if (stashfilename) { 1283 free(stashfilename); 1284 } 1285 1286 if (print_usage) { 1287 db_usage(DESTROY_SERVICE); 1288 } 1289 1290 return; 1291 } 1292 1293 1294 /* 1295 * This function will display information about the given service object 1296 */ 1297 void kdb5_ldap_view_service(argc, argv) 1298 int argc; 1299 char *argv[]; 1300 { 1301 krb5_ldap_service_params *lserparams = NULL; 1302 krb5_error_code retval = 0; 1303 char *servicedn = NULL; 1304 int mask = 0; 1305 krb5_boolean print_usage = FALSE; 1306 1307 if (!(argc == 2)) { 1308 exit_status++; 1309 goto err_usage; 1310 } 1311 1312 servicedn=strdup(argv[1]); 1313 if (servicedn == NULL) { 1314 /* Solaris Kerberos */ 1315 com_err(progname, ENOMEM, gettext("while viewing service")); 1316 exit_status++; 1317 goto cleanup; 1318 } 1319 1320 if ((retval = krb5_ldap_read_service(util_context, servicedn, &lserparams, &mask))) { 1321 /* Solaris Kerberos */ 1322 com_err(progname, retval, gettext("while viewing service '%s'"), servicedn); 1323 exit_status++; 1324 goto cleanup; 1325 } 1326 1327 print_service_params(lserparams, mask); 1328 1329 goto cleanup; 1330 1331 err_usage: 1332 print_usage = TRUE; 1333 1334 cleanup: 1335 1336 if (lserparams) { 1337 krb5_ldap_free_service(util_context, lserparams); 1338 } 1339 1340 if (servicedn) 1341 free(servicedn); 1342 1343 if (print_usage) { 1344 db_usage(VIEW_SERVICE); 1345 } 1346 1347 return; 1348 } 1349 1350 1351 /* 1352 * This function will list the DNs of kerberos services present on 1353 * the LDAP Server under a specific sub-tree (entire tree by default) 1354 */ 1355 void kdb5_ldap_list_services(argc, argv) 1356 int argc; 1357 char *argv[]; 1358 { 1359 /* Solaris Kerberos */ 1360 char *me = progname; 1361 krb5_error_code retval = 0; 1362 char *basedn = NULL; 1363 char **list = NULL; 1364 char **plist = NULL; 1365 krb5_boolean print_usage = FALSE; 1366 1367 /* Check for number of arguments */ 1368 if ((argc != 1) && (argc != 3)) { 1369 exit_status++; 1370 goto err_usage; 1371 } 1372 1373 /* Parse base DN argument if present */ 1374 if (argc == 3) { 1375 if (strcmp(argv[1], "-basedn")) { 1376 retval = EINVAL; 1377 goto err_usage; 1378 } 1379 1380 basedn = strdup(argv[2]); 1381 if (basedn == NULL) { 1382 com_err(me, ENOMEM, gettext("while listing services")); 1383 exit_status++; 1384 goto cleanup; 1385 } 1386 } 1387 1388 retval = krb5_ldap_list_services(util_context, basedn, &list); 1389 if ((retval != 0) || (list == NULL)) { 1390 exit_status++; 1391 goto cleanup; 1392 } 1393 1394 for (plist = list; *plist != NULL; plist++) { 1395 printf("%s\n", *plist); 1396 } 1397 1398 goto cleanup; 1399 1400 err_usage: 1401 print_usage = TRUE; 1402 1403 cleanup: 1404 if (list != NULL) { 1405 krb5_free_list_entries (list); 1406 free (list); 1407 } 1408 1409 if (basedn) 1410 free (basedn); 1411 1412 if (print_usage) { 1413 db_usage(LIST_SERVICE); 1414 } 1415 1416 if (retval) { 1417 com_err(me, retval, gettext("while listing policy objects")); 1418 exit_status++; 1419 } 1420 1421 return; 1422 } 1423 1424 1425 /* 1426 * This function will print the service object information 1427 * to the standard output 1428 */ 1429 static void 1430 print_service_params(lserparams, mask) 1431 krb5_ldap_service_params *lserparams; 1432 int mask; 1433 { 1434 int i=0; 1435 1436 /* Print the service dn */ 1437 printf("%20s%-20s\n", gettext("Service dn: "), lserparams->servicedn); 1438 1439 /* Print the service type of the object to be read */ 1440 if (lserparams->servicetype == LDAP_KDC_SERVICE) { 1441 printf("%20s%-20s\n", gettext("Service type: "), "kdc"); 1442 } else if (lserparams->servicetype == LDAP_ADMIN_SERVICE) { 1443 printf("%20s%-20s\n", gettext("Service type: "), "admin"); 1444 } else if (lserparams->servicetype == LDAP_PASSWD_SERVICE) { 1445 printf("%20s%-20s\n", gettext("Service type: "), "pwd"); 1446 } 1447 1448 /* Print the host server values */ 1449 printf("%20s\n", gettext("Service host list: ")); 1450 if (mask & LDAP_SERVICE_HOSTSERVER) { 1451 for (i=0; lserparams->krbhostservers[i] != NULL; ++i) { 1452 printf("%20s%-50s\n","",lserparams->krbhostservers[i]); 1453 } 1454 } 1455 1456 /* Print the realm reference dn values */ 1457 printf("%20s\n", gettext("Realm DN list: ")); 1458 if (mask & LDAP_SERVICE_REALMREFERENCE) { 1459 for (i=0; lserparams && lserparams->krbrealmreferences && lserparams->krbrealmreferences[i] != NULL; ++i) { 1460 printf("%20s%-50s\n","",lserparams->krbrealmreferences[i]); 1461 } 1462 } 1463 1464 return; 1465 } 1466 1467 1468 /* 1469 * This function will generate random password of length(RANDOM_PASSWD_LEN) 1470 * 1471 * 1472 * INPUT: 1473 * ctxt - context 1474 * 1475 * OUTPUT: 1476 * RANDOM_PASSWD_LEN length random password 1477 */ 1478 static int generate_random_password(krb5_context ctxt, char **randpwd, unsigned int *passlen) 1479 { 1480 char *random_pwd = NULL; 1481 int ret = 0; 1482 krb5_data data; 1483 int i=0; 1484 /*int len = 0;*/ 1485 1486 /* setting random password length in the range 16-32 */ 1487 srand((unsigned int)(time(0) ^ getpid())); 1488 1489 data.length = RANDOM_PASSWD_LEN; 1490 random_pwd = (char *)malloc(data.length + 1); 1491 if (random_pwd == NULL) { 1492 com_err("setsrvpw", ENOMEM, gettext("while generating random password")); 1493 return ENOMEM; 1494 } 1495 memset(random_pwd, 0, data.length + 1); 1496 data.data = random_pwd; 1497 1498 ret = krb5_c_random_make_octets(ctxt, &data); 1499 if (ret) { 1500 com_err("setsrvpw", ret, gettext("Error generating random password")); 1501 free(random_pwd); 1502 return ret; 1503 } 1504 1505 for (i=0; i<data.length; i++) { 1506 /* restricting to ascii chars. Need to change this when 8.8 supports */ 1507 if ((unsigned char)random_pwd[i] > 127) { 1508 random_pwd[i] = (unsigned char)random_pwd[i] % 128; 1509 } else if (random_pwd[i] == 0) { 1510 random_pwd[i] = (rand()/(RAND_MAX/127 + 1))+1; 1511 } 1512 } 1513 1514 *randpwd = random_pwd; 1515 *passlen = data.length; 1516 1517 return 0; 1518 } 1519 1520 1521 /* 1522 * This function will set the password of the service object in the directory 1523 * and/or the specified service password file. 1524 * 1525 * 1526 * INPUT: 1527 * argc - contains the number of arguments for this sub-command 1528 * argv - array of arguments for this sub-command 1529 * 1530 * OUTPUT: 1531 * void 1532 */ 1533 int 1534 kdb5_ldap_set_service_password(argc, argv) 1535 int argc; 1536 char **argv; 1537 { 1538 krb5_ldap_context *lparams = NULL; 1539 char *file_name = NULL; 1540 char *tmp_file = NULL; 1541 /* Solaris Kerberos */ 1542 char *me = progname; 1543 int filelen = 0; 1544 int random_passwd = 0; 1545 int set_dir_pwd = 1; 1546 krb5_boolean db_init_local = FALSE; 1547 char *service_object = NULL; 1548 char *passwd = NULL; 1549 char *prompt1 = NULL; 1550 char *prompt2 = NULL; 1551 unsigned int passwd_len = 0; 1552 krb5_error_code errcode = -1; 1553 int retval = 0, i = 0; 1554 unsigned int len = 0; 1555 krb5_boolean print_usage = FALSE; 1556 FILE *pfile = NULL; 1557 char *str = NULL; 1558 char line[MAX_LEN]; 1559 kdb5_dal_handle *dal_handle = NULL; 1560 struct data encrypted_passwd = {0, NULL}; 1561 1562 /* The arguments for setsrv password should contain the service object DN 1563 * and options to specify whether the password should be updated in file only 1564 * or both file and directory. So the possible combination of arguments are: 1565 * setsrvpw servicedn wherein argc is 2 1566 * setsrvpw -fileonly servicedn wherein argc is 3 1567 * setsrvpw -randpw servicedn wherein argc is 3 1568 * setsrvpw -f filename servicedn wherein argc is 4 1569 * setsrvpw -fileonly -f filename servicedn wherein argc is 5 1570 * setsrvpw -randpw -f filename servicedn wherein argc is 5 1571 */ 1572 if ((argc < 2) || (argc > 5)) { 1573 print_usage = TRUE; 1574 goto cleanup; 1575 } 1576 1577 dal_handle = (kdb5_dal_handle *)util_context->db_context; 1578 lparams = (krb5_ldap_context *) dal_handle->db_context; 1579 1580 if (lparams == NULL) { 1581 printf(gettext("%s: Invalid LDAP handle\n"), me); 1582 goto cleanup; 1583 } 1584 1585 /* Parse the arguments */ 1586 for (i = 1; i < argc -1 ; i++) { 1587 if (strcmp(argv[i], "-randpw") == 0) { 1588 random_passwd = 1; 1589 } else if (strcmp(argv[i], "-fileonly") == 0) { 1590 set_dir_pwd = 0; 1591 } else if (strcmp(argv[i], "-f") == 0) { 1592 if (argv[++i] == NULL) { 1593 print_usage = TRUE; 1594 goto cleanup; 1595 } 1596 1597 file_name = strdup(argv[i]); 1598 if (file_name == NULL) { 1599 com_err(me, ENOMEM, gettext("while setting service object password")); 1600 goto cleanup; 1601 } 1602 /* Verify if the file location has the proper file name 1603 * for eg, if the file location is a directory like /home/temp/, 1604 * we reject it. 1605 */ 1606 filelen = strlen(file_name); 1607 if ((filelen == 0) || (file_name[filelen-1] == '/')) { 1608 printf(gettext("%s: Filename not specified for setting service object password\n"), me); 1609 print_usage = TRUE; 1610 goto cleanup; 1611 } 1612 } else { 1613 printf(gettext("%s: Invalid option specified for \"setsrvpw\" command\n"), me); 1614 print_usage = TRUE; 1615 goto cleanup; 1616 } 1617 } 1618 1619 if (i != argc-1) { 1620 print_usage = TRUE; 1621 goto cleanup; 1622 } 1623 1624 service_object = strdup(argv[i]); 1625 if (service_object == NULL) { 1626 com_err(me, ENOMEM, gettext("while setting service object password")); 1627 goto cleanup; 1628 } 1629 1630 if (strlen(service_object) == 0) { 1631 printf(gettext("%s: Service object not specified for \"setsrvpw\" command\n"), me); 1632 print_usage = TRUE; 1633 goto cleanup; 1634 } 1635 1636 if (service_object[0] == '-') { 1637 print_usage = TRUE; 1638 goto cleanup; 1639 } 1640 1641 if (file_name == NULL) { 1642 file_name = strdup(DEF_SERVICE_PASSWD_FILE); 1643 if (file_name == NULL) { 1644 com_err(me, ENOMEM, gettext("while setting service object password")); 1645 goto cleanup; 1646 } 1647 } 1648 1649 if (set_dir_pwd) { 1650 if (db_inited == FALSE) { 1651 if ((errcode = krb5_ldap_db_init(util_context, lparams))) { 1652 com_err(me, errcode, gettext("while initializing database")); 1653 goto cleanup; 1654 } 1655 db_init_local = TRUE; 1656 } 1657 } 1658 1659 if (random_passwd) { 1660 if (!set_dir_pwd) { 1661 printf(gettext("%s: Invalid option specified for \"setsrvpw\" command\n"), me); 1662 print_usage = TRUE; 1663 goto cleanup; 1664 } else { 1665 /* Generate random password */ 1666 1667 if ((errcode = generate_random_password(util_context, &passwd, &passwd_len))) { 1668 printf(gettext("%s: Failed to set service object password\n"), me); 1669 goto cleanup; 1670 } 1671 passwd_len = strlen(passwd); 1672 } 1673 } else { 1674 /* Get the service object password from the terminal */ 1675 passwd = (char *)malloc(MAX_SERVICE_PASSWD_LEN + 1); 1676 if (passwd == NULL) { 1677 com_err(me, ENOMEM, gettext("while setting service object password")); 1678 goto cleanup; 1679 } 1680 memset(passwd, 0, MAX_SERVICE_PASSWD_LEN + 1); 1681 passwd_len = MAX_SERVICE_PASSWD_LEN; 1682 1683 len = strlen(service_object); 1684 /* size of allocation=strlen of servicedn + strlen("Password for \" \"")=20 */ 1685 prompt1 = (char *)malloc(len + 20); 1686 if (prompt1 == NULL) { 1687 com_err(me, ENOMEM, gettext("while setting service object password")); 1688 goto cleanup; 1689 } 1690 sprintf(prompt1, gettext("Password for \"%s\""), service_object); 1691 1692 /* size of allocation=strlen of servicedn + strlen("Re-enter Password for \" \"")=30 */ 1693 prompt2 = (char *)malloc(len + 30); 1694 if (prompt2 == NULL) { 1695 com_err(me, ENOMEM, gettext("while setting service object password")); 1696 free(prompt1); 1697 goto cleanup; 1698 } 1699 sprintf(prompt2, gettext("Re-enter password for \"%s\""), service_object); 1700 1701 retval = krb5_read_password(util_context, prompt1, prompt2, passwd, &passwd_len); 1702 free(prompt1); 1703 free(prompt2); 1704 if (retval) { 1705 com_err(me, retval, gettext("while setting service object password")); 1706 memset(passwd, 0, MAX_SERVICE_PASSWD_LEN); 1707 goto cleanup; 1708 } 1709 if (passwd_len == 0) { 1710 printf(gettext("%s: Invalid password\n"), me); 1711 memset(passwd, 0, MAX_SERVICE_PASSWD_LEN); 1712 goto cleanup; 1713 } 1714 passwd_len = strlen(passwd); 1715 } 1716 1717 /* Hex the password */ 1718 { 1719 krb5_data pwd, hex; 1720 pwd.length = passwd_len; 1721 pwd.data = passwd; 1722 1723 errcode = tohex(pwd, &hex); 1724 if (errcode != 0) { 1725 if (hex.length != 0) { 1726 memset(hex.data, 0, hex.length); 1727 free(hex.data); 1728 } 1729 com_err(me, errcode, gettext("Failed to convert the password to hex")); 1730 memset(passwd, 0, passwd_len); 1731 goto cleanup; 1732 } 1733 /* Password = {CRYPT}<encrypted password>:<encrypted key> */ 1734 encrypted_passwd.value = (unsigned char *)malloc(strlen(service_object) + 1735 1 + 5 + hex.length + 2); 1736 if (encrypted_passwd.value == NULL) { 1737 com_err(me, ENOMEM, gettext("while setting service object password")); 1738 memset(passwd, 0, passwd_len); 1739 memset(hex.data, 0, hex.length); 1740 free(hex.data); 1741 goto cleanup; 1742 } 1743 encrypted_passwd.value[strlen(service_object) + 1744 1 + 5 + hex.length + 1] = '\0'; 1745 sprintf((char *)encrypted_passwd.value, "%s#{HEX}%s\n", service_object, hex.data); 1746 encrypted_passwd.len = strlen((char *)encrypted_passwd.value); 1747 memset(hex.data, 0, hex.length); 1748 free(hex.data); 1749 } 1750 1751 /* We should check if the file exists and we have permission to write into that file */ 1752 if (access(file_name, W_OK) == -1) { 1753 if (errno == ENOENT) { 1754 mode_t omask; 1755 int fd = -1; 1756 1757 printf(gettext("File does not exist. Creating the file %s...\n"), file_name); 1758 omask = umask(077); 1759 fd = creat(file_name, S_IRUSR|S_IWUSR); 1760 umask(omask); 1761 if (fd == -1) { 1762 com_err(me, errno, gettext("Error creating file %s"), file_name); 1763 memset(passwd, 0, passwd_len); 1764 goto cleanup; 1765 } 1766 close(fd); 1767 } else { 1768 com_err(me, errno, gettext("Unable to access the file %s"), file_name); 1769 memset(passwd, 0, passwd_len); 1770 goto cleanup; 1771 } 1772 } 1773 1774 if (set_dir_pwd) { 1775 if ((errcode = krb5_ldap_set_service_passwd(util_context, service_object, passwd)) != 0) { 1776 com_err(me, errcode, gettext("Failed to set password for service object %s"), service_object); 1777 memset(passwd, 0, passwd_len); 1778 goto cleanup; 1779 } 1780 } 1781 1782 memset(passwd, 0, passwd_len); 1783 1784 1785 /* TODO: file lock for the service password file */ 1786 /* set password in the file */ 1787 pfile = fopen(file_name, "r+F"); 1788 if (pfile == NULL) { 1789 com_err(me, errno, gettext("Failed to open file %s"), file_name); 1790 goto cleanup; 1791 } 1792 1793 while (fgets(line, MAX_LEN, pfile) != NULL) { 1794 if ((str = strstr(line, service_object)) != NULL) { 1795 if (line[strlen(service_object)] == '#') { 1796 break; 1797 } 1798 str = NULL; 1799 } 1800 } 1801 if (str == NULL) { 1802 if (feof(pfile)) { 1803 /* If the service object dn is not present in the service password file */ 1804 if (fwrite(encrypted_passwd.value, (unsigned int)encrypted_passwd.len, 1, pfile) != 1) { 1805 com_err(me, errno, gettext("Failed to write service object password to file")); 1806 goto cleanup; 1807 } 1808 } else { 1809 com_err(me, errno, gettext("Error reading service object password file")); 1810 goto cleanup; 1811 } 1812 fclose(pfile); 1813 pfile = NULL; 1814 } else { 1815 /* Password entry for the service object is already present in the file */ 1816 /* Delete the existing entry and add the new entry */ 1817 FILE *newfile = NULL; 1818 mode_t omask; 1819 1820 /* Create a new file with the extension .tmp */ 1821 tmp_file = (char *) malloc(sizeof(char) * (strlen(file_name) + 4 + 1)); 1822 if (tmp_file == NULL) { 1823 com_err(me, ENOMEM, gettext("while setting service object password")); 1824 goto cleanup; 1825 } 1826 sprintf(tmp_file,"%s.%s",file_name,"tmp"); 1827 1828 omask = umask(077); 1829 newfile = fopen(tmp_file, "w+F"); 1830 umask(omask); 1831 if (newfile == NULL) { 1832 com_err(me, errno, gettext("Error creating file %s"), tmp_file); 1833 goto cleanup; 1834 } 1835 1836 1837 fseek(pfile, 0, SEEK_SET); 1838 while (fgets(line, MAX_LEN, pfile) != NULL) { 1839 if (((str = strstr(line, service_object)) != NULL) && (line[strlen(service_object)] == '#')) { 1840 if (fprintf(newfile, "%s", encrypted_passwd.value) < 0) { 1841 com_err(me, errno, gettext("Failed to write service object password to file")); 1842 fclose(newfile); 1843 unlink(tmp_file); 1844 goto cleanup; 1845 } 1846 } else { 1847 len = strlen(line); 1848 if (fprintf(newfile, "%s", line) < 0) { 1849 com_err(me, errno, gettext("Failed to write service object password to file")); 1850 fclose(newfile); 1851 unlink(tmp_file); 1852 goto cleanup; 1853 } 1854 } 1855 } 1856 1857 if (!feof(pfile)) { 1858 com_err(me, errno, gettext("Error reading service object password file")); 1859 fclose(newfile); 1860 unlink(tmp_file); 1861 goto cleanup; 1862 } 1863 1864 /* TODO: file lock for the service password file */ 1865 fclose(pfile); 1866 pfile = NULL; 1867 1868 fclose(newfile); 1869 newfile = NULL; 1870 1871 if (unlink(file_name) == 0) { 1872 link(tmp_file, file_name); 1873 } else { 1874 com_err(me, errno, gettext("Failed to write service object password to file")); 1875 unlink(tmp_file); 1876 goto cleanup; 1877 } 1878 unlink(tmp_file); 1879 } 1880 errcode = 0; 1881 1882 cleanup: 1883 if (db_init_local) 1884 krb5_ldap_close(util_context); 1885 1886 if (service_object) 1887 free(service_object); 1888 1889 if (file_name) 1890 free(file_name); 1891 1892 if (passwd) 1893 free(passwd); 1894 1895 if (encrypted_passwd.value) { 1896 memset(encrypted_passwd.value, 0, encrypted_passwd.len); 1897 free(encrypted_passwd.value); 1898 } 1899 1900 if (pfile) 1901 fclose(pfile); 1902 1903 if (tmp_file) 1904 free(tmp_file); 1905 1906 if (print_usage) 1907 db_usage(SET_SRV_PW); 1908 1909 return errcode; 1910 } 1911 1912 #else /* #ifdef HAVE_EDIRECTORY */ 1913 1914 /* 1915 * Convert the user supplied password into hexadecimal and stash it. Only a 1916 * little more secure than storing plain password in the file ... 1917 */ 1918 void 1919 kdb5_ldap_stash_service_password(argc, argv) 1920 int argc; 1921 char **argv; 1922 { 1923 int ret = 0; 1924 unsigned int passwd_len = 0; 1925 /* Solaris Kerberos */ 1926 char *me = progname; 1927 char *service_object = NULL; 1928 char *file_name = NULL, *tmp_file = NULL; 1929 char passwd[MAX_SERVICE_PASSWD_LEN]; 1930 char *str = NULL; 1931 char line[MAX_LEN]; 1932 int fd; 1933 FILE *pfile = NULL; 1934 krb5_boolean print_usage = FALSE; 1935 krb5_data hexpasswd = {0, 0, NULL}; 1936 mode_t old_mode = 0; 1937 1938 /* 1939 * Format: 1940 * stashsrvpw [-f filename] service_dn 1941 * where 1942 * 'service_dn' is the DN of the service object 1943 * 'filename' is the path of the stash file 1944 */ 1945 if (argc != 2 && argc != 4) { 1946 print_usage = TRUE; 1947 goto cleanup; 1948 } 1949 1950 if (argc == 4) { 1951 /* Find the stash file name */ 1952 if (strcmp (argv[1], "-f") == 0) { 1953 if (((file_name = strdup (argv[2])) == NULL) || 1954 ((service_object = strdup (argv[3])) == NULL)) { 1955 com_err(me, ENOMEM, gettext("while setting service object password")); 1956 goto cleanup; 1957 } 1958 } else if (strcmp (argv[2], "-f") == 0) { 1959 if (((file_name = strdup (argv[3])) == NULL) || 1960 ((service_object = strdup (argv[1])) == NULL)) { 1961 com_err(me, ENOMEM, gettext("while setting service object password")); 1962 goto cleanup; 1963 } 1964 } else { 1965 print_usage = TRUE; 1966 goto cleanup; 1967 } 1968 if (file_name == NULL) { 1969 com_err(me, ENOMEM, gettext("while setting service object password")); 1970 goto cleanup; 1971 } 1972 } else { /* argc == 2 */ 1973 char *section; 1974 1975 service_object = strdup (argv[1]); 1976 if (service_object == NULL) { 1977 com_err(me, ENOMEM, gettext("while setting service object password")); 1978 goto cleanup; 1979 } 1980 1981 /* Pick up the stash-file name from krb5.conf */ 1982 profile_get_string(util_context->profile, KDB_REALM_SECTION, 1983 util_context->default_realm, KDB_MODULE_POINTER, NULL, §ion); 1984 1985 if (section == NULL) { 1986 profile_get_string(util_context->profile, KDB_MODULE_DEF_SECTION, 1987 KDB_MODULE_POINTER, NULL, NULL, §ion); 1988 if (section == NULL) { 1989 /* Stash file path neither in krb5.conf nor on command line */ 1990 file_name = strdup(DEF_SERVICE_PASSWD_FILE); 1991 if (file_name == NULL) { 1992 com_err(me, ENOMEM, gettext("while setting service object password")); 1993 goto cleanup; 1994 } 1995 goto done; 1996 } 1997 } 1998 1999 profile_get_string (util_context->profile, KDB_MODULE_SECTION, section, 2000 "ldap_service_password_file", NULL, &file_name); 2001 2002 /* 2003 * Solaris Kerberos: use default if ldap_service_password_file not set 2004 */ 2005 if (file_name == NULL) { 2006 file_name = strdup(DEF_SERVICE_PASSWD_FILE); 2007 if (file_name == NULL) { 2008 com_err(me, ENOMEM, gettext("while setting service object password")); 2009 goto cleanup; 2010 } 2011 } 2012 } 2013 done: 2014 2015 /* Get password from user */ 2016 { 2017 char prompt1[256], prompt2[256]; 2018 2019 /* Get the service object password from the terminal */ 2020 memset(passwd, 0, sizeof (passwd)); 2021 passwd_len = sizeof (passwd); 2022 2023 /* size of prompt = strlen of servicedn + strlen("Password for \" \"") */ 2024 assert (sizeof (prompt1) > (strlen (service_object) 2025 + sizeof ("Password for \" \""))); 2026 sprintf(prompt1, gettext("Password for \"%s\""), service_object); 2027 2028 /* size of prompt = strlen of servicedn + strlen("Re-enter Password for \" \"") */ 2029 assert (sizeof (prompt2) > (strlen (service_object) 2030 + sizeof ("Re-enter Password for \" \""))); 2031 sprintf(prompt2, gettext("Re-enter password for \"%s\""), service_object); 2032 2033 ret = krb5_read_password(util_context, prompt1, prompt2, passwd, &passwd_len); 2034 if (ret != 0) { 2035 com_err(me, ret, gettext("while setting service object password")); 2036 memset(passwd, 0, sizeof (passwd)); 2037 goto cleanup; 2038 } 2039 2040 if (passwd_len == 0) { 2041 printf(gettext("%s: Invalid password\n"), me); 2042 memset(passwd, 0, MAX_SERVICE_PASSWD_LEN); 2043 goto cleanup; 2044 } 2045 } 2046 2047 /* Convert the password to hexadecimal */ 2048 { 2049 krb5_data pwd; 2050 2051 pwd.length = passwd_len; 2052 pwd.data = passwd; 2053 2054 ret = tohex(pwd, &hexpasswd); 2055 if (ret != 0) { 2056 com_err(me, ret, gettext("Failed to convert the password to hexadecimal")); 2057 memset(passwd, 0, passwd_len); 2058 goto cleanup; 2059 } 2060 } 2061 memset(passwd, 0, passwd_len); 2062 2063 /* TODO: file lock for the service passowrd file */ 2064 2065 /* set password in the file */ 2066 #if 0 /* ************ Begin IFDEF'ed OUT ***************************** */ 2067 old_mode = umask(0177); 2068 pfile = fopen(file_name, "a+"); 2069 if (pfile == NULL) { 2070 com_err(me, errno, gettext("Failed to open file %s: %s"), file_name, 2071 strerror (errno)); 2072 goto cleanup; 2073 } 2074 rewind (pfile); 2075 umask(old_mode); 2076 #else 2077 /* Solaris Kerberos: safer than the above */ 2078 fd = open(file_name, O_CREAT|O_RDWR|O_APPEND, 0600); 2079 if (fd < 0) { 2080 com_err(me, errno, gettext("Failed to open file %s: %s"), file_name, 2081 strerror (errno)); 2082 goto cleanup; 2083 } 2084 pfile = fdopen(fd, "a+F"); 2085 if (pfile == NULL) { 2086 com_err(me, errno, gettext("Failed to open file %s: %s"), file_name, 2087 strerror (errno)); 2088 goto cleanup; 2089 } 2090 rewind (pfile); 2091 #endif 2092 2093 while (fgets (line, MAX_LEN, pfile) != NULL) { 2094 if ((str = strstr (line, service_object)) != NULL) { 2095 /* 2096 * White spaces not allowed, # delimits the service dn from the 2097 * password 2098 */ 2099 if (line [strlen (service_object)] == '#') 2100 break; 2101 str = NULL; 2102 } 2103 } 2104 2105 if (str == NULL) { 2106 if (feof(pfile)) { 2107 /* If the service object dn is not present in the service password file */ 2108 if (fprintf(pfile, "%s#{HEX}%s\n", service_object, hexpasswd.data) < 0) { 2109 com_err(me, errno, gettext("Failed to write service object password to file")); 2110 fclose(pfile); 2111 goto cleanup; 2112 } 2113 } else { 2114 com_err(me, errno, gettext("Error reading service object password file")); 2115 fclose(pfile); 2116 goto cleanup; 2117 } 2118 fclose(pfile); 2119 } else { 2120 /* 2121 * Password entry for the service object is already present in the file 2122 * Delete the existing entry and add the new entry 2123 */ 2124 FILE *newfile; 2125 2126 mode_t omask; 2127 2128 /* Create a new file with the extension .tmp */ 2129 tmp_file = (char *) malloc(sizeof(char) * (strlen(file_name) + 4 + 1)); 2130 if (tmp_file == NULL) { 2131 com_err(me, ENOMEM, gettext("while setting service object password")); 2132 fclose(pfile); 2133 goto cleanup; 2134 } 2135 sprintf(tmp_file,"%s.%s",file_name,"tmp"); 2136 2137 omask = umask(077); 2138 newfile = fopen(tmp_file, "wF"); 2139 umask (omask); 2140 if (newfile == NULL) { 2141 com_err(me, errno, gettext("Error creating file %s"), tmp_file); 2142 fclose(pfile); 2143 goto cleanup; 2144 } 2145 2146 fseek(pfile, 0, SEEK_SET); 2147 while (fgets(line, MAX_LEN, pfile) != NULL) { 2148 if (((str = strstr(line, service_object)) != NULL) && 2149 (line[strlen(service_object)] == '#')) { 2150 if (fprintf(newfile, "%s#{HEX}%s\n", service_object, hexpasswd.data) < 0) { 2151 com_err(me, errno, gettext("Failed to write service object password to file")); 2152 fclose(newfile); 2153 unlink(tmp_file); 2154 fclose(pfile); 2155 goto cleanup; 2156 } 2157 } else { 2158 if (fprintf (newfile, "%s", line) < 0) { 2159 com_err(me, errno, gettext("Failed to write service object password to file")); 2160 fclose(newfile); 2161 unlink(tmp_file); 2162 fclose(pfile); 2163 goto cleanup; 2164 } 2165 } 2166 } 2167 2168 if (!feof(pfile)) { 2169 com_err(me, errno, gettext("Error reading service object password file")); 2170 fclose(newfile); 2171 unlink(tmp_file); 2172 fclose(pfile); 2173 goto cleanup; 2174 } 2175 2176 /* TODO: file lock for the service passowrd file */ 2177 2178 fclose(pfile); 2179 fclose(newfile); 2180 2181 ret = rename(tmp_file, file_name); 2182 if (ret != 0) { 2183 com_err(me, errno, gettext("Failed to write service object password to " 2184 "file")); 2185 goto cleanup; 2186 } 2187 } 2188 ret = 0; 2189 2190 cleanup: 2191 2192 if (hexpasswd.length != 0) { 2193 memset(hexpasswd.data, 0, hexpasswd.length); 2194 free(hexpasswd.data); 2195 } 2196 2197 if (service_object) 2198 free(service_object); 2199 2200 if (file_name) 2201 free(file_name); 2202 2203 if (tmp_file) 2204 free(tmp_file); 2205 2206 if (print_usage) 2207 usage(); 2208 /* db_usage(STASH_SRV_PW); */ 2209 2210 if (ret) 2211 exit_status++; 2212 } 2213 2214 #endif /* #ifdef HAVE_EDIRECTORY */ 2215