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
39extern char *crypt();
40extern long random();
41extern char *getpassphrase();
42extern char *program_name;
43static 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
70static struct __nsw_lookup lookup_files = {"files", DEF_ACTION, NULL, NULL},
71		lookup_nis = {"nis", DEF_ACTION, NULL, &lookup_files};
72static struct __nsw_switchconfig publickey_default =
73			{0, "publickey", 2, &lookup_nis};
74
75static int get_ldap_bindDN(char **);
76static 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 */
83static int
84get_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 */
144static int
145get_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
207char *
208switch_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
225int
226no_switch_policy(struct __nsw_switchconfig *conf)
227{
228	return (conf == NULL || conf->lookups == NULL);
229}
230
231int
232is_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
240char *
241first_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
292int
293check_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
333int
334get_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 *************************** */
373int
374keylogin(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
403nis_object *
404init_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
426static 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 */
435static int
436ldap_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
455static 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
466static int
467ldap_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 */
570static void
571update_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
707out:
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 */
727int
728ldap_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