xref: /onnv-gate/usr/src/cmd/krb5/ldap_util/kdb5_ldap_services.c (revision 8092:19771b16f0a8)
14960Swillf /*
2*8092SMark.Phalan@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
34960Swillf  * Use is subject to license terms.
44960Swillf  */
54960Swillf 
64960Swillf /*
74960Swillf  * kadmin/ldap_util/kdb5_ldap_services.c
84960Swillf  */
94960Swillf 
104960Swillf /* Copyright (c) 2004-2005, Novell, Inc.
114960Swillf  * All rights reserved.
124960Swillf  *
134960Swillf  * Redistribution and use in source and binary forms, with or without
144960Swillf  * modification, are permitted provided that the following conditions are met:
154960Swillf  *
164960Swillf  *   * Redistributions of source code must retain the above copyright notice,
174960Swillf  *       this list of conditions and the following disclaimer.
184960Swillf  *   * Redistributions in binary form must reproduce the above copyright
194960Swillf  *       notice, this list of conditions and the following disclaimer in the
204960Swillf  *       documentation and/or other materials provided with the distribution.
214960Swillf  *   * The copyright holder's name is not used to endorse or promote products
224960Swillf  *       derived from this software without specific prior written permission.
234960Swillf  *
244960Swillf  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
254960Swillf  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
264960Swillf  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
274960Swillf  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
284960Swillf  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
294960Swillf  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
304960Swillf  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
314960Swillf  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
324960Swillf  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
334960Swillf  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
344960Swillf  * POSSIBILITY OF SUCH DAMAGE.
354960Swillf  */
364960Swillf 
374960Swillf /*
384960Swillf  * Create / Delete / Modify / View / List service objects.
394960Swillf  */
404960Swillf 
414960Swillf /*
424960Swillf  * Service objects have rights over realm objects and principals. The following
434960Swillf  * functions manage the service objects.
444960Swillf  */
454960Swillf 
464960Swillf #include <stdio.h>
474960Swillf #include <k5-int.h>
484960Swillf #include <libintl.h> /* Solaris Kerberos */
494960Swillf #include <locale.h> /* Solaris Kerberos */
504960Swillf #include "kdb5_ldap_util.h"
514960Swillf #include "kdb5_ldap_list.h"
524960Swillf 
534960Swillf #ifdef HAVE_EDIRECTORY
544960Swillf 
554960Swillf krb5_error_code
564960Swillf rem_service_entry_from_file(int argc,
574960Swillf 			    char *argv[],
584960Swillf 			    char *file_name,
594960Swillf 			    char *service_object);
604960Swillf 
614960Swillf extern char *yes;
624960Swillf extern krb5_boolean db_inited;
634960Swillf 
process_host_list(char ** host_list,int servicetype)644960Swillf static int process_host_list(char **host_list, int servicetype)
654960Swillf {
664960Swillf     krb5_error_code retval = 0;
674960Swillf     char *pchr = NULL;
684960Swillf     char host_str[MAX_LEN_LIST_ENTRY] = "", proto_str[PROTOCOL_STR_LEN + 1] = "", port_str[PORT_STR_LEN + 1] = "";
694960Swillf     int j = 0;
704960Swillf 
714960Swillf     /* Protocol and port number processing */
724960Swillf     for (j = 0; host_list[j]; j++) {
734960Swillf 	/* Look for one hash */
744960Swillf 	if ((pchr = strchr(host_list[j], HOST_INFO_DELIMITER))) {
754960Swillf 	    unsigned int hostname_len = pchr - host_list[j];
764960Swillf 
774960Swillf 	    /* Check input for buffer overflow */
784960Swillf 	    if (hostname_len >= MAX_LEN_LIST_ENTRY) {
794960Swillf 		retval = EINVAL;
804960Swillf 		goto cleanup;
814960Swillf 	    }
824960Swillf 
834960Swillf 	    /* First copy off the host name portion */
844960Swillf 	    strncpy (host_str, host_list[j], hostname_len);
854960Swillf 
864960Swillf 	    /* Parse for the protocol string and translate to number */
874960Swillf 	    strncpy (proto_str, pchr + 1, PROTOCOL_STR_LEN);
884960Swillf 	    if (!strcmp(proto_str, "udp"))
894960Swillf 		sprintf (proto_str, "%d", PROTOCOL_NUM_UDP);
904960Swillf 	    else if (!strcmp(proto_str, "tcp"))
914960Swillf 		sprintf (proto_str, "%d", PROTOCOL_NUM_TCP);
924960Swillf 	    else
934960Swillf 		proto_str[0] = '\0'; /* Make the string null if invalid */
944960Swillf 
954960Swillf 	    /* Look for one more hash */
964960Swillf 	    if ((pchr = strchr(pchr + 1, HOST_INFO_DELIMITER))) {
974960Swillf 		/* Parse for the port string and check if it is numeric */
984960Swillf 		strncpy (port_str, pchr + 1, PORT_STR_LEN);
994960Swillf 		if (!strtol(port_str, NULL, 10)) /* Not a valid number */
1004960Swillf 		    port_str[0] = '\0';
1014960Swillf 	    } else
1024960Swillf 		port_str[0] = '\0';
1034960Swillf 	} else { /* We have only host name */
1044960Swillf 	    strncpy (host_str, host_list[j], MAX_LEN_LIST_ENTRY - 1);
1054960Swillf 	    proto_str[0] = '\0';
1064960Swillf 	    port_str[0] = '\0';
1074960Swillf 	}
1084960Swillf 
1094960Swillf 	/* Now, based on service type, fill in suitable protocol
1104960Swillf 	   and port values if they are absent or not matching */
1114960Swillf 	if (servicetype == LDAP_KDC_SERVICE) {
1124960Swillf 	    if (proto_str[0] == '\0')
1134960Swillf 		sprintf (proto_str, "%d", PROTOCOL_DEFAULT_KDC);
1144960Swillf 
1154960Swillf 	    if (port_str[0] == '\0')
1164960Swillf 		sprintf (port_str, "%d", PORT_DEFAULT_KDC);
1174960Swillf 	} else if (servicetype == LDAP_ADMIN_SERVICE) {
1184960Swillf 	    if (proto_str[0] == '\0')
1194960Swillf 		sprintf (proto_str, "%d", PROTOCOL_DEFAULT_ADM);
1204960Swillf 	    else if (strcmp(proto_str, "1")) {
1214960Swillf 		sprintf (proto_str, "%d", PROTOCOL_DEFAULT_ADM);
1224960Swillf 
1234960Swillf 		/* Print warning message */
1244960Swillf 		printf (gettext("Admin Server supports only TCP protocol, hence setting that\n"));
1254960Swillf 	    }
1264960Swillf 
1274960Swillf 	    if (port_str[0] == '\0')
1284960Swillf 		sprintf (port_str, "%d", PORT_DEFAULT_ADM);
1294960Swillf 	} else if (servicetype == LDAP_PASSWD_SERVICE) {
1304960Swillf 	    if (proto_str[0] == '\0')
1314960Swillf 		sprintf (proto_str, "%d", PROTOCOL_DEFAULT_PWD);
1324960Swillf 	    else if (strcmp(proto_str, "0")) {
1334960Swillf 		sprintf (proto_str, "%d", PROTOCOL_DEFAULT_PWD);
1344960Swillf 
1354960Swillf 		/* Print warning message */
1364960Swillf 		printf (gettext("Password Server supports only UDP protocol, hence setting that\n"));
1374960Swillf 	    }
1384960Swillf 
1394960Swillf 	    if (port_str[0] == '\0')
1404960Swillf 		sprintf (port_str, "%d", PORT_DEFAULT_PWD);
1414960Swillf 	}
1424960Swillf 
1434960Swillf 	/* Finally form back the string */
1444960Swillf 	free (host_list[j]);
1454960Swillf 	host_list[j] = (char*) malloc(sizeof(char) *
1464960Swillf 				      (strlen(host_str) + strlen(proto_str) + strlen(port_str) + 2 + 1));
1474960Swillf 	if (host_list[j] == NULL) {
1484960Swillf 	    retval = ENOMEM;
1494960Swillf 	    goto cleanup;
1504960Swillf 	}
1514960Swillf 	snprintf (host_list[j], strlen(host_str) + strlen(proto_str) + strlen(port_str) + 2 + 1,
1524960Swillf 		  "%s#%s#%s", host_str, proto_str, port_str);
1534960Swillf     }
1544960Swillf 
1554960Swillf cleanup:
1564960Swillf     return retval;
1574960Swillf }
1584960Swillf 
1594960Swillf 
1604960Swillf /*
1614960Swillf  * Given a realm name, this function will convert it to a DN by appending the
1624960Swillf  * Kerberos container location.
1634960Swillf  */
1644960Swillf static krb5_error_code
convert_realm_name2dn_list(list,krbcontainer_loc)1654960Swillf convert_realm_name2dn_list(list, krbcontainer_loc)
1664960Swillf     char **list;
1674960Swillf     const char *krbcontainer_loc;
1684960Swillf {
1694960Swillf     krb5_error_code retval = 0;
1704960Swillf     char temp_str[MAX_DN_CHARS] = "\0";
1714960Swillf     char *temp_node = NULL;
1724960Swillf     int i = 0;
1734960Swillf 
1744960Swillf     if (list == NULL) {
1754960Swillf 	return EINVAL;
1764960Swillf     }
1774960Swillf 
1784960Swillf     for (i = 0; (list[i] != NULL) && (i < MAX_LIST_ENTRIES); i++) {
1794960Swillf 	/* Restrict copying to max. length to avoid buffer overflow */
1804960Swillf 	snprintf (temp_str, MAX_DN_CHARS, "cn=%s,%s", list[i], krbcontainer_loc);
1814960Swillf 
1824960Swillf 	/* Make copy of string to temporary node */
1834960Swillf 	temp_node = strdup(temp_str);
1844960Swillf 	if (list[i] == NULL) {
1854960Swillf 	    retval = ENOMEM;
1864960Swillf 	    goto cleanup;
1874960Swillf 	}
1884960Swillf 
1894960Swillf 	/* On success, free list node and attach new one */
1904960Swillf 	free (list[i]);
1914960Swillf 	list[i] = temp_node;
1924960Swillf 	temp_node = NULL;
1934960Swillf     }
1944960Swillf 
1954960Swillf cleanup:
1964960Swillf     return retval;
1974960Swillf }
1984960Swillf 
1994960Swillf 
2004960Swillf /*
2014960Swillf  * This function will create a service object on the LDAP Server, with the
2024960Swillf  * specified attributes.
2034960Swillf  */
kdb5_ldap_create_service(argc,argv)2044960Swillf void kdb5_ldap_create_service(argc, argv)
2054960Swillf     int argc;
2064960Swillf     char *argv[];
2074960Swillf {
208*8092SMark.Phalan@Sun.COM     /* Solaris Kerberos */
209*8092SMark.Phalan@Sun.COM     char *me = progname;
2104960Swillf     krb5_error_code retval = 0;
2114960Swillf     krb5_ldap_service_params *srvparams = NULL;
2124960Swillf     krb5_boolean print_usage = FALSE;
2134960Swillf     krb5_boolean no_msg = FALSE;
2144960Swillf     int mask = 0;
2154960Swillf     char **extra_argv = NULL;
2164960Swillf     int extra_argc = 0;
2174960Swillf     int i = 0;
2184960Swillf     krb5_ldap_realm_params *rparams = NULL;
2194960Swillf     int rmask = 0;
2204960Swillf     int rightsmask =0;
2214960Swillf     char **temprdns = NULL;
2224960Swillf     char *realmName = NULL;
2234960Swillf     kdb5_dal_handle *dal_handle = NULL;
2244960Swillf     krb5_ldap_context *ldap_context=NULL;
2254960Swillf     krb5_boolean service_obj_created = FALSE;
2264960Swillf 
2274960Swillf     /* Check for number of arguments */
2284960Swillf     if ((argc < 3) || (argc > 10)) {
2294960Swillf 	exit_status++;
2304960Swillf 	goto err_usage;
2314960Swillf     }
2324960Swillf 
2334960Swillf     /* Allocate memory for service parameters structure */
2344960Swillf     srvparams = (krb5_ldap_service_params*) calloc(1, sizeof(krb5_ldap_service_params));
2354960Swillf     if (srvparams == NULL) {
2364960Swillf 	retval = ENOMEM;
2374960Swillf 	goto cleanup;
2384960Swillf     }
2394960Swillf 
2404960Swillf     dal_handle = (kdb5_dal_handle *) util_context->db_context;
2414960Swillf     ldap_context = (krb5_ldap_context *) dal_handle->db_context;
2424960Swillf 
2434960Swillf     /* Allocate memory for extra arguments to be used for setting
2444960Swillf        password -- it's OK to allocate as much as the total number
2454960Swillf        of arguments */
2464960Swillf     extra_argv = (char **) calloc((unsigned int)argc, sizeof(char*));
2474960Swillf     if (extra_argv == NULL) {
2484960Swillf 	retval = ENOMEM;
2494960Swillf 	goto cleanup;
2504960Swillf     }
2514960Swillf 
2524960Swillf     /* Set first of the extra arguments as the program name */
2534960Swillf     extra_argv[0] = me;
2544960Swillf     extra_argc++;
2554960Swillf 
2564960Swillf     /* Read Kerberos container info, to construct realm DN from name
2574960Swillf      * and for assigning rights
2584960Swillf      */
2594960Swillf     if ((retval = krb5_ldap_read_krbcontainer_params(util_context,
2604960Swillf 						     &(ldap_context->krbcontainer)))) {
2614960Swillf 	com_err(me, retval, gettext("while reading Kerberos container information"));
2624960Swillf 	goto cleanup;
2634960Swillf     }
2644960Swillf 
2654960Swillf     /* Parse all arguments */
2664960Swillf     for (i = 1; i < argc; i++) {
2674960Swillf 	if (!strcmp(argv[i], "-kdc")) {
2684960Swillf 	    srvparams->servicetype = LDAP_KDC_SERVICE;
2694960Swillf 	} else if (!strcmp(argv[i], "-admin")) {
2704960Swillf 	    srvparams->servicetype = LDAP_ADMIN_SERVICE;
2714960Swillf 	} else if (!strcmp(argv[i], "-pwd")) {
2724960Swillf 	    srvparams->servicetype = LDAP_PASSWD_SERVICE;
2734960Swillf 	} else if (!strcmp(argv[i], "-servicehost")) {
2744960Swillf 	    if (++i > argc - 1)
2754960Swillf 		goto err_usage;
2764960Swillf 
2774960Swillf 	    srvparams->krbhostservers = (char **)calloc(MAX_LIST_ENTRIES,
2784960Swillf 							sizeof(char *));
2794960Swillf 	    if (srvparams->krbhostservers == NULL) {
2804960Swillf 		retval = ENOMEM;
2814960Swillf 		goto cleanup;
2824960Swillf 	    }
2834960Swillf 
2844960Swillf 	    if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER,
2854960Swillf 					  srvparams->krbhostservers))) {
2864960Swillf 		goto cleanup;
2874960Swillf 	    }
2884960Swillf 
2894960Swillf 	    if ((retval = process_host_list (srvparams->krbhostservers,
2904960Swillf 					     srvparams->servicetype))) {
2914960Swillf 		goto cleanup;
2924960Swillf 	    }
2934960Swillf 
2944960Swillf 	    mask |= LDAP_SERVICE_HOSTSERVER;
2954960Swillf 	} else if (!strcmp(argv[i], "-realm")) {
2964960Swillf 	    if (++i > argc - 1)
2974960Swillf 		goto err_usage;
2984960Swillf 
2994960Swillf 	    srvparams->krbrealmreferences = (char **)calloc(MAX_LIST_ENTRIES,
3004960Swillf 							    sizeof(char *));
3014960Swillf 	    if (srvparams->krbrealmreferences == NULL) {
3024960Swillf 		retval = ENOMEM;
3034960Swillf 		goto cleanup;
3044960Swillf 	    }
3054960Swillf 
3064960Swillf 	    if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER,
3074960Swillf 					  srvparams->krbrealmreferences))) {
3084960Swillf 		goto cleanup;
3094960Swillf 	    }
3104960Swillf 
3114960Swillf 	    /* Convert realm names to realm DNs */
3124960Swillf 	    if ((retval = convert_realm_name2dn_list(
3134960Swillf 		     srvparams->krbrealmreferences,
3144960Swillf 		     ldap_context->krbcontainer->DN))) {
3154960Swillf 		goto cleanup;
3164960Swillf 	    }
3174960Swillf 
3184960Swillf 	    mask |= LDAP_SERVICE_REALMREFERENCE;
3194960Swillf 	}
3204960Swillf 	/* If argument is none of the above and beginning with '-',
3214960Swillf 	 * it must be related to password -- collect it
3224960Swillf 	 * to pass onto kdb5_ldap_set_service_password()
3234960Swillf 	 */
3244960Swillf 	else if (*(argv[i]) == '-') {
3254960Swillf 	    /* Checking for options of setting the password for the
3264960Swillf 	     * service (by using 'setsrvpw') is not modular. --need to
3274960Swillf 	     * have a common function that can be shared with 'setsrvpw'
3284960Swillf 	     */
3294960Swillf 	    if (!strcmp(argv[i], "-randpw")) {
3304960Swillf 		extra_argv[extra_argc] = argv[i];
3314960Swillf 		extra_argc++;
3324960Swillf 	    } else if (!strcmp(argv[i], "-fileonly")) {
3334960Swillf 		extra_argv[extra_argc] = argv[i];
3344960Swillf 		extra_argc++;
3354960Swillf 	    }
3364960Swillf 	    /* For '-f' option alone, pick up the following argument too */
3374960Swillf 	    else if (!strcmp(argv[i], "-f")) {
3384960Swillf 		extra_argv[extra_argc] = argv[i];
3394960Swillf 		extra_argc++;
3404960Swillf 
3414960Swillf 		if (++i > argc - 1)
3424960Swillf 		    goto err_usage;
3434960Swillf 
3444960Swillf 		extra_argv[extra_argc] = argv[i];
3454960Swillf 		extra_argc++;
3464960Swillf 	    } else { /* Any other option is invalid */
3474960Swillf 		exit_status++;
3484960Swillf 		goto err_usage;
3494960Swillf 	    }
3504960Swillf 	} else { /* Any other argument must be service DN */
3514960Swillf 	    /* First check if service DN is already provided --
3524960Swillf 	     * if so, there's a usage error
3534960Swillf 	     */
3544960Swillf 	    if (srvparams->servicedn != NULL) {
3554960Swillf 		com_err(me, EINVAL, gettext("while creating service object"));
3564960Swillf 		goto err_usage;
3574960Swillf 	    }
3584960Swillf 
3594960Swillf 	    /* If not present already, fill up service DN */
3604960Swillf 	    srvparams->servicedn = strdup(argv[i]);
3614960Swillf 	    if (srvparams->servicedn == NULL) {
3624960Swillf 		com_err(me, ENOMEM, gettext("while creating service object"));
3634960Swillf 		goto err_nomsg;
3644960Swillf 	    }
3654960Swillf 	}
3664960Swillf     }
3674960Swillf 
3684960Swillf     /* No point in proceeding further if service DN value is not available */
3694960Swillf     if (srvparams->servicedn == NULL) {
3704960Swillf 	com_err(me, EINVAL, gettext("while creating service object"));
3714960Swillf 	goto err_usage;
3724960Swillf     }
3734960Swillf 
3744960Swillf     if (srvparams->servicetype == 0) { /* Not provided and hence not set */
3754960Swillf 	com_err(me, EINVAL, gettext("while creating service object"));
3764960Swillf 	goto err_usage;
3774960Swillf     }
3784960Swillf 
3794960Swillf     /* Create object with all attributes provided */
3804960Swillf     if ((retval = krb5_ldap_create_service(util_context, srvparams, mask)))
3814960Swillf 	goto cleanup;
3824960Swillf 
3834960Swillf     service_obj_created = TRUE;
3844960Swillf 
3854960Swillf     /* ** NOTE ** srvparams structure should not be modified, as it is
3864960Swillf      * used for deletion of the service object in case of any failures
3874960Swillf      * from now on.
3884960Swillf      */
3894960Swillf 
3904960Swillf     /* Set password too */
3914960Swillf     if (extra_argc >= 1) {
3924960Swillf 	/* Set service DN as the last argument */
3934960Swillf 	extra_argv[extra_argc] = strdup(srvparams->servicedn);
3944960Swillf 	if (extra_argv[extra_argc] == NULL) {
3954960Swillf             retval = ENOMEM;
3964960Swillf             goto cleanup;
3974960Swillf         }
3984960Swillf 	extra_argc++;
3994960Swillf 
4004960Swillf 	if ((retval = kdb5_ldap_set_service_password(extra_argc, extra_argv)) != 0) {
4014960Swillf 	    goto err_nomsg;
4024960Swillf 	}
4034960Swillf     }
4044960Swillf     /* Rights assignment */
4054960Swillf     if (mask & LDAP_SERVICE_REALMREFERENCE) {
4064960Swillf 
4074960Swillf 	printf("%s", gettext("Changing rights for the service object. Please wait ... "));
4084960Swillf 	fflush(stdout);
4094960Swillf 
4104960Swillf 	rightsmask =0;
4114960Swillf 	rightsmask |= LDAP_REALM_RIGHTS;
4124960Swillf 	rightsmask |= LDAP_SUBTREE_RIGHTS;
4134960Swillf 
4144960Swillf 	if ((srvparams != NULL) && (srvparams->krbrealmreferences != NULL)) {
4154960Swillf 	    for (i=0; (srvparams->krbrealmreferences[i] != NULL); i++) {
4164960Swillf 
4174960Swillf 		/* Get the realm name, not the dn */
4184960Swillf 		temprdns = ldap_explode_dn(srvparams->krbrealmreferences[i], 1);
4194960Swillf 
4204960Swillf 		if (temprdns[0] == NULL) {
4214960Swillf 		    retval = EINVAL;
4224960Swillf 		    goto cleanup;
4234960Swillf 		}
4244960Swillf 
4254960Swillf 		realmName = strdup(temprdns[0]);
4264960Swillf 		if (realmName == NULL) {
4274960Swillf 		    retval = ENOMEM;
4284960Swillf 		    goto cleanup;
4294960Swillf 		}
4304960Swillf 
4314960Swillf 		if ((retval = krb5_ldap_read_realm_params(util_context,
4324960Swillf 							  realmName, &rparams, &rmask))) {
4334960Swillf 		    com_err(me, retval, gettext("while reading information of realm '%s'"),
4344960Swillf 			    realmName);
4354960Swillf 		    goto cleanup;
4364960Swillf 		}
4374960Swillf 
4384960Swillf 		if ((retval = krb5_ldap_add_service_rights(util_context,
4394960Swillf 							   srvparams->servicetype, srvparams->servicedn,
4404960Swillf 							   realmName, rparams->subtree, rightsmask))) {
4414960Swillf 		    printf(gettext("failed\n"));
4424960Swillf 		    com_err(me, retval, gettext("while assigning rights '%s'"),
4434960Swillf 			    srvparams->servicedn);
4444960Swillf 		    goto cleanup;
4454960Swillf 		}
4464960Swillf 
4474960Swillf 		if (rparams)
4484960Swillf 		    krb5_ldap_free_realm_params(rparams);
4494960Swillf 	    }
4504960Swillf 	}
4514960Swillf 	printf(gettext("done\n"));
4524960Swillf     }
4534960Swillf     goto cleanup;
4544960Swillf 
4554960Swillf err_usage:
4564960Swillf     print_usage = TRUE;
4574960Swillf 
4584960Swillf err_nomsg:
4594960Swillf     no_msg = TRUE;
4604960Swillf 
4614960Swillf cleanup:
4624960Swillf 
4634960Swillf     if ((retval != 0) && (service_obj_created == TRUE)) {
4644960Swillf 	/* This is for deleting the service object if something goes
4654960Swillf 	 * wrong in creating the service object
4664960Swillf 	 */
4674960Swillf 
4684960Swillf 	/* srvparams is populated from the user input and should be correct as
4694960Swillf 	 * we were successful in creating a service object. Reusing the same
4704960Swillf 	 */
4714960Swillf 	krb5_ldap_delete_service(util_context, srvparams, srvparams->servicedn);
4724960Swillf     }
4734960Swillf 
4744960Swillf     /* Clean-up structure */
4754960Swillf     krb5_ldap_free_service (util_context, srvparams);
4764960Swillf 
4774960Swillf     if (extra_argv) {
4784960Swillf 	free (extra_argv);
4794960Swillf 	extra_argv = NULL;
4804960Swillf     }
4814960Swillf     if (realmName) {
4824960Swillf 	free(realmName);
4834960Swillf 	realmName = NULL;
4844960Swillf     }
4854960Swillf     if (print_usage)
4864960Swillf 	db_usage (CREATE_SERVICE);
4874960Swillf 
4884960Swillf     if (retval) {
4894960Swillf 	if (!no_msg)
4904960Swillf 	    com_err(me, retval, gettext("while creating service object"));
4914960Swillf 
4924960Swillf 	exit_status++;
4934960Swillf     }
4944960Swillf 
4954960Swillf     return;
4964960Swillf }
4974960Swillf 
4984960Swillf 
4994960Swillf /*
5004960Swillf  * This function will modify the attributes of a given service
5014960Swillf  * object on the LDAP Server
5024960Swillf  */
kdb5_ldap_modify_service(argc,argv)5034960Swillf void kdb5_ldap_modify_service(argc, argv)
5044960Swillf     int argc;
5054960Swillf     char *argv[];
5064960Swillf {
507*8092SMark.Phalan@Sun.COM     /* Solaris Kerberos */
508*8092SMark.Phalan@Sun.COM     char *me = progname;
5094960Swillf     krb5_error_code retval = 0;
5104960Swillf     krb5_ldap_service_params *srvparams = NULL;
5114960Swillf     krb5_boolean print_usage = FALSE;
5124960Swillf     krb5_boolean no_msg = FALSE;
5134960Swillf     char *servicedn = NULL;
5144960Swillf     int i = 0;
5154960Swillf     int in_mask = 0, out_mask = 0;
5164960Swillf     int srvhost_flag = 0, realmdn_flag = 0;
5174960Swillf     char **list = NULL;
5184960Swillf     int existing_entries = 0, new_entries = 0;
5194960Swillf     char **temp_ptr = NULL;
5204960Swillf     krb5_ldap_realm_params *rparams = NULL;
5214960Swillf     int j = 0;
5224960Swillf     int rmask = 0;
5234960Swillf     int rightsmask =0;
5244960Swillf     char **oldrealmrefs = NULL;
5254960Swillf     char **newrealmrefs = NULL;
5264960Swillf     char **temprdns = NULL;
5274960Swillf     char *realmName = NULL;
5284960Swillf     kdb5_dal_handle *dal_handle = NULL;
5294960Swillf     krb5_ldap_context *ldap_context=NULL;
5304960Swillf 
5314960Swillf     /* Check for number of arguments */
5324960Swillf     if ((argc < 3) || (argc > 10)) {
5334960Swillf 	exit_status++;
5344960Swillf 	goto err_usage;
5354960Swillf     }
5364960Swillf 
5374960Swillf     dal_handle = (kdb5_dal_handle *) util_context->db_context;
5384960Swillf     ldap_context = (krb5_ldap_context *) dal_handle->db_context;
5394960Swillf 
5404960Swillf     /* Parse all arguments, only to pick up service DN (Pass 1) */
5414960Swillf     for (i = 1; i < argc; i++) {
5424960Swillf 	/* Skip arguments next to 'servicehost'
5434960Swillf 	   and 'realmdn' arguments */
5444960Swillf 	if (!strcmp(argv[i], "-servicehost")) {
5454960Swillf 	    ++i;
5464960Swillf 	} else if (!strcmp(argv[i], "-clearservicehost")) {
5474960Swillf 	    ++i;
5484960Swillf 	} else if (!strcmp(argv[i], "-addservicehost")) {
5494960Swillf 	    ++i;
5504960Swillf 	} else if (!strcmp(argv[i], "-realm")) {
5514960Swillf 	    ++i;
5524960Swillf 	} else if (!strcmp(argv[i], "-clearrealm")) {
5534960Swillf 	    ++i;
5544960Swillf 	} else if (!strcmp(argv[i], "-addrealm")) {
5554960Swillf 	    ++i;
5564960Swillf 	} else { /* Any other argument must be service DN */
5574960Swillf 	    /* First check if service DN is already provided --
5584960Swillf 	       if so, there's a usage error */
5594960Swillf 	    if (servicedn != NULL) {
5604960Swillf 		com_err(me, EINVAL, gettext("while modifying service object"));
5614960Swillf 		goto err_usage;
5624960Swillf 	    }
5634960Swillf 
5644960Swillf 	    /* If not present already, fill up service DN */
5654960Swillf 	    servicedn = strdup(argv[i]);
5664960Swillf 	    if (servicedn == NULL) {
5674960Swillf 		com_err(me, ENOMEM, gettext("while modifying service object"));
5684960Swillf 		goto err_nomsg;
5694960Swillf 	    }
5704960Swillf 	}
5714960Swillf     }
5724960Swillf 
5734960Swillf     /* No point in proceeding further if service DN value is not available */
5744960Swillf     if (servicedn == NULL) {
5754960Swillf 	com_err(me, EINVAL, gettext("while modifying service object"));
5764960Swillf 	goto err_usage;
5774960Swillf     }
5784960Swillf 
5794960Swillf     retval = krb5_ldap_read_service(util_context, servicedn, &srvparams, &in_mask);
5804960Swillf     if (retval) {
581*8092SMark.Phalan@Sun.COM 	/* Solaris Kerberos */
582*8092SMark.Phalan@Sun.COM 	com_err(me, retval, gettext("while reading information of service '%s'"),
5834960Swillf 		servicedn);
5844960Swillf 	goto err_nomsg;
5854960Swillf     }
5864960Swillf 
5874960Swillf     /* Read Kerberos container info, to construct realm DN from name
5884960Swillf      * and for assigning rights
5894960Swillf      */
5904960Swillf     if ((retval = krb5_ldap_read_krbcontainer_params(util_context,
5914960Swillf 						     &(ldap_context->krbcontainer)))) {
5924960Swillf 	com_err(me, retval, gettext("while reading Kerberos container information"));
5934960Swillf 	goto cleanup;
5944960Swillf     }
5954960Swillf 
5964960Swillf     /* Parse all arguments, but skip the service DN (Pass 2) */
5974960Swillf     for (i = 1; i < argc; i++) {
5984960Swillf 	if (!strcmp(argv[i], "-servicehost")) {
5994960Swillf 	    if (++i > argc - 1)
6004960Swillf 		goto err_usage;
6014960Swillf 
6024960Swillf 	    /* Free the old list if available */
6034960Swillf 	    if (srvparams->krbhostservers) {
6044960Swillf 		krb5_free_list_entries (srvparams->krbhostservers);
6054960Swillf 		free (srvparams->krbhostservers);
6064960Swillf 	    }
6074960Swillf 
6084960Swillf 	    srvparams->krbhostservers = (char **)calloc(MAX_LIST_ENTRIES,
6094960Swillf 							sizeof(char *));
6104960Swillf 	    if (srvparams->krbhostservers == NULL) {
6114960Swillf 		retval = ENOMEM;
6124960Swillf 		goto cleanup;
6134960Swillf 	    }
6144960Swillf 
6154960Swillf 	    if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER,
6164960Swillf 					  srvparams->krbhostservers))) {
6174960Swillf 		goto cleanup;
6184960Swillf 	    }
6194960Swillf 
6204960Swillf 	    if ((retval = process_host_list (srvparams->krbhostservers,
6214960Swillf 					     srvparams->servicetype))) {
6224960Swillf 		goto cleanup;
6234960Swillf 	    }
6244960Swillf 
6254960Swillf 	    out_mask |= LDAP_SERVICE_HOSTSERVER;
6264960Swillf 
6274960Swillf 	    /* Set flag to ignore 'add' and 'clear' */
6284960Swillf 	    srvhost_flag = 1;
6294960Swillf 	} else if (!strcmp(argv[i], "-clearservicehost")) {
6304960Swillf 	    if (++i > argc - 1)
6314960Swillf 		goto err_usage;
6324960Swillf 
6334960Swillf 	    if (!srvhost_flag) {
6344960Swillf 		/* If attribute doesn't exist, don't permit 'clear' option */
6354960Swillf 		if ((in_mask & LDAP_SERVICE_HOSTSERVER) == 0) {
6364960Swillf 		    /* Send out some proper error message here */
6374960Swillf 		    com_err(me, EINVAL, gettext("service host list is empty\n"));
6384960Swillf 		    goto err_nomsg;
6394960Swillf 		}
6404960Swillf 
6414960Swillf 		/* Allocate list for processing */
6424960Swillf 		list = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
6434960Swillf 		if (list == NULL) {
6444960Swillf 		    retval = ENOMEM;
6454960Swillf 		    goto cleanup;
6464960Swillf 		}
6474960Swillf 
6484960Swillf 		if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list)))
6494960Swillf 		    goto cleanup;
6504960Swillf 
6514960Swillf 		if ((retval = process_host_list (list, srvparams->servicetype))) {
6524960Swillf 		    goto cleanup;
6534960Swillf 		}
6544960Swillf 
6554960Swillf 		list_modify_str_array(&(srvparams->krbhostservers),
6564960Swillf 				      (const char**)list, LIST_MODE_DELETE);
6574960Swillf 
6584960Swillf 		out_mask |= LDAP_SERVICE_HOSTSERVER;
6594960Swillf 
6604960Swillf 		/* Clean up */
6614960Swillf 		free (list);
6624960Swillf 		list = NULL;
6634960Swillf 	    }
6644960Swillf 	} else if (!strcmp(argv[i], "-addservicehost")) {
6654960Swillf 	    if (++i > argc - 1)
6664960Swillf 		goto err_usage;
6674960Swillf 
6684960Swillf 	    if (!srvhost_flag) {
6694960Swillf 		/* Allocate list for processing */
6704960Swillf 		list = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
6714960Swillf 		if (list == NULL) {
6724960Swillf 		    retval = ENOMEM;
6734960Swillf 		    goto cleanup;
6744960Swillf 		}
6754960Swillf 
6764960Swillf 		if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list)))
6774960Swillf 		    goto cleanup;
6784960Swillf 
6794960Swillf 		if ((retval = process_host_list (list, srvparams->servicetype))) {
6804960Swillf 		    goto cleanup;
6814960Swillf 		}
6824960Swillf 
6834960Swillf 		/* Call list_modify_str_array() only if host server attribute
6844960Swillf 		 * exists already --Actually, it's better to handle this
6854960Swillf 		 * within list_modify_str_array()
6864960Swillf 		 */
6874960Swillf 		if (in_mask & LDAP_SERVICE_HOSTSERVER) {
6884960Swillf 		    /* Re-size existing list */
6894960Swillf 		    existing_entries = list_count_str_array(srvparams->krbhostservers);
6904960Swillf 		    new_entries = list_count_str_array(list);
6914960Swillf 		    temp_ptr = (char **) realloc(srvparams->krbhostservers,
6924960Swillf 						 sizeof(char *) * (existing_entries + new_entries + 1));
6934960Swillf 		    if (temp_ptr == NULL) {
6944960Swillf 			retval = ENOMEM;
6954960Swillf 			goto cleanup;
6964960Swillf 		    }
6974960Swillf 		    srvparams->krbhostservers = temp_ptr;
6984960Swillf 
6994960Swillf 		    list_modify_str_array(&(srvparams->krbhostservers),
7004960Swillf 					  (const char**)list, LIST_MODE_ADD);
7014960Swillf 
7024960Swillf 		    /* Clean up */
7034960Swillf 		    free (list);
7044960Swillf 		    list = NULL;
7054960Swillf 		} else
7064960Swillf 		    srvparams->krbhostservers = list;
7074960Swillf 
7084960Swillf 		out_mask |= LDAP_SERVICE_HOSTSERVER;
7094960Swillf 	    }
7104960Swillf 	} else if (!strcmp(argv[i], "-realm")) {
7114960Swillf 	    if (++i > argc - 1)
7124960Swillf 		goto err_usage;
7134960Swillf 
7144960Swillf 	    if ((in_mask & LDAP_SERVICE_REALMREFERENCE) && (srvparams->krbrealmreferences)) {
7154960Swillf 		if (!oldrealmrefs) {
7164960Swillf 		    /* Store the old realm list for removing rights */
7174960Swillf 		    oldrealmrefs = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
7184960Swillf 		    if (oldrealmrefs == NULL) {
7194960Swillf 			retval = ENOMEM;
7204960Swillf 			goto cleanup;
7214960Swillf 		    }
7224960Swillf 
7234960Swillf 		    for (j = 0; srvparams->krbrealmreferences[j] != NULL; j++) {
7244960Swillf 			oldrealmrefs[j] = strdup(srvparams->krbrealmreferences[j]);
7254960Swillf 			if (oldrealmrefs[j] == NULL) {
7264960Swillf 			    retval = ENOMEM;
7274960Swillf 			    goto cleanup;
7284960Swillf 			}
7294960Swillf 		    }
7304960Swillf 		    oldrealmrefs[j] = NULL;
7314960Swillf 		}
7324960Swillf 
7334960Swillf 		/* Free the old list if available */
7344960Swillf 		krb5_free_list_entries (srvparams->krbrealmreferences);
7354960Swillf 		free (srvparams->krbrealmreferences);
7364960Swillf 	    }
7374960Swillf 
7384960Swillf 	    srvparams->krbrealmreferences = (char **)calloc(MAX_LIST_ENTRIES,
7394960Swillf 							    sizeof(char *));
7404960Swillf 	    if (srvparams->krbrealmreferences == NULL) {
7414960Swillf 		retval = ENOMEM;
7424960Swillf 		goto cleanup;
7434960Swillf 	    }
7444960Swillf 
7454960Swillf 	    if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER,
7464960Swillf 					  srvparams->krbrealmreferences))) {
7474960Swillf 		goto cleanup;
7484960Swillf 	    }
7494960Swillf 
7504960Swillf 	    /* Convert realm names to realm DNs */
7514960Swillf 	    if ((retval = convert_realm_name2dn_list(
7524960Swillf 		     srvparams->krbrealmreferences,
7534960Swillf 		     ldap_context->krbcontainer->DN))) {
7544960Swillf 		goto cleanup;
7554960Swillf 	    }
7564960Swillf 
7574960Swillf 	    out_mask |= LDAP_SERVICE_REALMREFERENCE;
7584960Swillf 
7594960Swillf 	    /* Set flag to ignore 'add' and 'clear' */
7604960Swillf 	    realmdn_flag = 1;
7614960Swillf 	} else if (!strcmp(argv[i], "-clearrealm")) {
7624960Swillf 	    if (++i > argc - 1)
7634960Swillf 		goto err_usage;
7644960Swillf 
7654960Swillf 	    if (!realmdn_flag) {
7664960Swillf 		/* If attribute doesn't exist, don't permit 'clear' option */
7674960Swillf 		if (((in_mask & LDAP_SERVICE_REALMREFERENCE) == 0) || (srvparams->krbrealmreferences == NULL)) {
7684960Swillf 		    /* Send out some proper error message here */
7694960Swillf 		    goto err_nomsg;
7704960Swillf 		}
7714960Swillf 
7724960Swillf 		if (!oldrealmrefs) {
7734960Swillf 		    /* Store the old realm list for removing rights */
7744960Swillf 		    oldrealmrefs = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
7754960Swillf 		    if (oldrealmrefs == NULL) {
7764960Swillf 			retval = ENOMEM;
7774960Swillf 			goto cleanup;
7784960Swillf 		    }
7794960Swillf 
7804960Swillf 		    for (j = 0; srvparams->krbrealmreferences[j] != NULL; j++) {
7814960Swillf 			oldrealmrefs[j] = strdup(srvparams->krbrealmreferences[j]);
7824960Swillf 			if (oldrealmrefs[j] == NULL) {
7834960Swillf 			    retval = ENOMEM;
7844960Swillf 			    goto cleanup;
7854960Swillf 			}
7864960Swillf 		    }
7874960Swillf 		    oldrealmrefs[j] = NULL;
7884960Swillf 		}
7894960Swillf 
7904960Swillf 		/* Allocate list for processing */
7914960Swillf 		list = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
7924960Swillf 		if (list == NULL) {
7934960Swillf 		    retval = ENOMEM;
7944960Swillf 		    goto cleanup;
7954960Swillf 		}
7964960Swillf 
7974960Swillf 		if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list)))
7984960Swillf 		    goto cleanup;
7994960Swillf 
8004960Swillf 		/* Convert realm names to realm DNs */
8014960Swillf 		if ((retval = convert_realm_name2dn_list(list,
8024960Swillf 							 ldap_context->krbcontainer->DN))) {
8034960Swillf 		    goto cleanup;
8044960Swillf 		}
8054960Swillf 
8064960Swillf 		list_modify_str_array(&(srvparams->krbrealmreferences),
8074960Swillf 				      (const char**)list, LIST_MODE_DELETE);
8084960Swillf 
8094960Swillf 		out_mask |= LDAP_SERVICE_REALMREFERENCE;
8104960Swillf 
8114960Swillf 		/* Clean up */
8124960Swillf 		free (list);
8134960Swillf 		list = NULL;
8144960Swillf 	    }
8154960Swillf 	} else if (!strcmp(argv[i], "-addrealm")) {
8164960Swillf 	    if (++i > argc - 1)
8174960Swillf 		goto err_usage;
8184960Swillf 
8194960Swillf 	    if (!realmdn_flag) {
8204960Swillf 		/* Allocate list for processing */
8214960Swillf 		list = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
8224960Swillf 		if (list == NULL) {
8234960Swillf 		    retval = ENOMEM;
8244960Swillf 		    goto cleanup;
8254960Swillf 		}
8264960Swillf 
8274960Swillf 		if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list)))
8284960Swillf 		    goto cleanup;
8294960Swillf 
8304960Swillf 		/* Convert realm names to realm DNs */
8314960Swillf 		if ((retval = convert_realm_name2dn_list(list,
8324960Swillf 							 ldap_context->krbcontainer->DN))) {
8334960Swillf 		    goto cleanup;
8344960Swillf 		}
8354960Swillf 
8364960Swillf 		if ((in_mask & LDAP_SERVICE_REALMREFERENCE) && (srvparams->krbrealmreferences) && (!oldrealmrefs)) {
8374960Swillf 		    /* Store the old realm list for removing rights */
8384960Swillf 		    oldrealmrefs = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
8394960Swillf 		    if (oldrealmrefs == NULL) {
8404960Swillf 			retval = ENOMEM;
8414960Swillf 			goto cleanup;
8424960Swillf 		    }
8434960Swillf 
8444960Swillf 		    for (j = 0; srvparams->krbrealmreferences[j] != NULL; j++) {
8454960Swillf 			oldrealmrefs[j] = strdup(srvparams->krbrealmreferences[j]);
8464960Swillf 			if (oldrealmrefs[j] == NULL) {
8474960Swillf 			    retval = ENOMEM;
8484960Swillf 			    goto cleanup;
8494960Swillf 			}
8504960Swillf 		    }
8514960Swillf 		    oldrealmrefs[j] = NULL;
8524960Swillf 		}
8534960Swillf 
8544960Swillf 		/* Call list_modify_str_array() only if realm DN attribute
8554960Swillf 		 * exists already -- Actually, it's better to handle this
8564960Swillf 		 * within list_modify_str_array() */
8574960Swillf 		if (in_mask & LDAP_SERVICE_REALMREFERENCE) {
8584960Swillf 		    /* Re-size existing list */
8594960Swillf 		    existing_entries = list_count_str_array(
8604960Swillf 			srvparams->krbrealmreferences);
8614960Swillf 		    new_entries = list_count_str_array(list);
8624960Swillf 		    temp_ptr = (char **) realloc(srvparams->krbrealmreferences,
8634960Swillf 						 sizeof(char *) * (existing_entries + new_entries + 1));
8644960Swillf 		    if (temp_ptr == NULL) {
8654960Swillf 			retval = ENOMEM;
8664960Swillf 			goto cleanup;
8674960Swillf 		    }
8684960Swillf 		    srvparams->krbrealmreferences = temp_ptr;
8694960Swillf 
8704960Swillf 		    list_modify_str_array(&(srvparams->krbrealmreferences),
8714960Swillf 					  (const char**)list, LIST_MODE_ADD);
8724960Swillf 
8734960Swillf 		    /* Clean up */
8744960Swillf 		    free (list);
8754960Swillf 		    list = NULL;
8764960Swillf 		} else
8774960Swillf 		    srvparams->krbrealmreferences = list;
8784960Swillf 
8794960Swillf 		out_mask |= LDAP_SERVICE_REALMREFERENCE;
8804960Swillf 	    }
8814960Swillf 	} else {
8824960Swillf 	    /* Any other argument must be service DN
8834960Swillf 	       -- skip it */
8844960Swillf 	}
8854960Swillf     }
8864960Swillf 
8874960Swillf     /* Modify attributes of object */
8884960Swillf     if ((retval = krb5_ldap_modify_service(util_context, srvparams, out_mask)))
8894960Swillf 	goto cleanup;
8904960Swillf 
8914960Swillf     /* Service rights modification code */
8924960Swillf     if (out_mask & LDAP_SERVICE_REALMREFERENCE) {
8934960Swillf 
8944960Swillf 	printf("%s", gettext("Changing rights for the service object. Please wait ... "));
8954960Swillf 	fflush(stdout);
8964960Swillf 
8974960Swillf 	newrealmrefs = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
8984960Swillf 	if (newrealmrefs == NULL) {
8994960Swillf 	    retval = ENOMEM;
9004960Swillf 	    goto cleanup;
9014960Swillf 	}
9024960Swillf 
9034960Swillf 	if ((srvparams != NULL) && (srvparams->krbrealmreferences != NULL)) {
9044960Swillf 	    for (j = 0; srvparams->krbrealmreferences[j] != NULL; j++) {
9054960Swillf 		newrealmrefs[j] = strdup(srvparams->krbrealmreferences[j]);
9064960Swillf 		if (newrealmrefs[j] == NULL) {
9074960Swillf 		    retval = ENOMEM;
9084960Swillf 		    goto cleanup;
9094960Swillf 		}
9104960Swillf 	    }
9114960Swillf 	    newrealmrefs[j] = NULL;
9124960Swillf 	}
9134960Swillf 	disjoint_members(oldrealmrefs, newrealmrefs);
9144960Swillf 
9154960Swillf 	/* Delete the rights for the given service, on each of the realm
9164960Swillf 	 * container & subtree in the old realm reference list.
9174960Swillf 	 */
9184960Swillf 	if (oldrealmrefs) {
9194960Swillf 	    rightsmask = 0;
9204960Swillf 	    rightsmask |= LDAP_REALM_RIGHTS;
9214960Swillf 	    rightsmask |= LDAP_SUBTREE_RIGHTS;
9224960Swillf 
9234960Swillf 	    for (i = 0; (oldrealmrefs[i] != NULL); i++) {
9244960Swillf 		/* Get the realm name, not the dn */
9254960Swillf 		temprdns = ldap_explode_dn(oldrealmrefs[i], 1);
9264960Swillf 
9274960Swillf 		if (temprdns[0] == NULL) {
9284960Swillf 		    retval = EINVAL;
9294960Swillf 		    goto cleanup;
9304960Swillf 		}
9314960Swillf 
9324960Swillf 		realmName = strdup(temprdns[0]);
9334960Swillf 		if (realmName == NULL) {
9344960Swillf 		    retval = ENOMEM;
9354960Swillf 		    goto cleanup;
9364960Swillf 		}
9374960Swillf 
9384960Swillf 		if ((retval = krb5_ldap_read_realm_params(util_context,
9394960Swillf 							  realmName, &rparams, &rmask))) {
9404960Swillf 		    com_err(me, retval, gettext("while reading information of realm '%s'"),
9414960Swillf 			    realmName);
9424960Swillf 		    goto err_nomsg;
9434960Swillf 		}
9444960Swillf 
9454960Swillf 		if ((retval = krb5_ldap_delete_service_rights(util_context,
9464960Swillf 							      srvparams->servicetype, srvparams->servicedn,
9474960Swillf 							      realmName, rparams->subtree, rightsmask))) {
9484960Swillf 		    printf(gettext("failed\n"));
9494960Swillf 		    com_err(me, retval, gettext("while assigning rights '%s'"),
9504960Swillf 			    srvparams->servicedn);
9514960Swillf 		    goto err_nomsg;
9524960Swillf 		}
9534960Swillf 
9544960Swillf 		if (rparams)
9554960Swillf 		    krb5_ldap_free_realm_params(rparams);
9564960Swillf 	    }
9574960Swillf 	}
9584960Swillf 
9594960Swillf 	/* Add the rights for the given service, on each of the realm
9604960Swillf 	 * container & subtree in the new realm reference list.
9614960Swillf 	 */
9624960Swillf 	if (newrealmrefs) {
9634960Swillf 	    rightsmask = 0;
9644960Swillf 	    rightsmask |= LDAP_REALM_RIGHTS;
9654960Swillf 	    rightsmask |= LDAP_SUBTREE_RIGHTS;
9664960Swillf 
9674960Swillf 	    for (i = 0; (newrealmrefs[i] != NULL); i++) {
9684960Swillf 		/* Get the realm name, not the dn */
9694960Swillf 		temprdns = ldap_explode_dn(newrealmrefs[i], 1);
9704960Swillf 
9714960Swillf 		if (temprdns[0] == NULL) {
9724960Swillf 		    retval = EINVAL;
9734960Swillf 		    goto cleanup;
9744960Swillf 		}
9754960Swillf 
9764960Swillf 		realmName = strdup(temprdns[0]);
9774960Swillf 		if (realmName == NULL) {
9784960Swillf 		    retval = ENOMEM;
9794960Swillf 		    goto cleanup;
9804960Swillf 		}
9814960Swillf 
9824960Swillf 		if ((retval = krb5_ldap_read_krbcontainer_params(util_context,
9834960Swillf 								 &(ldap_context->krbcontainer)))) {
9844960Swillf 		    com_err(me, retval,
9854960Swillf 			    gettext("while reading Kerberos container information"));
9864960Swillf 		    goto cleanup;
9874960Swillf 		}
9884960Swillf 
9894960Swillf 		if ((retval = krb5_ldap_read_realm_params(util_context,
9904960Swillf 							  realmName, &rparams, &rmask))) {
9914960Swillf 		    com_err(me, retval, gettext("while reading information of realm '%s'"),
9924960Swillf 			    realmName);
9934960Swillf 		    goto err_nomsg;
9944960Swillf 		}
9954960Swillf 
9964960Swillf 		if ((retval = krb5_ldap_add_service_rights(util_context,
9974960Swillf 							   srvparams->servicetype, srvparams->servicedn,
9984960Swillf 							   realmName, rparams->subtree, rightsmask))) {
9994960Swillf 		    printf(gettext("failed\n"));
10004960Swillf 		    com_err(me, retval, gettext("while assigning rights '%s'"),
10014960Swillf 			    srvparams->servicedn);
10024960Swillf 		    goto err_nomsg;
10034960Swillf 		}
10044960Swillf 
10054960Swillf 		if (rparams) {
10064960Swillf 		    krb5_ldap_free_realm_params(rparams);
10074960Swillf 		    rparams = NULL;
10084960Swillf 		}
10094960Swillf 	    }
10104960Swillf 	    printf(gettext("done\n"));
10114960Swillf 	}
10124960Swillf     }
10134960Swillf     goto cleanup;
10144960Swillf 
10154960Swillf err_usage:
10164960Swillf     print_usage = TRUE;
10174960Swillf 
10184960Swillf err_nomsg:
10194960Swillf     no_msg = TRUE;
10204960Swillf 
10214960Swillf cleanup:
10224960Swillf     /* Clean-up structure */
10234960Swillf     krb5_ldap_free_service(util_context, srvparams);
10244960Swillf 
10254960Swillf     if (servicedn)
10264960Swillf 	free(servicedn);
10274960Swillf 
10284960Swillf     if (list) {
10294960Swillf 	free(list);
10304960Swillf 	list = NULL;
10314960Swillf     }
10324960Swillf 
10334960Swillf     if (oldrealmrefs) {
10344960Swillf 	for (i = 0; oldrealmrefs[i] != NULL; i++)
10354960Swillf 	    free(oldrealmrefs[i]);
10364960Swillf 	free(oldrealmrefs);
10374960Swillf     }
10384960Swillf 
10394960Swillf     if (newrealmrefs) {
10404960Swillf 	for (i = 0; newrealmrefs[i] != NULL; i++)
10414960Swillf 	    free(newrealmrefs[i]);
10424960Swillf 	free(newrealmrefs);
10434960Swillf     }
10444960Swillf     if (realmName) {
10454960Swillf 	free(realmName);
10464960Swillf 	realmName = NULL;
10474960Swillf     }
10484960Swillf 
10494960Swillf     if (print_usage)
10504960Swillf 	db_usage(MODIFY_SERVICE);
10514960Swillf 
10524960Swillf     if (retval) {
10534960Swillf 	if (!no_msg)
10544960Swillf 	    com_err(me, retval, gettext("while modifying service object"));
10554960Swillf 	exit_status++;
10564960Swillf     }
10574960Swillf 
10584960Swillf     return;
10594960Swillf }
10604960Swillf 
10614960Swillf 
10624960Swillf /*
10634960Swillf  * This function will delete the entry corresponding to the service object
10644960Swillf  * from the service password file.
10654960Swillf  */
10664960Swillf static krb5_error_code
rem_service_entry_from_file(argc,argv,file_name,service_object)10674960Swillf rem_service_entry_from_file(argc, argv, file_name, service_object)
10684960Swillf     int argc;
10694960Swillf     char *argv[];
10704960Swillf     char *file_name;
10714960Swillf     char *service_object;
10724960Swillf {
10734960Swillf     int     st        = EINVAL;
1074*8092SMark.Phalan@Sun.COM     /* Solaris Kerberos */
1075*8092SMark.Phalan@Sun.COM     char    *me       = progname;
10764960Swillf     char    *tmp_file = NULL;
10774960Swillf     int     tmpfd     = -1;
10784960Swillf     FILE    *pfile    = NULL;
10794960Swillf     unsigned int len  = 0;
10804960Swillf     char    line[MAX_LEN]={0};
10814960Swillf     mode_t  omask     = umask(077);
10824960Swillf 
10834960Swillf     /* Check for permissions on the password file */
10844960Swillf     if (access(file_name, W_OK) == -1) {
10854960Swillf 	/* If the specified file itself is not there, no need to show error */
10864960Swillf 	if (errno == ENOENT) {
10874960Swillf 	    st=0;
10884960Swillf 	    goto cleanup;
10894960Swillf 	} else {
10904960Swillf 	    com_err(me, errno, gettext("while deleting entry from file %s", file_name));
10914960Swillf 	    goto cleanup;
10924960Swillf 	}
10934960Swillf     }
10944960Swillf 
10954960Swillf     /* Create a temporary file which contains all the entries except the
10964960Swillf        entry for the given service dn */
10974960Swillf     pfile = fopen(file_name, "r+F");
10984960Swillf     if (pfile == NULL) {
10994960Swillf 	com_err(me, errno, gettext("while deleting entry from file %s"), file_name);
11004960Swillf 	goto cleanup;
11014960Swillf     }
11024960Swillf 
11034960Swillf     /* Create a new file with the extension .tmp */
11044960Swillf     tmp_file = (char *)malloc(strlen(file_name) + 4 + 1);
11054960Swillf     if (tmp_file == NULL) {
11064960Swillf 	com_err(me, ENOMEM, gettext("while deleting entry from file"));
11074960Swillf 	fclose(pfile);
11084960Swillf 	goto cleanup;
11094960Swillf     }
11104960Swillf     snprintf (tmp_file, strlen(file_name) + 4 + 1, "%s%s", file_name, ".tmp");
11114960Swillf 
11124960Swillf 
11134960Swillf     tmpfd = creat(tmp_file, S_IRUSR|S_IWUSR);
11144960Swillf     umask(omask);
11154960Swillf     if (tmpfd == -1) {
11164960Swillf 	com_err(me, errno, gettext("while deleting entry from file\n"));
11174960Swillf 	fclose(pfile);
11184960Swillf 	goto cleanup;
11194960Swillf     }
11204960Swillf 
11214960Swillf     /* Copy only those lines which donot have the specified service dn */
11224960Swillf     while (fgets(line, MAX_LEN, pfile) != NULL) {
11234960Swillf 	if ((strstr(line, service_object) != NULL) &&
11244960Swillf 	    (line[strlen(service_object)] == '#')) {
11254960Swillf 	    continue;
11264960Swillf 	} else {
11274960Swillf 	    len = strlen(line);
11284960Swillf 	    if (write(tmpfd, line, len) != len) {
11294960Swillf 		com_err(me, errno, gettext("while deleting entry from file\n"));
11304960Swillf 		close(tmpfd);
11314960Swillf 		unlink(tmp_file);
11324960Swillf 		fclose(pfile);
11334960Swillf 		goto cleanup;
11344960Swillf 	    }
11354960Swillf 	}
11364960Swillf     }
11374960Swillf 
11384960Swillf     fclose(pfile);
11394960Swillf     if (unlink(file_name) == 0) {
11404960Swillf 	link(tmp_file, file_name);
11414960Swillf     } else {
11424960Swillf 	com_err(me, errno, gettext("while deleting entry from file\n"));
11434960Swillf     }
11444960Swillf     unlink(tmp_file);
11454960Swillf 
11464960Swillf     st=0;
11474960Swillf 
11484960Swillf cleanup:
11494960Swillf 
11504960Swillf     if (tmp_file)
11514960Swillf 	free(tmp_file);
11524960Swillf 
11534960Swillf     return st;
11544960Swillf }
11554960Swillf 
11564960Swillf 
11574960Swillf /*
11584960Swillf  * This function will delete the service object from the LDAP Server
11594960Swillf  * and unlink the references to the Realm objects (if any)
11604960Swillf  */
11614960Swillf void
kdb5_ldap_destroy_service(argc,argv)11624960Swillf kdb5_ldap_destroy_service(argc, argv)
11634960Swillf     int argc;
11644960Swillf     char *argv[];
11654960Swillf {
11664960Swillf     int i = 0;
11674960Swillf     char buf[5] = {0};
11684960Swillf     krb5_error_code retval = EINVAL;
11694960Swillf     int force = 0;
11704960Swillf     char *servicedn = NULL;
11714960Swillf     char *stashfilename = NULL;
11724960Swillf     int mask = 0;
11734960Swillf     krb5_ldap_service_params *lserparams = NULL;
11744960Swillf     krb5_boolean print_usage = FALSE;
11754960Swillf 
11764960Swillf     if ((argc < 2) || (argc > 5)) {
11774960Swillf 	exit_status++;
11784960Swillf 	goto err_usage;
11794960Swillf     }
11804960Swillf 
11814960Swillf     for (i=1; i < argc; i++) {
11824960Swillf 
11834960Swillf 	if (strcmp(argv[i],"-force")==0) {
11844960Swillf 	    force++;
11854960Swillf 	} else if (strcmp(argv[i],"-f")==0) {
11864960Swillf 	    if (argv[i+1]) {
11874960Swillf 		stashfilename=strdup(argv[i+1]);
11884960Swillf 		if (stashfilename == NULL) {
1189*8092SMark.Phalan@Sun.COM 		    /* Solaris Kerberos */
1190*8092SMark.Phalan@Sun.COM 		    com_err(progname, ENOMEM, gettext("while destroying service"));
11914960Swillf 		    exit_status++;
11924960Swillf 		    goto cleanup;
11934960Swillf 		}
11944960Swillf 		i++;
11954960Swillf 	    } else {
11964960Swillf 		exit_status++;
11974960Swillf 		goto err_usage;
11984960Swillf 	    }
11994960Swillf 	} else {
12004960Swillf 	    if ((argv[i]) && (servicedn == NULL)) {
12014960Swillf 		servicedn=strdup(argv[i]);
12024960Swillf 		if (servicedn == NULL) {
1203*8092SMark.Phalan@Sun.COM 		    /* Solaris Kerberos */
1204*8092SMark.Phalan@Sun.COM 		    com_err(progname, ENOMEM, gettext("while destroying service"));
12054960Swillf 		    exit_status++;
12064960Swillf 		    goto cleanup;
12074960Swillf 		}
12084960Swillf 	    } else {
12094960Swillf 		exit_status++;
12104960Swillf 		goto err_usage;
12114960Swillf 	    }
12124960Swillf 	}
12134960Swillf     }
12144960Swillf 
12154960Swillf     if (!servicedn) {
12164960Swillf 	exit_status++;
12174960Swillf 	goto err_usage;
12184960Swillf     }
12194960Swillf 
12204960Swillf     if (!force) {
12214960Swillf 	printf(gettext("This will delete the service object '%s', are you sure?\n"), servicedn);
12224960Swillf 	printf(gettext("(type 'yes' to confirm)? "));
12234960Swillf 	if (fgets(buf, sizeof(buf), stdin) == NULL) {
12244960Swillf 	    exit_status++;
12254960Swillf 	    goto cleanup;;
12264960Swillf 	}
12274960Swillf 	if (strcmp(buf, yes)) {
12284960Swillf 	    exit_status++;
12294960Swillf 	    goto cleanup;
12304960Swillf 	}
12314960Swillf     }
12324960Swillf 
12334960Swillf     if ((retval = krb5_ldap_read_service(util_context, servicedn,
12344960Swillf 					 &lserparams, &mask))) {
1235*8092SMark.Phalan@Sun.COM 	/* Solaris Kerberos */
1236*8092SMark.Phalan@Sun.COM 	com_err(progname, retval, gettext("while destroying service '%s'"), servicedn);
12374960Swillf 	exit_status++;
12384960Swillf 	goto cleanup;
12394960Swillf     }
12404960Swillf 
12414960Swillf     retval = krb5_ldap_delete_service(util_context, lserparams, servicedn);
12424960Swillf 
12434960Swillf     if (retval) {
1244*8092SMark.Phalan@Sun.COM 	/* Solaris Kerberos */
1245*8092SMark.Phalan@Sun.COM 	com_err(progname, retval, gettext("while destroying service '%s'"), servicedn);
12464960Swillf 	exit_status++;
12474960Swillf 	goto cleanup;
12484960Swillf     }
12494960Swillf 
12504960Swillf     if (stashfilename == NULL) {
12514960Swillf 	stashfilename = strdup(DEF_SERVICE_PASSWD_FILE);
12524960Swillf 	if (stashfilename == NULL) {
1253*8092SMark.Phalan@Sun.COM 	    /* Solaris Kerberos */
1254*8092SMark.Phalan@Sun.COM 	    com_err(progname, ENOMEM, gettext("while destroying service"));
12554960Swillf 	    exit_status++;
12564960Swillf 	    goto cleanup;
12574960Swillf 	}
12584960Swillf     }
12594960Swillf     printf(gettext("** service object '%s' deleted.\n"), servicedn);
12604960Swillf     retval = rem_service_entry_from_file(argc, argv, stashfilename, servicedn);
12614960Swillf 
12624960Swillf     if (retval)
12634960Swillf 	printf(gettext("** error removing service object entry '%s' from password file.\n"),
12644960Swillf 	       servicedn);
12654960Swillf 
12664960Swillf     goto cleanup;
12674960Swillf 
12684960Swillf 
12694960Swillf err_usage:
12704960Swillf     print_usage = TRUE;
12714960Swillf 
12724960Swillf cleanup:
12734960Swillf 
12744960Swillf     if (lserparams) {
12754960Swillf 	krb5_ldap_free_service(util_context, lserparams);
12764960Swillf     }
12774960Swillf 
12784960Swillf     if (servicedn) {
12794960Swillf 	free(servicedn);
12804960Swillf     }
12814960Swillf 
12824960Swillf     if (stashfilename) {
12834960Swillf 	free(stashfilename);
12844960Swillf     }
12854960Swillf 
12864960Swillf     if (print_usage) {
12874960Swillf 	db_usage(DESTROY_SERVICE);
12884960Swillf     }
12894960Swillf 
12904960Swillf     return;
12914960Swillf }
12924960Swillf 
12934960Swillf 
12944960Swillf /*
12954960Swillf  * This function will display information about the given service object
12964960Swillf  */
kdb5_ldap_view_service(argc,argv)12974960Swillf void kdb5_ldap_view_service(argc, argv)
12984960Swillf     int argc;
12994960Swillf     char *argv[];
13004960Swillf {
13014960Swillf     krb5_ldap_service_params *lserparams = NULL;
13024960Swillf     krb5_error_code retval = 0;
13034960Swillf     char *servicedn = NULL;
13044960Swillf     int mask = 0;
13054960Swillf     krb5_boolean print_usage = FALSE;
13064960Swillf 
13074960Swillf     if (!(argc == 2)) {
13084960Swillf 	exit_status++;
13094960Swillf 	goto err_usage;
13104960Swillf     }
13114960Swillf 
13124960Swillf     servicedn=strdup(argv[1]);
13134960Swillf     if (servicedn == NULL) {
1314*8092SMark.Phalan@Sun.COM 	/* Solaris Kerberos */
1315*8092SMark.Phalan@Sun.COM 	com_err(progname, ENOMEM, gettext("while viewing service"));
13164960Swillf 	exit_status++;
13174960Swillf 	goto cleanup;
13184960Swillf     }
13194960Swillf 
13204960Swillf     if ((retval = krb5_ldap_read_service(util_context, servicedn, &lserparams, &mask))) {
1321*8092SMark.Phalan@Sun.COM 	/* Solaris Kerberos */
1322*8092SMark.Phalan@Sun.COM 	com_err(progname, retval, gettext("while viewing service '%s'"), servicedn);
13234960Swillf 	exit_status++;
13244960Swillf 	goto cleanup;
13254960Swillf     }
13264960Swillf 
13274960Swillf     print_service_params(lserparams, mask);
13284960Swillf 
13294960Swillf     goto cleanup;
13304960Swillf 
13314960Swillf err_usage:
13324960Swillf     print_usage = TRUE;
13334960Swillf 
13344960Swillf cleanup:
13354960Swillf 
13364960Swillf     if (lserparams) {
13374960Swillf 	krb5_ldap_free_service(util_context, lserparams);
13384960Swillf     }
13394960Swillf 
13404960Swillf     if (servicedn)
13414960Swillf 	free(servicedn);
13424960Swillf 
13434960Swillf     if (print_usage) {
13444960Swillf 	db_usage(VIEW_SERVICE);
13454960Swillf     }
13464960Swillf 
13474960Swillf     return;
13484960Swillf }
13494960Swillf 
13504960Swillf 
13514960Swillf /*
13524960Swillf  * This function will list the DNs of kerberos services present on
13534960Swillf  * the LDAP Server under a specific sub-tree (entire tree by default)
13544960Swillf  */
kdb5_ldap_list_services(argc,argv)13554960Swillf void kdb5_ldap_list_services(argc, argv)
13564960Swillf     int argc;
13574960Swillf     char *argv[];
13584960Swillf {
1359*8092SMark.Phalan@Sun.COM     /* Solaris Kerberos */
1360*8092SMark.Phalan@Sun.COM     char *me = progname;
13614960Swillf     krb5_error_code retval = 0;
13624960Swillf     char *basedn = NULL;
13634960Swillf     char **list = NULL;
13644960Swillf     char **plist = NULL;
13654960Swillf     krb5_boolean print_usage = FALSE;
13664960Swillf 
13674960Swillf     /* Check for number of arguments */
13684960Swillf     if ((argc != 1) && (argc != 3)) {
13694960Swillf 	exit_status++;
13704960Swillf 	goto err_usage;
13714960Swillf     }
13724960Swillf 
13734960Swillf     /* Parse base DN argument if present */
13744960Swillf     if (argc == 3) {
13754960Swillf 	if (strcmp(argv[1], "-basedn")) {
13764960Swillf 	    retval = EINVAL;
13774960Swillf 	    goto err_usage;
13784960Swillf 	}
13794960Swillf 
13804960Swillf 	basedn = strdup(argv[2]);
13814960Swillf 	if (basedn == NULL) {
13824960Swillf 	    com_err(me, ENOMEM, gettext("while listing services"));
13834960Swillf 	    exit_status++;
13844960Swillf 	    goto cleanup;
13854960Swillf 	}
13864960Swillf     }
13874960Swillf 
13884960Swillf     retval = krb5_ldap_list_services(util_context, basedn, &list);
13894960Swillf     if ((retval != 0) || (list == NULL)) {
13904960Swillf 	exit_status++;
13914960Swillf 	goto cleanup;
13924960Swillf     }
13934960Swillf 
13944960Swillf     for (plist = list; *plist != NULL; plist++) {
13954960Swillf 	printf("%s\n", *plist);
13964960Swillf     }
13974960Swillf 
13984960Swillf     goto cleanup;
13994960Swillf 
14004960Swillf err_usage:
14014960Swillf     print_usage = TRUE;
14024960Swillf 
14034960Swillf cleanup:
14044960Swillf     if (list != NULL) {
14054960Swillf 	krb5_free_list_entries (list);
14064960Swillf 	free (list);
14074960Swillf     }
14084960Swillf 
14094960Swillf     if (basedn)
14104960Swillf 	free (basedn);
14114960Swillf 
14124960Swillf     if (print_usage) {
14134960Swillf 	db_usage(LIST_SERVICE);
14144960Swillf     }
14154960Swillf 
14164960Swillf     if (retval) {
14174960Swillf 	com_err(me, retval, gettext("while listing policy objects"));
14184960Swillf 	exit_status++;
14194960Swillf     }
14204960Swillf 
14214960Swillf     return;
14224960Swillf }
14234960Swillf 
14244960Swillf 
14254960Swillf /*
14264960Swillf  * This function will print the service object information
14274960Swillf  * to the standard output
14284960Swillf  */
14294960Swillf static void
print_service_params(lserparams,mask)14304960Swillf print_service_params(lserparams, mask)
14314960Swillf     krb5_ldap_service_params *lserparams;
14324960Swillf     int mask;
14334960Swillf {
14344960Swillf     int            i=0;
14354960Swillf 
14364960Swillf     /* Print the service dn */
14374960Swillf     printf("%20s%-20s\n", gettext("Service dn: "), lserparams->servicedn);
14384960Swillf 
14394960Swillf     /* Print the service type of the object to be read */
14404960Swillf     if (lserparams->servicetype == LDAP_KDC_SERVICE) {
14414960Swillf 	printf("%20s%-20s\n", gettext("Service type: "), "kdc");
14424960Swillf     } else if (lserparams->servicetype == LDAP_ADMIN_SERVICE) {
14434960Swillf 	printf("%20s%-20s\n", gettext("Service type: "), "admin");
14444960Swillf     } else if (lserparams->servicetype == LDAP_PASSWD_SERVICE) {
14454960Swillf 	printf("%20s%-20s\n", gettext("Service type: "), "pwd");
14464960Swillf     }
14474960Swillf 
14484960Swillf     /* Print the host server values */
14494960Swillf     printf("%20s\n", gettext("Service host list: "));
14504960Swillf     if (mask & LDAP_SERVICE_HOSTSERVER) {
14514960Swillf 	for (i=0; lserparams->krbhostservers[i] != NULL; ++i) {
14524960Swillf 	    printf("%20s%-50s\n","",lserparams->krbhostservers[i]);
14534960Swillf 	}
14544960Swillf     }
14554960Swillf 
14564960Swillf     /* Print the realm reference dn values */
14574960Swillf     printf("%20s\n", gettext("Realm DN list: "));
14584960Swillf     if (mask & LDAP_SERVICE_REALMREFERENCE) {
14594960Swillf 	for (i=0; lserparams && lserparams->krbrealmreferences && lserparams->krbrealmreferences[i] != NULL; ++i) {
14604960Swillf 	    printf("%20s%-50s\n","",lserparams->krbrealmreferences[i]);
14614960Swillf 	}
14624960Swillf     }
14634960Swillf 
14644960Swillf     return;
14654960Swillf }
14664960Swillf 
14674960Swillf 
14684960Swillf /*
14694960Swillf  * This function will generate random  password of length(RANDOM_PASSWD_LEN)
14704960Swillf  *
14714960Swillf  *
14724960Swillf  * INPUT:
14734960Swillf  *      ctxt - context
14744960Swillf  *
14754960Swillf  * OUTPUT:
14764960Swillf  *     RANDOM_PASSWD_LEN length random password
14774960Swillf  */
generate_random_password(krb5_context ctxt,char ** randpwd,unsigned int * passlen)14784960Swillf static int generate_random_password(krb5_context ctxt, char **randpwd, unsigned int *passlen)
14794960Swillf {
14804960Swillf     char *random_pwd = NULL;
14814960Swillf     int ret = 0;
14824960Swillf     krb5_data data;
14834960Swillf     int i=0;
14844960Swillf     /*int len = 0;*/
14854960Swillf 
14864960Swillf     /* setting random password length in the range 16-32 */
14874960Swillf     srand((unsigned int)(time(0) ^ getpid()));
14884960Swillf 
14894960Swillf     data.length = RANDOM_PASSWD_LEN;
14904960Swillf     random_pwd = (char *)malloc(data.length + 1);
14914960Swillf     if (random_pwd == NULL) {
14924960Swillf 	com_err("setsrvpw", ENOMEM, gettext("while generating random password"));
14934960Swillf 	return ENOMEM;
14944960Swillf     }
14954960Swillf     memset(random_pwd, 0, data.length + 1);
14964960Swillf     data.data = random_pwd;
14974960Swillf 
14984960Swillf     ret = krb5_c_random_make_octets(ctxt, &data);
14994960Swillf     if (ret) {
15004960Swillf 	com_err("setsrvpw", ret, gettext("Error generating random password"));
15014960Swillf 	free(random_pwd);
15024960Swillf 	return ret;
15034960Swillf     }
15044960Swillf 
15054960Swillf     for (i=0; i<data.length; i++) {
15064960Swillf 	/* restricting to ascii chars. Need to change this when 8.8 supports */
15074960Swillf 	if ((unsigned char)random_pwd[i] > 127) {
15084960Swillf 	    random_pwd[i] = (unsigned char)random_pwd[i] % 128;
15094960Swillf 	} else if (random_pwd[i] == 0) {
15104960Swillf 	    random_pwd[i] = (rand()/(RAND_MAX/127 + 1))+1;
15114960Swillf 	}
15124960Swillf     }
15134960Swillf 
15144960Swillf     *randpwd = random_pwd;
15154960Swillf     *passlen = data.length;
15164960Swillf 
15174960Swillf     return 0;
15184960Swillf }
15194960Swillf 
15204960Swillf 
15214960Swillf /*
15224960Swillf  * This function will set the password of the service object in the directory
15234960Swillf  * and/or the specified service password file.
15244960Swillf  *
15254960Swillf  *
15264960Swillf  * INPUT:
15274960Swillf  *      argc - contains the number of arguments for this sub-command
15284960Swillf  *      argv - array of arguments for this sub-command
15294960Swillf  *
15304960Swillf  * OUTPUT:
15314960Swillf  *      void
15324960Swillf  */
15334960Swillf int
kdb5_ldap_set_service_password(argc,argv)15344960Swillf kdb5_ldap_set_service_password(argc, argv)
15354960Swillf     int argc;
15364960Swillf     char **argv;
15374960Swillf {
15384960Swillf     krb5_ldap_context *lparams = NULL;
15394960Swillf     char *file_name = NULL;
15404960Swillf     char *tmp_file = NULL;
1541*8092SMark.Phalan@Sun.COM     /* Solaris Kerberos */
1542*8092SMark.Phalan@Sun.COM     char *me = progname;
15434960Swillf     int filelen = 0;
15444960Swillf     int random_passwd = 0;
15454960Swillf     int set_dir_pwd = 1;
15464960Swillf     krb5_boolean db_init_local = FALSE;
15474960Swillf     char *service_object = NULL;
15484960Swillf     char *passwd = NULL;
15494960Swillf     char *prompt1 = NULL;
15504960Swillf     char *prompt2 = NULL;
15514960Swillf     unsigned int passwd_len = 0;
15524960Swillf     krb5_error_code errcode = -1;
15534960Swillf     int retval = 0, i = 0;
15544960Swillf     unsigned int len = 0;
15554960Swillf     krb5_boolean print_usage = FALSE;
15564960Swillf     FILE *pfile = NULL;
15574960Swillf     char *str = NULL;
15584960Swillf     char line[MAX_LEN];
15594960Swillf     kdb5_dal_handle *dal_handle = NULL;
15604960Swillf     struct data encrypted_passwd = {0, NULL};
15614960Swillf 
15624960Swillf     /* The arguments for setsrv password should contain the service object DN
15634960Swillf      * and options to specify whether the password should be updated in file only
15644960Swillf      * or both file and directory. So the possible combination of arguments are:
15654960Swillf      * setsrvpw servicedn				wherein argc is 2
15664960Swillf      * setsrvpw	-fileonly servicedn 			wherein argc is 3
15674960Swillf      * setsrvpw -randpw servicedn			wherein argc is 3
15684960Swillf      * setsrvpw -f filename servicedn			wherein argc is 4
15694960Swillf      * setsrvpw -fileonly -f filename servicedn 	wherein argc is 5
15704960Swillf      * setsrvpw -randpw -f filename servicedn 		wherein argc is 5
15714960Swillf      */
15724960Swillf     if ((argc < 2) || (argc > 5)) {
15734960Swillf 	print_usage = TRUE;
15744960Swillf 	goto cleanup;
15754960Swillf     }
15764960Swillf 
15774960Swillf     dal_handle = (kdb5_dal_handle *)util_context->db_context;
15784960Swillf     lparams = (krb5_ldap_context *) dal_handle->db_context;
15794960Swillf 
15804960Swillf     if (lparams == NULL) {
15814960Swillf 	printf(gettext("%s: Invalid LDAP handle\n"), me);
15824960Swillf 	goto cleanup;
15834960Swillf     }
15844960Swillf 
15854960Swillf     /* Parse the arguments */
15864960Swillf     for (i = 1; i < argc -1 ; i++) {
15874960Swillf 	if (strcmp(argv[i], "-randpw") == 0) {
15884960Swillf 	    random_passwd = 1;
15894960Swillf 	} else if (strcmp(argv[i], "-fileonly") == 0) {
15904960Swillf 	    set_dir_pwd = 0;
15914960Swillf 	} else if (strcmp(argv[i], "-f") == 0) {
15924960Swillf 	    if (argv[++i] == NULL) {
15934960Swillf 		print_usage = TRUE;
15944960Swillf 		goto cleanup;
15954960Swillf 	    }
15964960Swillf 
15974960Swillf 	    file_name = strdup(argv[i]);
15984960Swillf 	    if (file_name == NULL) {
15994960Swillf 		com_err(me, ENOMEM, gettext("while setting service object password"));
16004960Swillf 		goto cleanup;
16014960Swillf 	    }
16024960Swillf 	    /* Verify if the file location has the proper file name
16034960Swillf 	     * for eg, if the file location is a directory like /home/temp/,
16044960Swillf 	     * we reject it.
16054960Swillf 	     */
16064960Swillf 	    filelen = strlen(file_name);
16074960Swillf 	    if ((filelen == 0) || (file_name[filelen-1] == '/')) {
16084960Swillf 		printf(gettext("%s: Filename not specified for setting service object password\n"), me);
16094960Swillf 		print_usage = TRUE;
16104960Swillf 		goto cleanup;
16114960Swillf 	    }
16124960Swillf 	} else {
16134960Swillf 	    printf(gettext("%s: Invalid option specified for \"setsrvpw\" command\n"), me);
16144960Swillf 	    print_usage = TRUE;
16154960Swillf 	    goto cleanup;
16164960Swillf 	}
16174960Swillf     }
16184960Swillf 
16194960Swillf     if (i != argc-1) {
16204960Swillf 	print_usage = TRUE;
16214960Swillf 	goto cleanup;
16224960Swillf     }
16234960Swillf 
16244960Swillf     service_object = strdup(argv[i]);
16254960Swillf     if (service_object == NULL) {
16264960Swillf 	com_err(me, ENOMEM, gettext("while setting service object password"));
16274960Swillf 	goto cleanup;
16284960Swillf     }
16294960Swillf 
16304960Swillf     if (strlen(service_object) == 0) {
16314960Swillf 	printf(gettext("%s: Service object not specified for \"setsrvpw\" command\n"), me);
16324960Swillf 	print_usage = TRUE;
16334960Swillf 	goto cleanup;
16344960Swillf     }
16354960Swillf 
16364960Swillf     if (service_object[0] == '-') {
16374960Swillf 	print_usage = TRUE;
16384960Swillf 	goto cleanup;
16394960Swillf     }
16404960Swillf 
16414960Swillf     if (file_name == NULL) {
16424960Swillf 	file_name = strdup(DEF_SERVICE_PASSWD_FILE);
16434960Swillf 	if (file_name == NULL) {
16444960Swillf 	    com_err(me, ENOMEM, gettext("while setting service object password"));
16454960Swillf 	    goto cleanup;
16464960Swillf 	}
16474960Swillf     }
16484960Swillf 
16494960Swillf     if (set_dir_pwd) {
16504960Swillf 	if (db_inited == FALSE) {
16514960Swillf 	    if ((errcode = krb5_ldap_db_init(util_context, lparams))) {
16524960Swillf 		com_err(me, errcode, gettext("while initializing database"));
16534960Swillf 		goto cleanup;
16544960Swillf 	    }
16554960Swillf 	    db_init_local = TRUE;
16564960Swillf 	}
16574960Swillf     }
16584960Swillf 
16594960Swillf     if (random_passwd) {
16604960Swillf 	if (!set_dir_pwd) {
16614960Swillf 	    printf(gettext("%s: Invalid option specified for \"setsrvpw\" command\n"), me);
16624960Swillf 	    print_usage = TRUE;
16634960Swillf 	    goto cleanup;
16644960Swillf 	} else {
16654960Swillf 	    /* Generate random password */
16664960Swillf 
16674960Swillf 	    if ((errcode = generate_random_password(util_context, &passwd, &passwd_len))) {
16684960Swillf 		printf(gettext("%s: Failed to set service object password\n"), me);
16694960Swillf 		goto cleanup;
16704960Swillf 	    }
16714960Swillf 	    passwd_len = strlen(passwd);
16724960Swillf 	}
16734960Swillf     } else {
16744960Swillf 	/* Get the service object password from the terminal */
16754960Swillf 	passwd = (char *)malloc(MAX_SERVICE_PASSWD_LEN + 1);
16764960Swillf 	if (passwd == NULL) {
16774960Swillf 	    com_err(me, ENOMEM, gettext("while setting service object password"));
16784960Swillf 	    goto cleanup;
16794960Swillf 	}
16804960Swillf 	memset(passwd, 0, MAX_SERVICE_PASSWD_LEN + 1);
16814960Swillf 	passwd_len = MAX_SERVICE_PASSWD_LEN;
16824960Swillf 
16834960Swillf 	len = strlen(service_object);
16844960Swillf 	/* size of allocation=strlen of servicedn + strlen("Password for \" \"")=20 */
16854960Swillf 	prompt1 = (char *)malloc(len + 20);
16864960Swillf 	if (prompt1 == NULL) {
16874960Swillf 	    com_err(me, ENOMEM, gettext("while setting service object password"));
16884960Swillf 	    goto cleanup;
16894960Swillf 	}
16904960Swillf 	sprintf(prompt1, gettext("Password for \"%s\""), service_object);
16914960Swillf 
16924960Swillf 	/* size of allocation=strlen of servicedn + strlen("Re-enter Password for \" \"")=30 */
16934960Swillf 	prompt2 = (char *)malloc(len + 30);
16944960Swillf 	if (prompt2 == NULL) {
16954960Swillf 	    com_err(me, ENOMEM, gettext("while setting service object password"));
16964960Swillf 	    free(prompt1);
16974960Swillf 	    goto cleanup;
16984960Swillf 	}
16994960Swillf 	sprintf(prompt2, gettext("Re-enter password for \"%s\""), service_object);
17004960Swillf 
17014960Swillf 	retval = krb5_read_password(util_context, prompt1, prompt2, passwd, &passwd_len);
17024960Swillf 	free(prompt1);
17034960Swillf 	free(prompt2);
17044960Swillf 	if (retval) {
17054960Swillf 	    com_err(me, retval, gettext("while setting service object password"));
17064960Swillf 	    memset(passwd, 0, MAX_SERVICE_PASSWD_LEN);
17074960Swillf 	    goto cleanup;
17084960Swillf 	}
17094960Swillf 	if (passwd_len == 0) {
17104960Swillf 	    printf(gettext("%s: Invalid password\n"), me);
17114960Swillf 	    memset(passwd, 0, MAX_SERVICE_PASSWD_LEN);
17124960Swillf 	    goto cleanup;
17134960Swillf 	}
17144960Swillf 	passwd_len = strlen(passwd);
17154960Swillf     }
17164960Swillf 
17174960Swillf     /* Hex the password */
17184960Swillf     {
17194960Swillf 	krb5_data pwd, hex;
17204960Swillf 	pwd.length = passwd_len;
17214960Swillf 	pwd.data = passwd;
17224960Swillf 
17234960Swillf 	errcode = tohex(pwd, &hex);
17244960Swillf 	if (errcode != 0) {
17254960Swillf 	    if (hex.length != 0) {
17264960Swillf 		memset(hex.data, 0, hex.length);
17274960Swillf 		free(hex.data);
17284960Swillf 	    }
17294960Swillf 	    com_err(me, errcode, gettext("Failed to convert the password to hex"));
17304960Swillf 	    memset(passwd, 0, passwd_len);
17314960Swillf 	    goto cleanup;
17324960Swillf 	}
17334960Swillf 	/* Password = {CRYPT}<encrypted password>:<encrypted key> */
17344960Swillf 	encrypted_passwd.value = (unsigned char *)malloc(strlen(service_object) +
17354960Swillf 							 1 + 5 + hex.length + 2);
17364960Swillf 	if (encrypted_passwd.value == NULL) {
17374960Swillf 	    com_err(me, ENOMEM, gettext("while setting service object password"));
17384960Swillf 	    memset(passwd, 0, passwd_len);
17394960Swillf 	    memset(hex.data, 0, hex.length);
17404960Swillf 	    free(hex.data);
17414960Swillf 	    goto cleanup;
17424960Swillf 	}
17434960Swillf 	encrypted_passwd.value[strlen(service_object) +
17444960Swillf 			       1 + 5 + hex.length + 1] = '\0';
17454960Swillf 	sprintf((char *)encrypted_passwd.value, "%s#{HEX}%s\n", service_object, hex.data);
17464960Swillf 	encrypted_passwd.len = strlen((char *)encrypted_passwd.value);
17474960Swillf 	memset(hex.data, 0, hex.length);
17484960Swillf 	free(hex.data);
17494960Swillf     }
17504960Swillf 
17514960Swillf     /* We should check if the file exists and we have permission to write into that file */
17524960Swillf     if (access(file_name, W_OK) == -1) {
17534960Swillf 	if (errno == ENOENT) {
17544960Swillf 	    mode_t omask;
17554960Swillf 	    int fd = -1;
17564960Swillf 
17574960Swillf 	    printf(gettext("File does not exist. Creating the file %s...\n"), file_name);
17584960Swillf 	    omask = umask(077);
17594960Swillf 	    fd = creat(file_name, S_IRUSR|S_IWUSR);
17604960Swillf 	    umask(omask);
17614960Swillf 	    if (fd == -1) {
17624960Swillf 		com_err(me, errno, gettext("Error creating file %s"), file_name);
17634960Swillf 		memset(passwd, 0, passwd_len);
17644960Swillf 		goto cleanup;
17654960Swillf 	    }
17664960Swillf 	    close(fd);
17674960Swillf 	} else {
17684960Swillf 	    com_err(me, errno, gettext("Unable to access the file %s"), file_name);
17694960Swillf 	    memset(passwd, 0, passwd_len);
17704960Swillf 	    goto cleanup;
17714960Swillf 	}
17724960Swillf     }
17734960Swillf 
17744960Swillf     if (set_dir_pwd) {
17754960Swillf 	if ((errcode = krb5_ldap_set_service_passwd(util_context, service_object, passwd)) != 0) {
17764960Swillf 	    com_err(me, errcode, gettext("Failed to set password for service object %s"), service_object);
17774960Swillf 	    memset(passwd, 0, passwd_len);
17784960Swillf 	    goto cleanup;
17794960Swillf 	}
17804960Swillf     }
17814960Swillf 
17824960Swillf     memset(passwd, 0, passwd_len);
17834960Swillf 
17844960Swillf 
17854960Swillf     /* TODO: file lock for the service password file */
17864960Swillf     /* set password in the file */
17874960Swillf     pfile = fopen(file_name, "r+F");
17884960Swillf     if (pfile == NULL) {
17894960Swillf 	com_err(me, errno, gettext("Failed to open file %s"), file_name);
17904960Swillf 	goto cleanup;
17914960Swillf     }
17924960Swillf 
17934960Swillf     while (fgets(line, MAX_LEN, pfile) != NULL) {
17944960Swillf 	if ((str = strstr(line, service_object)) != NULL) {
17954960Swillf 	    if (line[strlen(service_object)] == '#') {
17964960Swillf 		break;
17974960Swillf 	    }
17984960Swillf 	    str = NULL;
17994960Swillf 	}
18004960Swillf     }
18014960Swillf     if (str == NULL) {
18024960Swillf 	if (feof(pfile)) {
18034960Swillf 	    /* If the service object dn is not present in the service password file */
18044960Swillf 	    if (fwrite(encrypted_passwd.value, (unsigned int)encrypted_passwd.len, 1, pfile) != 1) {
18054960Swillf 		com_err(me, errno, gettext("Failed to write service object password to file"));
18064960Swillf 		goto cleanup;
18074960Swillf 	    }
18084960Swillf 	} else {
18094960Swillf 	    com_err(me, errno, gettext("Error reading service object password file"));
18104960Swillf 	    goto cleanup;
18114960Swillf 	}
18124960Swillf 	fclose(pfile);
18134960Swillf 	pfile = NULL;
18144960Swillf     } else {
18154960Swillf 	/* Password entry for the service object is already present in the file */
18164960Swillf 	/* Delete the existing entry and add the new entry */
18174960Swillf 	FILE *newfile = NULL;
18184960Swillf 	mode_t omask;
18194960Swillf 
18204960Swillf 	/* Create a new file with the extension .tmp */
18214960Swillf 	tmp_file = (char *) malloc(sizeof(char) * (strlen(file_name) + 4 + 1));
18224960Swillf 	if (tmp_file == NULL) {
18234960Swillf 	    com_err(me, ENOMEM, gettext("while setting service object password"));
18244960Swillf 	    goto cleanup;
18254960Swillf 	}
18264960Swillf 	sprintf(tmp_file,"%s.%s",file_name,"tmp");
18274960Swillf 
18284960Swillf 	omask = umask(077);
18294960Swillf 	newfile = fopen(tmp_file, "w+F");
18304960Swillf 	umask(omask);
18314960Swillf 	if (newfile == NULL) {
18324960Swillf 	    com_err(me, errno, gettext("Error creating file %s"), tmp_file);
18334960Swillf 	    goto cleanup;
18344960Swillf 	}
18354960Swillf 
18364960Swillf 
18374960Swillf 	fseek(pfile, 0, SEEK_SET);
18384960Swillf 	while (fgets(line, MAX_LEN, pfile) != NULL) {
18394960Swillf 	    if (((str = strstr(line, service_object)) != NULL) && (line[strlen(service_object)] == '#')) {
18404960Swillf 		if (fprintf(newfile, "%s", encrypted_passwd.value) < 0) {
18414960Swillf 		    com_err(me, errno, gettext("Failed to write service object password to file"));
18424960Swillf 		    fclose(newfile);
18434960Swillf 		    unlink(tmp_file);
18444960Swillf 		    goto cleanup;
18454960Swillf 		}
18464960Swillf 	    } else {
18474960Swillf 		len = strlen(line);
18484960Swillf 		if (fprintf(newfile, "%s", line) < 0) {
18494960Swillf 		    com_err(me, errno, gettext("Failed to write service object password to file"));
18504960Swillf 		    fclose(newfile);
18514960Swillf 		    unlink(tmp_file);
18524960Swillf 		    goto cleanup;
18534960Swillf 		}
18544960Swillf 	    }
18554960Swillf 	}
18564960Swillf 
18574960Swillf 	if (!feof(pfile)) {
18584960Swillf 	    com_err(me, errno, gettext("Error reading service object password file"));
18594960Swillf 	    fclose(newfile);
18604960Swillf 	    unlink(tmp_file);
18614960Swillf 	    goto cleanup;
18624960Swillf 	}
18634960Swillf 
18644960Swillf 	/* TODO: file lock for the service password file */
18654960Swillf 	fclose(pfile);
18664960Swillf 	pfile = NULL;
18674960Swillf 
18684960Swillf 	fclose(newfile);
18694960Swillf 	newfile = NULL;
18704960Swillf 
18714960Swillf 	if (unlink(file_name) == 0) {
18724960Swillf 	    link(tmp_file, file_name);
18734960Swillf 	} else {
18744960Swillf 	    com_err(me, errno, gettext("Failed to write service object password to file"));
18754960Swillf 	    unlink(tmp_file);
18764960Swillf 	    goto cleanup;
18774960Swillf 	}
18784960Swillf 	unlink(tmp_file);
18794960Swillf     }
18804960Swillf     errcode = 0;
18814960Swillf 
18824960Swillf cleanup:
18834960Swillf     if (db_init_local)
18844960Swillf 	krb5_ldap_close(util_context);
18854960Swillf 
18864960Swillf     if (service_object)
18874960Swillf 	free(service_object);
18884960Swillf 
18894960Swillf     if (file_name)
18904960Swillf 	free(file_name);
18914960Swillf 
18924960Swillf     if (passwd)
18934960Swillf 	free(passwd);
18944960Swillf 
18954960Swillf     if (encrypted_passwd.value) {
18964960Swillf 	memset(encrypted_passwd.value, 0, encrypted_passwd.len);
18974960Swillf 	free(encrypted_passwd.value);
18984960Swillf     }
18994960Swillf 
19004960Swillf     if (pfile)
19014960Swillf 	fclose(pfile);
19024960Swillf 
19034960Swillf     if (tmp_file)
19044960Swillf 	free(tmp_file);
19054960Swillf 
19064960Swillf     if (print_usage)
19074960Swillf 	db_usage(SET_SRV_PW);
19084960Swillf 
19094960Swillf     return errcode;
19104960Swillf }
19114960Swillf 
19124960Swillf #else /* #ifdef HAVE_EDIRECTORY */
19134960Swillf 
19144960Swillf /*
19154960Swillf  * Convert the user supplied password into hexadecimal and stash it. Only a
19164960Swillf  * little more secure than storing plain password in the file ...
19174960Swillf  */
19184960Swillf void
kdb5_ldap_stash_service_password(argc,argv)19194960Swillf kdb5_ldap_stash_service_password(argc, argv)
19204960Swillf     int argc;
19214960Swillf     char **argv;
19224960Swillf {
19234960Swillf     int ret = 0;
19244960Swillf     unsigned int passwd_len = 0;
1925*8092SMark.Phalan@Sun.COM     /* Solaris Kerberos */
1926*8092SMark.Phalan@Sun.COM     char *me = progname;
19274960Swillf     char *service_object = NULL;
19284960Swillf     char *file_name = NULL, *tmp_file = NULL;
19294960Swillf     char passwd[MAX_SERVICE_PASSWD_LEN];
19304960Swillf     char *str = NULL;
19314960Swillf     char line[MAX_LEN];
19324960Swillf     int fd;
19334960Swillf     FILE *pfile = NULL;
19344960Swillf     krb5_boolean print_usage = FALSE;
19354960Swillf     krb5_data hexpasswd = {0, 0, NULL};
19364960Swillf     mode_t old_mode = 0;
19374960Swillf 
19384960Swillf     /*
19394960Swillf      * Format:
19404960Swillf      *   stashsrvpw [-f filename] service_dn
19414960Swillf      * where
19424960Swillf      *   'service_dn' is the DN of the service object
19434960Swillf      *   'filename' is the path of the stash file
19444960Swillf      */
19454960Swillf     if (argc != 2 && argc != 4) {
19464960Swillf 	print_usage = TRUE;
19474960Swillf 	goto cleanup;
19484960Swillf     }
19494960Swillf 
19504960Swillf     if (argc == 4) {
19514960Swillf 	/* Find the stash file name */
19524960Swillf 	if (strcmp (argv[1], "-f") == 0) {
19534960Swillf 	    if (((file_name = strdup (argv[2])) == NULL) ||
19544960Swillf 	        ((service_object = strdup (argv[3])) == NULL)) {
19554960Swillf 	        com_err(me, ENOMEM, gettext("while setting service object password"));
19564960Swillf 	        goto cleanup;
19574960Swillf 	    }
19584960Swillf 	} else if (strcmp (argv[2], "-f") == 0) {
19594960Swillf 	    if (((file_name = strdup (argv[3])) == NULL) ||
19604960Swillf 	        ((service_object = strdup (argv[1])) == NULL)) {
19614960Swillf 	        com_err(me, ENOMEM, gettext("while setting service object password"));
19624960Swillf 	        goto cleanup;
19634960Swillf 	    }
19644960Swillf 	} else {
19654960Swillf 	    print_usage = TRUE;
19664960Swillf 	    goto cleanup;
19674960Swillf 	}
19684960Swillf 	if (file_name == NULL) {
19694960Swillf 	    com_err(me, ENOMEM, gettext("while setting service object password"));
19704960Swillf 	    goto cleanup;
19714960Swillf 	}
19724960Swillf     } else { /* argc == 2 */
19734960Swillf 	char *section;
19744960Swillf 
19754960Swillf 	service_object = strdup (argv[1]);
19764960Swillf 	if (service_object == NULL) {
19774960Swillf 	    com_err(me, ENOMEM, gettext("while setting service object password"));
19784960Swillf 	    goto cleanup;
19794960Swillf 	}
19804960Swillf 
19814960Swillf 	/* Pick up the stash-file name from krb5.conf */
19824960Swillf 	profile_get_string(util_context->profile, KDB_REALM_SECTION,
19834960Swillf 			   util_context->default_realm, KDB_MODULE_POINTER, NULL, &section);
19844960Swillf 
19854960Swillf 	if (section == NULL) {
19864960Swillf 	    profile_get_string(util_context->profile, KDB_MODULE_DEF_SECTION,
19874960Swillf 			       KDB_MODULE_POINTER, NULL, NULL, &section);
19884960Swillf 	    if (section == NULL) {
19894960Swillf 		/* Stash file path neither in krb5.conf nor on command line */
19904960Swillf 		file_name = strdup(DEF_SERVICE_PASSWD_FILE);
19914960Swillf 	        if (file_name == NULL) {
19924960Swillf 	            com_err(me, ENOMEM, gettext("while setting service object password"));
19934960Swillf 	            goto cleanup;
19944960Swillf 	        }
19954960Swillf 		goto done;
19964960Swillf 	    }
19974960Swillf 	}
19984960Swillf 
19994960Swillf 	profile_get_string (util_context->profile, KDB_MODULE_SECTION, section,
20004960Swillf 			    "ldap_service_password_file", NULL, &file_name);
20014960Swillf 
20024960Swillf 	/*
20034960Swillf 	 * Solaris Kerberos: use default if ldap_service_password_file not set
20044960Swillf 	 */
20054960Swillf 	if (file_name == NULL) {
20064960Swillf 	    file_name = strdup(DEF_SERVICE_PASSWD_FILE);
20074960Swillf 	    if (file_name == NULL) {
20084960Swillf 		com_err(me, ENOMEM, gettext("while setting service object password"));
20094960Swillf 		goto cleanup;
20104960Swillf 	    }
20114960Swillf 	}
20124960Swillf     }
20134960Swillf done:
20144960Swillf 
20154960Swillf     /* Get password from user */
20164960Swillf     {
20174960Swillf 	char prompt1[256], prompt2[256];
20184960Swillf 
20194960Swillf 	/* Get the service object password from the terminal */
20204960Swillf 	memset(passwd, 0, sizeof (passwd));
20214960Swillf 	passwd_len = sizeof (passwd);
20224960Swillf 
20234960Swillf 	/* size of prompt = strlen of servicedn + strlen("Password for \" \"") */
20244960Swillf 	assert (sizeof (prompt1) > (strlen (service_object)
20254960Swillf 				    + sizeof ("Password for \" \"")));
20264960Swillf 	sprintf(prompt1, gettext("Password for \"%s\""), service_object);
20274960Swillf 
20284960Swillf 	/* size of prompt = strlen of servicedn + strlen("Re-enter Password for \" \"") */
20294960Swillf 	assert (sizeof (prompt2) > (strlen (service_object)
20304960Swillf 				    + sizeof ("Re-enter Password for \" \"")));
20314960Swillf 	sprintf(prompt2, gettext("Re-enter password for \"%s\""), service_object);
20324960Swillf 
20334960Swillf 	ret = krb5_read_password(util_context, prompt1, prompt2, passwd, &passwd_len);
20344960Swillf 	if (ret != 0) {
20354960Swillf 	    com_err(me, ret, gettext("while setting service object password"));
20364960Swillf 	    memset(passwd, 0, sizeof (passwd));
20374960Swillf 	    goto cleanup;
20384960Swillf 	}
20394960Swillf 
20404960Swillf 	if (passwd_len == 0) {
20414960Swillf 	    printf(gettext("%s: Invalid password\n"), me);
20424960Swillf 	    memset(passwd, 0, MAX_SERVICE_PASSWD_LEN);
20434960Swillf 	    goto cleanup;
20444960Swillf 	}
20454960Swillf     }
20464960Swillf 
20474960Swillf     /* Convert the password to hexadecimal */
20484960Swillf     {
20494960Swillf 	krb5_data pwd;
20504960Swillf 
20514960Swillf 	pwd.length = passwd_len;
20524960Swillf 	pwd.data = passwd;
20534960Swillf 
20544960Swillf 	ret = tohex(pwd, &hexpasswd);
20554960Swillf 	if (ret != 0) {
20564960Swillf 	    com_err(me, ret, gettext("Failed to convert the password to hexadecimal"));
20574960Swillf 	    memset(passwd, 0, passwd_len);
20584960Swillf 	    goto cleanup;
20594960Swillf 	}
20604960Swillf     }
20614960Swillf     memset(passwd, 0, passwd_len);
20624960Swillf 
20634960Swillf     /* TODO: file lock for the service passowrd file */
20644960Swillf 
20654960Swillf     /* set password in the file */
20664960Swillf #if 0 /* ************ Begin IFDEF'ed OUT ***************************** */
20674960Swillf     old_mode = umask(0177);
20684960Swillf     pfile = fopen(file_name, "a+");
20694960Swillf     if (pfile == NULL) {
20704960Swillf 	com_err(me, errno, gettext("Failed to open file %s: %s"), file_name,
20714960Swillf 		strerror (errno));
20724960Swillf 	goto cleanup;
20734960Swillf     }
20744960Swillf     rewind (pfile);
20754960Swillf     umask(old_mode);
20764960Swillf #else
20774960Swillf     /* Solaris Kerberos: safer than the above */
20784960Swillf     fd = open(file_name, O_CREAT|O_RDWR|O_APPEND, 0600);
20794960Swillf     if (fd < 0) {
20804960Swillf 	com_err(me, errno, gettext("Failed to open file %s: %s"), file_name,
20814960Swillf 		strerror (errno));
20824960Swillf 	goto cleanup;
20834960Swillf     }
20844960Swillf     pfile = fdopen(fd, "a+F");
20854960Swillf     if (pfile == NULL) {
20864960Swillf 	com_err(me, errno, gettext("Failed to open file %s: %s"), file_name,
20874960Swillf 		strerror (errno));
20884960Swillf 	goto cleanup;
20894960Swillf     }
20904960Swillf     rewind (pfile);
20914960Swillf #endif
20924960Swillf 
20934960Swillf     while (fgets (line, MAX_LEN, pfile) != NULL) {
20944960Swillf 	if ((str = strstr (line, service_object)) != NULL) {
20954960Swillf 	    /*
20964960Swillf 	     * White spaces not allowed, # delimits the service dn from the
20974960Swillf 	     * password
20984960Swillf 	     */
20994960Swillf 	    if (line [strlen (service_object)] == '#')
21004960Swillf 		break;
21014960Swillf 	    str = NULL;
21024960Swillf 	}
21034960Swillf     }
21044960Swillf 
21054960Swillf     if (str == NULL) {
21064960Swillf 	if (feof(pfile)) {
21074960Swillf 	    /* If the service object dn is not present in the service password file */
21084960Swillf 	    if (fprintf(pfile, "%s#{HEX}%s\n", service_object, hexpasswd.data) < 0) {
21094960Swillf 		com_err(me, errno, gettext("Failed to write service object password to file"));
21104960Swillf 		fclose(pfile);
21114960Swillf 		goto cleanup;
21124960Swillf 	    }
21134960Swillf 	} else {
21144960Swillf 	    com_err(me, errno, gettext("Error reading service object password file"));
21154960Swillf 	    fclose(pfile);
21164960Swillf 	    goto cleanup;
21174960Swillf 	}
21184960Swillf 	fclose(pfile);
21194960Swillf     } else {
21204960Swillf 	/*
21214960Swillf 	 * Password entry for the service object is already present in the file
21224960Swillf 	 * Delete the existing entry and add the new entry
21234960Swillf 	 */
21244960Swillf 	FILE *newfile;
21254960Swillf 
21264960Swillf 	mode_t omask;
21274960Swillf 
21284960Swillf 	/* Create a new file with the extension .tmp */
21294960Swillf 	tmp_file = (char *) malloc(sizeof(char) * (strlen(file_name) + 4 + 1));
21304960Swillf 	if (tmp_file == NULL) {
21314960Swillf 	    com_err(me, ENOMEM, gettext("while setting service object password"));
21324960Swillf 	    fclose(pfile);
21334960Swillf 	    goto cleanup;
21344960Swillf 	}
21354960Swillf 	sprintf(tmp_file,"%s.%s",file_name,"tmp");
21364960Swillf 
21374960Swillf 	omask = umask(077);
21384960Swillf 	newfile = fopen(tmp_file, "wF");
21394960Swillf 	umask (omask);
21404960Swillf 	if (newfile == NULL) {
21414960Swillf 	    com_err(me, errno, gettext("Error creating file %s"), tmp_file);
21424960Swillf 	    fclose(pfile);
21434960Swillf 	    goto cleanup;
21444960Swillf 	}
21454960Swillf 
21464960Swillf 	fseek(pfile, 0, SEEK_SET);
21474960Swillf 	while (fgets(line, MAX_LEN, pfile) != NULL) {
21484960Swillf 	    if (((str = strstr(line, service_object)) != NULL) &&
21494960Swillf 		(line[strlen(service_object)] == '#')) {
21504960Swillf 		if (fprintf(newfile, "%s#{HEX}%s\n", service_object, hexpasswd.data) < 0) {
21514960Swillf 		    com_err(me, errno, gettext("Failed to write service object password to file"));
21524960Swillf 		    fclose(newfile);
21534960Swillf 		    unlink(tmp_file);
21544960Swillf 		    fclose(pfile);
21554960Swillf 		    goto cleanup;
21564960Swillf 		}
21574960Swillf 	    } else {
21584960Swillf 		if (fprintf (newfile, "%s", line) < 0) {
21594960Swillf 		    com_err(me, errno, gettext("Failed to write service object password to file"));
21604960Swillf 		    fclose(newfile);
21614960Swillf 		    unlink(tmp_file);
21624960Swillf 		    fclose(pfile);
21634960Swillf 		    goto cleanup;
21644960Swillf 		}
21654960Swillf 	    }
21664960Swillf 	}
21674960Swillf 
21684960Swillf 	if (!feof(pfile)) {
21694960Swillf 	    com_err(me, errno, gettext("Error reading service object password file"));
21704960Swillf 	    fclose(newfile);
21714960Swillf 	    unlink(tmp_file);
21724960Swillf 	    fclose(pfile);
21734960Swillf 	    goto cleanup;
21744960Swillf 	}
21754960Swillf 
21764960Swillf 	/* TODO: file lock for the service passowrd file */
21774960Swillf 
21784960Swillf 	fclose(pfile);
21794960Swillf 	fclose(newfile);
21804960Swillf 
21814960Swillf 	ret = rename(tmp_file, file_name);
21824960Swillf 	if (ret != 0) {
21834960Swillf 	    com_err(me, errno, gettext("Failed to write service object password to "
21844960Swillf 		    "file"));
21854960Swillf 	    goto cleanup;
21864960Swillf 	}
21874960Swillf     }
21884960Swillf     ret = 0;
21894960Swillf 
21904960Swillf cleanup:
21914960Swillf 
21924960Swillf     if (hexpasswd.length != 0) {
21934960Swillf 	memset(hexpasswd.data, 0, hexpasswd.length);
21944960Swillf 	free(hexpasswd.data);
21954960Swillf     }
21964960Swillf 
21974960Swillf     if (service_object)
21984960Swillf 	free(service_object);
21994960Swillf 
22004960Swillf     if (file_name)
22014960Swillf 	free(file_name);
22024960Swillf 
22034960Swillf     if (tmp_file)
22044960Swillf 	free(tmp_file);
22054960Swillf 
22064960Swillf     if (print_usage)
22074960Swillf 	usage();
22084960Swillf /*	db_usage(STASH_SRV_PW); */
22094960Swillf 
22104960Swillf     if (ret)
22114960Swillf 	exit_status++;
22124960Swillf }
22134960Swillf 
22144960Swillf #endif /* #ifdef HAVE_EDIRECTORY */
2215