xref: /illumos-gate/usr/src/cmd/keyserv/chkey_common.c (revision b3700b074e637f8c6991b70754c88a2cfffb246b)
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 	char	bindDN[BUFSIZ];
87 	char	prompt[BUFSIZ];
88 	int	blen, pos;
89 
90 	/* set the initial value for bindDN buffer */
91 	(void) memset(bindDN, 0, BUFSIZ);
92 
93 	(void) snprintf(prompt, BUFSIZ,
94 	"\nThe LDAP bind DN and password are required for this update.\n"
95 	"If you are not sure what values to enter, please contact your\n"
96 	"LDAP administrator.\n\nPlease enter LDAP bind DN [%s]: ",
97 	LDAP_BINDDN_DEFAULT);
98 
99 	printf(prompt);
100 
101 	if (fgets(bindDN, sizeof (bindDN), stdin) == NULL) {
102 		(void) strlcpy(bindDN, LDAP_BINDDN_DEFAULT, BUFSIZ);
103 	}
104 
105 	blen = strlen(bindDN);
106 
107 	/* Check if the buffer ends with a newline */
108 	if ((blen > 0) && (bindDN[blen - 1] == '\n')) {
109 		bindDN[blen - 1] = '\0';
110 		blen -= 1;
111 	}
112 
113 	/* Remove the white spaces */
114 	if (blen > 0) {
115 		for (pos = blen - 1; pos >= 0; pos--) {
116 			if (isspace(bindDN[pos]))
117 				bindDN[pos] = '\0';
118 			else
119 				break;
120 		}
121 	}
122 
123 	/* Use the default bindDN, if the buffer contains no characters */
124 	if (strlen(bindDN) == 0)
125 		(void) strlcpy(bindDN, LDAP_BINDDN_DEFAULT, BUFSIZ);
126 
127 	if ((*ret_bindDN = (char *)malloc(strlen(bindDN)+1)) == NULL) {
128 		(void) memset(bindDN, 0, BUFSIZ);
129 		return (PROMPTGET_MEMORY_FAIL);
130 	}
131 
132 	(void) strlcpy(*ret_bindDN, bindDN, strlen(bindDN)+1);
133 
134 	/* Clean up and erase the credential info */
135 	(void) memset(bindDN, 0, BUFSIZ);
136 
137 	return (PROMPTGET_SUCCESS);
138 }
139 
140 
141 /*
142  * Prompt the user for a ldap bind password.
143  */
144 static int
145 get_ldap_bindPassword(char **ret_bindPass) {
146 
147 	char 	bindPassword[BUFSIZ];
148 	char	prompt[BUFSIZ];
149 	char	*bindPass = NULL;
150 
151 	/* set the initial value for bindPassword buffer */
152 	(void) memset(bindPassword, 0, BUFSIZ);
153 	*ret_bindPass = NULL;
154 
155 	(void) snprintf(prompt, BUFSIZ,
156 		"Please enter LDAP bind password: ");
157 
158 	bindPass = getpassphrase(prompt);
159 
160 	if (bindPass == NULL)
161 		return (PROMPTGET_FAIL);
162 
163 	(void) strlcpy(bindPassword, bindPass, BUFSIZ);
164 
165 	/* clean the static buffer returned from getpassphrase call */
166 	(void) memset(bindPass, 0, strlen(bindPass));
167 	bindPass = NULL;
168 
169 	/*
170 	 * Re-enter the bind passowrd and compare it with the one
171 	 * from previous entered.
172 	 */
173 	(void) snprintf(prompt, BUFSIZ,
174 		"Re-enter LDAP bind password to confirm: ");
175 
176 	bindPass = getpassphrase(prompt);
177 
178 	if (bindPass == NULL) {
179 		(void) memset(bindPassword, 0, BUFSIZ);
180 		return (PASSWD_UNMATCHED);
181 	}
182 
183 	if (strcmp(bindPass, bindPassword) != 0) {
184 		(void) memset(bindPassword, 0, BUFSIZ);
185 		(void) memset(bindPass, 0, strlen(bindPass));
186 		return (PASSWD_UNMATCHED);
187 	} else {
188 		(void) memset(bindPass, 0, strlen(bindPass));
189 		if ((*ret_bindPass = (char *)malloc(strlen(bindPassword)+1))
190 			== NULL) {
191 			(void) memset(bindPassword, 0, BUFSIZ);
192 			return (PROMPTGET_MEMORY_FAIL);
193 		}
194 
195 		(void) strlcpy(*ret_bindPass, bindPassword,
196 			strlen(bindPassword)+1);
197 
198 		/* Clean up and erase the credential info */
199 		(void) memset(bindPassword, 0, BUFSIZ);
200 
201 		return (PROMPTGET_SUCCESS);
202 	}
203 }
204 
205 
206 
207 char *
208 switch_policy_str(struct __nsw_switchconfig *conf)
209 {
210 	struct __nsw_lookup *look;
211 	static char policy[256];  /* 256 is enough for (nis, files...etc) */
212 	int previous = 0;
213 
214 	memset((char *)policy, 0, 256);
215 
216 	for (look = conf->lookups; look; look = look->next) {
217 		if (previous)
218 			strcat(policy, " ");
219 		strcat(policy, look->service_name);
220 		previous = 1;
221 	}
222 	return (policy);
223 }
224 
225 int
226 no_switch_policy(struct __nsw_switchconfig *conf)
227 {
228 	return (conf == NULL || conf->lookups == NULL);
229 }
230 
231 int
232 is_switch_policy(struct __nsw_switchconfig *conf, char *target)
233 {
234 	return (conf &&
235 	    conf->lookups &&
236 	    strcmp(conf->lookups->service_name, target) == 0 &&
237 	    conf->lookups->next == NULL);
238 }
239 
240 char *
241 first_and_only_switch_policy(char *policy,
242 		    struct __nsw_switchconfig *default_conf,
243 		    char *head_msg)
244 {
245 	struct __nsw_switchconfig *conf;
246 	enum __nsw_parse_err perr;
247 	int policy_correct = 1;
248 	char *target_service = 0;
249 	int use_default = 0;
250 
251 	if (default_conf == 0)
252 		default_conf = &publickey_default;
253 
254 	conf = __nsw_getconfig(policy, &perr);
255 	if (no_switch_policy(conf)) {
256 		use_default = 1;
257 		conf = default_conf;
258 	}
259 
260 	target_service = conf->lookups->service_name;
261 
262 	if (conf->lookups->next != NULL) {
263 		policy_correct = 0;
264 		if (use_default) {
265 			(void) fprintf(stderr,
266 			"\n%s\n There is no publickey entry in %s.\n",
267 			    head_msg, __NSW_CONFIG_FILE);
268 			(void) fprintf(stderr,
269 			"The default publickey policy is \"publickey: %s\".\n",
270 			    switch_policy_str(default_conf));
271 		} else
272 			(void) fprintf(stderr,
273 		"\n%s\nThe publickey entry in %s is \"publickey: %s\".\n",
274 			    head_msg, __NSW_CONFIG_FILE,
275 			    switch_policy_str(conf));
276 	}
277 
278 	if (policy_correct == 0)
279 		(void) fprintf(stderr,
280 	"I cannot figure out which publickey database you want to update.\n");
281 	if (!use_default && conf)
282 		__nsw_freeconfig(conf);
283 
284 	if (policy_correct)
285 		return (target_service);
286 	else
287 		return (0);
288 }
289 
290 
291 
292 int
293 check_switch_policy(char *policy, char *target_service,
294 		    struct __nsw_switchconfig *default_conf,
295 		    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,
468 	    char *mechname,
469 	    char *public,
470 	    ns_ldap_attr_t **pkeyattrs,
471 	    char *crypt,
472 	    ns_ldap_attr_t **ckeyattrs)
473 {
474 	char		**alist[2];
475 	char		*keys[2];
476 
477 	char		*mechfilter;
478 	int		mechfilterlen;
479 	int		q = 0;
480 	int		i, j;
481 	int		keycount[] = {0, 0};
482 	ns_ldap_attr_t	*attrs;
483 
484 	keys[0] = public;
485 	keys[1] = crypt;
486 
487 	mechfilter = (char *)malloc(strlen(mechname) + 3);
488 	if (mechfilter == NULL)
489 		return (0);
490 	sprintf(mechfilter, "{%s}", mechname);
491 	mechfilterlen = strlen(mechfilter);
492 
493 	for (q = 0; keyAttrs[q] != NULL; q++) {
494 		int		found = 0;
495 
496 		for (i = 0; i < entry->attr_count; i++) {
497 			int		rep = 0;
498 			ns_ldap_attr_t	*attr = entry->attr_pair[i];
499 			char		*name = attr->attrname;
500 			int		count = 0;
501 
502 			if (strcasecmp(keyAttrs[q], name) == 0) {
503 				found++;
504 				count = attr->value_count;
505 		alist[q] = (char **)malloc(sizeof (char *) * (count + 1));
506 				if (alist[q] == NULL)
507 					return (0);
508 				alist[q][attr->value_count] = NULL;
509 				for (j = 0; j < attr->value_count; j++) {
510 					char	*val = attr->attrvalue[j];
511 					if (strncasecmp(val, mechfilter,
512 					    mechfilterlen) == 0) {
513 						/* Replace entry */
514 						rep++;
515 						alist[q][j] = keys[q];
516 					} else
517 						alist[q][j] = val;
518 					++keycount[q];
519 				}
520 				if (!rep) {
521 					/* Add entry to list */
522 					alist[q] = (char **)realloc(alist[q],
523 					    sizeof (char *) * (count + 2));
524 					if (alist[q] == NULL)
525 						return (0);
526 					alist[q][attr->value_count + 1] = NULL;
527 					alist[q][attr->value_count] = keys[q];
528 					++keycount[q];
529 				}
530 			}
531 		}
532 		if (!found) {
533 			/* Attribute does not exist, add entry anyways */
534 			alist[q] = (char **)malloc(sizeof (char *) * 2);
535 			if (alist[q] == NULL)
536 				return (0);
537 			alist[q][0] = keys[q];
538 			alist[q][1] = NULL;
539 			++keycount[q];
540 		}
541 	}
542 	if ((attrs = (ns_ldap_attr_t *)calloc(1,
543 	    sizeof (ns_ldap_attr_t))) == NULL)
544 		return (0);
545 	attrs->attrname = "nisPublicKey";
546 	attrs->attrvalue = alist[0];
547 	attrs->value_count = keycount[0];
548 	*pkeyattrs = attrs;
549 
550 	if ((attrs = (ns_ldap_attr_t *)calloc(1,
551 	    sizeof (ns_ldap_attr_t))) == NULL)
552 		return (0);
553 	attrs->attrname = "nisSecretKey";
554 	attrs->attrvalue = alist[1];
555 	attrs->value_count = keycount[1];
556 	*ckeyattrs = attrs;
557 	return (1);
558 }
559 
560 
561 /*
562  * Do the actual Add or update of attributes in attrs.
563  * The parameter 'update4host' is a flag that tells the function which
564  * DN and password should be used to bind to ldap. If it is an update
565  * for a host (update4host > 0), the two parameters "bindDN" and
566  * "bindPasswd" would be used to bind as the directory manager,
567  * otherwise "dn" and "passwd" would be used to bind as an individual
568  * user.
569  */
570 static void
571 update_ldap_attr(const char *dn,
572 		ns_ldap_attr_t **attrs,
573 		const char *passwd,
574 		int add,
575 		int update4host,
576 		const char *bindDN,
577 		const char *bindPasswd)
578 {
579 	int		ldaprc;
580 	int		authstried = 0;
581 	char		*msg;
582 	char		*ldap_pw;
583 	char		**certpath = NULL;
584 	ns_auth_t	**app;
585 	ns_auth_t	**authpp = NULL;
586 	ns_auth_t	*authp = NULL;
587 	ns_cred_t	*credp;
588 	ns_ldap_error_t	*errorp = NULL;
589 	int		status;
590 
591 	if ((credp = (ns_cred_t *)calloc(1, sizeof (ns_cred_t))) == NULL) {
592 		fprintf(stderr, "Can not allocate cred buffer.\n");
593 		goto out;
594 	}
595 
596 	/*
597 	 * if this is an update for host, use the bindDN from the
598 	 * command prompt, otherwise use user's DN directly.
599 	 */
600 	if (update4host)
601 		credp->cred.unix_cred.userID = strdup(bindDN);
602 	else
603 		credp->cred.unix_cred.userID = strdup(dn);
604 
605 	if (credp->cred.unix_cred.userID == NULL) {
606 		fprintf(stderr, "Memory allocation failure (userID)\n");
607 		goto out;
608 	}
609 
610 	if (update4host) {
611 		credp->cred.unix_cred.passwd = strdup(bindPasswd);
612 	} else {
613 		if (passwd)
614 			credp->cred.unix_cred.passwd = strdup(passwd);
615 		else {
616 			/* Make sure a valid password is received. */
617 			status = get_ldap_bindPassword(&ldap_pw);
618 
619 			if (status != PROMPTGET_SUCCESS) {
620 				if (!ldap_pw)
621 					free(ldap_pw);
622 				goto out;
623 			}
624 			credp->cred.unix_cred.passwd = ldap_pw;
625 		}
626 	}
627 
628 	if (credp->cred.unix_cred.passwd == NULL) {
629 		fprintf(stderr, "Memory allocation failure (passwd)\n");
630 		goto out;
631 	}
632 
633 	/* get host certificate path, if one is configured */
634 	if (__ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P,
635 	    (void ***)&certpath, &errorp) != NS_LDAP_SUCCESS)
636 		goto out;
637 
638 	if (certpath && *certpath)
639 		credp->hostcertpath = *certpath;
640 
641 	/* Load the service specific authentication method */
642 	if (__ns_ldap_getServiceAuthMethods("keyserv", &authpp, &errorp) !=
643 	    NS_LDAP_SUCCESS)
644 		goto out;
645 
646 	/*
647 	 * if authpp is null, there is no serviceAuthenticationMethod
648 	 * try default authenticationMethod
649 	 */
650 	if (authpp == NULL) {
651 		if (__ns_ldap_getParam(NS_LDAP_AUTH_P, (void ***)&authpp,
652 		    &errorp) != NS_LDAP_SUCCESS)
653 			goto out;
654 	}
655 
656 	/*
657 	 * if authpp is still null, then can not authenticate, log
658 	 * error message and return error
659 	 */
660 	if (authpp == NULL) {
661 		fprintf(stderr, "No LDAP authentication method configured.\n"
662 		    " configured.\n");
663 		goto out;
664 	}
665 
666 	/*
667 	 * Walk the array and try all authentication methods in order except
668 	 * for "none".
669 	 */
670 	for (app = authpp; *app; app++) {
671 		authp = *app;
672 		/* what about disabling other mechanisms? "tls:sasl/EXTERNAL" */
673 		if (authp->type == NS_LDAP_AUTH_NONE)
674 			continue;
675 		authstried++;
676 		credp->auth.type = authp->type;
677 		credp->auth.tlstype = authp->tlstype;
678 		credp->auth.saslmech = authp->saslmech;
679 		credp->auth.saslopt = authp->saslopt;
680 
681 		if (add == TRUE)
682 			ldaprc = __ns_ldap_addAttr("publickey", dn,
683 			    (const ns_ldap_attr_t * const *)attrs,
684 			    credp, NULL, &errorp);
685 		else
686 			ldaprc = __ns_ldap_repAttr("publickey", dn,
687 			    (const ns_ldap_attr_t * const *)attrs,
688 			    credp, NULL, &errorp);
689 		if (ldaprc == NS_LDAP_SUCCESS) {
690 			/* clean up ns_cred_t structure in memory */
691 			if (credp != NULL)
692 				(void) __ns_ldap_freeCred(&credp);
693 			return;
694 		}
695 
696 		/* XXX add checking for cases of authentication errors */
697 		if ((ldaprc == NS_LDAP_INTERNAL) &&
698 		    ((errorp->status == LDAP_INAPPROPRIATE_AUTH) ||
699 		    (errorp->status == LDAP_INVALID_CREDENTIALS))) {
700 			fprintf(stderr, "LDAP authentication failed.\n");
701 			goto out;
702 		}
703 	}
704 	if (authstried == 0)
705 		fprintf(stderr, "No legal authentication method configured.\n");
706 
707 out:
708 	/* clean up ns_cred_t structure in memory */
709 	if (credp != NULL) {
710 		(void) __ns_ldap_freeCred(&credp);
711 	}
712 
713 	if (errorp) {
714 		__ns_ldap_err2str(errorp->status, &msg);
715 		fprintf(stderr, "LDAP error: %s.\n", msg);
716 	}
717 	fprintf(stderr, "%s: key-pair(s) unchanged.\n", program_name);
718 	exit(1);
719 }
720 
721 
722 /*
723  * Update LDAP nisplublickey entry with new key information via SLDAP.
724  * Free and clean up memory that stores credential data soon after
725  * they are not used or an error comes up.
726  */
727 int
728 ldap_update(char *mechname,
729 	    char *netname,
730 	    char *public,
731 	    char *crypt,
732 	    char *passwd)
733 {
734 	char		*netnamecpy;
735 	char		*id;
736 	char		*domain;
737 	char		*dn;
738 	char		*db;
739 	char		*filter;
740 	ns_ldap_error_t	*errorp;
741 	char		*pkeyatval, *ckeyatval;
742 	ns_ldap_result_t	*res;
743 	ns_ldap_attr_t	*pattrs, *cattrs;
744 	int		update4host = FALSE;
745 	char		*bindDN = NULL;
746 	char		*bindPasswd = NULL;
747 	int		status;
748 
749 	/* Generate DN */
750 	if ((netnamecpy = strdup(netname)) == NULL)
751 		return (0);
752 	if (((id = strchr(netnamecpy, '.')) == NULL) ||
753 	    ((domain = strchr(netnamecpy, '@')) == NULL))
754 		return (0);
755 	else {
756 		*domain++ = '\0';
757 		*id++ = '\0';
758 
759 		id = strdup(id);
760 		if (id == NULL) {
761 			free(netnamecpy);
762 			fprintf(stderr, "LDAP memory error (id)\n");
763 			return (0);
764 		}
765 		domain = strdup(domain);
766 		if (domain == NULL) {
767 			free(netnamecpy);
768 			free(id);
769 			fprintf(stderr, "LDAP memory error (domain)\n");
770 			return (0);
771 		}
772 		free(netnamecpy);
773 	}
774 
775 	if (isdigit(*id)) {
776 		/* We be user. */
777 		__ns_ldap_uid2dn(id, &dn, NULL, &errorp);
778 		if (dn == NULL) {
779 			fprintf(stderr, "Could not obtain LDAP dn\n");
780 			fprintf(stderr, "%s: key-pair(s) unchanged.\n",
781 			    program_name);
782 			exit(1);
783 		}
784 		db = "passwd";
785 		filter = (char *)malloc(strlen(id) + 13);
786 		if (filter)
787 			sprintf(filter, "(uidnumber=%s)", id);
788 		else {
789 			fprintf(stderr, "Can not allocate filter buffer.\n");
790 			fprintf(stderr, "%s: key-pair(s) unchanged.\n",
791 			    program_name);
792 			exit(1);
793 		}
794 	} else {
795 		/* We be host. */
796 		update4host = TRUE;
797 
798 		__ns_ldap_host2dn(id, NULL, &dn, NULL, &errorp);
799 		if (dn == NULL) {
800 			fprintf(stderr, "Could not obtain LDAP dn\n");
801 			fprintf(stderr, "%s: key-pair(s) unchanged.\n",
802 			    program_name);
803 			exit(1);
804 		}
805 
806 		db = "hosts";
807 		filter = (char *)malloc(strlen(id) + 6);
808 		if (filter)
809 			sprintf(filter, "(cn=%s)", id);
810 		else {
811 			fprintf(stderr, "Can not allocate filter buffer.\n");
812 			fprintf(stderr, "%s: key-pair(s) unchanged.\n",
813 			    program_name);
814 			exit(1);
815 		}
816 
817 		/* Prompt for ldap bind DN for entry udpates */
818 		status = get_ldap_bindDN(&bindDN);
819 
820 		if (status != PROMPTGET_SUCCESS) {
821 			FREE_CREDINFO(bindDN);
822 			fprintf(stderr,
823 			    "Failed to get a valid LDAP bind DN.\n"
824 			    "%s: key-pair(s) unchanged.\n",
825 			    program_name);
826 			exit(1);
827 		}
828 
829 		/* Prompt for ldap bind password */
830 		status = get_ldap_bindPassword(&bindPasswd);
831 
832 		if (status != PROMPTGET_SUCCESS) {
833 			FREE_CREDINFO(bindPasswd);
834 			FREE_CREDINFO(bindDN);
835 
836 			fprintf(stderr,
837 			    "Failed to get a valid LDAP bind password."
838 			    "\n%s: key-pair(s) unchanged.\n",
839 			    program_name);
840 			exit(1);
841 		}
842 	}
843 
844 	/* Construct attribute values */
845 	pkeyatval = (char *)malloc(strlen(mechname) + strlen(public) + 3);
846 	if (pkeyatval == NULL) {
847 		FREE_CREDINFO(bindPasswd);
848 		FREE_CREDINFO(bindDN);
849 		fprintf(stderr, "LDAP memory error (pkeyatval)\n");
850 		fprintf(stderr, "%s: key-pair(s) unchanged.\n", program_name);
851 		exit(1);
852 	}
853 	sprintf(pkeyatval, "{%s}%s", mechname, public);
854 	ckeyatval = (char *)malloc(strlen(mechname) + strlen(crypt) + 3);
855 	if (ckeyatval == NULL) {
856 		FREE_CREDINFO(pkeyatval);
857 		FREE_CREDINFO(bindPasswd);
858 		FREE_CREDINFO(bindDN);
859 		fprintf(stderr, "LDAP memory error (pkeyatval)\n");
860 		fprintf(stderr, "%s: key-pair(s) unchanged.\n", program_name);
861 		exit(1);
862 	}
863 	sprintf(ckeyatval, "{%s}%s", mechname, crypt);
864 
865 	/* Does entry exist? */
866 	if ((__ns_ldap_list(db, filter, NULL, (const char **)attrFilter,
867 	    NULL, 0, &res, &errorp,
868 	    NULL, NULL) == NS_LDAP_SUCCESS) && res == NULL) {
869 		FREE_CREDINFO(ckeyatval);
870 		FREE_CREDINFO(pkeyatval);
871 		FREE_CREDINFO(bindPasswd);
872 		FREE_CREDINFO(bindDN);
873 		fprintf(stderr, "LDAP entry does not exist.\n");
874 		fprintf(stderr, "%s: key-pair(s) unchanged.\n", program_name);
875 		exit(1);
876 	}
877 
878 	/* Entry exists, modify attributes for public and secret keys */
879 
880 	/* Is there a NisKeyObject in entry? */
881 	if (!ldap_keyobj_exist(&res->entry[0])) {
882 		/* Add NisKeyObject objectclass and the keys */
883 		char	**newattr;
884 		ns_ldap_attr_t	*attrs[4]; /* objectclass, pk, sk, NULL */
885 
886 		/* set objectclass */
887 		newattr = (char **)calloc(2, sizeof (char *));
888 		newattr[0] = "NisKeyObject";
889 		newattr[1] = NULL;
890 		if ((attrs[0] = (ns_ldap_attr_t *)calloc(1,
891 		    sizeof (ns_ldap_attr_t))) == NULL) {
892 			FREE_CREDINFO(ckeyatval);
893 			FREE_CREDINFO(pkeyatval);
894 			FREE_CREDINFO(bindPasswd);
895 			FREE_CREDINFO(bindDN);
896 			fprintf(stderr, "Memory allocation failed\n");
897 			fprintf(stderr, "%s: key-pair(s) unchanged.\n",
898 			    program_name);
899 			exit(1);
900 		}
901 		attrs[0]->attrname = "objectClass";
902 		attrs[0]->attrvalue = newattr;
903 		attrs[0]->value_count = 1;
904 
905 		/* set publickey */
906 		newattr = (char **)calloc(2, sizeof (char *));
907 		newattr[0] = pkeyatval;
908 		newattr[1] = NULL;
909 		if ((attrs[1] = (ns_ldap_attr_t *)calloc(1,
910 		    sizeof (ns_ldap_attr_t))) == NULL) {
911 			FREE_CREDINFO(ckeyatval);
912 			FREE_CREDINFO(pkeyatval);
913 			FREE_CREDINFO(bindPasswd);
914 			FREE_CREDINFO(bindDN);
915 			fprintf(stderr, "Memory allocation failed\n");
916 			fprintf(stderr, "%s: key-pair(s) unchanged.\n",
917 			    program_name);
918 			exit(1);
919 		}
920 		attrs[1]->attrname = "nisPublicKey";
921 		attrs[1]->attrvalue = newattr;
922 		attrs[1]->value_count = 1;
923 
924 		/* set privatekey */
925 		newattr = (char **)calloc(2, sizeof (char *));
926 		newattr[0] = ckeyatval;
927 		newattr[1] = NULL;
928 		if ((attrs[2] = (ns_ldap_attr_t *)calloc(1,
929 		    sizeof (ns_ldap_attr_t))) == NULL) {
930 			FREE_CREDINFO(ckeyatval);
931 			FREE_CREDINFO(pkeyatval);
932 			FREE_CREDINFO(bindPasswd);
933 			FREE_CREDINFO(bindDN);
934 			fprintf(stderr, "Memory allocation failed\n");
935 			fprintf(stderr, "%s: key-pair(s) unchanged.\n",
936 			    program_name);
937 			exit(1);
938 		}
939 		attrs[2]->attrname = "nisSecretKey";
940 		attrs[2]->attrvalue = newattr;
941 		attrs[2]->value_count = 1;
942 
943 		/* terminator */
944 		attrs[3] = NULL;
945 
946 		update_ldap_attr(dn, attrs, passwd, TRUE, update4host,
947 		    bindDN, bindPasswd);
948 	} else {
949 		/* object class already exists, replace keys */
950 		ns_ldap_attr_t	*attrs[4]; /* objectclass, pk, sk, NULL */
951 
952 		if (!ldap_attr_mod(&res->entry[0], mechname,
953 		    pkeyatval, &pattrs,
954 		    ckeyatval, &cattrs)) {
955 			FREE_CREDINFO(ckeyatval);
956 			FREE_CREDINFO(pkeyatval);
957 			FREE_CREDINFO(bindPasswd);
958 			FREE_CREDINFO(bindDN);
959 			fprintf(stderr,
960 			    "Could not generate LDAP attribute list.\n");
961 			fprintf(stderr,
962 			    "%s: key-pair(s) unchanged.\n", program_name);
963 			exit(1);
964 		}
965 
966 		attrs[0] = pattrs;
967 		attrs[1] = cattrs;
968 		attrs[2] = NULL;
969 
970 		update_ldap_attr(dn, attrs, passwd, FALSE, update4host,
971 		    bindDN, bindPasswd);
972 	}
973 
974 	FREE_CREDINFO(ckeyatval);
975 	FREE_CREDINFO(pkeyatval);
976 	FREE_CREDINFO(bindPasswd);
977 	FREE_CREDINFO(bindDN);
978 
979 	return (0);
980 }
981