8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / krb5 / ldap_util / kdb5_ldap_services.c
blob297bec818aa9a9dfa74742a81590d9e9e7a8e1f4
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 **) realloc(srvparams->krbhostservers,
692 sizeof(char *) * (existing_entries + new_entries + 1));
693 if (temp_ptr == NULL) {
694 retval = ENOMEM;
695 goto cleanup;
697 srvparams->krbhostservers = temp_ptr;
699 list_modify_str_array(&(srvparams->krbhostservers),
700 (const char**)list, LIST_MODE_ADD);
702 /* Clean up */
703 free (list);
704 list = NULL;
705 } else
706 srvparams->krbhostservers = list;
708 out_mask |= LDAP_SERVICE_HOSTSERVER;
710 } else if (!strcmp(argv[i], "-realm")) {
711 if (++i > argc - 1)
712 goto err_usage;
714 if ((in_mask & LDAP_SERVICE_REALMREFERENCE) && (srvparams->krbrealmreferences)) {
715 if (!oldrealmrefs) {
716 /* Store the old realm list for removing rights */
717 oldrealmrefs = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
718 if (oldrealmrefs == NULL) {
719 retval = ENOMEM;
720 goto cleanup;
723 for (j = 0; srvparams->krbrealmreferences[j] != NULL; j++) {
724 oldrealmrefs[j] = strdup(srvparams->krbrealmreferences[j]);
725 if (oldrealmrefs[j] == NULL) {
726 retval = ENOMEM;
727 goto cleanup;
730 oldrealmrefs[j] = NULL;
733 /* Free the old list if available */
734 krb5_free_list_entries (srvparams->krbrealmreferences);
735 free (srvparams->krbrealmreferences);
738 srvparams->krbrealmreferences = (char **)calloc(MAX_LIST_ENTRIES,
739 sizeof(char *));
740 if (srvparams->krbrealmreferences == NULL) {
741 retval = ENOMEM;
742 goto cleanup;
745 if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER,
746 srvparams->krbrealmreferences))) {
747 goto cleanup;
750 /* Convert realm names to realm DNs */
751 if ((retval = convert_realm_name2dn_list(
752 srvparams->krbrealmreferences,
753 ldap_context->krbcontainer->DN))) {
754 goto cleanup;
757 out_mask |= LDAP_SERVICE_REALMREFERENCE;
759 /* Set flag to ignore 'add' and 'clear' */
760 realmdn_flag = 1;
761 } else if (!strcmp(argv[i], "-clearrealm")) {
762 if (++i > argc - 1)
763 goto err_usage;
765 if (!realmdn_flag) {
766 /* If attribute doesn't exist, don't permit 'clear' option */
767 if (((in_mask & LDAP_SERVICE_REALMREFERENCE) == 0) || (srvparams->krbrealmreferences == NULL)) {
768 /* Send out some proper error message here */
769 goto err_nomsg;
772 if (!oldrealmrefs) {
773 /* Store the old realm list for removing rights */
774 oldrealmrefs = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
775 if (oldrealmrefs == NULL) {
776 retval = ENOMEM;
777 goto cleanup;
780 for (j = 0; srvparams->krbrealmreferences[j] != NULL; j++) {
781 oldrealmrefs[j] = strdup(srvparams->krbrealmreferences[j]);
782 if (oldrealmrefs[j] == NULL) {
783 retval = ENOMEM;
784 goto cleanup;
787 oldrealmrefs[j] = NULL;
790 /* Allocate list for processing */
791 list = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
792 if (list == NULL) {
793 retval = ENOMEM;
794 goto cleanup;
797 if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list)))
798 goto cleanup;
800 /* Convert realm names to realm DNs */
801 if ((retval = convert_realm_name2dn_list(list,
802 ldap_context->krbcontainer->DN))) {
803 goto cleanup;
806 list_modify_str_array(&(srvparams->krbrealmreferences),
807 (const char**)list, LIST_MODE_DELETE);
809 out_mask |= LDAP_SERVICE_REALMREFERENCE;
811 /* Clean up */
812 free (list);
813 list = NULL;
815 } else if (!strcmp(argv[i], "-addrealm")) {
816 if (++i > argc - 1)
817 goto err_usage;
819 if (!realmdn_flag) {
820 /* Allocate list for processing */
821 list = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
822 if (list == NULL) {
823 retval = ENOMEM;
824 goto cleanup;
827 if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list)))
828 goto cleanup;
830 /* Convert realm names to realm DNs */
831 if ((retval = convert_realm_name2dn_list(list,
832 ldap_context->krbcontainer->DN))) {
833 goto cleanup;
836 if ((in_mask & LDAP_SERVICE_REALMREFERENCE) && (srvparams->krbrealmreferences) && (!oldrealmrefs)) {
837 /* Store the old realm list for removing rights */
838 oldrealmrefs = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
839 if (oldrealmrefs == NULL) {
840 retval = ENOMEM;
841 goto cleanup;
844 for (j = 0; srvparams->krbrealmreferences[j] != NULL; j++) {
845 oldrealmrefs[j] = strdup(srvparams->krbrealmreferences[j]);
846 if (oldrealmrefs[j] == NULL) {
847 retval = ENOMEM;
848 goto cleanup;
851 oldrealmrefs[j] = NULL;
854 /* Call list_modify_str_array() only if realm DN attribute
855 * exists already -- Actually, it's better to handle this
856 * within list_modify_str_array() */
857 if (in_mask & LDAP_SERVICE_REALMREFERENCE) {
858 /* Re-size existing list */
859 existing_entries = list_count_str_array(
860 srvparams->krbrealmreferences);
861 new_entries = list_count_str_array(list);
862 temp_ptr = (char **) realloc(srvparams->krbrealmreferences,
863 sizeof(char *) * (existing_entries + new_entries + 1));
864 if (temp_ptr == NULL) {
865 retval = ENOMEM;
866 goto cleanup;
868 srvparams->krbrealmreferences = temp_ptr;
870 list_modify_str_array(&(srvparams->krbrealmreferences),
871 (const char**)list, LIST_MODE_ADD);
873 /* Clean up */
874 free (list);
875 list = NULL;
876 } else
877 srvparams->krbrealmreferences = list;
879 out_mask |= LDAP_SERVICE_REALMREFERENCE;
881 } else {
882 /* Any other argument must be service DN
883 -- skip it */
887 /* Modify attributes of object */
888 if ((retval = krb5_ldap_modify_service(util_context, srvparams, out_mask)))
889 goto cleanup;
891 /* Service rights modification code */
892 if (out_mask & LDAP_SERVICE_REALMREFERENCE) {
894 printf("%s", gettext("Changing rights for the service object. Please wait ... "));
895 fflush(stdout);
897 newrealmrefs = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
898 if (newrealmrefs == NULL) {
899 retval = ENOMEM;
900 goto cleanup;
903 if ((srvparams != NULL) && (srvparams->krbrealmreferences != NULL)) {
904 for (j = 0; srvparams->krbrealmreferences[j] != NULL; j++) {
905 newrealmrefs[j] = strdup(srvparams->krbrealmreferences[j]);
906 if (newrealmrefs[j] == NULL) {
907 retval = ENOMEM;
908 goto cleanup;
911 newrealmrefs[j] = NULL;
913 disjoint_members(oldrealmrefs, newrealmrefs);
915 /* Delete the rights for the given service, on each of the realm
916 * container & subtree in the old realm reference list.
918 if (oldrealmrefs) {
919 rightsmask = 0;
920 rightsmask |= LDAP_REALM_RIGHTS;
921 rightsmask |= LDAP_SUBTREE_RIGHTS;
923 for (i = 0; (oldrealmrefs[i] != NULL); i++) {
924 /* Get the realm name, not the dn */
925 temprdns = ldap_explode_dn(oldrealmrefs[i], 1);
927 if (temprdns[0] == NULL) {
928 retval = EINVAL;
929 goto cleanup;
932 realmName = strdup(temprdns[0]);
933 if (realmName == NULL) {
934 retval = ENOMEM;
935 goto cleanup;
938 if ((retval = krb5_ldap_read_realm_params(util_context,
939 realmName, &rparams, &rmask))) {
940 com_err(me, retval, gettext("while reading information of realm '%s'"),
941 realmName);
942 goto err_nomsg;
945 if ((retval = krb5_ldap_delete_service_rights(util_context,
946 srvparams->servicetype, srvparams->servicedn,
947 realmName, rparams->subtree, rightsmask))) {
948 printf(gettext("failed\n"));
949 com_err(me, retval, gettext("while assigning rights '%s'"),
950 srvparams->servicedn);
951 goto err_nomsg;
954 if (rparams)
955 krb5_ldap_free_realm_params(rparams);
959 /* Add the rights for the given service, on each of the realm
960 * container & subtree in the new realm reference list.
962 if (newrealmrefs) {
963 rightsmask = 0;
964 rightsmask |= LDAP_REALM_RIGHTS;
965 rightsmask |= LDAP_SUBTREE_RIGHTS;
967 for (i = 0; (newrealmrefs[i] != NULL); i++) {
968 /* Get the realm name, not the dn */
969 temprdns = ldap_explode_dn(newrealmrefs[i], 1);
971 if (temprdns[0] == NULL) {
972 retval = EINVAL;
973 goto cleanup;
976 realmName = strdup(temprdns[0]);
977 if (realmName == NULL) {
978 retval = ENOMEM;
979 goto cleanup;
982 if ((retval = krb5_ldap_read_krbcontainer_params(util_context,
983 &(ldap_context->krbcontainer)))) {
984 com_err(me, retval,
985 gettext("while reading Kerberos container information"));
986 goto cleanup;
989 if ((retval = krb5_ldap_read_realm_params(util_context,
990 realmName, &rparams, &rmask))) {
991 com_err(me, retval, gettext("while reading information of realm '%s'"),
992 realmName);
993 goto err_nomsg;
996 if ((retval = krb5_ldap_add_service_rights(util_context,
997 srvparams->servicetype, srvparams->servicedn,
998 realmName, rparams->subtree, rightsmask))) {
999 printf(gettext("failed\n"));
1000 com_err(me, retval, gettext("while assigning rights '%s'"),
1001 srvparams->servicedn);
1002 goto err_nomsg;
1005 if (rparams) {
1006 krb5_ldap_free_realm_params(rparams);
1007 rparams = NULL;
1010 printf(gettext("done\n"));
1013 goto cleanup;
1015 err_usage:
1016 print_usage = TRUE;
1018 err_nomsg:
1019 no_msg = TRUE;
1021 cleanup:
1022 /* Clean-up structure */
1023 krb5_ldap_free_service(util_context, srvparams);
1025 if (servicedn)
1026 free(servicedn);
1028 if (list) {
1029 free(list);
1030 list = NULL;
1033 if (oldrealmrefs) {
1034 for (i = 0; oldrealmrefs[i] != NULL; i++)
1035 free(oldrealmrefs[i]);
1036 free(oldrealmrefs);
1039 if (newrealmrefs) {
1040 for (i = 0; newrealmrefs[i] != NULL; i++)
1041 free(newrealmrefs[i]);
1042 free(newrealmrefs);
1044 if (realmName) {
1045 free(realmName);
1046 realmName = NULL;
1049 if (print_usage)
1050 db_usage(MODIFY_SERVICE);
1052 if (retval) {
1053 if (!no_msg)
1054 com_err(me, retval, gettext("while modifying service object"));
1055 exit_status++;
1058 return;
1063 * This function will delete the entry corresponding to the service object
1064 * from the service password file.
1066 static krb5_error_code
1067 rem_service_entry_from_file(argc, argv, file_name, service_object)
1068 int argc;
1069 char *argv[];
1070 char *file_name;
1071 char *service_object;
1073 int st = EINVAL;
1074 /* Solaris Kerberos */
1075 char *me = progname;
1076 char *tmp_file = NULL;
1077 int tmpfd = -1;
1078 FILE *pfile = NULL;
1079 unsigned int len = 0;
1080 char line[MAX_LEN]={0};
1081 mode_t omask = umask(077);
1083 /* Check for permissions on the password file */
1084 if (access(file_name, W_OK) == -1) {
1085 /* If the specified file itself is not there, no need to show error */
1086 if (errno == ENOENT) {
1087 st=0;
1088 goto cleanup;
1089 } else {
1090 com_err(me, errno, gettext("while deleting entry from file %s", file_name));
1091 goto cleanup;
1095 /* Create a temporary file which contains all the entries except the
1096 entry for the given service dn */
1097 pfile = fopen(file_name, "r+F");
1098 if (pfile == NULL) {
1099 com_err(me, errno, gettext("while deleting entry from file %s"), file_name);
1100 goto cleanup;
1103 /* Create a new file with the extension .tmp */
1104 tmp_file = (char *)malloc(strlen(file_name) + 4 + 1);
1105 if (tmp_file == NULL) {
1106 com_err(me, ENOMEM, gettext("while deleting entry from file"));
1107 fclose(pfile);
1108 goto cleanup;
1110 snprintf (tmp_file, strlen(file_name) + 4 + 1, "%s%s", file_name, ".tmp");
1113 tmpfd = creat(tmp_file, S_IRUSR|S_IWUSR);
1114 umask(omask);
1115 if (tmpfd == -1) {
1116 com_err(me, errno, gettext("while deleting entry from file\n"));
1117 fclose(pfile);
1118 goto cleanup;
1121 /* Copy only those lines which donot have the specified service dn */
1122 while (fgets(line, MAX_LEN, pfile) != NULL) {
1123 if ((strstr(line, service_object) != NULL) &&
1124 (line[strlen(service_object)] == '#')) {
1125 continue;
1126 } else {
1127 len = strlen(line);
1128 if (write(tmpfd, line, len) != len) {
1129 com_err(me, errno, gettext("while deleting entry from file\n"));
1130 close(tmpfd);
1131 unlink(tmp_file);
1132 fclose(pfile);
1133 goto cleanup;
1138 fclose(pfile);
1139 if (unlink(file_name) == 0) {
1140 link(tmp_file, file_name);
1141 } else {
1142 com_err(me, errno, gettext("while deleting entry from file\n"));
1144 unlink(tmp_file);
1146 st=0;
1148 cleanup:
1150 if (tmp_file)
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 if (servicedn)
1341 free(servicedn);
1343 if (print_usage) {
1344 db_usage(VIEW_SERVICE);
1347 return;
1352 * This function will list the DNs of kerberos services present on
1353 * the LDAP Server under a specific sub-tree (entire tree by default)
1355 void kdb5_ldap_list_services(argc, argv)
1356 int argc;
1357 char *argv[];
1359 /* Solaris Kerberos */
1360 char *me = progname;
1361 krb5_error_code retval = 0;
1362 char *basedn = NULL;
1363 char **list = NULL;
1364 char **plist = NULL;
1365 krb5_boolean print_usage = FALSE;
1367 /* Check for number of arguments */
1368 if ((argc != 1) && (argc != 3)) {
1369 exit_status++;
1370 goto err_usage;
1373 /* Parse base DN argument if present */
1374 if (argc == 3) {
1375 if (strcmp(argv[1], "-basedn")) {
1376 retval = EINVAL;
1377 goto err_usage;
1380 basedn = strdup(argv[2]);
1381 if (basedn == NULL) {
1382 com_err(me, ENOMEM, gettext("while listing services"));
1383 exit_status++;
1384 goto cleanup;
1388 retval = krb5_ldap_list_services(util_context, basedn, &list);
1389 if ((retval != 0) || (list == NULL)) {
1390 exit_status++;
1391 goto cleanup;
1394 for (plist = list; *plist != NULL; plist++) {
1395 printf("%s\n", *plist);
1398 goto cleanup;
1400 err_usage:
1401 print_usage = TRUE;
1403 cleanup:
1404 if (list != NULL) {
1405 krb5_free_list_entries (list);
1406 free (list);
1409 if (basedn)
1410 free (basedn);
1412 if (print_usage) {
1413 db_usage(LIST_SERVICE);
1416 if (retval) {
1417 com_err(me, retval, gettext("while listing policy objects"));
1418 exit_status++;
1421 return;
1426 * This function will print the service object information
1427 * to the standard output
1429 static void
1430 print_service_params(lserparams, mask)
1431 krb5_ldap_service_params *lserparams;
1432 int mask;
1434 int i=0;
1436 /* Print the service dn */
1437 printf("%20s%-20s\n", gettext("Service dn: "), lserparams->servicedn);
1439 /* Print the service type of the object to be read */
1440 if (lserparams->servicetype == LDAP_KDC_SERVICE) {
1441 printf("%20s%-20s\n", gettext("Service type: "), "kdc");
1442 } else if (lserparams->servicetype == LDAP_ADMIN_SERVICE) {
1443 printf("%20s%-20s\n", gettext("Service type: "), "admin");
1444 } else if (lserparams->servicetype == LDAP_PASSWD_SERVICE) {
1445 printf("%20s%-20s\n", gettext("Service type: "), "pwd");
1448 /* Print the host server values */
1449 printf("%20s\n", gettext("Service host list: "));
1450 if (mask & LDAP_SERVICE_HOSTSERVER) {
1451 for (i=0; lserparams->krbhostservers[i] != NULL; ++i) {
1452 printf("%20s%-50s\n","",lserparams->krbhostservers[i]);
1456 /* Print the realm reference dn values */
1457 printf("%20s\n", gettext("Realm DN list: "));
1458 if (mask & LDAP_SERVICE_REALMREFERENCE) {
1459 for (i=0; lserparams && lserparams->krbrealmreferences && lserparams->krbrealmreferences[i] != NULL; ++i) {
1460 printf("%20s%-50s\n","",lserparams->krbrealmreferences[i]);
1464 return;
1469 * This function will generate random password of length(RANDOM_PASSWD_LEN)
1472 * INPUT:
1473 * ctxt - context
1475 * OUTPUT:
1476 * RANDOM_PASSWD_LEN length random password
1478 static int generate_random_password(krb5_context ctxt, char **randpwd, unsigned int *passlen)
1480 char *random_pwd = NULL;
1481 int ret = 0;
1482 krb5_data data;
1483 int i=0;
1484 /*int len = 0;*/
1486 /* setting random password length in the range 16-32 */
1487 srand((unsigned int)(time(0) ^ getpid()));
1489 data.length = RANDOM_PASSWD_LEN;
1490 random_pwd = (char *)malloc(data.length + 1);
1491 if (random_pwd == NULL) {
1492 com_err("setsrvpw", ENOMEM, gettext("while generating random password"));
1493 return ENOMEM;
1495 memset(random_pwd, 0, data.length + 1);
1496 data.data = random_pwd;
1498 ret = krb5_c_random_make_octets(ctxt, &data);
1499 if (ret) {
1500 com_err("setsrvpw", ret, gettext("Error generating random password"));
1501 free(random_pwd);
1502 return ret;
1505 for (i=0; i<data.length; i++) {
1506 /* restricting to ascii chars. Need to change this when 8.8 supports */
1507 if ((unsigned char)random_pwd[i] > 127) {
1508 random_pwd[i] = (unsigned char)random_pwd[i] % 128;
1509 } else if (random_pwd[i] == 0) {
1510 random_pwd[i] = (rand()/(RAND_MAX/127 + 1))+1;
1514 *randpwd = random_pwd;
1515 *passlen = data.length;
1517 return 0;
1522 * This function will set the password of the service object in the directory
1523 * and/or the specified service password file.
1526 * INPUT:
1527 * argc - contains the number of arguments for this sub-command
1528 * argv - array of arguments for this sub-command
1530 * OUTPUT:
1531 * void
1534 kdb5_ldap_set_service_password(argc, argv)
1535 int argc;
1536 char **argv;
1538 krb5_ldap_context *lparams = NULL;
1539 char *file_name = NULL;
1540 char *tmp_file = NULL;
1541 /* Solaris Kerberos */
1542 char *me = progname;
1543 int filelen = 0;
1544 int random_passwd = 0;
1545 int set_dir_pwd = 1;
1546 krb5_boolean db_init_local = FALSE;
1547 char *service_object = NULL;
1548 char *passwd = NULL;
1549 char *prompt1 = NULL;
1550 char *prompt2 = NULL;
1551 unsigned int passwd_len = 0;
1552 krb5_error_code errcode = -1;
1553 int retval = 0, i = 0;
1554 unsigned int len = 0;
1555 krb5_boolean print_usage = FALSE;
1556 FILE *pfile = NULL;
1557 char *str = NULL;
1558 char line[MAX_LEN];
1559 kdb5_dal_handle *dal_handle = NULL;
1560 struct data encrypted_passwd = {0, NULL};
1562 /* The arguments for setsrv password should contain the service object DN
1563 * and options to specify whether the password should be updated in file only
1564 * or both file and directory. So the possible combination of arguments are:
1565 * setsrvpw servicedn wherein argc is 2
1566 * setsrvpw -fileonly servicedn wherein argc is 3
1567 * setsrvpw -randpw servicedn wherein argc is 3
1568 * setsrvpw -f filename servicedn wherein argc is 4
1569 * setsrvpw -fileonly -f filename servicedn wherein argc is 5
1570 * setsrvpw -randpw -f filename servicedn wherein argc is 5
1572 if ((argc < 2) || (argc > 5)) {
1573 print_usage = TRUE;
1574 goto cleanup;
1577 dal_handle = (kdb5_dal_handle *)util_context->db_context;
1578 lparams = (krb5_ldap_context *) dal_handle->db_context;
1580 if (lparams == NULL) {
1581 printf(gettext("%s: Invalid LDAP handle\n"), me);
1582 goto cleanup;
1585 /* Parse the arguments */
1586 for (i = 1; i < argc -1 ; i++) {
1587 if (strcmp(argv[i], "-randpw") == 0) {
1588 random_passwd = 1;
1589 } else if (strcmp(argv[i], "-fileonly") == 0) {
1590 set_dir_pwd = 0;
1591 } else if (strcmp(argv[i], "-f") == 0) {
1592 if (argv[++i] == NULL) {
1593 print_usage = TRUE;
1594 goto cleanup;
1597 file_name = strdup(argv[i]);
1598 if (file_name == NULL) {
1599 com_err(me, ENOMEM, gettext("while setting service object password"));
1600 goto cleanup;
1602 /* Verify if the file location has the proper file name
1603 * for eg, if the file location is a directory like /home/temp/,
1604 * we reject it.
1606 filelen = strlen(file_name);
1607 if ((filelen == 0) || (file_name[filelen-1] == '/')) {
1608 printf(gettext("%s: Filename not specified for setting service object password\n"), me);
1609 print_usage = TRUE;
1610 goto cleanup;
1612 } else {
1613 printf(gettext("%s: Invalid option specified for \"setsrvpw\" command\n"), me);
1614 print_usage = TRUE;
1615 goto cleanup;
1619 if (i != argc-1) {
1620 print_usage = TRUE;
1621 goto cleanup;
1624 service_object = strdup(argv[i]);
1625 if (service_object == NULL) {
1626 com_err(me, ENOMEM, gettext("while setting service object password"));
1627 goto cleanup;
1630 if (strlen(service_object) == 0) {
1631 printf(gettext("%s: Service object not specified for \"setsrvpw\" command\n"), me);
1632 print_usage = TRUE;
1633 goto cleanup;
1636 if (service_object[0] == '-') {
1637 print_usage = TRUE;
1638 goto cleanup;
1641 if (file_name == NULL) {
1642 file_name = strdup(DEF_SERVICE_PASSWD_FILE);
1643 if (file_name == NULL) {
1644 com_err(me, ENOMEM, gettext("while setting service object password"));
1645 goto cleanup;
1649 if (set_dir_pwd) {
1650 if (db_inited == FALSE) {
1651 if ((errcode = krb5_ldap_db_init(util_context, lparams))) {
1652 com_err(me, errcode, gettext("while initializing database"));
1653 goto cleanup;
1655 db_init_local = TRUE;
1659 if (random_passwd) {
1660 if (!set_dir_pwd) {
1661 printf(gettext("%s: Invalid option specified for \"setsrvpw\" command\n"), me);
1662 print_usage = TRUE;
1663 goto cleanup;
1664 } else {
1665 /* Generate random password */
1667 if ((errcode = generate_random_password(util_context, &passwd, &passwd_len))) {
1668 printf(gettext("%s: Failed to set service object password\n"), me);
1669 goto cleanup;
1671 passwd_len = strlen(passwd);
1673 } else {
1674 /* Get the service object password from the terminal */
1675 passwd = (char *)malloc(MAX_SERVICE_PASSWD_LEN + 1);
1676 if (passwd == NULL) {
1677 com_err(me, ENOMEM, gettext("while setting service object password"));
1678 goto cleanup;
1680 memset(passwd, 0, MAX_SERVICE_PASSWD_LEN + 1);
1681 passwd_len = MAX_SERVICE_PASSWD_LEN;
1683 len = strlen(service_object);
1684 /* size of allocation=strlen of servicedn + strlen("Password for \" \"")=20 */
1685 prompt1 = (char *)malloc(len + 20);
1686 if (prompt1 == NULL) {
1687 com_err(me, ENOMEM, gettext("while setting service object password"));
1688 goto cleanup;
1690 sprintf(prompt1, gettext("Password for \"%s\""), service_object);
1692 /* size of allocation=strlen of servicedn + strlen("Re-enter Password for \" \"")=30 */
1693 prompt2 = (char *)malloc(len + 30);
1694 if (prompt2 == NULL) {
1695 com_err(me, ENOMEM, gettext("while setting service object password"));
1696 free(prompt1);
1697 goto cleanup;
1699 sprintf(prompt2, gettext("Re-enter password for \"%s\""), service_object);
1701 retval = krb5_read_password(util_context, prompt1, prompt2, passwd, &passwd_len);
1702 free(prompt1);
1703 free(prompt2);
1704 if (retval) {
1705 com_err(me, retval, gettext("while setting service object password"));
1706 memset(passwd, 0, MAX_SERVICE_PASSWD_LEN);
1707 goto cleanup;
1709 if (passwd_len == 0) {
1710 printf(gettext("%s: Invalid password\n"), me);
1711 memset(passwd, 0, MAX_SERVICE_PASSWD_LEN);
1712 goto cleanup;
1714 passwd_len = strlen(passwd);
1717 /* Hex the password */
1719 krb5_data pwd, hex;
1720 pwd.length = passwd_len;
1721 pwd.data = passwd;
1723 errcode = tohex(pwd, &hex);
1724 if (errcode != 0) {
1725 if (hex.length != 0) {
1726 memset(hex.data, 0, hex.length);
1727 free(hex.data);
1729 com_err(me, errcode, gettext("Failed to convert the password to hex"));
1730 memset(passwd, 0, passwd_len);
1731 goto cleanup;
1733 /* Password = {CRYPT}<encrypted password>:<encrypted key> */
1734 encrypted_passwd.value = (unsigned char *)malloc(strlen(service_object) +
1735 1 + 5 + hex.length + 2);
1736 if (encrypted_passwd.value == NULL) {
1737 com_err(me, ENOMEM, gettext("while setting service object password"));
1738 memset(passwd, 0, passwd_len);
1739 memset(hex.data, 0, hex.length);
1740 free(hex.data);
1741 goto cleanup;
1743 encrypted_passwd.value[strlen(service_object) +
1744 1 + 5 + hex.length + 1] = '\0';
1745 sprintf((char *)encrypted_passwd.value, "%s#{HEX}%s\n", service_object, hex.data);
1746 encrypted_passwd.len = strlen((char *)encrypted_passwd.value);
1747 memset(hex.data, 0, hex.length);
1748 free(hex.data);
1751 /* We should check if the file exists and we have permission to write into that file */
1752 if (access(file_name, W_OK) == -1) {
1753 if (errno == ENOENT) {
1754 mode_t omask;
1755 int fd = -1;
1757 printf(gettext("File does not exist. Creating the file %s...\n"), file_name);
1758 omask = umask(077);
1759 fd = creat(file_name, S_IRUSR|S_IWUSR);
1760 umask(omask);
1761 if (fd == -1) {
1762 com_err(me, errno, gettext("Error creating file %s"), file_name);
1763 memset(passwd, 0, passwd_len);
1764 goto cleanup;
1766 close(fd);
1767 } else {
1768 com_err(me, errno, gettext("Unable to access the file %s"), file_name);
1769 memset(passwd, 0, passwd_len);
1770 goto cleanup;
1774 if (set_dir_pwd) {
1775 if ((errcode = krb5_ldap_set_service_passwd(util_context, service_object, passwd)) != 0) {
1776 com_err(me, errcode, gettext("Failed to set password for service object %s"), service_object);
1777 memset(passwd, 0, passwd_len);
1778 goto cleanup;
1782 memset(passwd, 0, passwd_len);
1785 /* TODO: file lock for the service password file */
1786 /* set password in the file */
1787 pfile = fopen(file_name, "r+F");
1788 if (pfile == NULL) {
1789 com_err(me, errno, gettext("Failed to open file %s"), file_name);
1790 goto cleanup;
1793 while (fgets(line, MAX_LEN, pfile) != NULL) {
1794 if ((str = strstr(line, service_object)) != NULL) {
1795 if (line[strlen(service_object)] == '#') {
1796 break;
1798 str = NULL;
1801 if (str == NULL) {
1802 if (feof(pfile)) {
1803 /* If the service object dn is not present in the service password file */
1804 if (fwrite(encrypted_passwd.value, (unsigned int)encrypted_passwd.len, 1, pfile) != 1) {
1805 com_err(me, errno, gettext("Failed to write service object password to file"));
1806 goto cleanup;
1808 } else {
1809 com_err(me, errno, gettext("Error reading service object password file"));
1810 goto cleanup;
1812 fclose(pfile);
1813 pfile = NULL;
1814 } else {
1815 /* Password entry for the service object is already present in the file */
1816 /* Delete the existing entry and add the new entry */
1817 FILE *newfile = NULL;
1818 mode_t omask;
1820 /* Create a new file with the extension .tmp */
1821 tmp_file = (char *) malloc(sizeof(char) * (strlen(file_name) + 4 + 1));
1822 if (tmp_file == NULL) {
1823 com_err(me, ENOMEM, gettext("while setting service object password"));
1824 goto cleanup;
1826 sprintf(tmp_file,"%s.%s",file_name,"tmp");
1828 omask = umask(077);
1829 newfile = fopen(tmp_file, "w+F");
1830 umask(omask);
1831 if (newfile == NULL) {
1832 com_err(me, errno, gettext("Error creating file %s"), tmp_file);
1833 goto cleanup;
1837 fseek(pfile, 0, SEEK_SET);
1838 while (fgets(line, MAX_LEN, pfile) != NULL) {
1839 if (((str = strstr(line, service_object)) != NULL) && (line[strlen(service_object)] == '#')) {
1840 if (fprintf(newfile, "%s", encrypted_passwd.value) < 0) {
1841 com_err(me, errno, gettext("Failed to write service object password to file"));
1842 fclose(newfile);
1843 unlink(tmp_file);
1844 goto cleanup;
1846 } else {
1847 len = strlen(line);
1848 if (fprintf(newfile, "%s", line) < 0) {
1849 com_err(me, errno, gettext("Failed to write service object password to file"));
1850 fclose(newfile);
1851 unlink(tmp_file);
1852 goto cleanup;
1857 if (!feof(pfile)) {
1858 com_err(me, errno, gettext("Error reading service object password file"));
1859 fclose(newfile);
1860 unlink(tmp_file);
1861 goto cleanup;
1864 /* TODO: file lock for the service password file */
1865 fclose(pfile);
1866 pfile = NULL;
1868 fclose(newfile);
1869 newfile = NULL;
1871 if (unlink(file_name) == 0) {
1872 link(tmp_file, file_name);
1873 } else {
1874 com_err(me, errno, gettext("Failed to write service object password to file"));
1875 unlink(tmp_file);
1876 goto cleanup;
1878 unlink(tmp_file);
1880 errcode = 0;
1882 cleanup:
1883 if (db_init_local)
1884 krb5_ldap_close(util_context);
1886 if (service_object)
1887 free(service_object);
1889 if (file_name)
1890 free(file_name);
1892 if (passwd)
1893 free(passwd);
1895 if (encrypted_passwd.value) {
1896 memset(encrypted_passwd.value, 0, encrypted_passwd.len);
1897 free(encrypted_passwd.value);
1900 if (pfile)
1901 fclose(pfile);
1903 if (tmp_file)
1904 free(tmp_file);
1906 if (print_usage)
1907 db_usage(SET_SRV_PW);
1909 return errcode;
1912 #else /* #ifdef HAVE_EDIRECTORY */
1915 * Convert the user supplied password into hexadecimal and stash it. Only a
1916 * little more secure than storing plain password in the file ...
1918 void
1919 kdb5_ldap_stash_service_password(argc, argv)
1920 int argc;
1921 char **argv;
1923 int ret = 0;
1924 unsigned int passwd_len = 0;
1925 /* Solaris Kerberos */
1926 char *me = progname;
1927 char *service_object = NULL;
1928 char *file_name = NULL, *tmp_file = NULL;
1929 char passwd[MAX_SERVICE_PASSWD_LEN];
1930 char *str = NULL;
1931 char line[MAX_LEN];
1932 int fd;
1933 FILE *pfile = NULL;
1934 krb5_boolean print_usage = FALSE;
1935 krb5_data hexpasswd = {0, 0, NULL};
1936 mode_t old_mode = 0;
1939 * Format:
1940 * stashsrvpw [-f filename] service_dn
1941 * where
1942 * 'service_dn' is the DN of the service object
1943 * 'filename' is the path of the stash file
1945 if (argc != 2 && argc != 4) {
1946 print_usage = TRUE;
1947 goto cleanup;
1950 if (argc == 4) {
1951 /* Find the stash file name */
1952 if (strcmp (argv[1], "-f") == 0) {
1953 if (((file_name = strdup (argv[2])) == NULL) ||
1954 ((service_object = strdup (argv[3])) == NULL)) {
1955 com_err(me, ENOMEM, gettext("while setting service object password"));
1956 goto cleanup;
1958 } else if (strcmp (argv[2], "-f") == 0) {
1959 if (((file_name = strdup (argv[3])) == NULL) ||
1960 ((service_object = strdup (argv[1])) == NULL)) {
1961 com_err(me, ENOMEM, gettext("while setting service object password"));
1962 goto cleanup;
1964 } else {
1965 print_usage = TRUE;
1966 goto cleanup;
1968 if (file_name == NULL) {
1969 com_err(me, ENOMEM, gettext("while setting service object password"));
1970 goto cleanup;
1972 } else { /* argc == 2 */
1973 char *section;
1975 service_object = strdup (argv[1]);
1976 if (service_object == NULL) {
1977 com_err(me, ENOMEM, gettext("while setting service object password"));
1978 goto cleanup;
1981 /* Pick up the stash-file name from krb5.conf */
1982 profile_get_string(util_context->profile, KDB_REALM_SECTION,
1983 util_context->default_realm, KDB_MODULE_POINTER, NULL, &section);
1985 if (section == NULL) {
1986 profile_get_string(util_context->profile, KDB_MODULE_DEF_SECTION,
1987 KDB_MODULE_POINTER, NULL, NULL, &section);
1988 if (section == NULL) {
1989 /* Stash file path neither in krb5.conf nor on command line */
1990 file_name = strdup(DEF_SERVICE_PASSWD_FILE);
1991 if (file_name == NULL) {
1992 com_err(me, ENOMEM, gettext("while setting service object password"));
1993 goto cleanup;
1995 goto done;
1999 profile_get_string (util_context->profile, KDB_MODULE_SECTION, section,
2000 "ldap_service_password_file", NULL, &file_name);
2003 * Solaris Kerberos: use default if ldap_service_password_file not set
2005 if (file_name == NULL) {
2006 file_name = strdup(DEF_SERVICE_PASSWD_FILE);
2007 if (file_name == NULL) {
2008 com_err(me, ENOMEM, gettext("while setting service object password"));
2009 goto cleanup;
2013 done:
2015 /* Get password from user */
2017 char prompt1[256], prompt2[256];
2019 /* Get the service object password from the terminal */
2020 memset(passwd, 0, sizeof (passwd));
2021 passwd_len = sizeof (passwd);
2023 /* size of prompt = strlen of servicedn + strlen("Password for \" \"") */
2024 assert (sizeof (prompt1) > (strlen (service_object)
2025 + sizeof ("Password for \" \"")));
2026 sprintf(prompt1, gettext("Password for \"%s\""), service_object);
2028 /* size of prompt = strlen of servicedn + strlen("Re-enter Password for \" \"") */
2029 assert (sizeof (prompt2) > (strlen (service_object)
2030 + sizeof ("Re-enter Password for \" \"")));
2031 sprintf(prompt2, gettext("Re-enter password for \"%s\""), service_object);
2033 ret = krb5_read_password(util_context, prompt1, prompt2, passwd, &passwd_len);
2034 if (ret != 0) {
2035 com_err(me, ret, gettext("while setting service object password"));
2036 memset(passwd, 0, sizeof (passwd));
2037 goto cleanup;
2040 if (passwd_len == 0) {
2041 printf(gettext("%s: Invalid password\n"), me);
2042 memset(passwd, 0, MAX_SERVICE_PASSWD_LEN);
2043 goto cleanup;
2047 /* Convert the password to hexadecimal */
2049 krb5_data pwd;
2051 pwd.length = passwd_len;
2052 pwd.data = passwd;
2054 ret = tohex(pwd, &hexpasswd);
2055 if (ret != 0) {
2056 com_err(me, ret, gettext("Failed to convert the password to hexadecimal"));
2057 memset(passwd, 0, passwd_len);
2058 goto cleanup;
2061 memset(passwd, 0, passwd_len);
2063 /* TODO: file lock for the service passowrd file */
2065 /* set password in the file */
2066 #if 0 /* ************ Begin IFDEF'ed OUT ***************************** */
2067 old_mode = umask(0177);
2068 pfile = fopen(file_name, "a+");
2069 if (pfile == NULL) {
2070 com_err(me, errno, gettext("Failed to open file %s: %s"), file_name,
2071 strerror (errno));
2072 goto cleanup;
2074 rewind (pfile);
2075 umask(old_mode);
2076 #else
2077 /* Solaris Kerberos: safer than the above */
2078 fd = open(file_name, O_CREAT|O_RDWR|O_APPEND, 0600);
2079 if (fd < 0) {
2080 com_err(me, errno, gettext("Failed to open file %s: %s"), file_name,
2081 strerror (errno));
2082 goto cleanup;
2084 pfile = fdopen(fd, "a+F");
2085 if (pfile == NULL) {
2086 com_err(me, errno, gettext("Failed to open file %s: %s"), file_name,
2087 strerror (errno));
2088 goto cleanup;
2090 rewind (pfile);
2091 #endif
2093 while (fgets (line, MAX_LEN, pfile) != NULL) {
2094 if ((str = strstr (line, service_object)) != NULL) {
2096 * White spaces not allowed, # delimits the service dn from the
2097 * password
2099 if (line [strlen (service_object)] == '#')
2100 break;
2101 str = NULL;
2105 if (str == NULL) {
2106 if (feof(pfile)) {
2107 /* If the service object dn is not present in the service password file */
2108 if (fprintf(pfile, "%s#{HEX}%s\n", service_object, hexpasswd.data) < 0) {
2109 com_err(me, errno, gettext("Failed to write service object password to file"));
2110 fclose(pfile);
2111 goto cleanup;
2113 } else {
2114 com_err(me, errno, gettext("Error reading service object password file"));
2115 fclose(pfile);
2116 goto cleanup;
2118 fclose(pfile);
2119 } else {
2121 * Password entry for the service object is already present in the file
2122 * Delete the existing entry and add the new entry
2124 FILE *newfile;
2126 mode_t omask;
2128 /* Create a new file with the extension .tmp */
2129 tmp_file = (char *) malloc(sizeof(char) * (strlen(file_name) + 4 + 1));
2130 if (tmp_file == NULL) {
2131 com_err(me, ENOMEM, gettext("while setting service object password"));
2132 fclose(pfile);
2133 goto cleanup;
2135 sprintf(tmp_file,"%s.%s",file_name,"tmp");
2137 omask = umask(077);
2138 newfile = fopen(tmp_file, "wF");
2139 umask (omask);
2140 if (newfile == NULL) {
2141 com_err(me, errno, gettext("Error creating file %s"), tmp_file);
2142 fclose(pfile);
2143 goto cleanup;
2146 fseek(pfile, 0, SEEK_SET);
2147 while (fgets(line, MAX_LEN, pfile) != NULL) {
2148 if (((str = strstr(line, service_object)) != NULL) &&
2149 (line[strlen(service_object)] == '#')) {
2150 if (fprintf(newfile, "%s#{HEX}%s\n", service_object, hexpasswd.data) < 0) {
2151 com_err(me, errno, gettext("Failed to write service object password to file"));
2152 fclose(newfile);
2153 unlink(tmp_file);
2154 fclose(pfile);
2155 goto cleanup;
2157 } else {
2158 if (fprintf (newfile, "%s", line) < 0) {
2159 com_err(me, errno, gettext("Failed to write service object password to file"));
2160 fclose(newfile);
2161 unlink(tmp_file);
2162 fclose(pfile);
2163 goto cleanup;
2168 if (!feof(pfile)) {
2169 com_err(me, errno, gettext("Error reading service object password file"));
2170 fclose(newfile);
2171 unlink(tmp_file);
2172 fclose(pfile);
2173 goto cleanup;
2176 /* TODO: file lock for the service passowrd file */
2178 fclose(pfile);
2179 fclose(newfile);
2181 ret = rename(tmp_file, file_name);
2182 if (ret != 0) {
2183 com_err(me, errno, gettext("Failed to write service object password to "
2184 "file"));
2185 goto cleanup;
2188 ret = 0;
2190 cleanup:
2192 if (hexpasswd.length != 0) {
2193 memset(hexpasswd.data, 0, hexpasswd.length);
2194 free(hexpasswd.data);
2197 if (service_object)
2198 free(service_object);
2200 if (file_name)
2201 free(file_name);
2203 if (tmp_file)
2204 free(tmp_file);
2206 if (print_usage)
2207 usage();
2208 /* db_usage(STASH_SRV_PW); */
2210 if (ret)
2211 exit_status++;
2214 #endif /* #ifdef HAVE_EDIRECTORY */