xref: /illumos-gate/usr/src/cmd/keyserv/chkey_common.c (revision 069e6b7e31ba5dcbc5441b98af272714d9a5455c)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <ctype.h>
29 #include <strings.h>
30 #include <pwd.h>
31 #include <shadow.h>
32 #include <netdb.h>
33 #include <mp.h>
34 #include <rpcsvc/nis.h>
35 #include <rpc/key_prot.h>
36 #include <nsswitch.h>
37 #include <ns_sldap.h>
38 
39 extern char *crypt();
40 extern long random();
41 extern char *getpassphrase();
42 extern char *program_name;
43 static const char *CRED_TABLE = "cred.org_dir";
44 
45 #define	ROOTKEY_FILE	"/etc/.rootkey"
46 
47 #ifndef MAXHOSTNAMELEN
48 #define	MAXHOSTNAMELEN 256
49 #endif
50 
51 #define	PK_FILES	1
52 #define	PK_YP		2
53 #define	PK_LDAP		4
54 
55 #define	LDAP_BINDDN_DEFAULT	"cn=Directory Manager"
56 #define	PROMPTGET_SUCCESS	1
57 #define	PROMPTGET_FAIL		-1
58 #define	PROMPTGET_MEMORY_FAIL	-2
59 #define	PASSWD_UNMATCHED	-3
60 
61 #define	FREE_CREDINFO(s) \
62 	if ((s)) { (void) memset((s), 0, strlen((s))); }
63 
64 
65 /* ************************ switch functions *************************** */
66 
67 /*	NSW_NOTSUCCESS  NSW_NOTFOUND   NSW_UNAVAIL    NSW_TRYAGAIN */
68 #define	DEF_ACTION {__NSW_RETURN, __NSW_RETURN, __NSW_CONTINUE, __NSW_CONTINUE}
69 
70 static struct __nsw_lookup lookup_files = {"files", DEF_ACTION, NULL, NULL},
71 		lookup_nis = {"nis", DEF_ACTION, NULL, &lookup_files};
72 static struct __nsw_switchconfig publickey_default =
73 			{0, "publickey", 2, &lookup_nis};
74 
75 static int get_ldap_bindDN(char **);
76 static int get_ldap_bindPassword(char **);
77 
78 /*
79  * Prompt the users for a ldap bind DN. If users do not enter a value but just
80  * simply hit the return key, the default bindDN "cn=Directory Manager"
81  * will be used.
82  */
83 static int
84 get_ldap_bindDN(char **ret_bindDN)
85 {
86 
87 	char	bindDN[BUFSIZ];
88 	char	prompt[BUFSIZ];
89 	int	blen, pos;
90 
91 	/* set the initial value for bindDN buffer */
92 	(void) memset(bindDN, 0, BUFSIZ);
93 
94 	(void) snprintf(prompt, BUFSIZ,
95 	"\nThe LDAP bind DN and password are required for this update.\n"
96 	"If you are not sure what values to enter, please contact your\n"
97 	"LDAP administrator.\n\nPlease enter LDAP bind DN [%s]: ",
98 	    LDAP_BINDDN_DEFAULT);
99 
100 	printf(prompt);
101 
102 	if (fgets(bindDN, sizeof (bindDN), stdin) == NULL) {
103 		(void) strlcpy(bindDN, LDAP_BINDDN_DEFAULT, BUFSIZ);
104 	}
105 
106 	blen = strlen(bindDN);
107 
108 	/* Check if the buffer ends with a newline */
109 	if ((blen > 0) && (bindDN[blen - 1] == '\n')) {
110 		bindDN[blen - 1] = '\0';
111 		blen -= 1;
112 	}
113 
114 	/* Remove the white spaces */
115 	if (blen > 0) {
116 		for (pos = blen - 1; pos >= 0; pos--) {
117 			if (isspace(bindDN[pos]))
118 				bindDN[pos] = '\0';
119 			else
120 				break;
121 		}
122 	}
123 
124 	/* Use the default bindDN, if the buffer contains no characters */
125 	if (strlen(bindDN) == 0)
126 		(void) strlcpy(bindDN, LDAP_BINDDN_DEFAULT, BUFSIZ);
127 
128 	if ((*ret_bindDN = (char *)malloc(strlen(bindDN)+1)) == NULL) {
129 		(void) memset(bindDN, 0, BUFSIZ);
130 		return (PROMPTGET_MEMORY_FAIL);
131 	}
132 
133 	(void) strlcpy(*ret_bindDN, bindDN, strlen(bindDN)+1);
134 
135 	/* Clean up and erase the credential info */
136 	(void) memset(bindDN, 0, BUFSIZ);
137 
138 	return (PROMPTGET_SUCCESS);
139 }
140 
141 
142 /*
143  * Prompt the user for a ldap bind password.
144  */
145 static int
146 get_ldap_bindPassword(char **ret_bindPass)
147 {
148 
149 	char	bindPassword[BUFSIZ];
150 	char	prompt[BUFSIZ];
151 	char	*bindPass = NULL;
152 
153 	/* set the initial value for bindPassword buffer */
154 	(void) memset(bindPassword, 0, BUFSIZ);
155 	*ret_bindPass = NULL;
156 
157 	(void) snprintf(prompt, BUFSIZ,
158 	    "Please enter LDAP bind password: ");
159 
160 	bindPass = getpassphrase(prompt);
161 
162 	if (bindPass == NULL)
163 		return (PROMPTGET_FAIL);
164 
165 	(void) strlcpy(bindPassword, bindPass, BUFSIZ);
166 
167 	/* clean the static buffer returned from getpassphrase call */
168 	(void) memset(bindPass, 0, strlen(bindPass));
169 	bindPass = NULL;
170 
171 	/*
172 	 * Re-enter the bind passowrd and compare it with the one
173 	 * from previous entered.
174 	 */
175 	(void) snprintf(prompt, BUFSIZ,
176 	    "Re-enter LDAP bind password to confirm: ");
177 
178 	bindPass = getpassphrase(prompt);
179 
180 	if (bindPass == NULL) {
181 		(void) memset(bindPassword, 0, BUFSIZ);
182 		return (PASSWD_UNMATCHED);
183 	}
184 
185 	if (strcmp(bindPass, bindPassword) != 0) {
186 		(void) memset(bindPassword, 0, BUFSIZ);
187 		(void) memset(bindPass, 0, strlen(bindPass));
188 		return (PASSWD_UNMATCHED);
189 	} else {
190 		(void) memset(bindPass, 0, strlen(bindPass));
191 		if ((*ret_bindPass = (char *)malloc(strlen(bindPassword)+1))
192 		    == NULL) {
193 			(void) memset(bindPassword, 0, BUFSIZ);
194 			return (PROMPTGET_MEMORY_FAIL);
195 		}
196 
197 		(void) strlcpy(*ret_bindPass, bindPassword,
198 		    strlen(bindPassword)+1);
199 
200 		/* Clean up and erase the credential info */
201 		(void) memset(bindPassword, 0, BUFSIZ);
202 
203 		return (PROMPTGET_SUCCESS);
204 	}
205 }
206 
207 
208 
209 char *
210 switch_policy_str(struct __nsw_switchconfig *conf)
211 {
212 	struct __nsw_lookup *look;
213 	static char policy[256];  /* 256 is enough for (nis, files...etc) */
214 	int previous = 0;
215 
216 	memset((char *)policy, 0, 256);
217 
218 	for (look = conf->lookups; look; look = look->next) {
219 		if (previous)
220 			strcat(policy, " ");
221 		strcat(policy, look->service_name);
222 		previous = 1;
223 	}
224 	return (policy);
225 }
226 
227 int
228 no_switch_policy(struct __nsw_switchconfig *conf)
229 {
230 	return (conf == NULL || conf->lookups == NULL);
231 }
232 
233 int
234 is_switch_policy(struct __nsw_switchconfig *conf, char *target)
235 {
236 	return (conf &&
237 	    conf->lookups &&
238 	    strcmp(conf->lookups->service_name, target) == 0 &&
239 	    conf->lookups->next == NULL);
240 }
241 
242 char *
243 first_and_only_switch_policy(char *policy,
244     struct __nsw_switchconfig *default_conf, char *head_msg)
245 {
246 	struct __nsw_switchconfig *conf;
247 	enum __nsw_parse_err perr;
248 	int policy_correct = 1;
249 	char *target_service = 0;
250 	int use_default = 0;
251 
252 	if (default_conf == 0)
253 		default_conf = &publickey_default;
254 
255 	conf = __nsw_getconfig(policy, &perr);
256 	if (no_switch_policy(conf)) {
257 		use_default = 1;
258 		conf = default_conf;
259 	}
260 
261 	target_service = conf->lookups->service_name;
262 
263 	if (conf->lookups->next != NULL) {
264 		policy_correct = 0;
265 		if (use_default) {
266 			(void) fprintf(stderr,
267 			"\n%s\n There is no publickey entry in %s.\n",
268 			    head_msg, __NSW_CONFIG_FILE);
269 			(void) fprintf(stderr,
270 			"The default publickey policy is \"publickey: %s\".\n",
271 			    switch_policy_str(default_conf));
272 		} else
273 			(void) fprintf(stderr,
274 		"\n%s\nThe publickey entry in %s is \"publickey: %s\".\n",
275 			    head_msg, __NSW_CONFIG_FILE,
276 			    switch_policy_str(conf));
277 	}
278 
279 	if (policy_correct == 0)
280 		(void) fprintf(stderr,
281 	"I cannot figure out which publickey database you want to update.\n");
282 	if (!use_default && conf)
283 		__nsw_freeconfig(conf);
284 
285 	if (policy_correct)
286 		return (target_service);
287 	else
288 		return (0);
289 }
290 
291 
292 
293 int
294 check_switch_policy(char *policy, char *target_service,
295     struct __nsw_switchconfig *default_conf, char *head_msg, char *tail_msg)
296 {
297 	struct __nsw_switchconfig *conf;
298 	enum __nsw_parse_err perr;
299 	int policy_correct = 1;
300 
301 	if (default_conf == 0)
302 		default_conf = &publickey_default;
303 
304 	conf = __nsw_getconfig(policy, &perr);
305 	if (no_switch_policy(conf)) {
306 		if (!is_switch_policy(default_conf, target_service)) {
307 			(void) fprintf(stderr,
308 			    "\n%s\nThere is no publickey entry in %s.\n",
309 			    head_msg, __NSW_CONFIG_FILE);
310 			(void) fprintf(stderr,
311 			"The default publickey policy is \"publickey: %s\".\n",
312 			    switch_policy_str(default_conf));
313 			policy_correct = 0;
314 		}
315 	} else if (!is_switch_policy(conf, target_service)) {
316 		(void) fprintf(stderr,
317 		"\n%s\nThe publickey entry in %s is \"publickey: %s\".\n",
318 		    head_msg, __NSW_CONFIG_FILE,
319 		    switch_policy_str(conf));
320 		policy_correct = 0;
321 	}
322 	/* should we exit ? */
323 	if (policy_correct == 0)
324 		(void) fprintf(stderr,
325 		"It should be \"publickey: %s\"%s\n\n",
326 		    target_service, tail_msg);
327 	if (conf)
328 		__nsw_freeconfig(conf);
329 
330 	return (policy_correct);
331 }
332 
333 int
334 get_pk_source(char *pk_service)
335 {
336 	int db = 0, got_from_switch = 0;
337 
338 	/* No service specified, try to figure out from switch */
339 	if (pk_service == 0) {
340 		pk_service = first_and_only_switch_policy("publickey", 0,
341 		    "ERROR:");
342 		if (pk_service == 0)
343 			return (0);
344 		(void) fprintf(stdout,
345 		    "Updating %s publickey database.\n",
346 		    pk_service);
347 		got_from_switch = 1;
348 	}
349 
350 	if (strcmp(pk_service, "ldap") == 0)
351 		db = PK_LDAP;
352 	else if (strcmp(pk_service, "nis") == 0)
353 		db = PK_YP;
354 	else if (strcmp(pk_service, "files") == 0)
355 		db = PK_FILES;
356 	else return (0);
357 
358 	/*
359 	 * If we didn't get service name from switch, check switch
360 	 * and print warning about it source of publickeys if not unique
361 	 */
362 	if (got_from_switch == 0)
363 		check_switch_policy("publickey", pk_service, 0, "WARNING:",
364 		    db == PK_FILES ? "" :
365 		    "; add 'files' if you want the 'nobody' key.");
366 
367 
368 	return (db); /* all passed */
369 }
370 
371 
372 /* ***************************** keylogin stuff *************************** */
373 int
374 keylogin(char *netname, char *secret)
375 {
376 	struct key_netstarg netst;
377 
378 	netst.st_pub_key[0] = 0;
379 	memcpy(netst.st_priv_key, secret, HEXKEYBYTES);
380 	netst.st_netname = netname;
381 
382 #ifdef NFS_AUTH
383 	nra.authtype = AUTH_DES;	/* only revoke DES creds */
384 	nra.uid = getuid();		/* use the real uid */
385 	if (_nfssys(NFS_REVAUTH, &nra) < 0) {
386 		perror("Warning: NFS credentials not destroyed");
387 		err = 1;
388 	}
389 #endif
390 
391 
392 	/* do actual key login */
393 	if (key_setnet(&netst) < 0) {
394 		(void) fprintf(stderr,
395 		    "Could not set %s's secret key\n", netname);
396 		(void) fprintf(stderr, "May be the keyserv is down?\n");
397 		return (0);
398 	}
399 
400 	return (1);
401 }
402 
403 nis_object *
404 init_entry()
405 {
406 	static nis_object	obj;
407 	static entry_col	cred_data[10];
408 	entry_obj		*eo;
409 
410 	memset((char *)(&obj), 0, sizeof (obj));
411 	memset((char *)(cred_data), 0, sizeof (entry_col) * 10);
412 
413 	obj.zo_name = "cred";
414 	obj.zo_group = "";
415 	obj.zo_ttl = 43200;
416 	obj.zo_data.zo_type = NIS_ENTRY_OBJ;
417 	eo = &(obj.EN_data);
418 	eo->en_type = "cred_tbl";
419 	eo->en_cols.en_cols_val = cred_data;
420 	eo->en_cols.en_cols_len = 5;
421 	cred_data[4].ec_flags |= EN_CRYPT;
422 	return (&obj);
423 }
424 
425 
426 static char	*attrFilter[] = {
427 	"objectclass",
428 	"nispublickey",
429 	"nissecretkey",
430 	(char *)NULL
431 };
432 
433 
434 /* Determines if there is a NisKeyObject objectclass in a given entry */
435 static int
436 ldap_keyobj_exist(ns_ldap_entry_t *entry)
437 {
438 	char		**fattrs;
439 
440 	fattrs = __ns_ldap_getAttr(entry, "objectClass");
441 
442 	if (fattrs == NULL)
443 		return (1);
444 
445 	while (*fattrs) {
446 		if (strcasecmp("NisKeyObject", *fattrs) == 0)
447 			return (1);
448 		fattrs++;
449 	}
450 
451 	return (0);
452 }
453 
454 
455 static char *keyAttrs[] = {
456 	"nispublickey",
457 	"nissecretkey",
458 	NULL
459 };
460 
461 /*
462  * Replace or append new attribute value(s) to an attribute.
463  * Don't care about memory leaks, because program is short running.
464  */
465 
466 static int
467 ldap_attr_mod(ns_ldap_entry_t *entry, char *mechname, char *public,
468     ns_ldap_attr_t **pkeyattrs, char *crypt, ns_ldap_attr_t **ckeyattrs)
469 {
470 	char		**alist[2];
471 	char		*keys[2];
472 
473 	char		*mechfilter;
474 	int		mechfilterlen;
475 	int		q = 0;
476 	int		i, j;
477 	int		keycount[] = {0, 0};
478 	ns_ldap_attr_t	*attrs;
479 
480 	keys[0] = public;
481 	keys[1] = crypt;
482 
483 	mechfilter = (char *)malloc(strlen(mechname) + 3);
484 	if (mechfilter == NULL)
485 		return (0);
486 	sprintf(mechfilter, "{%s}", mechname);
487 	mechfilterlen = strlen(mechfilter);
488 
489 	for (q = 0; keyAttrs[q] != NULL; q++) {
490 		int		found = 0;
491 
492 		for (i = 0; i < entry->attr_count; i++) {
493 			int		rep = 0;
494 			ns_ldap_attr_t	*attr = entry->attr_pair[i];
495 			char		*name = attr->attrname;
496 			int		count = 0;
497 
498 			if (strcasecmp(keyAttrs[q], name) == 0) {
499 				found++;
500 				count = attr->value_count;
501 		alist[q] = (char **)malloc(sizeof (char *) * (count + 1));
502 				if (alist[q] == NULL)
503 					return (0);
504 				alist[q][attr->value_count] = NULL;
505 				for (j = 0; j < attr->value_count; j++) {
506 					char	*val = attr->attrvalue[j];
507 					if (strncasecmp(val, mechfilter,
508 					    mechfilterlen) == 0) {
509 						/* Replace entry */
510 						rep++;
511 						alist[q][j] = keys[q];
512 					} else
513 						alist[q][j] = val;
514 					++keycount[q];
515 				}
516 				if (!rep) {
517 					/* Add entry to list */
518 					alist[q] = (char **)realloc(alist[q],
519 					    sizeof (char *) * (count + 2));
520 					if (alist[q] == NULL)
521 						return (0);
522 					alist[q][attr->value_count + 1] = NULL;
523 					alist[q][attr->value_count] = keys[q];
524 					++keycount[q];
525 				}
526 			}
527 		}
528 		if (!found) {
529 			/* Attribute does not exist, add entry anyways */
530 			alist[q] = (char **)malloc(sizeof (char *) * 2);
531 			if (alist[q] == NULL)
532 				return (0);
533 			alist[q][0] = keys[q];
534 			alist[q][1] = NULL;
535 			++keycount[q];
536 		}
537 	}
538 	if ((attrs = (ns_ldap_attr_t *)calloc(1,
539 	    sizeof (ns_ldap_attr_t))) == NULL)
540 		return (0);
541 	attrs->attrname = "nisPublicKey";
542 	attrs->attrvalue = alist[0];
543 	attrs->value_count = keycount[0];
544 	*pkeyattrs = attrs;
545 
546 	if ((attrs = (ns_ldap_attr_t *)calloc(1,
547 	    sizeof (ns_ldap_attr_t))) == NULL)
548 		return (0);
549 	attrs->attrname = "nisSecretKey";
550 	attrs->attrvalue = alist[1];
551 	attrs->value_count = keycount[1];
552 	*ckeyattrs = attrs;
553 	return (1);
554 }
555 
556 
557 /*
558  * Do the actual Add or update of attributes in attrs.
559  * The parameter 'update4host' is a flag that tells the function which
560  * DN and password should be used to bind to ldap. If it is an update
561  * for a host (update4host > 0), the two parameters "bindDN" and
562  * "bindPasswd" would be used to bind as the directory manager,
563  * otherwise "dn" and "passwd" would be used to bind as an individual
564  * user.
565  */
566 static void
567 update_ldap_attr(const char *dn, ns_ldap_attr_t **attrs, const char *passwd,
568     int add, int update4host, const char *bindDN, const char *bindPasswd)
569 {
570 	int		ldaprc;
571 	int		authstried = 0;
572 	char		*msg;
573 	char		*ldap_pw;
574 	char		**certpath = NULL;
575 	ns_auth_t	**app;
576 	ns_auth_t	**authpp = NULL;
577 	ns_auth_t	*authp = NULL;
578 	ns_cred_t	*credp;
579 	ns_ldap_error_t	*errorp = NULL;
580 	int		status;
581 
582 	if ((credp = (ns_cred_t *)calloc(1, sizeof (ns_cred_t))) == NULL) {
583 		fprintf(stderr, "Can not allocate cred buffer.\n");
584 		goto out;
585 	}
586 
587 	/*
588 	 * if this is an update for host, use the bindDN from the
589 	 * command prompt, otherwise use user's DN directly.
590 	 */
591 	if (update4host)
592 		credp->cred.unix_cred.userID = strdup(bindDN);
593 	else
594 		credp->cred.unix_cred.userID = strdup(dn);
595 
596 	if (credp->cred.unix_cred.userID == NULL) {
597 		fprintf(stderr, "Memory allocation failure (userID)\n");
598 		goto out;
599 	}
600 
601 	if (update4host) {
602 		credp->cred.unix_cred.passwd = strdup(bindPasswd);
603 	} else {
604 		if (passwd)
605 			credp->cred.unix_cred.passwd = strdup(passwd);
606 		else {
607 			/* Make sure a valid password is received. */
608 			status = get_ldap_bindPassword(&ldap_pw);
609 
610 			if (status != PROMPTGET_SUCCESS) {
611 				if (!ldap_pw)
612 					free(ldap_pw);
613 				goto out;
614 			}
615 			credp->cred.unix_cred.passwd = ldap_pw;
616 		}
617 	}
618 
619 	if (credp->cred.unix_cred.passwd == NULL) {
620 		fprintf(stderr, "Memory allocation failure (passwd)\n");
621 		goto out;
622 	}
623 
624 	/* get host certificate path, if one is configured */
625 	if (__ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P,
626 	    (void ***)&certpath, &errorp) != NS_LDAP_SUCCESS)
627 		goto out;
628 
629 	if (certpath && *certpath)
630 		credp->hostcertpath = *certpath;
631 
632 	/* Load the service specific authentication method */
633 	if (__ns_ldap_getServiceAuthMethods("keyserv", &authpp, &errorp) !=
634 	    NS_LDAP_SUCCESS)
635 		goto out;
636 
637 	/*
638 	 * if authpp is null, there is no serviceAuthenticationMethod
639 	 * try default authenticationMethod
640 	 */
641 	if (authpp == NULL) {
642 		if (__ns_ldap_getParam(NS_LDAP_AUTH_P, (void ***)&authpp,
643 		    &errorp) != NS_LDAP_SUCCESS)
644 			goto out;
645 	}
646 
647 	/*
648 	 * if authpp is still null, then can not authenticate, log
649 	 * error message and return error
650 	 */
651 	if (authpp == NULL) {
652 		fprintf(stderr, "No LDAP authentication method configured.\n"
653 		    " configured.\n");
654 		goto out;
655 	}
656 
657 	/*
658 	 * Walk the array and try all authentication methods in order except
659 	 * for "none".
660 	 */
661 	for (app = authpp; *app; app++) {
662 		authp = *app;
663 		/* what about disabling other mechanisms? "tls:sasl/EXTERNAL" */
664 		if (authp->type == NS_LDAP_AUTH_NONE)
665 			continue;
666 		authstried++;
667 		credp->auth.type = authp->type;
668 		credp->auth.tlstype = authp->tlstype;
669 		credp->auth.saslmech = authp->saslmech;
670 		credp->auth.saslopt = authp->saslopt;
671 
672 		if (add == TRUE)
673 			ldaprc = __ns_ldap_addAttr("publickey", dn,
674 			    (const ns_ldap_attr_t * const *)attrs,
675 			    credp, 0, &errorp);
676 		else
677 			ldaprc = __ns_ldap_repAttr("publickey", dn,
678 			    (const ns_ldap_attr_t * const *)attrs,
679 			    credp, 0, &errorp);
680 		if (ldaprc == NS_LDAP_SUCCESS) {
681 			/* clean up ns_cred_t structure in memory */
682 			if (credp != NULL)
683 				(void) __ns_ldap_freeCred(&credp);
684 			return;
685 		}
686 
687 		/* XXX add checking for cases of authentication errors */
688 		if ((ldaprc == NS_LDAP_INTERNAL) &&
689 		    ((errorp->status == LDAP_INAPPROPRIATE_AUTH) ||
690 		    (errorp->status == LDAP_INVALID_CREDENTIALS))) {
691 			fprintf(stderr, "LDAP authentication failed.\n");
692 			goto out;
693 		}
694 	}
695 	if (authstried == 0)
696 		fprintf(stderr, "No legal authentication method configured.\n");
697 
698 out:
699 	/* clean up ns_cred_t structure in memory */
700 	if (credp != NULL) {
701 		(void) __ns_ldap_freeCred(&credp);
702 	}
703 
704 	if (errorp) {
705 		__ns_ldap_err2str(errorp->status, &msg);
706 		fprintf(stderr, "LDAP error: %s.\n", msg);
707 	}
708 	fprintf(stderr, "%s: key-pair(s) unchanged.\n", program_name);
709 	exit(1);
710 }
711 
712 
713 /*
714  * Update LDAP nisplublickey entry with new key information via SLDAP.
715  * Free and clean up memory that stores credential data soon after
716  * they are not used or an error comes up.
717  */
718 int
719 ldap_update(char *mechname, char *netname, char *public, char *crypt,
720     char *passwd)
721 {
722 	char		*netnamecpy;
723 	char		*id;
724 	char		*domain;
725 	char		*dn;
726 	char		*db;
727 	char		*filter;
728 	ns_ldap_error_t	*errorp;
729 	char		*pkeyatval, *ckeyatval;
730 	ns_ldap_result_t	*res;
731 	ns_ldap_attr_t	*pattrs, *cattrs;
732 	int		update4host = FALSE;
733 	char		*bindDN = NULL;
734 	char		*bindPasswd = NULL;
735 	int		status;
736 
737 	/* Generate DN */
738 	if ((netnamecpy = strdup(netname)) == NULL)
739 		return (0);
740 	if (((id = strchr(netnamecpy, '.')) == NULL) ||
741 	    ((domain = strchr(netnamecpy, '@')) == NULL))
742 		return (0);
743 	else {
744 		*domain++ = '\0';
745 		*id++ = '\0';
746 
747 		id = strdup(id);
748 		if (id == NULL) {
749 			free(netnamecpy);
750 			fprintf(stderr, "LDAP memory error (id)\n");
751 			return (0);
752 		}
753 		domain = strdup(domain);
754 		if (domain == NULL) {
755 			free(netnamecpy);
756 			free(id);
757 			fprintf(stderr, "LDAP memory error (domain)\n");
758 			return (0);
759 		}
760 		free(netnamecpy);
761 	}
762 
763 	if (isdigit(*id)) {
764 		/* We be user. */
765 		__ns_ldap_uid2dn(id, &dn, NULL, &errorp);
766 		if (dn == NULL) {
767 			fprintf(stderr, "Could not obtain LDAP dn\n");
768 			fprintf(stderr, "%s: key-pair(s) unchanged.\n",
769 			    program_name);
770 			exit(1);
771 		}
772 		db = "passwd";
773 		filter = (char *)malloc(strlen(id) + 13);
774 		if (filter)
775 			sprintf(filter, "(uidnumber=%s)", id);
776 		else {
777 			fprintf(stderr, "Can not allocate filter buffer.\n");
778 			fprintf(stderr, "%s: key-pair(s) unchanged.\n",
779 			    program_name);
780 			exit(1);
781 		}
782 	} else {
783 		/* We be host. */
784 		update4host = TRUE;
785 
786 		__ns_ldap_host2dn(id, NULL, &dn, NULL, &errorp);
787 		if (dn == NULL) {
788 			fprintf(stderr, "Could not obtain LDAP dn\n");
789 			fprintf(stderr, "%s: key-pair(s) unchanged.\n",
790 			    program_name);
791 			exit(1);
792 		}
793 
794 		db = "hosts";
795 		filter = (char *)malloc(strlen(id) + 6);
796 		if (filter)
797 			sprintf(filter, "(cn=%s)", id);
798 		else {
799 			fprintf(stderr, "Can not allocate filter buffer.\n");
800 			fprintf(stderr, "%s: key-pair(s) unchanged.\n",
801 			    program_name);
802 			exit(1);
803 		}
804 
805 		/* Prompt for ldap bind DN for entry udpates */
806 		status = get_ldap_bindDN(&bindDN);
807 
808 		if (status != PROMPTGET_SUCCESS) {
809 			FREE_CREDINFO(bindDN);
810 			fprintf(stderr,
811 			    "Failed to get a valid LDAP bind DN.\n"
812 			    "%s: key-pair(s) unchanged.\n",
813 			    program_name);
814 			exit(1);
815 		}
816 
817 		/* Prompt for ldap bind password */
818 		status = get_ldap_bindPassword(&bindPasswd);
819 
820 		if (status != PROMPTGET_SUCCESS) {
821 			FREE_CREDINFO(bindPasswd);
822 			FREE_CREDINFO(bindDN);
823 
824 			fprintf(stderr,
825 			    "Failed to get a valid LDAP bind password."
826 			    "\n%s: key-pair(s) unchanged.\n",
827 			    program_name);
828 			exit(1);
829 		}
830 	}
831 
832 	/* Construct attribute values */
833 	pkeyatval = (char *)malloc(strlen(mechname) + strlen(public) + 3);
834 	if (pkeyatval == NULL) {
835 		FREE_CREDINFO(bindPasswd);
836 		FREE_CREDINFO(bindDN);
837 		fprintf(stderr, "LDAP memory error (pkeyatval)\n");
838 		fprintf(stderr, "%s: key-pair(s) unchanged.\n", program_name);
839 		exit(1);
840 	}
841 	sprintf(pkeyatval, "{%s}%s", mechname, public);
842 	ckeyatval = (char *)malloc(strlen(mechname) + strlen(crypt) + 3);
843 	if (ckeyatval == NULL) {
844 		FREE_CREDINFO(pkeyatval);
845 		FREE_CREDINFO(bindPasswd);
846 		FREE_CREDINFO(bindDN);
847 		fprintf(stderr, "LDAP memory error (pkeyatval)\n");
848 		fprintf(stderr, "%s: key-pair(s) unchanged.\n", program_name);
849 		exit(1);
850 	}
851 	sprintf(ckeyatval, "{%s}%s", mechname, crypt);
852 
853 	/* Does entry exist? */
854 	if ((__ns_ldap_list(db, filter, NULL, (const char **)attrFilter,
855 	    NULL, 0, &res, &errorp,
856 	    NULL, NULL) == NS_LDAP_SUCCESS) && res == NULL) {
857 		FREE_CREDINFO(ckeyatval);
858 		FREE_CREDINFO(pkeyatval);
859 		FREE_CREDINFO(bindPasswd);
860 		FREE_CREDINFO(bindDN);
861 		fprintf(stderr, "LDAP entry does not exist.\n");
862 		fprintf(stderr, "%s: key-pair(s) unchanged.\n", program_name);
863 		exit(1);
864 	}
865 
866 	/* Entry exists, modify attributes for public and secret keys */
867 
868 	/* Is there a NisKeyObject in entry? */
869 	if (!ldap_keyobj_exist(&res->entry[0])) {
870 		/* Add NisKeyObject objectclass and the keys */
871 		char	**newattr;
872 		ns_ldap_attr_t	*attrs[4]; /* objectclass, pk, sk, NULL */
873 
874 		/* set objectclass */
875 		newattr = (char **)calloc(2, sizeof (char *));
876 		newattr[0] = "NisKeyObject";
877 		newattr[1] = NULL;
878 		if ((attrs[0] = (ns_ldap_attr_t *)calloc(1,
879 		    sizeof (ns_ldap_attr_t))) == NULL) {
880 			FREE_CREDINFO(ckeyatval);
881 			FREE_CREDINFO(pkeyatval);
882 			FREE_CREDINFO(bindPasswd);
883 			FREE_CREDINFO(bindDN);
884 			fprintf(stderr, "Memory allocation failed\n");
885 			fprintf(stderr, "%s: key-pair(s) unchanged.\n",
886 			    program_name);
887 			exit(1);
888 		}
889 		attrs[0]->attrname = "objectClass";
890 		attrs[0]->attrvalue = newattr;
891 		attrs[0]->value_count = 1;
892 
893 		/* set publickey */
894 		newattr = (char **)calloc(2, sizeof (char *));
895 		newattr[0] = pkeyatval;
896 		newattr[1] = NULL;
897 		if ((attrs[1] = (ns_ldap_attr_t *)calloc(1,
898 		    sizeof (ns_ldap_attr_t))) == NULL) {
899 			FREE_CREDINFO(ckeyatval);
900 			FREE_CREDINFO(pkeyatval);
901 			FREE_CREDINFO(bindPasswd);
902 			FREE_CREDINFO(bindDN);
903 			fprintf(stderr, "Memory allocation failed\n");
904 			fprintf(stderr, "%s: key-pair(s) unchanged.\n",
905 			    program_name);
906 			exit(1);
907 		}
908 		attrs[1]->attrname = "nisPublicKey";
909 		attrs[1]->attrvalue = newattr;
910 		attrs[1]->value_count = 1;
911 
912 		/* set privatekey */
913 		newattr = (char **)calloc(2, sizeof (char *));
914 		newattr[0] = ckeyatval;
915 		newattr[1] = NULL;
916 		if ((attrs[2] = (ns_ldap_attr_t *)calloc(1,
917 		    sizeof (ns_ldap_attr_t))) == NULL) {
918 			FREE_CREDINFO(ckeyatval);
919 			FREE_CREDINFO(pkeyatval);
920 			FREE_CREDINFO(bindPasswd);
921 			FREE_CREDINFO(bindDN);
922 			fprintf(stderr, "Memory allocation failed\n");
923 			fprintf(stderr, "%s: key-pair(s) unchanged.\n",
924 			    program_name);
925 			exit(1);
926 		}
927 		attrs[2]->attrname = "nisSecretKey";
928 		attrs[2]->attrvalue = newattr;
929 		attrs[2]->value_count = 1;
930 
931 		/* terminator */
932 		attrs[3] = NULL;
933 
934 		update_ldap_attr(dn, attrs, passwd, TRUE, update4host,
935 		    bindDN, bindPasswd);
936 	} else {
937 		/* object class already exists, replace keys */
938 		ns_ldap_attr_t	*attrs[4]; /* objectclass, pk, sk, NULL */
939 
940 		if (!ldap_attr_mod(&res->entry[0], mechname,
941 		    pkeyatval, &pattrs,
942 		    ckeyatval, &cattrs)) {
943 			FREE_CREDINFO(ckeyatval);
944 			FREE_CREDINFO(pkeyatval);
945 			FREE_CREDINFO(bindPasswd);
946 			FREE_CREDINFO(bindDN);
947 			fprintf(stderr,
948 			    "Could not generate LDAP attribute list.\n");
949 			fprintf(stderr,
950 			    "%s: key-pair(s) unchanged.\n", program_name);
951 			exit(1);
952 		}
953 
954 		attrs[0] = pattrs;
955 		attrs[1] = cattrs;
956 		attrs[2] = NULL;
957 
958 		update_ldap_attr(dn, attrs, passwd, FALSE, update4host,
959 		    bindDN, bindPasswd);
960 	}
961 
962 	FREE_CREDINFO(ckeyatval);
963 	FREE_CREDINFO(pkeyatval);
964 	FREE_CREDINFO(bindPasswd);
965 	FREE_CREDINFO(bindDN);
966 
967 	return (0);
968 }
969