/* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * kadmin/ldap_util/kdb5_ldap_services.c */ /* Copyright (c) 2004-2005, Novell, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * The copyright holder's name is not used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Create / Delete / Modify / View / List service objects. */ /* * Service objects have rights over realm objects and principals. The following * functions manage the service objects. */ #include #include #include /* Solaris Kerberos */ #include /* Solaris Kerberos */ #include "kdb5_ldap_util.h" #include "kdb5_ldap_list.h" #ifdef HAVE_EDIRECTORY krb5_error_code rem_service_entry_from_file(int argc, char *argv[], char *file_name, char *service_object); extern char *yes; extern krb5_boolean db_inited; static int process_host_list(char **host_list, int servicetype) { krb5_error_code retval = 0; char *pchr = NULL; char host_str[MAX_LEN_LIST_ENTRY] = "", proto_str[PROTOCOL_STR_LEN + 1] = "", port_str[PORT_STR_LEN + 1] = ""; int j = 0; /* Protocol and port number processing */ for (j = 0; host_list[j]; j++) { /* Look for one hash */ if ((pchr = strchr(host_list[j], HOST_INFO_DELIMITER))) { unsigned int hostname_len = pchr - host_list[j]; /* Check input for buffer overflow */ if (hostname_len >= MAX_LEN_LIST_ENTRY) { retval = EINVAL; goto cleanup; } /* First copy off the host name portion */ strncpy (host_str, host_list[j], hostname_len); /* Parse for the protocol string and translate to number */ strncpy (proto_str, pchr + 1, PROTOCOL_STR_LEN); if (!strcmp(proto_str, "udp")) sprintf (proto_str, "%d", PROTOCOL_NUM_UDP); else if (!strcmp(proto_str, "tcp")) sprintf (proto_str, "%d", PROTOCOL_NUM_TCP); else proto_str[0] = '\0'; /* Make the string null if invalid */ /* Look for one more hash */ if ((pchr = strchr(pchr + 1, HOST_INFO_DELIMITER))) { /* Parse for the port string and check if it is numeric */ strncpy (port_str, pchr + 1, PORT_STR_LEN); if (!strtol(port_str, NULL, 10)) /* Not a valid number */ port_str[0] = '\0'; } else port_str[0] = '\0'; } else { /* We have only host name */ strncpy (host_str, host_list[j], MAX_LEN_LIST_ENTRY - 1); proto_str[0] = '\0'; port_str[0] = '\0'; } /* Now, based on service type, fill in suitable protocol and port values if they are absent or not matching */ if (servicetype == LDAP_KDC_SERVICE) { if (proto_str[0] == '\0') sprintf (proto_str, "%d", PROTOCOL_DEFAULT_KDC); if (port_str[0] == '\0') sprintf (port_str, "%d", PORT_DEFAULT_KDC); } else if (servicetype == LDAP_ADMIN_SERVICE) { if (proto_str[0] == '\0') sprintf (proto_str, "%d", PROTOCOL_DEFAULT_ADM); else if (strcmp(proto_str, "1")) { sprintf (proto_str, "%d", PROTOCOL_DEFAULT_ADM); /* Print warning message */ printf (gettext("Admin Server supports only TCP protocol, hence setting that\n")); } if (port_str[0] == '\0') sprintf (port_str, "%d", PORT_DEFAULT_ADM); } else if (servicetype == LDAP_PASSWD_SERVICE) { if (proto_str[0] == '\0') sprintf (proto_str, "%d", PROTOCOL_DEFAULT_PWD); else if (strcmp(proto_str, "0")) { sprintf (proto_str, "%d", PROTOCOL_DEFAULT_PWD); /* Print warning message */ printf (gettext("Password Server supports only UDP protocol, hence setting that\n")); } if (port_str[0] == '\0') sprintf (port_str, "%d", PORT_DEFAULT_PWD); } /* Finally form back the string */ free (host_list[j]); host_list[j] = (char*) malloc(sizeof(char) * (strlen(host_str) + strlen(proto_str) + strlen(port_str) + 2 + 1)); if (host_list[j] == NULL) { retval = ENOMEM; goto cleanup; } snprintf (host_list[j], strlen(host_str) + strlen(proto_str) + strlen(port_str) + 2 + 1, "%s#%s#%s", host_str, proto_str, port_str); } cleanup: return retval; } /* * Given a realm name, this function will convert it to a DN by appending the * Kerberos container location. */ static krb5_error_code convert_realm_name2dn_list(list, krbcontainer_loc) char **list; const char *krbcontainer_loc; { krb5_error_code retval = 0; char temp_str[MAX_DN_CHARS] = "\0"; char *temp_node = NULL; int i = 0; if (list == NULL) { return EINVAL; } for (i = 0; (list[i] != NULL) && (i < MAX_LIST_ENTRIES); i++) { /* Restrict copying to max. length to avoid buffer overflow */ snprintf (temp_str, MAX_DN_CHARS, "cn=%s,%s", list[i], krbcontainer_loc); /* Make copy of string to temporary node */ temp_node = strdup(temp_str); if (list[i] == NULL) { retval = ENOMEM; goto cleanup; } /* On success, free list node and attach new one */ free (list[i]); list[i] = temp_node; temp_node = NULL; } cleanup: return retval; } /* * This function will create a service object on the LDAP Server, with the * specified attributes. */ void kdb5_ldap_create_service(argc, argv) int argc; char *argv[]; { /* Solaris Kerberos */ char *me = progname; krb5_error_code retval = 0; krb5_ldap_service_params *srvparams = NULL; krb5_boolean print_usage = FALSE; krb5_boolean no_msg = FALSE; int mask = 0; char **extra_argv = NULL; int extra_argc = 0; int i = 0; krb5_ldap_realm_params *rparams = NULL; int rmask = 0; int rightsmask =0; char **temprdns = NULL; char *realmName = NULL; kdb5_dal_handle *dal_handle = NULL; krb5_ldap_context *ldap_context=NULL; krb5_boolean service_obj_created = FALSE; /* Check for number of arguments */ if ((argc < 3) || (argc > 10)) { exit_status++; goto err_usage; } /* Allocate memory for service parameters structure */ srvparams = (krb5_ldap_service_params*) calloc(1, sizeof(krb5_ldap_service_params)); if (srvparams == NULL) { retval = ENOMEM; goto cleanup; } dal_handle = (kdb5_dal_handle *) util_context->db_context; ldap_context = (krb5_ldap_context *) dal_handle->db_context; /* Allocate memory for extra arguments to be used for setting password -- it's OK to allocate as much as the total number of arguments */ extra_argv = (char **) calloc((unsigned int)argc, sizeof(char*)); if (extra_argv == NULL) { retval = ENOMEM; goto cleanup; } /* Set first of the extra arguments as the program name */ extra_argv[0] = me; extra_argc++; /* Read Kerberos container info, to construct realm DN from name * and for assigning rights */ if ((retval = krb5_ldap_read_krbcontainer_params(util_context, &(ldap_context->krbcontainer)))) { com_err(me, retval, gettext("while reading Kerberos container information")); goto cleanup; } /* Parse all arguments */ for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-kdc")) { srvparams->servicetype = LDAP_KDC_SERVICE; } else if (!strcmp(argv[i], "-admin")) { srvparams->servicetype = LDAP_ADMIN_SERVICE; } else if (!strcmp(argv[i], "-pwd")) { srvparams->servicetype = LDAP_PASSWD_SERVICE; } else if (!strcmp(argv[i], "-servicehost")) { if (++i > argc - 1) goto err_usage; srvparams->krbhostservers = (char **)calloc(MAX_LIST_ENTRIES, sizeof(char *)); if (srvparams->krbhostservers == NULL) { retval = ENOMEM; goto cleanup; } if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, srvparams->krbhostservers))) { goto cleanup; } if ((retval = process_host_list (srvparams->krbhostservers, srvparams->servicetype))) { goto cleanup; } mask |= LDAP_SERVICE_HOSTSERVER; } else if (!strcmp(argv[i], "-realm")) { if (++i > argc - 1) goto err_usage; srvparams->krbrealmreferences = (char **)calloc(MAX_LIST_ENTRIES, sizeof(char *)); if (srvparams->krbrealmreferences == NULL) { retval = ENOMEM; goto cleanup; } if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, srvparams->krbrealmreferences))) { goto cleanup; } /* Convert realm names to realm DNs */ if ((retval = convert_realm_name2dn_list( srvparams->krbrealmreferences, ldap_context->krbcontainer->DN))) { goto cleanup; } mask |= LDAP_SERVICE_REALMREFERENCE; } /* If argument is none of the above and beginning with '-', * it must be related to password -- collect it * to pass onto kdb5_ldap_set_service_password() */ else if (*(argv[i]) == '-') { /* Checking for options of setting the password for the * service (by using 'setsrvpw') is not modular. --need to * have a common function that can be shared with 'setsrvpw' */ if (!strcmp(argv[i], "-randpw")) { extra_argv[extra_argc] = argv[i]; extra_argc++; } else if (!strcmp(argv[i], "-fileonly")) { extra_argv[extra_argc] = argv[i]; extra_argc++; } /* For '-f' option alone, pick up the following argument too */ else if (!strcmp(argv[i], "-f")) { extra_argv[extra_argc] = argv[i]; extra_argc++; if (++i > argc - 1) goto err_usage; extra_argv[extra_argc] = argv[i]; extra_argc++; } else { /* Any other option is invalid */ exit_status++; goto err_usage; } } else { /* Any other argument must be service DN */ /* First check if service DN is already provided -- * if so, there's a usage error */ if (srvparams->servicedn != NULL) { com_err(me, EINVAL, gettext("while creating service object")); goto err_usage; } /* If not present already, fill up service DN */ srvparams->servicedn = strdup(argv[i]); if (srvparams->servicedn == NULL) { com_err(me, ENOMEM, gettext("while creating service object")); goto err_nomsg; } } } /* No point in proceeding further if service DN value is not available */ if (srvparams->servicedn == NULL) { com_err(me, EINVAL, gettext("while creating service object")); goto err_usage; } if (srvparams->servicetype == 0) { /* Not provided and hence not set */ com_err(me, EINVAL, gettext("while creating service object")); goto err_usage; } /* Create object with all attributes provided */ if ((retval = krb5_ldap_create_service(util_context, srvparams, mask))) goto cleanup; service_obj_created = TRUE; /* ** NOTE ** srvparams structure should not be modified, as it is * used for deletion of the service object in case of any failures * from now on. */ /* Set password too */ if (extra_argc >= 1) { /* Set service DN as the last argument */ extra_argv[extra_argc] = strdup(srvparams->servicedn); if (extra_argv[extra_argc] == NULL) { retval = ENOMEM; goto cleanup; } extra_argc++; if ((retval = kdb5_ldap_set_service_password(extra_argc, extra_argv)) != 0) { goto err_nomsg; } } /* Rights assignment */ if (mask & LDAP_SERVICE_REALMREFERENCE) { printf("%s", gettext("Changing rights for the service object. Please wait ... ")); fflush(stdout); rightsmask =0; rightsmask |= LDAP_REALM_RIGHTS; rightsmask |= LDAP_SUBTREE_RIGHTS; if ((srvparams != NULL) && (srvparams->krbrealmreferences != NULL)) { for (i=0; (srvparams->krbrealmreferences[i] != NULL); i++) { /* Get the realm name, not the dn */ temprdns = ldap_explode_dn(srvparams->krbrealmreferences[i], 1); if (temprdns[0] == NULL) { retval = EINVAL; goto cleanup; } realmName = strdup(temprdns[0]); if (realmName == NULL) { retval = ENOMEM; goto cleanup; } if ((retval = krb5_ldap_read_realm_params(util_context, realmName, &rparams, &rmask))) { com_err(me, retval, gettext("while reading information of realm '%s'"), realmName); goto cleanup; } if ((retval = krb5_ldap_add_service_rights(util_context, srvparams->servicetype, srvparams->servicedn, realmName, rparams->subtree, rightsmask))) { printf(gettext("failed\n")); com_err(me, retval, gettext("while assigning rights '%s'"), srvparams->servicedn); goto cleanup; } if (rparams) krb5_ldap_free_realm_params(rparams); } } printf(gettext("done\n")); } goto cleanup; err_usage: print_usage = TRUE; err_nomsg: no_msg = TRUE; cleanup: if ((retval != 0) && (service_obj_created == TRUE)) { /* This is for deleting the service object if something goes * wrong in creating the service object */ /* srvparams is populated from the user input and should be correct as * we were successful in creating a service object. Reusing the same */ krb5_ldap_delete_service(util_context, srvparams, srvparams->servicedn); } /* Clean-up structure */ krb5_ldap_free_service (util_context, srvparams); if (extra_argv) { free (extra_argv); extra_argv = NULL; } if (realmName) { free(realmName); realmName = NULL; } if (print_usage) db_usage (CREATE_SERVICE); if (retval) { if (!no_msg) com_err(me, retval, gettext("while creating service object")); exit_status++; } return; } /* * This function will modify the attributes of a given service * object on the LDAP Server */ void kdb5_ldap_modify_service(argc, argv) int argc; char *argv[]; { /* Solaris Kerberos */ char *me = progname; krb5_error_code retval = 0; krb5_ldap_service_params *srvparams = NULL; krb5_boolean print_usage = FALSE; krb5_boolean no_msg = FALSE; char *servicedn = NULL; int i = 0; int in_mask = 0, out_mask = 0; int srvhost_flag = 0, realmdn_flag = 0; char **list = NULL; int existing_entries = 0, new_entries = 0; char **temp_ptr = NULL; krb5_ldap_realm_params *rparams = NULL; int j = 0; int rmask = 0; int rightsmask =0; char **oldrealmrefs = NULL; char **newrealmrefs = NULL; char **temprdns = NULL; char *realmName = NULL; kdb5_dal_handle *dal_handle = NULL; krb5_ldap_context *ldap_context=NULL; /* Check for number of arguments */ if ((argc < 3) || (argc > 10)) { exit_status++; goto err_usage; } dal_handle = (kdb5_dal_handle *) util_context->db_context; ldap_context = (krb5_ldap_context *) dal_handle->db_context; /* Parse all arguments, only to pick up service DN (Pass 1) */ for (i = 1; i < argc; i++) { /* Skip arguments next to 'servicehost' and 'realmdn' arguments */ if (!strcmp(argv[i], "-servicehost")) { ++i; } else if (!strcmp(argv[i], "-clearservicehost")) { ++i; } else if (!strcmp(argv[i], "-addservicehost")) { ++i; } else if (!strcmp(argv[i], "-realm")) { ++i; } else if (!strcmp(argv[i], "-clearrealm")) { ++i; } else if (!strcmp(argv[i], "-addrealm")) { ++i; } else { /* Any other argument must be service DN */ /* First check if service DN is already provided -- if so, there's a usage error */ if (servicedn != NULL) { com_err(me, EINVAL, gettext("while modifying service object")); goto err_usage; } /* If not present already, fill up service DN */ servicedn = strdup(argv[i]); if (servicedn == NULL) { com_err(me, ENOMEM, gettext("while modifying service object")); goto err_nomsg; } } } /* No point in proceeding further if service DN value is not available */ if (servicedn == NULL) { com_err(me, EINVAL, gettext("while modifying service object")); goto err_usage; } retval = krb5_ldap_read_service(util_context, servicedn, &srvparams, &in_mask); if (retval) { /* Solaris Kerberos */ com_err(me, retval, gettext("while reading information of service '%s'"), servicedn); goto err_nomsg; } /* Read Kerberos container info, to construct realm DN from name * and for assigning rights */ if ((retval = krb5_ldap_read_krbcontainer_params(util_context, &(ldap_context->krbcontainer)))) { com_err(me, retval, gettext("while reading Kerberos container information")); goto cleanup; } /* Parse all arguments, but skip the service DN (Pass 2) */ for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-servicehost")) { if (++i > argc - 1) goto err_usage; /* Free the old list if available */ if (srvparams->krbhostservers) { krb5_free_list_entries (srvparams->krbhostservers); free (srvparams->krbhostservers); } srvparams->krbhostservers = (char **)calloc(MAX_LIST_ENTRIES, sizeof(char *)); if (srvparams->krbhostservers == NULL) { retval = ENOMEM; goto cleanup; } if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, srvparams->krbhostservers))) { goto cleanup; } if ((retval = process_host_list (srvparams->krbhostservers, srvparams->servicetype))) { goto cleanup; } out_mask |= LDAP_SERVICE_HOSTSERVER; /* Set flag to ignore 'add' and 'clear' */ srvhost_flag = 1; } else if (!strcmp(argv[i], "-clearservicehost")) { if (++i > argc - 1) goto err_usage; if (!srvhost_flag) { /* If attribute doesn't exist, don't permit 'clear' option */ if ((in_mask & LDAP_SERVICE_HOSTSERVER) == 0) { /* Send out some proper error message here */ com_err(me, EINVAL, gettext("service host list is empty\n")); goto err_nomsg; } /* Allocate list for processing */ list = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); if (list == NULL) { retval = ENOMEM; goto cleanup; } if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) goto cleanup; if ((retval = process_host_list (list, srvparams->servicetype))) { goto cleanup; } list_modify_str_array(&(srvparams->krbhostservers), (const char**)list, LIST_MODE_DELETE); out_mask |= LDAP_SERVICE_HOSTSERVER; /* Clean up */ free (list); list = NULL; } } else if (!strcmp(argv[i], "-addservicehost")) { if (++i > argc - 1) goto err_usage; if (!srvhost_flag) { /* Allocate list for processing */ list = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); if (list == NULL) { retval = ENOMEM; goto cleanup; } if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) goto cleanup; if ((retval = process_host_list (list, srvparams->servicetype))) { goto cleanup; } /* Call list_modify_str_array() only if host server attribute * exists already --Actually, it's better to handle this * within list_modify_str_array() */ if (in_mask & LDAP_SERVICE_HOSTSERVER) { /* Re-size existing list */ existing_entries = list_count_str_array(srvparams->krbhostservers); new_entries = list_count_str_array(list); temp_ptr = (char **) realloc(srvparams->krbhostservers, sizeof(char *) * (existing_entries + new_entries + 1)); if (temp_ptr == NULL) { retval = ENOMEM; goto cleanup; } srvparams->krbhostservers = temp_ptr; list_modify_str_array(&(srvparams->krbhostservers), (const char**)list, LIST_MODE_ADD); /* Clean up */ free (list); list = NULL; } else srvparams->krbhostservers = list; out_mask |= LDAP_SERVICE_HOSTSERVER; } } else if (!strcmp(argv[i], "-realm")) { if (++i > argc - 1) goto err_usage; if ((in_mask & LDAP_SERVICE_REALMREFERENCE) && (srvparams->krbrealmreferences)) { if (!oldrealmrefs) { /* Store the old realm list for removing rights */ oldrealmrefs = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); if (oldrealmrefs == NULL) { retval = ENOMEM; goto cleanup; } for (j = 0; srvparams->krbrealmreferences[j] != NULL; j++) { oldrealmrefs[j] = strdup(srvparams->krbrealmreferences[j]); if (oldrealmrefs[j] == NULL) { retval = ENOMEM; goto cleanup; } } oldrealmrefs[j] = NULL; } /* Free the old list if available */ krb5_free_list_entries (srvparams->krbrealmreferences); free (srvparams->krbrealmreferences); } srvparams->krbrealmreferences = (char **)calloc(MAX_LIST_ENTRIES, sizeof(char *)); if (srvparams->krbrealmreferences == NULL) { retval = ENOMEM; goto cleanup; } if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, srvparams->krbrealmreferences))) { goto cleanup; } /* Convert realm names to realm DNs */ if ((retval = convert_realm_name2dn_list( srvparams->krbrealmreferences, ldap_context->krbcontainer->DN))) { goto cleanup; } out_mask |= LDAP_SERVICE_REALMREFERENCE; /* Set flag to ignore 'add' and 'clear' */ realmdn_flag = 1; } else if (!strcmp(argv[i], "-clearrealm")) { if (++i > argc - 1) goto err_usage; if (!realmdn_flag) { /* If attribute doesn't exist, don't permit 'clear' option */ if (((in_mask & LDAP_SERVICE_REALMREFERENCE) == 0) || (srvparams->krbrealmreferences == NULL)) { /* Send out some proper error message here */ goto err_nomsg; } if (!oldrealmrefs) { /* Store the old realm list for removing rights */ oldrealmrefs = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); if (oldrealmrefs == NULL) { retval = ENOMEM; goto cleanup; } for (j = 0; srvparams->krbrealmreferences[j] != NULL; j++) { oldrealmrefs[j] = strdup(srvparams->krbrealmreferences[j]); if (oldrealmrefs[j] == NULL) { retval = ENOMEM; goto cleanup; } } oldrealmrefs[j] = NULL; } /* Allocate list for processing */ list = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); if (list == NULL) { retval = ENOMEM; goto cleanup; } if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) goto cleanup; /* Convert realm names to realm DNs */ if ((retval = convert_realm_name2dn_list(list, ldap_context->krbcontainer->DN))) { goto cleanup; } list_modify_str_array(&(srvparams->krbrealmreferences), (const char**)list, LIST_MODE_DELETE); out_mask |= LDAP_SERVICE_REALMREFERENCE; /* Clean up */ free (list); list = NULL; } } else if (!strcmp(argv[i], "-addrealm")) { if (++i > argc - 1) goto err_usage; if (!realmdn_flag) { /* Allocate list for processing */ list = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); if (list == NULL) { retval = ENOMEM; goto cleanup; } if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) goto cleanup; /* Convert realm names to realm DNs */ if ((retval = convert_realm_name2dn_list(list, ldap_context->krbcontainer->DN))) { goto cleanup; } if ((in_mask & LDAP_SERVICE_REALMREFERENCE) && (srvparams->krbrealmreferences) && (!oldrealmrefs)) { /* Store the old realm list for removing rights */ oldrealmrefs = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); if (oldrealmrefs == NULL) { retval = ENOMEM; goto cleanup; } for (j = 0; srvparams->krbrealmreferences[j] != NULL; j++) { oldrealmrefs[j] = strdup(srvparams->krbrealmreferences[j]); if (oldrealmrefs[j] == NULL) { retval = ENOMEM; goto cleanup; } } oldrealmrefs[j] = NULL; } /* Call list_modify_str_array() only if realm DN attribute * exists already -- Actually, it's better to handle this * within list_modify_str_array() */ if (in_mask & LDAP_SERVICE_REALMREFERENCE) { /* Re-size existing list */ existing_entries = list_count_str_array( srvparams->krbrealmreferences); new_entries = list_count_str_array(list); temp_ptr = (char **) realloc(srvparams->krbrealmreferences, sizeof(char *) * (existing_entries + new_entries + 1)); if (temp_ptr == NULL) { retval = ENOMEM; goto cleanup; } srvparams->krbrealmreferences = temp_ptr; list_modify_str_array(&(srvparams->krbrealmreferences), (const char**)list, LIST_MODE_ADD); /* Clean up */ free (list); list = NULL; } else srvparams->krbrealmreferences = list; out_mask |= LDAP_SERVICE_REALMREFERENCE; } } else { /* Any other argument must be service DN -- skip it */ } } /* Modify attributes of object */ if ((retval = krb5_ldap_modify_service(util_context, srvparams, out_mask))) goto cleanup; /* Service rights modification code */ if (out_mask & LDAP_SERVICE_REALMREFERENCE) { printf("%s", gettext("Changing rights for the service object. Please wait ... ")); fflush(stdout); newrealmrefs = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); if (newrealmrefs == NULL) { retval = ENOMEM; goto cleanup; } if ((srvparams != NULL) && (srvparams->krbrealmreferences != NULL)) { for (j = 0; srvparams->krbrealmreferences[j] != NULL; j++) { newrealmrefs[j] = strdup(srvparams->krbrealmreferences[j]); if (newrealmrefs[j] == NULL) { retval = ENOMEM; goto cleanup; } } newrealmrefs[j] = NULL; } disjoint_members(oldrealmrefs, newrealmrefs); /* Delete the rights for the given service, on each of the realm * container & subtree in the old realm reference list. */ if (oldrealmrefs) { rightsmask = 0; rightsmask |= LDAP_REALM_RIGHTS; rightsmask |= LDAP_SUBTREE_RIGHTS; for (i = 0; (oldrealmrefs[i] != NULL); i++) { /* Get the realm name, not the dn */ temprdns = ldap_explode_dn(oldrealmrefs[i], 1); if (temprdns[0] == NULL) { retval = EINVAL; goto cleanup; } realmName = strdup(temprdns[0]); if (realmName == NULL) { retval = ENOMEM; goto cleanup; } if ((retval = krb5_ldap_read_realm_params(util_context, realmName, &rparams, &rmask))) { com_err(me, retval, gettext("while reading information of realm '%s'"), realmName); goto err_nomsg; } if ((retval = krb5_ldap_delete_service_rights(util_context, srvparams->servicetype, srvparams->servicedn, realmName, rparams->subtree, rightsmask))) { printf(gettext("failed\n")); com_err(me, retval, gettext("while assigning rights '%s'"), srvparams->servicedn); goto err_nomsg; } if (rparams) krb5_ldap_free_realm_params(rparams); } } /* Add the rights for the given service, on each of the realm * container & subtree in the new realm reference list. */ if (newrealmrefs) { rightsmask = 0; rightsmask |= LDAP_REALM_RIGHTS; rightsmask |= LDAP_SUBTREE_RIGHTS; for (i = 0; (newrealmrefs[i] != NULL); i++) { /* Get the realm name, not the dn */ temprdns = ldap_explode_dn(newrealmrefs[i], 1); if (temprdns[0] == NULL) { retval = EINVAL; goto cleanup; } realmName = strdup(temprdns[0]); if (realmName == NULL) { retval = ENOMEM; goto cleanup; } if ((retval = krb5_ldap_read_krbcontainer_params(util_context, &(ldap_context->krbcontainer)))) { com_err(me, retval, gettext("while reading Kerberos container information")); goto cleanup; } if ((retval = krb5_ldap_read_realm_params(util_context, realmName, &rparams, &rmask))) { com_err(me, retval, gettext("while reading information of realm '%s'"), realmName); goto err_nomsg; } if ((retval = krb5_ldap_add_service_rights(util_context, srvparams->servicetype, srvparams->servicedn, realmName, rparams->subtree, rightsmask))) { printf(gettext("failed\n")); com_err(me, retval, gettext("while assigning rights '%s'"), srvparams->servicedn); goto err_nomsg; } if (rparams) { krb5_ldap_free_realm_params(rparams); rparams = NULL; } } printf(gettext("done\n")); } } goto cleanup; err_usage: print_usage = TRUE; err_nomsg: no_msg = TRUE; cleanup: /* Clean-up structure */ krb5_ldap_free_service(util_context, srvparams); if (servicedn) free(servicedn); if (list) { free(list); list = NULL; } if (oldrealmrefs) { for (i = 0; oldrealmrefs[i] != NULL; i++) free(oldrealmrefs[i]); free(oldrealmrefs); } if (newrealmrefs) { for (i = 0; newrealmrefs[i] != NULL; i++) free(newrealmrefs[i]); free(newrealmrefs); } if (realmName) { free(realmName); realmName = NULL; } if (print_usage) db_usage(MODIFY_SERVICE); if (retval) { if (!no_msg) com_err(me, retval, gettext("while modifying service object")); exit_status++; } return; } /* * This function will delete the entry corresponding to the service object * from the service password file. */ static krb5_error_code rem_service_entry_from_file(argc, argv, file_name, service_object) int argc; char *argv[]; char *file_name; char *service_object; { int st = EINVAL; /* Solaris Kerberos */ char *me = progname; char *tmp_file = NULL; int tmpfd = -1; FILE *pfile = NULL; unsigned int len = 0; char line[MAX_LEN]={0}; mode_t omask = umask(077); /* Check for permissions on the password file */ if (access(file_name, W_OK) == -1) { /* If the specified file itself is not there, no need to show error */ if (errno == ENOENT) { st=0; goto cleanup; } else { com_err(me, errno, gettext("while deleting entry from file %s", file_name)); goto cleanup; } } /* Create a temporary file which contains all the entries except the entry for the given service dn */ pfile = fopen(file_name, "r+F"); if (pfile == NULL) { com_err(me, errno, gettext("while deleting entry from file %s"), file_name); goto cleanup; } /* Create a new file with the extension .tmp */ tmp_file = (char *)malloc(strlen(file_name) + 4 + 1); if (tmp_file == NULL) { com_err(me, ENOMEM, gettext("while deleting entry from file")); fclose(pfile); goto cleanup; } snprintf (tmp_file, strlen(file_name) + 4 + 1, "%s%s", file_name, ".tmp"); tmpfd = creat(tmp_file, S_IRUSR|S_IWUSR); umask(omask); if (tmpfd == -1) { com_err(me, errno, gettext("while deleting entry from file\n")); fclose(pfile); goto cleanup; } /* Copy only those lines which donot have the specified service dn */ while (fgets(line, MAX_LEN, pfile) != NULL) { if ((strstr(line, service_object) != NULL) && (line[strlen(service_object)] == '#')) { continue; } else { len = strlen(line); if (write(tmpfd, line, len) != len) { com_err(me, errno, gettext("while deleting entry from file\n")); close(tmpfd); unlink(tmp_file); fclose(pfile); goto cleanup; } } } fclose(pfile); if (unlink(file_name) == 0) { link(tmp_file, file_name); } else { com_err(me, errno, gettext("while deleting entry from file\n")); } unlink(tmp_file); st=0; cleanup: if (tmp_file) free(tmp_file); return st; } /* * This function will delete the service object from the LDAP Server * and unlink the references to the Realm objects (if any) */ void kdb5_ldap_destroy_service(argc, argv) int argc; char *argv[]; { int i = 0; char buf[5] = {0}; krb5_error_code retval = EINVAL; int force = 0; char *servicedn = NULL; char *stashfilename = NULL; int mask = 0; krb5_ldap_service_params *lserparams = NULL; krb5_boolean print_usage = FALSE; if ((argc < 2) || (argc > 5)) { exit_status++; goto err_usage; } for (i=1; i < argc; i++) { if (strcmp(argv[i],"-force")==0) { force++; } else if (strcmp(argv[i],"-f")==0) { if (argv[i+1]) { stashfilename=strdup(argv[i+1]); if (stashfilename == NULL) { /* Solaris Kerberos */ com_err(progname, ENOMEM, gettext("while destroying service")); exit_status++; goto cleanup; } i++; } else { exit_status++; goto err_usage; } } else { if ((argv[i]) && (servicedn == NULL)) { servicedn=strdup(argv[i]); if (servicedn == NULL) { /* Solaris Kerberos */ com_err(progname, ENOMEM, gettext("while destroying service")); exit_status++; goto cleanup; } } else { exit_status++; goto err_usage; } } } if (!servicedn) { exit_status++; goto err_usage; } if (!force) { printf(gettext("This will delete the service object '%s', are you sure?\n"), servicedn); printf(gettext("(type 'yes' to confirm)? ")); if (fgets(buf, sizeof(buf), stdin) == NULL) { exit_status++; goto cleanup;; } if (strcmp(buf, yes)) { exit_status++; goto cleanup; } } if ((retval = krb5_ldap_read_service(util_context, servicedn, &lserparams, &mask))) { /* Solaris Kerberos */ com_err(progname, retval, gettext("while destroying service '%s'"), servicedn); exit_status++; goto cleanup; } retval = krb5_ldap_delete_service(util_context, lserparams, servicedn); if (retval) { /* Solaris Kerberos */ com_err(progname, retval, gettext("while destroying service '%s'"), servicedn); exit_status++; goto cleanup; } if (stashfilename == NULL) { stashfilename = strdup(DEF_SERVICE_PASSWD_FILE); if (stashfilename == NULL) { /* Solaris Kerberos */ com_err(progname, ENOMEM, gettext("while destroying service")); exit_status++; goto cleanup; } } printf(gettext("** service object '%s' deleted.\n"), servicedn); retval = rem_service_entry_from_file(argc, argv, stashfilename, servicedn); if (retval) printf(gettext("** error removing service object entry '%s' from password file.\n"), servicedn); goto cleanup; err_usage: print_usage = TRUE; cleanup: if (lserparams) { krb5_ldap_free_service(util_context, lserparams); } if (servicedn) { free(servicedn); } if (stashfilename) { free(stashfilename); } if (print_usage) { db_usage(DESTROY_SERVICE); } return; } /* * This function will display information about the given service object */ void kdb5_ldap_view_service(argc, argv) int argc; char *argv[]; { krb5_ldap_service_params *lserparams = NULL; krb5_error_code retval = 0; char *servicedn = NULL; int mask = 0; krb5_boolean print_usage = FALSE; if (!(argc == 2)) { exit_status++; goto err_usage; } servicedn=strdup(argv[1]); if (servicedn == NULL) { /* Solaris Kerberos */ com_err(progname, ENOMEM, gettext("while viewing service")); exit_status++; goto cleanup; } if ((retval = krb5_ldap_read_service(util_context, servicedn, &lserparams, &mask))) { /* Solaris Kerberos */ com_err(progname, retval, gettext("while viewing service '%s'"), servicedn); exit_status++; goto cleanup; } print_service_params(lserparams, mask); goto cleanup; err_usage: print_usage = TRUE; cleanup: if (lserparams) { krb5_ldap_free_service(util_context, lserparams); } if (servicedn) free(servicedn); if (print_usage) { db_usage(VIEW_SERVICE); } return; } /* * This function will list the DNs of kerberos services present on * the LDAP Server under a specific sub-tree (entire tree by default) */ void kdb5_ldap_list_services(argc, argv) int argc; char *argv[]; { /* Solaris Kerberos */ char *me = progname; krb5_error_code retval = 0; char *basedn = NULL; char **list = NULL; char **plist = NULL; krb5_boolean print_usage = FALSE; /* Check for number of arguments */ if ((argc != 1) && (argc != 3)) { exit_status++; goto err_usage; } /* Parse base DN argument if present */ if (argc == 3) { if (strcmp(argv[1], "-basedn")) { retval = EINVAL; goto err_usage; } basedn = strdup(argv[2]); if (basedn == NULL) { com_err(me, ENOMEM, gettext("while listing services")); exit_status++; goto cleanup; } } retval = krb5_ldap_list_services(util_context, basedn, &list); if ((retval != 0) || (list == NULL)) { exit_status++; goto cleanup; } for (plist = list; *plist != NULL; plist++) { printf("%s\n", *plist); } goto cleanup; err_usage: print_usage = TRUE; cleanup: if (list != NULL) { krb5_free_list_entries (list); free (list); } if (basedn) free (basedn); if (print_usage) { db_usage(LIST_SERVICE); } if (retval) { com_err(me, retval, gettext("while listing policy objects")); exit_status++; } return; } /* * This function will print the service object information * to the standard output */ static void print_service_params(lserparams, mask) krb5_ldap_service_params *lserparams; int mask; { int i=0; /* Print the service dn */ printf("%20s%-20s\n", gettext("Service dn: "), lserparams->servicedn); /* Print the service type of the object to be read */ if (lserparams->servicetype == LDAP_KDC_SERVICE) { printf("%20s%-20s\n", gettext("Service type: "), "kdc"); } else if (lserparams->servicetype == LDAP_ADMIN_SERVICE) { printf("%20s%-20s\n", gettext("Service type: "), "admin"); } else if (lserparams->servicetype == LDAP_PASSWD_SERVICE) { printf("%20s%-20s\n", gettext("Service type: "), "pwd"); } /* Print the host server values */ printf("%20s\n", gettext("Service host list: ")); if (mask & LDAP_SERVICE_HOSTSERVER) { for (i=0; lserparams->krbhostservers[i] != NULL; ++i) { printf("%20s%-50s\n","",lserparams->krbhostservers[i]); } } /* Print the realm reference dn values */ printf("%20s\n", gettext("Realm DN list: ")); if (mask & LDAP_SERVICE_REALMREFERENCE) { for (i=0; lserparams && lserparams->krbrealmreferences && lserparams->krbrealmreferences[i] != NULL; ++i) { printf("%20s%-50s\n","",lserparams->krbrealmreferences[i]); } } return; } /* * This function will generate random password of length(RANDOM_PASSWD_LEN) * * * INPUT: * ctxt - context * * OUTPUT: * RANDOM_PASSWD_LEN length random password */ static int generate_random_password(krb5_context ctxt, char **randpwd, unsigned int *passlen) { char *random_pwd = NULL; int ret = 0; krb5_data data; int i=0; /*int len = 0;*/ /* setting random password length in the range 16-32 */ srand((unsigned int)(time(0) ^ getpid())); data.length = RANDOM_PASSWD_LEN; random_pwd = (char *)malloc(data.length + 1); if (random_pwd == NULL) { com_err("setsrvpw", ENOMEM, gettext("while generating random password")); return ENOMEM; } memset(random_pwd, 0, data.length + 1); data.data = random_pwd; ret = krb5_c_random_make_octets(ctxt, &data); if (ret) { com_err("setsrvpw", ret, gettext("Error generating random password")); free(random_pwd); return ret; } for (i=0; i 127) { random_pwd[i] = (unsigned char)random_pwd[i] % 128; } else if (random_pwd[i] == 0) { random_pwd[i] = (rand()/(RAND_MAX/127 + 1))+1; } } *randpwd = random_pwd; *passlen = data.length; return 0; } /* * This function will set the password of the service object in the directory * and/or the specified service password file. * * * INPUT: * argc - contains the number of arguments for this sub-command * argv - array of arguments for this sub-command * * OUTPUT: * void */ int kdb5_ldap_set_service_password(argc, argv) int argc; char **argv; { krb5_ldap_context *lparams = NULL; char *file_name = NULL; char *tmp_file = NULL; /* Solaris Kerberos */ char *me = progname; int filelen = 0; int random_passwd = 0; int set_dir_pwd = 1; krb5_boolean db_init_local = FALSE; char *service_object = NULL; char *passwd = NULL; char *prompt1 = NULL; char *prompt2 = NULL; unsigned int passwd_len = 0; krb5_error_code errcode = -1; int retval = 0, i = 0; unsigned int len = 0; krb5_boolean print_usage = FALSE; FILE *pfile = NULL; char *str = NULL; char line[MAX_LEN]; kdb5_dal_handle *dal_handle = NULL; struct data encrypted_passwd = {0, NULL}; /* The arguments for setsrv password should contain the service object DN * and options to specify whether the password should be updated in file only * or both file and directory. So the possible combination of arguments are: * setsrvpw servicedn wherein argc is 2 * setsrvpw -fileonly servicedn wherein argc is 3 * setsrvpw -randpw servicedn wherein argc is 3 * setsrvpw -f filename servicedn wherein argc is 4 * setsrvpw -fileonly -f filename servicedn wherein argc is 5 * setsrvpw -randpw -f filename servicedn wherein argc is 5 */ if ((argc < 2) || (argc > 5)) { print_usage = TRUE; goto cleanup; } dal_handle = (kdb5_dal_handle *)util_context->db_context; lparams = (krb5_ldap_context *) dal_handle->db_context; if (lparams == NULL) { printf(gettext("%s: Invalid LDAP handle\n"), me); goto cleanup; } /* Parse the arguments */ for (i = 1; i < argc -1 ; i++) { if (strcmp(argv[i], "-randpw") == 0) { random_passwd = 1; } else if (strcmp(argv[i], "-fileonly") == 0) { set_dir_pwd = 0; } else if (strcmp(argv[i], "-f") == 0) { if (argv[++i] == NULL) { print_usage = TRUE; goto cleanup; } file_name = strdup(argv[i]); if (file_name == NULL) { com_err(me, ENOMEM, gettext("while setting service object password")); goto cleanup; } /* Verify if the file location has the proper file name * for eg, if the file location is a directory like /home/temp/, * we reject it. */ filelen = strlen(file_name); if ((filelen == 0) || (file_name[filelen-1] == '/')) { printf(gettext("%s: Filename not specified for setting service object password\n"), me); print_usage = TRUE; goto cleanup; } } else { printf(gettext("%s: Invalid option specified for \"setsrvpw\" command\n"), me); print_usage = TRUE; goto cleanup; } } if (i != argc-1) { print_usage = TRUE; goto cleanup; } service_object = strdup(argv[i]); if (service_object == NULL) { com_err(me, ENOMEM, gettext("while setting service object password")); goto cleanup; } if (strlen(service_object) == 0) { printf(gettext("%s: Service object not specified for \"setsrvpw\" command\n"), me); print_usage = TRUE; goto cleanup; } if (service_object[0] == '-') { print_usage = TRUE; goto cleanup; } if (file_name == NULL) { file_name = strdup(DEF_SERVICE_PASSWD_FILE); if (file_name == NULL) { com_err(me, ENOMEM, gettext("while setting service object password")); goto cleanup; } } if (set_dir_pwd) { if (db_inited == FALSE) { if ((errcode = krb5_ldap_db_init(util_context, lparams))) { com_err(me, errcode, gettext("while initializing database")); goto cleanup; } db_init_local = TRUE; } } if (random_passwd) { if (!set_dir_pwd) { printf(gettext("%s: Invalid option specified for \"setsrvpw\" command\n"), me); print_usage = TRUE; goto cleanup; } else { /* Generate random password */ if ((errcode = generate_random_password(util_context, &passwd, &passwd_len))) { printf(gettext("%s: Failed to set service object password\n"), me); goto cleanup; } passwd_len = strlen(passwd); } } else { /* Get the service object password from the terminal */ passwd = (char *)malloc(MAX_SERVICE_PASSWD_LEN + 1); if (passwd == NULL) { com_err(me, ENOMEM, gettext("while setting service object password")); goto cleanup; } memset(passwd, 0, MAX_SERVICE_PASSWD_LEN + 1); passwd_len = MAX_SERVICE_PASSWD_LEN; len = strlen(service_object); /* size of allocation=strlen of servicedn + strlen("Password for \" \"")=20 */ prompt1 = (char *)malloc(len + 20); if (prompt1 == NULL) { com_err(me, ENOMEM, gettext("while setting service object password")); goto cleanup; } sprintf(prompt1, gettext("Password for \"%s\""), service_object); /* size of allocation=strlen of servicedn + strlen("Re-enter Password for \" \"")=30 */ prompt2 = (char *)malloc(len + 30); if (prompt2 == NULL) { com_err(me, ENOMEM, gettext("while setting service object password")); free(prompt1); goto cleanup; } sprintf(prompt2, gettext("Re-enter password for \"%s\""), service_object); retval = krb5_read_password(util_context, prompt1, prompt2, passwd, &passwd_len); free(prompt1); free(prompt2); if (retval) { com_err(me, retval, gettext("while setting service object password")); memset(passwd, 0, MAX_SERVICE_PASSWD_LEN); goto cleanup; } if (passwd_len == 0) { printf(gettext("%s: Invalid password\n"), me); memset(passwd, 0, MAX_SERVICE_PASSWD_LEN); goto cleanup; } passwd_len = strlen(passwd); } /* Hex the password */ { krb5_data pwd, hex; pwd.length = passwd_len; pwd.data = passwd; errcode = tohex(pwd, &hex); if (errcode != 0) { if (hex.length != 0) { memset(hex.data, 0, hex.length); free(hex.data); } com_err(me, errcode, gettext("Failed to convert the password to hex")); memset(passwd, 0, passwd_len); goto cleanup; } /* Password = {CRYPT}: */ encrypted_passwd.value = (unsigned char *)malloc(strlen(service_object) + 1 + 5 + hex.length + 2); if (encrypted_passwd.value == NULL) { com_err(me, ENOMEM, gettext("while setting service object password")); memset(passwd, 0, passwd_len); memset(hex.data, 0, hex.length); free(hex.data); goto cleanup; } encrypted_passwd.value[strlen(service_object) + 1 + 5 + hex.length + 1] = '\0'; sprintf((char *)encrypted_passwd.value, "%s#{HEX}%s\n", service_object, hex.data); encrypted_passwd.len = strlen((char *)encrypted_passwd.value); memset(hex.data, 0, hex.length); free(hex.data); } /* We should check if the file exists and we have permission to write into that file */ if (access(file_name, W_OK) == -1) { if (errno == ENOENT) { mode_t omask; int fd = -1; printf(gettext("File does not exist. Creating the file %s...\n"), file_name); omask = umask(077); fd = creat(file_name, S_IRUSR|S_IWUSR); umask(omask); if (fd == -1) { com_err(me, errno, gettext("Error creating file %s"), file_name); memset(passwd, 0, passwd_len); goto cleanup; } close(fd); } else { com_err(me, errno, gettext("Unable to access the file %s"), file_name); memset(passwd, 0, passwd_len); goto cleanup; } } if (set_dir_pwd) { if ((errcode = krb5_ldap_set_service_passwd(util_context, service_object, passwd)) != 0) { com_err(me, errcode, gettext("Failed to set password for service object %s"), service_object); memset(passwd, 0, passwd_len); goto cleanup; } } memset(passwd, 0, passwd_len); /* TODO: file lock for the service password file */ /* set password in the file */ pfile = fopen(file_name, "r+F"); if (pfile == NULL) { com_err(me, errno, gettext("Failed to open file %s"), file_name); goto cleanup; } while (fgets(line, MAX_LEN, pfile) != NULL) { if ((str = strstr(line, service_object)) != NULL) { if (line[strlen(service_object)] == '#') { break; } str = NULL; } } if (str == NULL) { if (feof(pfile)) { /* If the service object dn is not present in the service password file */ if (fwrite(encrypted_passwd.value, (unsigned int)encrypted_passwd.len, 1, pfile) != 1) { com_err(me, errno, gettext("Failed to write service object password to file")); goto cleanup; } } else { com_err(me, errno, gettext("Error reading service object password file")); goto cleanup; } fclose(pfile); pfile = NULL; } else { /* Password entry for the service object is already present in the file */ /* Delete the existing entry and add the new entry */ FILE *newfile = NULL; mode_t omask; /* Create a new file with the extension .tmp */ tmp_file = (char *) malloc(sizeof(char) * (strlen(file_name) + 4 + 1)); if (tmp_file == NULL) { com_err(me, ENOMEM, gettext("while setting service object password")); goto cleanup; } sprintf(tmp_file,"%s.%s",file_name,"tmp"); omask = umask(077); newfile = fopen(tmp_file, "w+F"); umask(omask); if (newfile == NULL) { com_err(me, errno, gettext("Error creating file %s"), tmp_file); goto cleanup; } fseek(pfile, 0, SEEK_SET); while (fgets(line, MAX_LEN, pfile) != NULL) { if (((str = strstr(line, service_object)) != NULL) && (line[strlen(service_object)] == '#')) { if (fprintf(newfile, "%s", encrypted_passwd.value) < 0) { com_err(me, errno, gettext("Failed to write service object password to file")); fclose(newfile); unlink(tmp_file); goto cleanup; } } else { len = strlen(line); if (fprintf(newfile, "%s", line) < 0) { com_err(me, errno, gettext("Failed to write service object password to file")); fclose(newfile); unlink(tmp_file); goto cleanup; } } } if (!feof(pfile)) { com_err(me, errno, gettext("Error reading service object password file")); fclose(newfile); unlink(tmp_file); goto cleanup; } /* TODO: file lock for the service password file */ fclose(pfile); pfile = NULL; fclose(newfile); newfile = NULL; if (unlink(file_name) == 0) { link(tmp_file, file_name); } else { com_err(me, errno, gettext("Failed to write service object password to file")); unlink(tmp_file); goto cleanup; } unlink(tmp_file); } errcode = 0; cleanup: if (db_init_local) krb5_ldap_close(util_context); if (service_object) free(service_object); if (file_name) free(file_name); if (passwd) free(passwd); if (encrypted_passwd.value) { memset(encrypted_passwd.value, 0, encrypted_passwd.len); free(encrypted_passwd.value); } if (pfile) fclose(pfile); if (tmp_file) free(tmp_file); if (print_usage) db_usage(SET_SRV_PW); return errcode; } #else /* #ifdef HAVE_EDIRECTORY */ /* * Convert the user supplied password into hexadecimal and stash it. Only a * little more secure than storing plain password in the file ... */ void kdb5_ldap_stash_service_password(argc, argv) int argc; char **argv; { int ret = 0; unsigned int passwd_len = 0; /* Solaris Kerberos */ char *me = progname; char *service_object = NULL; char *file_name = NULL, *tmp_file = NULL; char passwd[MAX_SERVICE_PASSWD_LEN]; char *str = NULL; char line[MAX_LEN]; int fd; FILE *pfile = NULL; krb5_boolean print_usage = FALSE; krb5_data hexpasswd = {0, 0, NULL}; mode_t old_mode = 0; /* * Format: * stashsrvpw [-f filename] service_dn * where * 'service_dn' is the DN of the service object * 'filename' is the path of the stash file */ if (argc != 2 && argc != 4) { print_usage = TRUE; goto cleanup; } if (argc == 4) { /* Find the stash file name */ if (strcmp (argv[1], "-f") == 0) { if (((file_name = strdup (argv[2])) == NULL) || ((service_object = strdup (argv[3])) == NULL)) { com_err(me, ENOMEM, gettext("while setting service object password")); goto cleanup; } } else if (strcmp (argv[2], "-f") == 0) { if (((file_name = strdup (argv[3])) == NULL) || ((service_object = strdup (argv[1])) == NULL)) { com_err(me, ENOMEM, gettext("while setting service object password")); goto cleanup; } } else { print_usage = TRUE; goto cleanup; } if (file_name == NULL) { com_err(me, ENOMEM, gettext("while setting service object password")); goto cleanup; } } else { /* argc == 2 */ char *section; service_object = strdup (argv[1]); if (service_object == NULL) { com_err(me, ENOMEM, gettext("while setting service object password")); goto cleanup; } /* Pick up the stash-file name from krb5.conf */ profile_get_string(util_context->profile, KDB_REALM_SECTION, util_context->default_realm, KDB_MODULE_POINTER, NULL, §ion); if (section == NULL) { profile_get_string(util_context->profile, KDB_MODULE_DEF_SECTION, KDB_MODULE_POINTER, NULL, NULL, §ion); if (section == NULL) { /* Stash file path neither in krb5.conf nor on command line */ file_name = strdup(DEF_SERVICE_PASSWD_FILE); if (file_name == NULL) { com_err(me, ENOMEM, gettext("while setting service object password")); goto cleanup; } goto done; } } profile_get_string (util_context->profile, KDB_MODULE_SECTION, section, "ldap_service_password_file", NULL, &file_name); /* * Solaris Kerberos: use default if ldap_service_password_file not set */ if (file_name == NULL) { file_name = strdup(DEF_SERVICE_PASSWD_FILE); if (file_name == NULL) { com_err(me, ENOMEM, gettext("while setting service object password")); goto cleanup; } } } done: /* Get password from user */ { char prompt1[256], prompt2[256]; /* Get the service object password from the terminal */ memset(passwd, 0, sizeof (passwd)); passwd_len = sizeof (passwd); /* size of prompt = strlen of servicedn + strlen("Password for \" \"") */ assert (sizeof (prompt1) > (strlen (service_object) + sizeof ("Password for \" \""))); sprintf(prompt1, gettext("Password for \"%s\""), service_object); /* size of prompt = strlen of servicedn + strlen("Re-enter Password for \" \"") */ assert (sizeof (prompt2) > (strlen (service_object) + sizeof ("Re-enter Password for \" \""))); sprintf(prompt2, gettext("Re-enter password for \"%s\""), service_object); ret = krb5_read_password(util_context, prompt1, prompt2, passwd, &passwd_len); if (ret != 0) { com_err(me, ret, gettext("while setting service object password")); memset(passwd, 0, sizeof (passwd)); goto cleanup; } if (passwd_len == 0) { printf(gettext("%s: Invalid password\n"), me); memset(passwd, 0, MAX_SERVICE_PASSWD_LEN); goto cleanup; } } /* Convert the password to hexadecimal */ { krb5_data pwd; pwd.length = passwd_len; pwd.data = passwd; ret = tohex(pwd, &hexpasswd); if (ret != 0) { com_err(me, ret, gettext("Failed to convert the password to hexadecimal")); memset(passwd, 0, passwd_len); goto cleanup; } } memset(passwd, 0, passwd_len); /* TODO: file lock for the service passowrd file */ /* set password in the file */ #if 0 /* ************ Begin IFDEF'ed OUT ***************************** */ old_mode = umask(0177); pfile = fopen(file_name, "a+"); if (pfile == NULL) { com_err(me, errno, gettext("Failed to open file %s: %s"), file_name, strerror (errno)); goto cleanup; } rewind (pfile); umask(old_mode); #else /* Solaris Kerberos: safer than the above */ fd = open(file_name, O_CREAT|O_RDWR|O_APPEND, 0600); if (fd < 0) { com_err(me, errno, gettext("Failed to open file %s: %s"), file_name, strerror (errno)); goto cleanup; } pfile = fdopen(fd, "a+F"); if (pfile == NULL) { com_err(me, errno, gettext("Failed to open file %s: %s"), file_name, strerror (errno)); goto cleanup; } rewind (pfile); #endif while (fgets (line, MAX_LEN, pfile) != NULL) { if ((str = strstr (line, service_object)) != NULL) { /* * White spaces not allowed, # delimits the service dn from the * password */ if (line [strlen (service_object)] == '#') break; str = NULL; } } if (str == NULL) { if (feof(pfile)) { /* If the service object dn is not present in the service password file */ if (fprintf(pfile, "%s#{HEX}%s\n", service_object, hexpasswd.data) < 0) { com_err(me, errno, gettext("Failed to write service object password to file")); fclose(pfile); goto cleanup; } } else { com_err(me, errno, gettext("Error reading service object password file")); fclose(pfile); goto cleanup; } fclose(pfile); } else { /* * Password entry for the service object is already present in the file * Delete the existing entry and add the new entry */ FILE *newfile; mode_t omask; /* Create a new file with the extension .tmp */ tmp_file = (char *) malloc(sizeof(char) * (strlen(file_name) + 4 + 1)); if (tmp_file == NULL) { com_err(me, ENOMEM, gettext("while setting service object password")); fclose(pfile); goto cleanup; } sprintf(tmp_file,"%s.%s",file_name,"tmp"); omask = umask(077); newfile = fopen(tmp_file, "wF"); umask (omask); if (newfile == NULL) { com_err(me, errno, gettext("Error creating file %s"), tmp_file); fclose(pfile); goto cleanup; } fseek(pfile, 0, SEEK_SET); while (fgets(line, MAX_LEN, pfile) != NULL) { if (((str = strstr(line, service_object)) != NULL) && (line[strlen(service_object)] == '#')) { if (fprintf(newfile, "%s#{HEX}%s\n", service_object, hexpasswd.data) < 0) { com_err(me, errno, gettext("Failed to write service object password to file")); fclose(newfile); unlink(tmp_file); fclose(pfile); goto cleanup; } } else { if (fprintf (newfile, "%s", line) < 0) { com_err(me, errno, gettext("Failed to write service object password to file")); fclose(newfile); unlink(tmp_file); fclose(pfile); goto cleanup; } } } if (!feof(pfile)) { com_err(me, errno, gettext("Error reading service object password file")); fclose(newfile); unlink(tmp_file); fclose(pfile); goto cleanup; } /* TODO: file lock for the service passowrd file */ fclose(pfile); fclose(newfile); ret = rename(tmp_file, file_name); if (ret != 0) { com_err(me, errno, gettext("Failed to write service object password to " "file")); goto cleanup; } } ret = 0; cleanup: if (hexpasswd.length != 0) { memset(hexpasswd.data, 0, hexpasswd.length); free(hexpasswd.data); } if (service_object) free(service_object); if (file_name) free(file_name); if (tmp_file) free(tmp_file); if (print_usage) usage(); /* db_usage(STASH_SRV_PW); */ if (ret) exit_status++; } #endif /* #ifdef HAVE_EDIRECTORY */