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