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
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 */
145static int
146get_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
209char *
210switch_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
227int
228no_switch_policy(struct __nsw_switchconfig *conf)
229{
230	return (conf == NULL || conf->lookups == NULL);
231}
232
233int
234is_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
242char *
243first_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
293int
294check_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
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, 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 */
566static void
567update_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
698out:
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 */
718int
719ldap_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