dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / krb5 / ldap_util / kdb5_ldap_services.c
blob392fa37b665f4d210bce4077ccffa60b12e86b2a
1 /*
2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
6 /*
7 * kadmin/ldap_util/kdb5_ldap_services.c
8 */
10 /* Copyright (c) 2004-2005, Novell, Inc.
11 * All rights reserved.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions are met:
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.
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.
38 * Create / Delete / Modify / View / List service objects.
42 * Service objects have rights over realm objects and principals. The following
43 * functions manage the service objects.
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"
53 #ifdef HAVE_EDIRECTORY
55 krb5_error_code
56 rem_service_entry_from_file(int argc,
57 char *argv[],
58 char *file_name,
59 char *service_object);
61 extern char *yes;
62 extern krb5_boolean db_inited;
64 static int process_host_list(char **host_list, int servicetype)
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;
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];
77 /* Check input for buffer overflow */
78 if (hostname_len >= MAX_LEN_LIST_ENTRY) {
79 retval = EINVAL;
80 goto cleanup;
83 /* First copy off the host name portion */
84 strncpy (host_str, host_list[j], hostname_len);
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 */
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';
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);
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);
123 /* Print warning message */
124 printf (gettext("Admin Server supports only TCP protocol, hence setting that\n"));
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);
135 /* Print warning message */
136 printf (gettext("Password Server supports only UDP protocol, hence setting that\n"));
139 if (port_str[0] == '\0')
140 sprintf (port_str, "%d", PORT_DEFAULT_PWD);
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;
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);
155 cleanup:
156 return retval;
161 * Given a realm name, this function will convert it to a DN by appending the
162 * Kerberos container location.
164 static krb5_error_code
165 convert_realm_name2dn_list(list, krbcontainer_loc)
166 char **list;
167 const char *krbcontainer_loc;
169 krb5_error_code retval = 0;
170 char temp_str[MAX_DN_CHARS] = "\0";
171 char *temp_node = NULL;
172 int i = 0;
174 if (list == NULL) {
175 return EINVAL;
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);
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;
189 /* On success, free list node and attach new one */
190 free (list[i]);
191 list[i] = temp_node;
192 temp_node = NULL;
195 cleanup:
196 return retval;
201 * This function will create a service object on the LDAP Server, with the
202 * specified attributes.
204 void kdb5_ldap_create_service(argc, argv)
205 int argc;
206 char *argv[];
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;
227 /* Check for number of arguments */
228 if ((argc < 3) || (argc > 10)) {
229 exit_status++;
230 goto err_usage;
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;
240 dal_handle = (kdb5_dal_handle *) util_context->db_context;
241 ldap_context = (krb5_ldap_context *) dal_handle->db_context;
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;
252 /* Set first of the extra arguments as the program name */
253 extra_argv[0] = me;
254 extra_argc++;
256 /* Read Kerberos container info, to construct realm DN from name
257 * and for assigning rights
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;
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;
277 srvparams->krbhostservers = (char **)calloc(MAX_LIST_ENTRIES,
278 sizeof(char *));
279 if (srvparams->krbhostservers == NULL) {
280 retval = ENOMEM;
281 goto cleanup;
284 if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER,
285 srvparams->krbhostservers))) {
286 goto cleanup;
289 if ((retval = process_host_list (srvparams->krbhostservers,
290 srvparams->servicetype))) {
291 goto cleanup;
294 mask |= LDAP_SERVICE_HOSTSERVER;
295 } else if (!strcmp(argv[i], "-realm")) {
296 if (++i > argc - 1)
297 goto err_usage;
299 srvparams->krbrealmreferences = (char **)calloc(MAX_LIST_ENTRIES,
300 sizeof(char *));
301 if (srvparams->krbrealmreferences == NULL) {
302 retval = ENOMEM;
303 goto cleanup;
306 if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER,
307 srvparams->krbrealmreferences))) {
308 goto cleanup;
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;
318 mask |= LDAP_SERVICE_REALMREFERENCE;
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()
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'
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++;
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++;
341 if (++i > argc - 1)
342 goto err_usage;
344 extra_argv[extra_argc] = argv[i];
345 extra_argc++;
346 } else { /* Any other option is invalid */
347 exit_status++;
348 goto err_usage;
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
354 if (srvparams->servicedn != NULL) {
355 com_err(me, EINVAL, gettext("while creating service object"));
356 goto err_usage;
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;
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;
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;
379 /* Create object with all attributes provided */
380 if ((retval = krb5_ldap_create_service(util_context, srvparams, mask)))
381 goto cleanup;
383 service_obj_created = TRUE;
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.
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;
398 extra_argc++;
400 if ((retval = kdb5_ldap_set_service_password(extra_argc, extra_argv)) != 0) {
401 goto err_nomsg;
404 /* Rights assignment */
405 if (mask & LDAP_SERVICE_REALMREFERENCE) {
407 printf("%s", gettext("Changing rights for the service object. Please wait ... "));
408 fflush(stdout);
410 rightsmask =0;
411 rightsmask |= LDAP_REALM_RIGHTS;
412 rightsmask |= LDAP_SUBTREE_RIGHTS;
414 if ((srvparams != NULL) && (srvparams->krbrealmreferences != NULL)) {
415 for (i=0; (srvparams->krbrealmreferences[i] != NULL); i++) {
417 /* Get the realm name, not the dn */
418 temprdns = ldap_explode_dn(srvparams->krbrealmreferences[i], 1);
420 if (temprdns[0] == NULL) {
421 retval = EINVAL;
422 goto cleanup;
425 realmName = strdup(temprdns[0]);
426 if (realmName == NULL) {
427 retval = ENOMEM;
428 goto cleanup;
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;
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;
447 if (rparams)
448 krb5_ldap_free_realm_params(rparams);
451 printf(gettext("done\n"));
453 goto cleanup;
455 err_usage:
456 print_usage = TRUE;
458 err_nomsg:
459 no_msg = TRUE;
461 cleanup:
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
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
471 krb5_ldap_delete_service(util_context, srvparams, srvparams->servicedn);
474 /* Clean-up structure */
475 krb5_ldap_free_service (util_context, srvparams);
477 if (extra_argv) {
478 free (extra_argv);
479 extra_argv = NULL;
481 if (realmName) {
482 free(realmName);
483 realmName = NULL;
485 if (print_usage)
486 db_usage (CREATE_SERVICE);
488 if (retval) {
489 if (!no_msg)
490 com_err(me, retval, gettext("while creating service object"));
492 exit_status++;
495 return;
500 * This function will modify the attributes of a given service
501 * object on the LDAP Server
503 void kdb5_ldap_modify_service(argc, argv)
504 int argc;
505 char *argv[];
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;
531 /* Check for number of arguments */
532 if ((argc < 3) || (argc > 10)) {
533 exit_status++;
534 goto err_usage;
537 dal_handle = (kdb5_dal_handle *) util_context->db_context;
538 ldap_context = (krb5_ldap_context *) dal_handle->db_context;
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;
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;
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;
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;
587 /* Read Kerberos container info, to construct realm DN from name
588 * and for assigning rights
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;
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;
602 /* Free the old list if available */
603 if (srvparams->krbhostservers) {
604 krb5_free_list_entries (srvparams->krbhostservers);
605 free (srvparams->krbhostservers);
608 srvparams->krbhostservers = (char **)calloc(MAX_LIST_ENTRIES,
609 sizeof(char *));
610 if (srvparams->krbhostservers == NULL) {
611 retval = ENOMEM;
612 goto cleanup;
615 if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER,
616 srvparams->krbhostservers))) {
617 goto cleanup;
620 if ((retval = process_host_list (srvparams->krbhostservers,
621 srvparams->servicetype))) {
622 goto cleanup;
625 out_mask |= LDAP_SERVICE_HOSTSERVER;
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;
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;
641 /* Allocate list for processing */
642 list = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
643 if (list == NULL) {
644 retval = ENOMEM;
645 goto cleanup;
648 if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list)))
649 goto cleanup;
651 if ((retval = process_host_list (list, srvparams->servicetype))) {
652 goto cleanup;
655 list_modify_str_array(&(srvparams->krbhostservers),
656 (const char**)list, LIST_MODE_DELETE);
658 out_mask |= LDAP_SERVICE_HOSTSERVER;
660 /* Clean up */
661 free (list);
662 list = NULL;
664 } else if (!strcmp(argv[i], "-addservicehost")) {
665 if (++i > argc - 1)
666 goto err_usage;
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;
676 if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list)))
677 goto cleanup;
679 if ((retval = process_host_list (list, srvparams->servicetype))) {
680 goto cleanup;
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()
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 **) reallocarray(srvparams->krbhostservers,
692 (existing_entries + new_entries + 1),
693 sizeof(char *));
694 if (temp_ptr == NULL) {
695 retval = ENOMEM;
696 goto cleanup;
698 srvparams->krbhostservers = temp_ptr;
700 list_modify_str_array(&(srvparams->krbhostservers),
701 (const char**)list, LIST_MODE_ADD);
703 /* Clean up */
704 free (list);
705 list = NULL;
706 } else
707 srvparams->krbhostservers = list;
709 out_mask |= LDAP_SERVICE_HOSTSERVER;
711 } else if (!strcmp(argv[i], "-realm")) {
712 if (++i > argc - 1)
713 goto err_usage;
715 if ((in_mask & LDAP_SERVICE_REALMREFERENCE) && (srvparams->krbrealmreferences)) {
716 if (!oldrealmrefs) {
717 /* Store the old realm list for removing rights */
718 oldrealmrefs = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
719 if (oldrealmrefs == NULL) {
720 retval = ENOMEM;
721 goto cleanup;
724 for (j = 0; srvparams->krbrealmreferences[j] != NULL; j++) {
725 oldrealmrefs[j] = strdup(srvparams->krbrealmreferences[j]);
726 if (oldrealmrefs[j] == NULL) {
727 retval = ENOMEM;
728 goto cleanup;
731 oldrealmrefs[j] = NULL;
734 /* Free the old list if available */
735 krb5_free_list_entries (srvparams->krbrealmreferences);
736 free (srvparams->krbrealmreferences);
739 srvparams->krbrealmreferences = (char **)calloc(MAX_LIST_ENTRIES,
740 sizeof(char *));
741 if (srvparams->krbrealmreferences == NULL) {
742 retval = ENOMEM;
743 goto cleanup;
746 if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER,
747 srvparams->krbrealmreferences))) {
748 goto cleanup;
751 /* Convert realm names to realm DNs */
752 if ((retval = convert_realm_name2dn_list(
753 srvparams->krbrealmreferences,
754 ldap_context->krbcontainer->DN))) {
755 goto cleanup;
758 out_mask |= LDAP_SERVICE_REALMREFERENCE;
760 /* Set flag to ignore 'add' and 'clear' */
761 realmdn_flag = 1;
762 } else if (!strcmp(argv[i], "-clearrealm")) {
763 if (++i > argc - 1)
764 goto err_usage;
766 if (!realmdn_flag) {
767 /* If attribute doesn't exist, don't permit 'clear' option */
768 if (((in_mask & LDAP_SERVICE_REALMREFERENCE) == 0) || (srvparams->krbrealmreferences == NULL)) {
769 /* Send out some proper error message here */
770 goto err_nomsg;
773 if (!oldrealmrefs) {
774 /* Store the old realm list for removing rights */
775 oldrealmrefs = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
776 if (oldrealmrefs == NULL) {
777 retval = ENOMEM;
778 goto cleanup;
781 for (j = 0; srvparams->krbrealmreferences[j] != NULL; j++) {
782 oldrealmrefs[j] = strdup(srvparams->krbrealmreferences[j]);
783 if (oldrealmrefs[j] == NULL) {
784 retval = ENOMEM;
785 goto cleanup;
788 oldrealmrefs[j] = NULL;
791 /* Allocate list for processing */
792 list = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
793 if (list == NULL) {
794 retval = ENOMEM;
795 goto cleanup;
798 if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list)))
799 goto cleanup;
801 /* Convert realm names to realm DNs */
802 if ((retval = convert_realm_name2dn_list(list,
803 ldap_context->krbcontainer->DN))) {
804 goto cleanup;
807 list_modify_str_array(&(srvparams->krbrealmreferences),
808 (const char**)list, LIST_MODE_DELETE);
810 out_mask |= LDAP_SERVICE_REALMREFERENCE;
812 /* Clean up */
813 free (list);
814 list = NULL;
816 } else if (!strcmp(argv[i], "-addrealm")) {
817 if (++i > argc - 1)
818 goto err_usage;
820 if (!realmdn_flag) {
821 /* Allocate list for processing */
822 list = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
823 if (list == NULL) {
824 retval = ENOMEM;
825 goto cleanup;
828 if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list)))
829 goto cleanup;
831 /* Convert realm names to realm DNs */
832 if ((retval = convert_realm_name2dn_list(list,
833 ldap_context->krbcontainer->DN))) {
834 goto cleanup;
837 if ((in_mask & LDAP_SERVICE_REALMREFERENCE) && (srvparams->krbrealmreferences) && (!oldrealmrefs)) {
838 /* Store the old realm list for removing rights */
839 oldrealmrefs = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
840 if (oldrealmrefs == NULL) {
841 retval = ENOMEM;
842 goto cleanup;
845 for (j = 0; srvparams->krbrealmreferences[j] != NULL; j++) {
846 oldrealmrefs[j] = strdup(srvparams->krbrealmreferences[j]);
847 if (oldrealmrefs[j] == NULL) {
848 retval = ENOMEM;
849 goto cleanup;
852 oldrealmrefs[j] = NULL;
855 /* Call list_modify_str_array() only if realm DN attribute
856 * exists already -- Actually, it's better to handle this
857 * within list_modify_str_array() */
858 if (in_mask & LDAP_SERVICE_REALMREFERENCE) {
859 /* Re-size existing list */
860 existing_entries = list_count_str_array(
861 srvparams->krbrealmreferences);
862 new_entries = list_count_str_array(list);
863 temp_ptr = (char **) reallocarray(srvparams->krbrealmreferences,
864 (existing_entries + new_entries + 1),
865 sizeof(char *));
866 if (temp_ptr == NULL) {
867 retval = ENOMEM;
868 goto cleanup;
870 srvparams->krbrealmreferences = temp_ptr;
872 list_modify_str_array(&(srvparams->krbrealmreferences),
873 (const char**)list, LIST_MODE_ADD);
875 /* Clean up */
876 free (list);
877 list = NULL;
878 } else
879 srvparams->krbrealmreferences = list;
881 out_mask |= LDAP_SERVICE_REALMREFERENCE;
883 } else {
884 /* Any other argument must be service DN
885 -- skip it */
889 /* Modify attributes of object */
890 if ((retval = krb5_ldap_modify_service(util_context, srvparams, out_mask)))
891 goto cleanup;
893 /* Service rights modification code */
894 if (out_mask & LDAP_SERVICE_REALMREFERENCE) {
896 printf("%s", gettext("Changing rights for the service object. Please wait ... "));
897 fflush(stdout);
899 newrealmrefs = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
900 if (newrealmrefs == NULL) {
901 retval = ENOMEM;
902 goto cleanup;
905 if ((srvparams != NULL) && (srvparams->krbrealmreferences != NULL)) {
906 for (j = 0; srvparams->krbrealmreferences[j] != NULL; j++) {
907 newrealmrefs[j] = strdup(srvparams->krbrealmreferences[j]);
908 if (newrealmrefs[j] == NULL) {
909 retval = ENOMEM;
910 goto cleanup;
913 newrealmrefs[j] = NULL;
915 disjoint_members(oldrealmrefs, newrealmrefs);
917 /* Delete the rights for the given service, on each of the realm
918 * container & subtree in the old realm reference list.
920 if (oldrealmrefs) {
921 rightsmask = 0;
922 rightsmask |= LDAP_REALM_RIGHTS;
923 rightsmask |= LDAP_SUBTREE_RIGHTS;
925 for (i = 0; (oldrealmrefs[i] != NULL); i++) {
926 /* Get the realm name, not the dn */
927 temprdns = ldap_explode_dn(oldrealmrefs[i], 1);
929 if (temprdns[0] == NULL) {
930 retval = EINVAL;
931 goto cleanup;
934 realmName = strdup(temprdns[0]);
935 if (realmName == NULL) {
936 retval = ENOMEM;
937 goto cleanup;
940 if ((retval = krb5_ldap_read_realm_params(util_context,
941 realmName, &rparams, &rmask))) {
942 com_err(me, retval, gettext("while reading information of realm '%s'"),
943 realmName);
944 goto err_nomsg;
947 if ((retval = krb5_ldap_delete_service_rights(util_context,
948 srvparams->servicetype, srvparams->servicedn,
949 realmName, rparams->subtree, rightsmask))) {
950 printf(gettext("failed\n"));
951 com_err(me, retval, gettext("while assigning rights '%s'"),
952 srvparams->servicedn);
953 goto err_nomsg;
956 if (rparams)
957 krb5_ldap_free_realm_params(rparams);
961 /* Add the rights for the given service, on each of the realm
962 * container & subtree in the new realm reference list.
964 if (newrealmrefs) {
965 rightsmask = 0;
966 rightsmask |= LDAP_REALM_RIGHTS;
967 rightsmask |= LDAP_SUBTREE_RIGHTS;
969 for (i = 0; (newrealmrefs[i] != NULL); i++) {
970 /* Get the realm name, not the dn */
971 temprdns = ldap_explode_dn(newrealmrefs[i], 1);
973 if (temprdns[0] == NULL) {
974 retval = EINVAL;
975 goto cleanup;
978 realmName = strdup(temprdns[0]);
979 if (realmName == NULL) {
980 retval = ENOMEM;
981 goto cleanup;
984 if ((retval = krb5_ldap_read_krbcontainer_params(util_context,
985 &(ldap_context->krbcontainer)))) {
986 com_err(me, retval,
987 gettext("while reading Kerberos container information"));
988 goto cleanup;
991 if ((retval = krb5_ldap_read_realm_params(util_context,
992 realmName, &rparams, &rmask))) {
993 com_err(me, retval, gettext("while reading information of realm '%s'"),
994 realmName);
995 goto err_nomsg;
998 if ((retval = krb5_ldap_add_service_rights(util_context,
999 srvparams->servicetype, srvparams->servicedn,
1000 realmName, rparams->subtree, rightsmask))) {
1001 printf(gettext("failed\n"));
1002 com_err(me, retval, gettext("while assigning rights '%s'"),
1003 srvparams->servicedn);
1004 goto err_nomsg;
1007 if (rparams) {
1008 krb5_ldap_free_realm_params(rparams);
1009 rparams = NULL;
1012 printf(gettext("done\n"));
1015 goto cleanup;
1017 err_usage:
1018 print_usage = TRUE;
1020 err_nomsg:
1021 no_msg = TRUE;
1023 cleanup:
1024 /* Clean-up structure */
1025 krb5_ldap_free_service(util_context, srvparams);
1027 free(servicedn);
1029 if (list) {
1030 free(list);
1031 list = NULL;
1034 if (oldrealmrefs) {
1035 for (i = 0; oldrealmrefs[i] != NULL; i++)
1036 free(oldrealmrefs[i]);
1037 free(oldrealmrefs);
1040 if (newrealmrefs) {
1041 for (i = 0; newrealmrefs[i] != NULL; i++)
1042 free(newrealmrefs[i]);
1043 free(newrealmrefs);
1045 if (realmName) {
1046 free(realmName);
1047 realmName = NULL;
1050 if (print_usage)
1051 db_usage(MODIFY_SERVICE);
1053 if (retval) {
1054 if (!no_msg)
1055 com_err(me, retval, gettext("while modifying service object"));
1056 exit_status++;
1059 return;
1064 * This function will delete the entry corresponding to the service object
1065 * from the service password file.
1067 static krb5_error_code
1068 rem_service_entry_from_file(argc, argv, file_name, service_object)
1069 int argc;
1070 char *argv[];
1071 char *file_name;
1072 char *service_object;
1074 int st = EINVAL;
1075 /* Solaris Kerberos */
1076 char *me = progname;
1077 char *tmp_file = NULL;
1078 int tmpfd = -1;
1079 FILE *pfile = NULL;
1080 unsigned int len = 0;
1081 char line[MAX_LEN]={0};
1082 mode_t omask = umask(077);
1084 /* Check for permissions on the password file */
1085 if (access(file_name, W_OK) == -1) {
1086 /* If the specified file itself is not there, no need to show error */
1087 if (errno == ENOENT) {
1088 st=0;
1089 goto cleanup;
1090 } else {
1091 com_err(me, errno, gettext("while deleting entry from file %s", file_name));
1092 goto cleanup;
1096 /* Create a temporary file which contains all the entries except the
1097 entry for the given service dn */
1098 pfile = fopen(file_name, "r+F");
1099 if (pfile == NULL) {
1100 com_err(me, errno, gettext("while deleting entry from file %s"), file_name);
1101 goto cleanup;
1104 /* Create a new file with the extension .tmp */
1105 tmp_file = (char *)malloc(strlen(file_name) + 4 + 1);
1106 if (tmp_file == NULL) {
1107 com_err(me, ENOMEM, gettext("while deleting entry from file"));
1108 fclose(pfile);
1109 goto cleanup;
1111 snprintf (tmp_file, strlen(file_name) + 4 + 1, "%s%s", file_name, ".tmp");
1114 tmpfd = creat(tmp_file, S_IRUSR|S_IWUSR);
1115 umask(omask);
1116 if (tmpfd == -1) {
1117 com_err(me, errno, gettext("while deleting entry from file\n"));
1118 fclose(pfile);
1119 goto cleanup;
1122 /* Copy only those lines which donot have the specified service dn */
1123 while (fgets(line, MAX_LEN, pfile) != NULL) {
1124 if ((strstr(line, service_object) != NULL) &&
1125 (line[strlen(service_object)] == '#')) {
1126 continue;
1127 } else {
1128 len = strlen(line);
1129 if (write(tmpfd, line, len) != len) {
1130 com_err(me, errno, gettext("while deleting entry from file\n"));
1131 close(tmpfd);
1132 unlink(tmp_file);
1133 fclose(pfile);
1134 goto cleanup;
1139 fclose(pfile);
1140 if (unlink(file_name) == 0) {
1141 link(tmp_file, file_name);
1142 } else {
1143 com_err(me, errno, gettext("while deleting entry from file\n"));
1145 unlink(tmp_file);
1147 st=0;
1149 cleanup:
1151 free(tmp_file);
1153 return st;
1158 * This function will delete the service object from the LDAP Server
1159 * and unlink the references to the Realm objects (if any)
1161 void
1162 kdb5_ldap_destroy_service(argc, argv)
1163 int argc;
1164 char *argv[];
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;
1176 if ((argc < 2) || (argc > 5)) {
1177 exit_status++;
1178 goto err_usage;
1181 for (i=1; i < argc; i++) {
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;
1194 i++;
1195 } else {
1196 exit_status++;
1197 goto err_usage;
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;
1208 } else {
1209 exit_status++;
1210 goto err_usage;
1215 if (!servicedn) {
1216 exit_status++;
1217 goto err_usage;
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;;
1227 if (strcmp(buf, yes)) {
1228 exit_status++;
1229 goto cleanup;
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;
1241 retval = krb5_ldap_delete_service(util_context, lserparams, servicedn);
1243 if (retval) {
1244 /* Solaris Kerberos */
1245 com_err(progname, retval, gettext("while destroying service '%s'"), servicedn);
1246 exit_status++;
1247 goto cleanup;
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;
1259 printf(gettext("** service object '%s' deleted.\n"), servicedn);
1260 retval = rem_service_entry_from_file(argc, argv, stashfilename, servicedn);
1262 if (retval)
1263 printf(gettext("** error removing service object entry '%s' from password file.\n"),
1264 servicedn);
1266 goto cleanup;
1269 err_usage:
1270 print_usage = TRUE;
1272 cleanup:
1274 if (lserparams) {
1275 krb5_ldap_free_service(util_context, lserparams);
1278 if (servicedn) {
1279 free(servicedn);
1282 if (stashfilename) {
1283 free(stashfilename);
1286 if (print_usage) {
1287 db_usage(DESTROY_SERVICE);
1290 return;
1295 * This function will display information about the given service object
1297 void kdb5_ldap_view_service(argc, argv)
1298 int argc;
1299 char *argv[];
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;
1307 if (!(argc == 2)) {
1308 exit_status++;
1309 goto err_usage;
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;
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;
1327 print_service_params(lserparams, mask);
1329 goto cleanup;
1331 err_usage:
1332 print_usage = TRUE;
1334 cleanup:
1336 if (lserparams) {
1337 krb5_ldap_free_service(util_context, lserparams);
1340 free(servicedn);
1342 if (print_usage) {
1343 db_usage(VIEW_SERVICE);
1346 return;
1351 * This function will list the DNs of kerberos services present on
1352 * the LDAP Server under a specific sub-tree (entire tree by default)
1354 void kdb5_ldap_list_services(argc, argv)
1355 int argc;
1356 char *argv[];
1358 /* Solaris Kerberos */
1359 char *me = progname;
1360 krb5_error_code retval = 0;
1361 char *basedn = NULL;
1362 char **list = NULL;
1363 char **plist = NULL;
1364 krb5_boolean print_usage = FALSE;
1366 /* Check for number of arguments */
1367 if ((argc != 1) && (argc != 3)) {
1368 exit_status++;
1369 goto err_usage;
1372 /* Parse base DN argument if present */
1373 if (argc == 3) {
1374 if (strcmp(argv[1], "-basedn")) {
1375 retval = EINVAL;
1376 goto err_usage;
1379 basedn = strdup(argv[2]);
1380 if (basedn == NULL) {
1381 com_err(me, ENOMEM, gettext("while listing services"));
1382 exit_status++;
1383 goto cleanup;
1387 retval = krb5_ldap_list_services(util_context, basedn, &list);
1388 if ((retval != 0) || (list == NULL)) {
1389 exit_status++;
1390 goto cleanup;
1393 for (plist = list; *plist != NULL; plist++) {
1394 printf("%s\n", *plist);
1397 goto cleanup;
1399 err_usage:
1400 print_usage = TRUE;
1402 cleanup:
1403 if (list != NULL) {
1404 krb5_free_list_entries (list);
1405 free (list);
1408 free(basedn);
1410 if (print_usage) {
1411 db_usage(LIST_SERVICE);
1414 if (retval) {
1415 com_err(me, retval, gettext("while listing policy objects"));
1416 exit_status++;
1419 return;
1424 * This function will print the service object information
1425 * to the standard output
1427 static void
1428 print_service_params(lserparams, mask)
1429 krb5_ldap_service_params *lserparams;
1430 int mask;
1432 int i=0;
1434 /* Print the service dn */
1435 printf("%20s%-20s\n", gettext("Service dn: "), lserparams->servicedn);
1437 /* Print the service type of the object to be read */
1438 if (lserparams->servicetype == LDAP_KDC_SERVICE) {
1439 printf("%20s%-20s\n", gettext("Service type: "), "kdc");
1440 } else if (lserparams->servicetype == LDAP_ADMIN_SERVICE) {
1441 printf("%20s%-20s\n", gettext("Service type: "), "admin");
1442 } else if (lserparams->servicetype == LDAP_PASSWD_SERVICE) {
1443 printf("%20s%-20s\n", gettext("Service type: "), "pwd");
1446 /* Print the host server values */
1447 printf("%20s\n", gettext("Service host list: "));
1448 if (mask & LDAP_SERVICE_HOSTSERVER) {
1449 for (i=0; lserparams->krbhostservers[i] != NULL; ++i) {
1450 printf("%20s%-50s\n","",lserparams->krbhostservers[i]);
1454 /* Print the realm reference dn values */
1455 printf("%20s\n", gettext("Realm DN list: "));
1456 if (mask & LDAP_SERVICE_REALMREFERENCE) {
1457 for (i=0; lserparams && lserparams->krbrealmreferences && lserparams->krbrealmreferences[i] != NULL; ++i) {
1458 printf("%20s%-50s\n","",lserparams->krbrealmreferences[i]);
1462 return;
1467 * This function will generate random password of length(RANDOM_PASSWD_LEN)
1470 * INPUT:
1471 * ctxt - context
1473 * OUTPUT:
1474 * RANDOM_PASSWD_LEN length random password
1476 static int generate_random_password(krb5_context ctxt, char **randpwd, unsigned int *passlen)
1478 char *random_pwd = NULL;
1479 int ret = 0;
1480 krb5_data data;
1481 int i=0;
1482 /*int len = 0;*/
1484 /* setting random password length in the range 16-32 */
1485 srand((unsigned int)(time(0) ^ getpid()));
1487 data.length = RANDOM_PASSWD_LEN;
1488 random_pwd = (char *)malloc(data.length + 1);
1489 if (random_pwd == NULL) {
1490 com_err("setsrvpw", ENOMEM, gettext("while generating random password"));
1491 return ENOMEM;
1493 memset(random_pwd, 0, data.length + 1);
1494 data.data = random_pwd;
1496 ret = krb5_c_random_make_octets(ctxt, &data);
1497 if (ret) {
1498 com_err("setsrvpw", ret, gettext("Error generating random password"));
1499 free(random_pwd);
1500 return ret;
1503 for (i=0; i<data.length; i++) {
1504 /* restricting to ascii chars. Need to change this when 8.8 supports */
1505 if ((unsigned char)random_pwd[i] > 127) {
1506 random_pwd[i] = (unsigned char)random_pwd[i] % 128;
1507 } else if (random_pwd[i] == 0) {
1508 random_pwd[i] = (rand()/(RAND_MAX/127 + 1))+1;
1512 *randpwd = random_pwd;
1513 *passlen = data.length;
1515 return 0;
1520 * This function will set the password of the service object in the directory
1521 * and/or the specified service password file.
1524 * INPUT:
1525 * argc - contains the number of arguments for this sub-command
1526 * argv - array of arguments for this sub-command
1528 * OUTPUT:
1529 * void
1532 kdb5_ldap_set_service_password(argc, argv)
1533 int argc;
1534 char **argv;
1536 krb5_ldap_context *lparams = NULL;
1537 char *file_name = NULL;
1538 char *tmp_file = NULL;
1539 /* Solaris Kerberos */
1540 char *me = progname;
1541 int filelen = 0;
1542 int random_passwd = 0;
1543 int set_dir_pwd = 1;
1544 krb5_boolean db_init_local = FALSE;
1545 char *service_object = NULL;
1546 char *passwd = NULL;
1547 char *prompt1 = NULL;
1548 char *prompt2 = NULL;
1549 unsigned int passwd_len = 0;
1550 krb5_error_code errcode = -1;
1551 int retval = 0, i = 0;
1552 unsigned int len = 0;
1553 krb5_boolean print_usage = FALSE;
1554 FILE *pfile = NULL;
1555 char *str = NULL;
1556 char line[MAX_LEN];
1557 kdb5_dal_handle *dal_handle = NULL;
1558 struct data encrypted_passwd = {0, NULL};
1560 /* The arguments for setsrv password should contain the service object DN
1561 * and options to specify whether the password should be updated in file only
1562 * or both file and directory. So the possible combination of arguments are:
1563 * setsrvpw servicedn wherein argc is 2
1564 * setsrvpw -fileonly servicedn wherein argc is 3
1565 * setsrvpw -randpw servicedn wherein argc is 3
1566 * setsrvpw -f filename servicedn wherein argc is 4
1567 * setsrvpw -fileonly -f filename servicedn wherein argc is 5
1568 * setsrvpw -randpw -f filename servicedn wherein argc is 5
1570 if ((argc < 2) || (argc > 5)) {
1571 print_usage = TRUE;
1572 goto cleanup;
1575 dal_handle = (kdb5_dal_handle *)util_context->db_context;
1576 lparams = (krb5_ldap_context *) dal_handle->db_context;
1578 if (lparams == NULL) {
1579 printf(gettext("%s: Invalid LDAP handle\n"), me);
1580 goto cleanup;
1583 /* Parse the arguments */
1584 for (i = 1; i < argc -1 ; i++) {
1585 if (strcmp(argv[i], "-randpw") == 0) {
1586 random_passwd = 1;
1587 } else if (strcmp(argv[i], "-fileonly") == 0) {
1588 set_dir_pwd = 0;
1589 } else if (strcmp(argv[i], "-f") == 0) {
1590 if (argv[++i] == NULL) {
1591 print_usage = TRUE;
1592 goto cleanup;
1595 file_name = strdup(argv[i]);
1596 if (file_name == NULL) {
1597 com_err(me, ENOMEM, gettext("while setting service object password"));
1598 goto cleanup;
1600 /* Verify if the file location has the proper file name
1601 * for eg, if the file location is a directory like /home/temp/,
1602 * we reject it.
1604 filelen = strlen(file_name);
1605 if ((filelen == 0) || (file_name[filelen-1] == '/')) {
1606 printf(gettext("%s: Filename not specified for setting service object password\n"), me);
1607 print_usage = TRUE;
1608 goto cleanup;
1610 } else {
1611 printf(gettext("%s: Invalid option specified for \"setsrvpw\" command\n"), me);
1612 print_usage = TRUE;
1613 goto cleanup;
1617 if (i != argc-1) {
1618 print_usage = TRUE;
1619 goto cleanup;
1622 service_object = strdup(argv[i]);
1623 if (service_object == NULL) {
1624 com_err(me, ENOMEM, gettext("while setting service object password"));
1625 goto cleanup;
1628 if (strlen(service_object) == 0) {
1629 printf(gettext("%s: Service object not specified for \"setsrvpw\" command\n"), me);
1630 print_usage = TRUE;
1631 goto cleanup;
1634 if (service_object[0] == '-') {
1635 print_usage = TRUE;
1636 goto cleanup;
1639 if (file_name == NULL) {
1640 file_name = strdup(DEF_SERVICE_PASSWD_FILE);
1641 if (file_name == NULL) {
1642 com_err(me, ENOMEM, gettext("while setting service object password"));
1643 goto cleanup;
1647 if (set_dir_pwd) {
1648 if (db_inited == FALSE) {
1649 if ((errcode = krb5_ldap_db_init(util_context, lparams))) {
1650 com_err(me, errcode, gettext("while initializing database"));
1651 goto cleanup;
1653 db_init_local = TRUE;
1657 if (random_passwd) {
1658 if (!set_dir_pwd) {
1659 printf(gettext("%s: Invalid option specified for \"setsrvpw\" command\n"), me);
1660 print_usage = TRUE;
1661 goto cleanup;
1662 } else {
1663 /* Generate random password */
1665 if ((errcode = generate_random_password(util_context, &passwd, &passwd_len))) {
1666 printf(gettext("%s: Failed to set service object password\n"), me);
1667 goto cleanup;
1669 passwd_len = strlen(passwd);
1671 } else {
1672 /* Get the service object password from the terminal */
1673 passwd = (char *)malloc(MAX_SERVICE_PASSWD_LEN + 1);
1674 if (passwd == NULL) {
1675 com_err(me, ENOMEM, gettext("while setting service object password"));
1676 goto cleanup;
1678 memset(passwd, 0, MAX_SERVICE_PASSWD_LEN + 1);
1679 passwd_len = MAX_SERVICE_PASSWD_LEN;
1681 len = strlen(service_object);
1682 /* size of allocation=strlen of servicedn + strlen("Password for \" \"")=20 */
1683 prompt1 = (char *)malloc(len + 20);
1684 if (prompt1 == NULL) {
1685 com_err(me, ENOMEM, gettext("while setting service object password"));
1686 goto cleanup;
1688 sprintf(prompt1, gettext("Password for \"%s\""), service_object);
1690 /* size of allocation=strlen of servicedn + strlen("Re-enter Password for \" \"")=30 */
1691 prompt2 = (char *)malloc(len + 30);
1692 if (prompt2 == NULL) {
1693 com_err(me, ENOMEM, gettext("while setting service object password"));
1694 free(prompt1);
1695 goto cleanup;
1697 sprintf(prompt2, gettext("Re-enter password for \"%s\""), service_object);
1699 retval = krb5_read_password(util_context, prompt1, prompt2, passwd, &passwd_len);
1700 free(prompt1);
1701 free(prompt2);
1702 if (retval) {
1703 com_err(me, retval, gettext("while setting service object password"));
1704 memset(passwd, 0, MAX_SERVICE_PASSWD_LEN);
1705 goto cleanup;
1707 if (passwd_len == 0) {
1708 printf(gettext("%s: Invalid password\n"), me);
1709 memset(passwd, 0, MAX_SERVICE_PASSWD_LEN);
1710 goto cleanup;
1712 passwd_len = strlen(passwd);
1715 /* Hex the password */
1717 krb5_data pwd, hex;
1718 pwd.length = passwd_len;
1719 pwd.data = passwd;
1721 errcode = tohex(pwd, &hex);
1722 if (errcode != 0) {
1723 if (hex.length != 0) {
1724 memset(hex.data, 0, hex.length);
1725 free(hex.data);
1727 com_err(me, errcode, gettext("Failed to convert the password to hex"));
1728 memset(passwd, 0, passwd_len);
1729 goto cleanup;
1731 /* Password = {CRYPT}<encrypted password>:<encrypted key> */
1732 encrypted_passwd.value = (unsigned char *)malloc(strlen(service_object) +
1733 1 + 5 + hex.length + 2);
1734 if (encrypted_passwd.value == NULL) {
1735 com_err(me, ENOMEM, gettext("while setting service object password"));
1736 memset(passwd, 0, passwd_len);
1737 memset(hex.data, 0, hex.length);
1738 free(hex.data);
1739 goto cleanup;
1741 encrypted_passwd.value[strlen(service_object) +
1742 1 + 5 + hex.length + 1] = '\0';
1743 sprintf((char *)encrypted_passwd.value, "%s#{HEX}%s\n", service_object, hex.data);
1744 encrypted_passwd.len = strlen((char *)encrypted_passwd.value);
1745 memset(hex.data, 0, hex.length);
1746 free(hex.data);
1749 /* We should check if the file exists and we have permission to write into that file */
1750 if (access(file_name, W_OK) == -1) {
1751 if (errno == ENOENT) {
1752 mode_t omask;
1753 int fd = -1;
1755 printf(gettext("File does not exist. Creating the file %s...\n"), file_name);
1756 omask = umask(077);
1757 fd = creat(file_name, S_IRUSR|S_IWUSR);
1758 umask(omask);
1759 if (fd == -1) {
1760 com_err(me, errno, gettext("Error creating file %s"), file_name);
1761 memset(passwd, 0, passwd_len);
1762 goto cleanup;
1764 close(fd);
1765 } else {
1766 com_err(me, errno, gettext("Unable to access the file %s"), file_name);
1767 memset(passwd, 0, passwd_len);
1768 goto cleanup;
1772 if (set_dir_pwd) {
1773 if ((errcode = krb5_ldap_set_service_passwd(util_context, service_object, passwd)) != 0) {
1774 com_err(me, errcode, gettext("Failed to set password for service object %s"), service_object);
1775 memset(passwd, 0, passwd_len);
1776 goto cleanup;
1780 memset(passwd, 0, passwd_len);
1783 /* TODO: file lock for the service password file */
1784 /* set password in the file */
1785 pfile = fopen(file_name, "r+F");
1786 if (pfile == NULL) {
1787 com_err(me, errno, gettext("Failed to open file %s"), file_name);
1788 goto cleanup;
1791 while (fgets(line, MAX_LEN, pfile) != NULL) {
1792 if ((str = strstr(line, service_object)) != NULL) {
1793 if (line[strlen(service_object)] == '#') {
1794 break;
1796 str = NULL;
1799 if (str == NULL) {
1800 if (feof(pfile)) {
1801 /* If the service object dn is not present in the service password file */
1802 if (fwrite(encrypted_passwd.value, (unsigned int)encrypted_passwd.len, 1, pfile) != 1) {
1803 com_err(me, errno, gettext("Failed to write service object password to file"));
1804 goto cleanup;
1806 } else {
1807 com_err(me, errno, gettext("Error reading service object password file"));
1808 goto cleanup;
1810 fclose(pfile);
1811 pfile = NULL;
1812 } else {
1813 /* Password entry for the service object is already present in the file */
1814 /* Delete the existing entry and add the new entry */
1815 FILE *newfile = NULL;
1816 mode_t omask;
1818 /* Create a new file with the extension .tmp */
1819 tmp_file = (char *) malloc(sizeof(char) * (strlen(file_name) + 4 + 1));
1820 if (tmp_file == NULL) {
1821 com_err(me, ENOMEM, gettext("while setting service object password"));
1822 goto cleanup;
1824 sprintf(tmp_file,"%s.%s",file_name,"tmp");
1826 omask = umask(077);
1827 newfile = fopen(tmp_file, "w+F");
1828 umask(omask);
1829 if (newfile == NULL) {
1830 com_err(me, errno, gettext("Error creating file %s"), tmp_file);
1831 goto cleanup;
1835 fseek(pfile, 0, SEEK_SET);
1836 while (fgets(line, MAX_LEN, pfile) != NULL) {
1837 if (((str = strstr(line, service_object)) != NULL) && (line[strlen(service_object)] == '#')) {
1838 if (fprintf(newfile, "%s", encrypted_passwd.value) < 0) {
1839 com_err(me, errno, gettext("Failed to write service object password to file"));
1840 fclose(newfile);
1841 unlink(tmp_file);
1842 goto cleanup;
1844 } else {
1845 len = strlen(line);
1846 if (fprintf(newfile, "%s", line) < 0) {
1847 com_err(me, errno, gettext("Failed to write service object password to file"));
1848 fclose(newfile);
1849 unlink(tmp_file);
1850 goto cleanup;
1855 if (!feof(pfile)) {
1856 com_err(me, errno, gettext("Error reading service object password file"));
1857 fclose(newfile);
1858 unlink(tmp_file);
1859 goto cleanup;
1862 /* TODO: file lock for the service password file */
1863 fclose(pfile);
1864 pfile = NULL;
1866 fclose(newfile);
1867 newfile = NULL;
1869 if (unlink(file_name) == 0) {
1870 link(tmp_file, file_name);
1871 } else {
1872 com_err(me, errno, gettext("Failed to write service object password to file"));
1873 unlink(tmp_file);
1874 goto cleanup;
1876 unlink(tmp_file);
1878 errcode = 0;
1880 cleanup:
1881 if (db_init_local)
1882 krb5_ldap_close(util_context);
1884 free(service_object);
1886 free(file_name);
1888 free(passwd);
1890 if (encrypted_passwd.value) {
1891 memset(encrypted_passwd.value, 0, encrypted_passwd.len);
1892 free(encrypted_passwd.value);
1895 if (pfile)
1896 fclose(pfile);
1898 free(tmp_file);
1900 if (print_usage)
1901 db_usage(SET_SRV_PW);
1903 return errcode;
1906 #else /* #ifdef HAVE_EDIRECTORY */
1909 * Convert the user supplied password into hexadecimal and stash it. Only a
1910 * little more secure than storing plain password in the file ...
1912 void
1913 kdb5_ldap_stash_service_password(argc, argv)
1914 int argc;
1915 char **argv;
1917 int ret = 0;
1918 unsigned int passwd_len = 0;
1919 /* Solaris Kerberos */
1920 char *me = progname;
1921 char *service_object = NULL;
1922 char *file_name = NULL, *tmp_file = NULL;
1923 char passwd[MAX_SERVICE_PASSWD_LEN];
1924 char *str = NULL;
1925 char line[MAX_LEN];
1926 int fd;
1927 FILE *pfile = NULL;
1928 krb5_boolean print_usage = FALSE;
1929 krb5_data hexpasswd = {0, 0, NULL};
1930 mode_t old_mode = 0;
1933 * Format:
1934 * stashsrvpw [-f filename] service_dn
1935 * where
1936 * 'service_dn' is the DN of the service object
1937 * 'filename' is the path of the stash file
1939 if (argc != 2 && argc != 4) {
1940 print_usage = TRUE;
1941 goto cleanup;
1944 if (argc == 4) {
1945 /* Find the stash file name */
1946 if (strcmp (argv[1], "-f") == 0) {
1947 if (((file_name = strdup (argv[2])) == NULL) ||
1948 ((service_object = strdup (argv[3])) == NULL)) {
1949 com_err(me, ENOMEM, gettext("while setting service object password"));
1950 goto cleanup;
1952 } else if (strcmp (argv[2], "-f") == 0) {
1953 if (((file_name = strdup (argv[3])) == NULL) ||
1954 ((service_object = strdup (argv[1])) == NULL)) {
1955 com_err(me, ENOMEM, gettext("while setting service object password"));
1956 goto cleanup;
1958 } else {
1959 print_usage = TRUE;
1960 goto cleanup;
1962 if (file_name == NULL) {
1963 com_err(me, ENOMEM, gettext("while setting service object password"));
1964 goto cleanup;
1966 } else { /* argc == 2 */
1967 char *section;
1969 service_object = strdup (argv[1]);
1970 if (service_object == NULL) {
1971 com_err(me, ENOMEM, gettext("while setting service object password"));
1972 goto cleanup;
1975 /* Pick up the stash-file name from krb5.conf */
1976 profile_get_string(util_context->profile, KDB_REALM_SECTION,
1977 util_context->default_realm, KDB_MODULE_POINTER, NULL, &section);
1979 if (section == NULL) {
1980 profile_get_string(util_context->profile, KDB_MODULE_DEF_SECTION,
1981 KDB_MODULE_POINTER, NULL, NULL, &section);
1982 if (section == NULL) {
1983 /* Stash file path neither in krb5.conf nor on command line */
1984 file_name = strdup(DEF_SERVICE_PASSWD_FILE);
1985 if (file_name == NULL) {
1986 com_err(me, ENOMEM, gettext("while setting service object password"));
1987 goto cleanup;
1989 goto done;
1993 profile_get_string (util_context->profile, KDB_MODULE_SECTION, section,
1994 "ldap_service_password_file", NULL, &file_name);
1997 * Solaris Kerberos: use default if ldap_service_password_file not set
1999 if (file_name == NULL) {
2000 file_name = strdup(DEF_SERVICE_PASSWD_FILE);
2001 if (file_name == NULL) {
2002 com_err(me, ENOMEM, gettext("while setting service object password"));
2003 goto cleanup;
2007 done:
2009 /* Get password from user */
2011 char prompt1[256], prompt2[256];
2013 /* Get the service object password from the terminal */
2014 memset(passwd, 0, sizeof (passwd));
2015 passwd_len = sizeof (passwd);
2017 /* size of prompt = strlen of servicedn + strlen("Password for \" \"") */
2018 assert (sizeof (prompt1) > (strlen (service_object)
2019 + sizeof ("Password for \" \"")));
2020 sprintf(prompt1, gettext("Password for \"%s\""), service_object);
2022 /* size of prompt = strlen of servicedn + strlen("Re-enter Password for \" \"") */
2023 assert (sizeof (prompt2) > (strlen (service_object)
2024 + sizeof ("Re-enter Password for \" \"")));
2025 sprintf(prompt2, gettext("Re-enter password for \"%s\""), service_object);
2027 ret = krb5_read_password(util_context, prompt1, prompt2, passwd, &passwd_len);
2028 if (ret != 0) {
2029 com_err(me, ret, gettext("while setting service object password"));
2030 memset(passwd, 0, sizeof (passwd));
2031 goto cleanup;
2034 if (passwd_len == 0) {
2035 printf(gettext("%s: Invalid password\n"), me);
2036 memset(passwd, 0, MAX_SERVICE_PASSWD_LEN);
2037 goto cleanup;
2041 /* Convert the password to hexadecimal */
2043 krb5_data pwd;
2045 pwd.length = passwd_len;
2046 pwd.data = passwd;
2048 ret = tohex(pwd, &hexpasswd);
2049 if (ret != 0) {
2050 com_err(me, ret, gettext("Failed to convert the password to hexadecimal"));
2051 memset(passwd, 0, passwd_len);
2052 goto cleanup;
2055 memset(passwd, 0, passwd_len);
2057 /* TODO: file lock for the service passowrd file */
2059 /* set password in the file */
2060 #if 0 /* ************ Begin IFDEF'ed OUT ***************************** */
2061 old_mode = umask(0177);
2062 pfile = fopen(file_name, "a+");
2063 if (pfile == NULL) {
2064 com_err(me, errno, gettext("Failed to open file %s: %s"), file_name,
2065 strerror (errno));
2066 goto cleanup;
2068 rewind (pfile);
2069 umask(old_mode);
2070 #else
2071 /* Solaris Kerberos: safer than the above */
2072 fd = open(file_name, O_CREAT|O_RDWR|O_APPEND, 0600);
2073 if (fd < 0) {
2074 com_err(me, errno, gettext("Failed to open file %s: %s"), file_name,
2075 strerror (errno));
2076 goto cleanup;
2078 pfile = fdopen(fd, "a+F");
2079 if (pfile == NULL) {
2080 com_err(me, errno, gettext("Failed to open file %s: %s"), file_name,
2081 strerror (errno));
2082 goto cleanup;
2084 rewind (pfile);
2085 #endif
2087 while (fgets (line, MAX_LEN, pfile) != NULL) {
2088 if ((str = strstr (line, service_object)) != NULL) {
2090 * White spaces not allowed, # delimits the service dn from the
2091 * password
2093 if (line [strlen (service_object)] == '#')
2094 break;
2095 str = NULL;
2099 if (str == NULL) {
2100 if (feof(pfile)) {
2101 /* If the service object dn is not present in the service password file */
2102 if (fprintf(pfile, "%s#{HEX}%s\n", service_object, hexpasswd.data) < 0) {
2103 com_err(me, errno, gettext("Failed to write service object password to file"));
2104 fclose(pfile);
2105 goto cleanup;
2107 } else {
2108 com_err(me, errno, gettext("Error reading service object password file"));
2109 fclose(pfile);
2110 goto cleanup;
2112 fclose(pfile);
2113 } else {
2115 * Password entry for the service object is already present in the file
2116 * Delete the existing entry and add the new entry
2118 FILE *newfile;
2120 mode_t omask;
2122 /* Create a new file with the extension .tmp */
2123 tmp_file = (char *) malloc(sizeof(char) * (strlen(file_name) + 4 + 1));
2124 if (tmp_file == NULL) {
2125 com_err(me, ENOMEM, gettext("while setting service object password"));
2126 fclose(pfile);
2127 goto cleanup;
2129 sprintf(tmp_file,"%s.%s",file_name,"tmp");
2131 omask = umask(077);
2132 newfile = fopen(tmp_file, "wF");
2133 umask (omask);
2134 if (newfile == NULL) {
2135 com_err(me, errno, gettext("Error creating file %s"), tmp_file);
2136 fclose(pfile);
2137 goto cleanup;
2140 fseek(pfile, 0, SEEK_SET);
2141 while (fgets(line, MAX_LEN, pfile) != NULL) {
2142 if (((str = strstr(line, service_object)) != NULL) &&
2143 (line[strlen(service_object)] == '#')) {
2144 if (fprintf(newfile, "%s#{HEX}%s\n", service_object, hexpasswd.data) < 0) {
2145 com_err(me, errno, gettext("Failed to write service object password to file"));
2146 fclose(newfile);
2147 unlink(tmp_file);
2148 fclose(pfile);
2149 goto cleanup;
2151 } else {
2152 if (fprintf (newfile, "%s", line) < 0) {
2153 com_err(me, errno, gettext("Failed to write service object password to file"));
2154 fclose(newfile);
2155 unlink(tmp_file);
2156 fclose(pfile);
2157 goto cleanup;
2162 if (!feof(pfile)) {
2163 com_err(me, errno, gettext("Error reading service object password file"));
2164 fclose(newfile);
2165 unlink(tmp_file);
2166 fclose(pfile);
2167 goto cleanup;
2170 /* TODO: file lock for the service passowrd file */
2172 fclose(pfile);
2173 fclose(newfile);
2175 ret = rename(tmp_file, file_name);
2176 if (ret != 0) {
2177 com_err(me, errno, gettext("Failed to write service object password to "
2178 "file"));
2179 goto cleanup;
2182 ret = 0;
2184 cleanup:
2186 if (hexpasswd.length != 0) {
2187 memset(hexpasswd.data, 0, hexpasswd.length);
2188 free(hexpasswd.data);
2191 free(service_object);
2193 free(file_name);
2195 free(tmp_file);
2197 if (print_usage)
2198 usage();
2199 /* db_usage(STASH_SRV_PW); */
2201 if (ret)
2202 exit_status++;
2205 #endif /* #ifdef HAVE_EDIRECTORY */