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