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