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
get_ldap_bindDN(char ** ret_bindDN)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
get_ldap_bindPassword(char ** ret_bindPass)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 *
switch_policy_str(struct __nsw_switchconfig * conf)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
no_switch_policy(struct __nsw_switchconfig * conf)226 no_switch_policy(struct __nsw_switchconfig *conf)
227 {
228 return (conf == NULL || conf->lookups == NULL);
229 }
230
231 int
is_switch_policy(struct __nsw_switchconfig * conf,char * target)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 *
first_and_only_switch_policy(char * policy,struct __nsw_switchconfig * default_conf,char * head_msg)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
check_switch_policy(char * policy,char * target_service,struct __nsw_switchconfig * default_conf,char * head_msg,char * tail_msg)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
get_pk_source(char * pk_service)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
keylogin(char * netname,char * secret)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 *
init_entry()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
ldap_keyobj_exist(ns_ldap_entry_t * entry)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
ldap_attr_mod(ns_ldap_entry_t * entry,char * mechname,char * public,ns_ldap_attr_t ** pkeyattrs,char * crypt,ns_ldap_attr_t ** ckeyattrs)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
update_ldap_attr(const char * dn,ns_ldap_attr_t ** attrs,const char * passwd,int add,int update4host,const char * bindDN,const char * bindPasswd)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
ldap_update(char * mechname,char * netname,char * public,char * crypt,char * passwd)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