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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
24 */
25
26
27 #include <errno.h>
28 #include <ldap.h>
29 #include <sasl/sasl.h>
30 #include <libintl.h>
31 #include <strings.h>
32 #include <syslog.h>
33 #include <stdarg.h>
34
35 #include "addisc.h"
36 #include "libadutils.h"
37 #include "idmap_priv.h"
38 #include "ns_sldap.h"
39 #include "namemaps.h"
40
41 /* From adutils.c: */
42
43 /* A single DS */
44 struct idmap_nm_handle {
45 LDAP *ad; /* LDAP connection */
46 /* LDAP DS info */
47 char *ad_host;
48 int ad_port;
49
50 /* hardwired to SASL GSSAPI only for now */
51 char *saslmech;
52 unsigned saslflags;
53 char *windomain;
54 char *ad_unixuser_attr;
55 char *ad_unixgroup_attr;
56 char *nldap_winname_attr;
57 char *default_domain;
58 bool_t is_nldap;
59 bool_t is_ad;
60 int direction;
61 ns_cred_t nsc;
62 };
63
64 /* PRINTFLIKE1 */
65 static
66 void
namemap_log(char * fmt,...)67 namemap_log(char *fmt, ...)
68 {
69 va_list va;
70
71 va_start(va, fmt);
72 (void) vfprintf(stderr, fmt, va);
73 va_end(va);
74 (void) fprintf(stderr, "\n");
75 }
76
77 static
78 idmap_stat
string2auth(const char * from,ns_auth_t * na)79 string2auth(const char *from, ns_auth_t *na)
80 {
81 if (from == NULL) {
82 na->type = NS_LDAP_AUTH_SASL;
83 na->tlstype = NS_LDAP_TLS_SASL;
84 na->saslmech = NS_LDAP_SASL_GSSAPI;
85 na->saslopt = NS_LDAP_SASLOPT_PRIV |
86 NS_LDAP_SASLOPT_INT;
87 return (IDMAP_SUCCESS);
88 }
89
90 if (strcasecmp(from, "simple") == 0) {
91 na->type = NS_LDAP_AUTH_SIMPLE;
92 na->tlstype = NS_LDAP_TLS_NONE;
93 na->saslmech = NS_LDAP_SASL_NONE;
94 na->saslopt = NS_LDAP_SASLOPT_NONE;
95 } else if (strcasecmp(from, "sasl/CRAM-MD5") == 0) {
96 na->type = NS_LDAP_AUTH_SASL;
97 na->tlstype = NS_LDAP_TLS_SASL;
98 na->saslmech = NS_LDAP_SASL_CRAM_MD5;
99 na->saslopt = NS_LDAP_SASLOPT_NONE;
100 } else if (strcasecmp(from, "sasl/DIGEST-MD5") == 0) {
101 na->type = NS_LDAP_AUTH_SASL;
102 na->tlstype = NS_LDAP_TLS_SASL;
103 na->saslmech = NS_LDAP_SASL_DIGEST_MD5;
104 na->saslopt = NS_LDAP_SASLOPT_NONE;
105 } else if (strcasecmp(from, "sasl/GSSAPI") == 0) {
106 na->type = NS_LDAP_AUTH_SASL;
107 na->tlstype = NS_LDAP_TLS_SASL;
108 na->saslmech = NS_LDAP_SASL_GSSAPI;
109 na->saslopt = NS_LDAP_SASLOPT_PRIV |
110 NS_LDAP_SASLOPT_INT;
111 } else if (strcasecmp(from, "tls:simple") == 0) {
112 na->type = NS_LDAP_AUTH_TLS;
113 na->tlstype = NS_LDAP_TLS_SIMPLE;
114 na->saslmech = NS_LDAP_SASL_NONE;
115 na->saslopt = NS_LDAP_SASLOPT_NONE;
116 } else if (strcasecmp(from, "tls:sasl/CRAM-MD5") == 0) {
117 na->type = NS_LDAP_AUTH_TLS;
118 na->tlstype = NS_LDAP_TLS_SASL;
119 na->saslmech = NS_LDAP_SASL_CRAM_MD5;
120 na->saslopt = NS_LDAP_SASLOPT_NONE;
121 } else if (strcasecmp(from, "tls:sasl/DIGEST-MD5") == 0) {
122 na->type = NS_LDAP_AUTH_TLS;
123 na->tlstype = NS_LDAP_TLS_SASL;
124 na->saslmech = NS_LDAP_SASL_DIGEST_MD5;
125 na->saslopt = NS_LDAP_SASLOPT_NONE;
126 } else {
127 namemap_log(
128 gettext("Invalid authentication method \"%s\" specified\n"),
129 from);
130 return (IDMAP_ERR_ARG);
131 }
132
133 return (IDMAP_SUCCESS);
134 }
135
136
137
138 static
139 idmap_stat
strings2cred(ns_cred_t * nsc,char * user,char * passwd,char * auth)140 strings2cred(ns_cred_t *nsc, char *user, char *passwd, char *auth)
141 {
142 idmap_stat rc;
143 (void) memset(nsc, 0, sizeof (ns_cred_t));
144
145 if ((rc = string2auth(auth, &nsc->auth)) != IDMAP_SUCCESS)
146 return (rc);
147
148 if (user != NULL) {
149 nsc->cred.unix_cred.userID = strdup(user);
150 if (nsc->cred.unix_cred.userID == NULL)
151 return (IDMAP_ERR_MEMORY);
152 }
153
154 if (passwd != NULL) {
155 nsc->cred.unix_cred.passwd = strdup(passwd);
156 if (nsc->cred.unix_cred.passwd == NULL) {
157 free(nsc->cred.unix_cred.userID);
158 return (IDMAP_ERR_MEMORY);
159 }
160 }
161
162 return (IDMAP_SUCCESS);
163 }
164
165
166
167
168
169 /*ARGSUSED*/
170 static int
idmap_saslcallback(LDAP * ld,unsigned flags,void * defaults,void * prompts)171 idmap_saslcallback(LDAP *ld, unsigned flags, void *defaults, void *prompts)
172 {
173 sasl_interact_t *interact;
174
175 if (prompts == NULL || flags != LDAP_SASL_INTERACTIVE)
176 return (LDAP_PARAM_ERROR);
177
178 /* There should be no extra arguemnts for SASL/GSSAPI authentication */
179 for (interact = prompts; interact->id != SASL_CB_LIST_END;
180 interact++) {
181 interact->result = NULL;
182 interact->len = 0;
183 }
184 return (LDAP_SUCCESS);
185 }
186
187 static
188 idmap_stat
idmap_open_ad_conn(idmap_nm_handle_t * adh)189 idmap_open_ad_conn(idmap_nm_handle_t *adh)
190 {
191 int zero = 0;
192 int timeoutms = 30 * 1000;
193 int ldversion, ldap_rc;
194 idmap_stat rc = IDMAP_SUCCESS;
195
196 /* Open and bind an LDAP connection */
197 adh->ad = ldap_init(adh->ad_host, adh->ad_port);
198 if (adh->ad == NULL) {
199 namemap_log(
200 gettext("ldap_init() to server %s port %d failed. (%s)"),
201 CHECK_NULL(adh->ad_host),
202 adh->ad_port, strerror(errno));
203 rc = IDMAP_ERR_INTERNAL;
204 goto out;
205 }
206 ldversion = LDAP_VERSION3;
207 (void) ldap_set_option(adh->ad, LDAP_OPT_PROTOCOL_VERSION, &ldversion);
208 (void) ldap_set_option(adh->ad, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
209 (void) ldap_set_option(adh->ad, LDAP_OPT_TIMELIMIT, &zero);
210 (void) ldap_set_option(adh->ad, LDAP_OPT_SIZELIMIT, &zero);
211 (void) ldap_set_option(adh->ad, LDAP_X_OPT_CONNECT_TIMEOUT, &timeoutms);
212 (void) ldap_set_option(adh->ad, LDAP_OPT_RESTART, LDAP_OPT_ON);
213 ldap_rc = ldap_sasl_interactive_bind_s(adh->ad, "" /* binddn */,
214 adh->saslmech, NULL, NULL, adh->saslflags, &idmap_saslcallback,
215 NULL);
216
217 if (ldap_rc != LDAP_SUCCESS) {
218 (void) ldap_unbind(adh->ad);
219 adh->ad = NULL;
220 namemap_log(
221 gettext("ldap_sasl_interactive_bind_s() to server "
222 "%s port %d failed. (%s)"), CHECK_NULL(adh->ad_host),
223 adh->ad_port, ldap_err2string(ldap_rc));
224 rc = IDMAP_ERR_INTERNAL;
225 }
226
227 out:
228 return (rc);
229 }
230
231 static
232 idmap_stat
idmap_init_nldap(idmap_nm_handle_t * p)233 idmap_init_nldap(idmap_nm_handle_t *p)
234 {
235 /*
236 * For now, there is nothing to initialize in nldap. This is just to
237 * make it future-proof, especially standalone libsldap-proof
238 */
239 p->is_nldap = TRUE;
240 return (0);
241 }
242
243 static
244 idmap_stat
idmap_init_ad(idmap_nm_handle_t * p)245 idmap_init_ad(idmap_nm_handle_t *p)
246 {
247 idmap_stat rc = IDMAP_SUCCESS;
248 ad_disc_ds_t *dc = NULL;
249 ad_disc_t ad_ctx;
250
251 ad_ctx = ad_disc_init();
252 if (ad_ctx == NULL) {
253 namemap_log(
254 gettext("AD autodiscovery initialization failed"));
255 return (IDMAP_ERR_INTERNAL);
256 }
257 ad_disc_refresh(ad_ctx);
258
259
260 /* Based on the supplied or default domain, find the proper AD: */
261 if (ad_disc_set_DomainName(ad_ctx, p->windomain)) {
262 rc = IDMAP_ERR_INTERNAL;
263 namemap_log(
264 gettext("Setting a domain name \"%s\" for autodiscovery"
265 " failed, most likely not enough memory"), p->windomain);
266 goto cleanup;
267 }
268
269 dc = ad_disc_get_DomainController(ad_ctx, AD_DISC_GLOBAL, NULL);
270 if (dc == NULL) {
271 rc = IDMAP_ERR_ARG;
272 namemap_log(
273 gettext("A domain controller for the "
274 "domain \"%s\" not found."), p->windomain);
275 goto cleanup;
276 }
277
278
279 p->ad_port = dc->port;
280 p->ad_host = strdup(dc->host);
281
282 if (p->ad_host == NULL) {
283 rc = IDMAP_ERR_MEMORY;
284 goto cleanup;
285 }
286
287 p->saslflags = LDAP_SASL_INTERACTIVE;
288 p->saslmech = strdup("GSSAPI");
289
290 if (p->saslmech == NULL) {
291 rc = IDMAP_ERR_MEMORY;
292 goto cleanup;
293 }
294
295 rc = idmap_open_ad_conn(p);
296
297 if (rc != IDMAP_SUCCESS)
298 goto cleanup;
299
300 p->is_ad = TRUE;
301
302 cleanup:
303 ad_disc_fini(ad_ctx);
304 free(dc);
305 return (rc);
306 }
307
308 void
idmap_fini_namemaps(idmap_nm_handle_t * p)309 idmap_fini_namemaps(idmap_nm_handle_t *p)
310 {
311 if (p == NULL)
312 return;
313
314 if (p->ad_unixgroup_attr != NULL)
315 free(p->ad_unixgroup_attr);
316
317 if (p->ad_unixuser_attr != NULL)
318 free(p->ad_unixuser_attr);
319
320 if (p->nldap_winname_attr)
321 free(p->nldap_winname_attr);
322
323 if (p->windomain != NULL)
324 free(p->windomain);
325
326 if (p->default_domain != NULL)
327 free(p->default_domain);
328
329 if (p->saslmech != NULL)
330 free(p->saslmech);
331
332 if (p->ad_host != NULL)
333 free(p->ad_host);
334
335 if (p->nsc.cred.unix_cred.userID != NULL) {
336 free(p->nsc.cred.unix_cred.userID);
337 }
338
339 if (p->nsc.cred.unix_cred.passwd != NULL) {
340 /* No archeology: */
341 (void) memset(p->nsc.cred.unix_cred.passwd, 0,
342 strlen(p->nsc.cred.unix_cred.passwd));
343 free(p->nsc.cred.unix_cred.passwd);
344 }
345
346 if (p->ad)
347 (void) ldap_unbind(p->ad);
348 free(p);
349
350 }
351
352
353
354 idmap_stat
idmap_init_namemaps(idmap_nm_handle_t ** adh,char * user,char * passwd,char * auth,char * windomain,int direction)355 idmap_init_namemaps(idmap_nm_handle_t **adh,
356 char *user, char *passwd, char *auth, char *windomain,
357 int direction)
358 {
359 idmap_stat rc;
360 idmap_nm_handle_t *p;
361
362 p = (idmap_nm_handle_t *)calloc(1, sizeof (idmap_nm_handle_t));
363 if (p == NULL)
364 return (IDMAP_ERR_MEMORY);
365
366 rc = idmap_get_prop_str(PROP_DEFAULT_DOMAIN,
367 &p->default_domain);
368 if (rc != IDMAP_SUCCESS) {
369 namemap_log(
370 gettext("Error obtaining default domain from idmapd (%s)"),
371 idmap_stat2string(rc));
372 goto cleanup;
373 }
374
375 rc = idmap_get_prop_str(PROP_AD_UNIXUSER_ATTR,
376 &p->ad_unixuser_attr);
377 if (rc != IDMAP_SUCCESS) {
378 namemap_log(
379 gettext("Error obtaining AD unixuser attribute (%s)"),
380 idmap_stat2string(rc));
381 goto cleanup;
382 }
383
384 rc = idmap_get_prop_str(PROP_AD_UNIXGROUP_ATTR,
385 &p->ad_unixgroup_attr);
386 if (rc != IDMAP_SUCCESS) {
387 namemap_log(
388 gettext("Error obtaining AD unixgroup attribute (%s)"),
389 idmap_stat2string(rc));
390 goto cleanup;
391 }
392
393
394 rc = idmap_get_prop_str(PROP_NLDAP_WINNAME_ATTR,
395 &p->nldap_winname_attr);
396 if (rc != IDMAP_SUCCESS) {
397 namemap_log(
398 gettext("Error obtaining AD unixgroup attribute (%s)"),
399 idmap_stat2string(rc));
400 goto cleanup;
401 }
402
403 if (windomain != NULL) {
404 p->windomain = strdup(windomain);
405 if (p->windomain == NULL) {
406 rc = IDMAP_ERR_MEMORY;
407 goto cleanup;
408 }
409 } else if (!EMPTY_STRING(p->default_domain)) {
410 p->windomain = strdup(p->default_domain);
411 if (p->windomain == NULL) {
412 rc = IDMAP_ERR_MEMORY;
413 goto cleanup;
414 }
415 } else if (direction == IDMAP_DIRECTION_W2U) {
416 namemap_log(
417 gettext("Windows domain not given and idmapd daemon"
418 " didn't provide a default one"));
419 rc = IDMAP_ERR_ARG;
420 goto cleanup;
421 }
422
423 p->direction = direction;
424
425 if ((p->ad_unixuser_attr != NULL || p->ad_unixgroup_attr != NULL) &&
426 direction != IDMAP_DIRECTION_U2W) {
427 rc = idmap_init_ad(p);
428 if (rc != IDMAP_SUCCESS) {
429 goto cleanup;
430 }
431 }
432
433 if (p->nldap_winname_attr != NULL && direction != IDMAP_DIRECTION_W2U) {
434 rc = idmap_init_nldap(p);
435 if (rc != IDMAP_SUCCESS) {
436 goto cleanup;
437 }
438
439 rc = strings2cred(&p->nsc, user, passwd, auth);
440 if (rc != IDMAP_SUCCESS) {
441 goto cleanup;
442 }
443 }
444
445 cleanup:
446
447 if (rc == IDMAP_SUCCESS) {
448 *adh = p;
449 return (IDMAP_SUCCESS);
450 }
451
452 /* There was an error: */
453 idmap_fini_namemaps(*adh);
454 return (rc);
455 }
456
457 static
458 char *
dns2dn(const char * dns,const char * prefix)459 dns2dn(const char *dns, const char *prefix)
460 {
461 int num_lvl = 1;
462 char *buf;
463 const char *it, *new_it;
464
465 for (it = dns; it != NULL; it = strchr(it, '.')) {
466 it ++;
467 num_lvl ++;
468 }
469
470 buf = (char *)malloc(strlen(prefix) + strlen(dns) + 4 * num_lvl);
471 (void) strcpy(buf, prefix);
472
473
474 it = dns;
475 for (;;) {
476 new_it = strchr(it, '.');
477 (void) strcat(buf, "DC=");
478 if (new_it == NULL) {
479 (void) strcat(buf, it);
480 break;
481 } else {
482 (void) strncat(buf, it, new_it - it);
483 (void) strcat(buf, ",");
484 }
485
486 it = new_it + 1;
487 }
488
489 return (buf);
490 }
491
492
493 static
494 idmap_stat
extract_attribute(idmap_nm_handle_t * p,LDAPMessage * entry,char * name,char ** value)495 extract_attribute(idmap_nm_handle_t *p, LDAPMessage *entry, char *name,
496 char **value)
497 {
498 char **values = NULL;
499 idmap_stat rc = IDMAP_SUCCESS;
500 /* No value means it is not requested */
501 if (value == NULL)
502 return (IDMAP_SUCCESS);
503
504 values = ldap_get_values(p->ad, entry, name);
505 if (values == NULL || values[0] == NULL)
506 *value = NULL;
507 else {
508 *value = strdup(values[0]);
509 if (*value == NULL)
510 rc = IDMAP_ERR_MEMORY;
511 }
512 errout:
513 ldap_value_free(values);
514 return (rc);
515 }
516
517
518 /* Split winname to its name and domain part */
519 static
520 idmap_stat
split_fqwn(char * fqwn,char ** name,char ** domain)521 split_fqwn(char *fqwn, char **name, char **domain)
522 {
523 char *at;
524
525 *name = NULL;
526 *domain = NULL;
527
528 at = strchr(fqwn, '@');
529 if (at == NULL) {
530 at = strchr(fqwn, '\\');
531 }
532 if (at == NULL) {
533 /* There is no domain - leave domain NULL */
534 *name = strdup(fqwn);
535 if (*name == NULL)
536 goto errout;
537 return (IDMAP_SUCCESS);
538 }
539
540
541 *domain = strdup(at+1);
542 if (*domain == NULL)
543 goto errout;
544 *name = (char *)malloc(at - fqwn + 1);
545 if (*name == NULL)
546 goto errout;
547 (void) strlcpy(*name, fqwn, at - fqwn + 1);
548
549 if (*at == '\\') {
550 char *it = *name;
551 *name = *domain;
552 *domain = it;
553 }
554
555 return (IDMAP_SUCCESS);
556
557
558 errout:
559 free(*name);
560 *name = NULL;
561 free(*domain);
562 *domain = NULL;
563 return (IDMAP_ERR_MEMORY);
564 }
565
566 static
567 idmap_stat
unixname2dn(idmap_nm_handle_t * p,char * unixname,int is_user,char ** dn,char ** winname,char ** windomain)568 unixname2dn(idmap_nm_handle_t *p, char *unixname, int is_user, char **dn,
569 char **winname, char **windomain)
570 {
571 idmap_stat rc = IDMAP_SUCCESS;
572 int rc_ns;
573
574
575 char filter[255];
576 static const char *attribs[3];
577 ns_ldap_result_t *res;
578 ns_ldap_error_t *errorp = NULL;
579 char **attrs;
580
581
582 attribs[0] = p->nldap_winname_attr;
583 attribs[1] = "dn";
584 attribs[2] = NULL;
585
586 (void) snprintf(filter, sizeof (filter), is_user ? "uid=%s" : "cn=%s",
587 unixname);
588
589 rc_ns = __ns_ldap_list(is_user ? "passwd" : "group",
590 filter, NULL, attribs, NULL, 0, &res, &errorp, NULL, NULL);
591
592
593 if (rc_ns == NS_LDAP_NOTFOUND) {
594 namemap_log(is_user ? gettext("User %s not found.")
595 : gettext("Group %s not found."), unixname);
596 return (IDMAP_ERR_NOTFOUND);
597 } else if (rc_ns != NS_LDAP_SUCCESS) {
598 char *msg = "Cause unidentified";
599 if (errorp != NULL) {
600 (void) __ns_ldap_err2str(errorp->status, &msg);
601 }
602 namemap_log(gettext("Ldap list failed (%s)."), msg);
603 return (IDMAP_ERR_ARG);
604 }
605
606 if (res == NULL) {
607 namemap_log(gettext("User %s not found"), unixname);
608 return (IDMAP_ERR_ARG);
609 }
610
611 if (winname != NULL && windomain != NULL) {
612 attrs = __ns_ldap_getAttr(&res->entry[0],
613 p->nldap_winname_attr);
614 if (attrs != NULL && attrs[0] != NULL) {
615 rc = split_fqwn(attrs[0], winname, windomain);
616 } else {
617 *winname = *windomain = NULL;
618 }
619 }
620
621 if (dn != NULL) {
622 attrs = __ns_ldap_getAttr(&res->entry[0], "dn");
623 if (attrs == NULL || attrs[0] == NULL) {
624 namemap_log(gettext("dn for %s not found"),
625 unixname);
626 return (IDMAP_ERR_ARG);
627 }
628 *dn = strdup(attrs[0]);
629 }
630
631
632 return (rc);
633
634 }
635
636 #define FILTER "(sAMAccountName=%s)"
637
638 /* Puts the values of attributes to unixuser and unixgroup, unless NULL */
639
640 static
641 idmap_stat
winname2dn(idmap_nm_handle_t * p,char * winname,int * is_wuser,char ** dn,char ** unixuser,char ** unixgroup)642 winname2dn(idmap_nm_handle_t *p, char *winname,
643 int *is_wuser, char **dn, char **unixuser, char **unixgroup)
644 {
645 idmap_stat rc = IDMAP_SUCCESS;
646 char *base;
647 char *filter;
648 int flen;
649 char *attribs[4];
650 int i;
651 LDAPMessage *results = NULL;
652 LDAPMessage *entry;
653 int ldap_rc;
654
655 /* Query: */
656
657 base = dns2dn(p->windomain, "");
658 if (base == NULL) {
659 return (IDMAP_ERR_MEMORY);
660 }
661
662 i = 0;
663 attribs[i++] = "objectClass";
664 if (unixuser != NULL)
665 attribs[i++] = p->ad_unixuser_attr;
666 if (unixgroup != NULL)
667 attribs[i++] = p->ad_unixgroup_attr;
668 attribs[i] = NULL;
669
670 flen = snprintf(NULL, 0, FILTER, winname) + 1;
671 if ((filter = (char *)malloc(flen)) == NULL) {
672 free(base);
673 return (IDMAP_ERR_MEMORY);
674 }
675 (void) snprintf(filter, flen, FILTER, winname);
676
677 ldap_rc = ldap_search_s(p->ad, base, LDAP_SCOPE_SUBTREE, filter,
678 attribs, 0, &results);
679
680 free(base);
681 free(filter);
682
683 if (ldap_rc != LDAP_SUCCESS) {
684 namemap_log(
685 gettext("Ldap query to server %s port %d failed. (%s)"),
686 p->ad_host, p->ad_port, ldap_err2string(ldap_rc));
687 (void) ldap_msgfree(results);
688 return (IDMAP_ERR_OTHER);
689 }
690
691
692 for (entry = ldap_first_entry(p->ad, results), *dn = NULL;
693 entry != NULL;
694 entry = ldap_next_entry(p->ad, entry)) {
695 char **values = NULL;
696 int i = 0;
697 values = ldap_get_values(p->ad, entry, "objectClass");
698
699 if (values == NULL) {
700 (void) ldap_msgfree(results);
701 return (IDMAP_ERR_MEMORY);
702 }
703
704 for (i = 0; i < ldap_count_values(values); i++) {
705 /*
706 * is_wuser can be IDMAP_UNKNOWN, in that case we accept
707 * both User/Group
708 */
709 if (*is_wuser != IDMAP_NO &&
710 strcasecmp(values[i], "User") == 0 ||
711 *is_wuser != IDMAP_YES &&
712 strcasecmp(values[i], "Group") == 0) {
713 *dn = ldap_get_dn(p->ad, entry);
714 if (*dn == NULL) {
715 ldap_value_free(values);
716 (void) ldap_msgfree(results);
717 return (IDMAP_ERR_MEMORY);
718 }
719 *is_wuser = strcasecmp(values[i], "User") == 0
720 ? IDMAP_YES : IDMAP_NO;
721 break;
722 }
723 }
724
725 ldap_value_free(values);
726 if (*dn != NULL)
727 break;
728 }
729
730 if (*dn == NULL) {
731 namemap_log(
732 *is_wuser == IDMAP_YES ? gettext("User %s@%s not found") :
733 *is_wuser == IDMAP_NO ? gettext("Group %s@%s not found") :
734 gettext("%s@%s not found"), winname, p->windomain);
735 return (IDMAP_ERR_NOTFOUND);
736 }
737
738 if (unixuser != NULL)
739 rc = extract_attribute(p, entry, p->ad_unixuser_attr,
740 unixuser);
741
742 if (rc == IDMAP_SUCCESS && unixgroup != NULL)
743 rc = extract_attribute(p, entry, p->ad_unixgroup_attr,
744 unixgroup);
745
746 (void) ldap_msgfree(results);
747
748 return (rc);
749 }
750
751
752 /* set the given attribute to the given value. If value is NULL, unset it */
753 static
754 idmap_stat
idmap_ad_set(idmap_nm_handle_t * p,char * dn,char * attr,char * value)755 idmap_ad_set(idmap_nm_handle_t *p, char *dn, char *attr, char *value)
756 {
757 idmap_stat rc = IDMAP_SUCCESS;
758 int ldap_rc;
759 char *new_values[2] = {NULL, NULL};
760 LDAPMod *mods[2] = {NULL, NULL};
761
762 mods[0] = (LDAPMod *)calloc(1, sizeof (LDAPMod));
763 mods[0]->mod_type = strdup(attr);
764 if (value != NULL) {
765 mods[0]->mod_op = LDAP_MOD_REPLACE;
766 new_values[0] = strdup(value);
767 mods[0]->mod_values = new_values;
768 } else {
769 mods[0]->mod_op = LDAP_MOD_DELETE;
770 mods[0]->mod_values = NULL;
771 }
772
773 ldap_rc = ldap_modify_s(p->ad, dn, mods);
774 if (ldap_rc != LDAP_SUCCESS) {
775 namemap_log(
776 gettext("Ldap modify of %s, attribute %s failed. (%s)"),
777 dn, attr, ldap_err2string(ldap_rc));
778 rc = IDMAP_ERR_INTERNAL;
779 }
780
781
782 ldap_mods_free(mods, 0);
783 return (rc);
784 }
785
786
787 /*
788 * This function takes the p argument just for the beauty of the symmetry
789 * with idmap_ad_set (and for future enhancements).
790 */
791 static
792 idmap_stat
793 /* LINTED E_FUNC_ARG_UNUSED */
idmap_nldap_set(idmap_nm_handle_t * p,ns_cred_t * nsc,char * dn,char * attr,char * value,bool_t is_new,int is_user)794 idmap_nldap_set(idmap_nm_handle_t *p, ns_cred_t *nsc, char *dn, char *attr,
795 char *value, bool_t is_new, int is_user)
796 {
797 int ldaprc;
798 ns_ldap_error_t *errorp = NULL;
799 ns_ldap_attr_t *attrs[2];
800
801
802
803 attrs[0] = (ns_ldap_attr_t *)malloc(sizeof (ns_ldap_attr_t));
804 if (attrs == NULL)
805 return (IDMAP_ERR_MEMORY);
806
807 attrs[0]->attrname = attr;
808
809 if (value != NULL) {
810 char **newattr = (char **)calloc(2, sizeof (char *));
811 if (newattr == NULL) {
812 free(attrs[0]);
813 return (IDMAP_ERR_MEMORY);
814 }
815 newattr[0] = value;
816 newattr[1] = NULL;
817
818 attrs[0]->attrvalue = newattr;
819 attrs[0]->value_count = 1;
820 } else {
821 attrs[0]->attrvalue = NULL;
822 attrs[0]->value_count = 0;
823 }
824
825
826 attrs[1] = NULL;
827
828 if (value == NULL) {
829 ldaprc = __ns_ldap_delAttr(
830 is_user == IDMAP_YES ? "passwd": "group",
831 dn, (const ns_ldap_attr_t * const *)attrs,
832 nsc, 0, &errorp);
833 } else if (is_new)
834 ldaprc = __ns_ldap_addAttr(
835 is_user == IDMAP_YES ? "passwd": "group",
836 dn, (const ns_ldap_attr_t * const *)attrs,
837 nsc, 0, &errorp);
838 else
839 ldaprc = __ns_ldap_repAttr(
840 is_user == IDMAP_YES ? "passwd": "group",
841 dn, (const ns_ldap_attr_t * const *)attrs,
842 nsc, 0, &errorp);
843
844 if (ldaprc != NS_LDAP_SUCCESS) {
845 char *msg = "Cause unidentified";
846 if (errorp != NULL) {
847 (void) __ns_ldap_err2str(errorp->status, &msg);
848 }
849 namemap_log(
850 gettext("__ns_ldap_addAttr/rep/delAttr failed (%s)"),
851 msg);
852 return (IDMAP_ERR_ARG);
853 }
854
855 return (IDMAP_SUCCESS);
856 }
857
858 idmap_stat
idmap_set_namemap(idmap_nm_handle_t * p,char * winname,char * unixname,int is_user,int is_wuser,int direction)859 idmap_set_namemap(idmap_nm_handle_t *p, char *winname, char *unixname,
860 int is_user, int is_wuser, int direction)
861 {
862 idmap_stat rc = IDMAP_SUCCESS;
863 char *dn = NULL;
864 char *oldwinname = NULL;
865 char *oldwindomain = NULL;
866
867 if (direction == IDMAP_DIRECTION_W2U) {
868 if (!p->is_ad) {
869 rc = IDMAP_ERR_ARG;
870 namemap_log(
871 gettext("AD namemaps aren't set up."));
872 goto cleanup;
873 }
874
875 rc = winname2dn(p, winname, &is_wuser,
876 &dn, NULL, NULL);
877 if (rc != IDMAP_SUCCESS)
878 goto cleanup;
879
880 rc = idmap_ad_set(p, dn, is_user ? p->ad_unixuser_attr :
881 p->ad_unixgroup_attr, unixname);
882 if (rc != IDMAP_SUCCESS)
883 goto cleanup;
884
885 }
886
887
888 if (direction == IDMAP_DIRECTION_U2W) {
889 char *fullname;
890
891 if (!p->is_nldap) {
892 rc = IDMAP_ERR_ARG;
893 namemap_log(
894 gettext("Native ldap namemaps aren't set up."));
895 goto cleanup;
896 }
897
898
899 rc = unixname2dn(p, unixname, is_user, &dn,
900 &oldwinname, &oldwindomain);
901 if (rc != IDMAP_SUCCESS)
902 goto cleanup;
903
904 if (p->windomain == NULL) {
905 fullname = strdup(winname);
906 if (fullname == NULL)
907 rc = IDMAP_ERR_MEMORY;
908 goto cleanup;
909 } else {
910 fullname = malloc(strlen(winname) +
911 strlen(p->windomain) + 2);
912 if (fullname == NULL) {
913 rc = IDMAP_ERR_MEMORY;
914 goto cleanup;
915 }
916
917 (void) snprintf(fullname,
918 strlen(winname) + strlen(p->windomain) + 2,
919 "%s\\%s", p->windomain, winname);
920 }
921 rc = idmap_nldap_set(p, &p->nsc, dn, p->nldap_winname_attr,
922 fullname, oldwinname == NULL ? TRUE : FALSE, is_user);
923
924 free(fullname);
925 free(oldwindomain);
926 free(oldwinname);
927
928 if (rc != IDMAP_SUCCESS)
929 goto cleanup;
930
931 }
932
933 cleanup:
934 if (dn != NULL)
935 free(dn);
936
937 if (oldwindomain != NULL)
938 free(oldwindomain);
939
940 if (oldwinname != NULL)
941 free(oldwinname);
942
943 return (rc);
944
945 }
946
947
948 idmap_stat
idmap_unset_namemap(idmap_nm_handle_t * p,char * winname,char * unixname,int is_user,int is_wuser,int direction)949 idmap_unset_namemap(idmap_nm_handle_t *p, char *winname, char *unixname,
950 int is_user, int is_wuser, int direction)
951 {
952 idmap_stat rc = IDMAP_SUCCESS;
953 char *dn = NULL;
954 char *oldwinname = NULL;
955 char *oldwindomain = NULL;
956
957 if (direction == IDMAP_DIRECTION_W2U) {
958 if (!p->is_ad) {
959 rc = IDMAP_ERR_ARG;
960 namemap_log(
961 gettext("AD namemaps aren't set up."));
962 goto cleanup;
963 }
964
965 rc = winname2dn(p, winname, &is_wuser,
966 &dn, NULL, NULL);
967 if (rc != IDMAP_SUCCESS)
968 goto cleanup;
969
970 rc = idmap_ad_set(p, dn, is_user ? p->ad_unixuser_attr :
971 p->ad_unixgroup_attr, unixname);
972 if (rc != IDMAP_SUCCESS)
973 goto cleanup;
974
975 } else { /* direction == IDMAP_DIRECTION_U2W */
976 if (!p->is_nldap) {
977 rc = IDMAP_ERR_ARG;
978 namemap_log(
979 gettext("Native ldap namemaps aren't set up."));
980 goto cleanup;
981 }
982
983 rc = unixname2dn(p, unixname, is_user, &dn, NULL, NULL);
984 if (rc != IDMAP_SUCCESS)
985 goto cleanup;
986
987 rc = idmap_nldap_set(p, &p->nsc, dn, p->nldap_winname_attr,
988 NULL, TRUE, is_user);
989 if (rc != IDMAP_SUCCESS)
990 goto cleanup;
991
992 }
993
994 cleanup:
995 if (oldwindomain != NULL)
996 free(oldwindomain);
997 if (oldwinname != NULL)
998 free(oldwinname);
999 if (dn != NULL)
1000 free(dn);
1001 return (rc);
1002 }
1003
1004 idmap_stat
idmap_get_namemap(idmap_nm_handle_t * p,int * is_source_ad,char ** winname,char ** windomain,int * is_wuser,char ** unixuser,char ** unixgroup)1005 idmap_get_namemap(idmap_nm_handle_t *p, int *is_source_ad, char **winname,
1006 char **windomain, int *is_wuser, char **unixuser, char **unixgroup)
1007 {
1008 idmap_stat rc = IDMAP_SUCCESS;
1009 char *dn = NULL;
1010
1011 *is_source_ad = IDMAP_UNKNOWN;
1012 if (*winname != NULL) {
1013 *is_source_ad = IDMAP_YES;
1014
1015 if (p->is_ad == NULL) {
1016 rc = IDMAP_ERR_ARG;
1017 namemap_log(
1018 gettext("AD namemaps are not active."));
1019 goto cleanup;
1020 /* In future maybe resolve winname and try nldap? */
1021 }
1022
1023 rc = winname2dn(p, *winname, is_wuser, &dn, unixuser,
1024 unixgroup);
1025 if (rc != IDMAP_SUCCESS) {
1026 namemap_log(
1027 gettext("Winname %s@%s not found in AD."),
1028 *winname, p->windomain);
1029 }
1030 } else if (*unixuser != NULL || *unixgroup != NULL) {
1031 char *unixname;
1032 int is_user;
1033
1034 *is_source_ad = IDMAP_NO;
1035
1036 if (p->is_nldap == NULL) {
1037 rc = IDMAP_ERR_ARG;
1038 namemap_log(
1039 gettext("Native ldap namemaps aren't active."));
1040 goto cleanup;
1041 /* In future maybe resolve unixname and try AD? */
1042 }
1043
1044 if (*unixuser != NULL) {
1045 is_user = IDMAP_YES;
1046 unixname = *unixuser;
1047 } else if (*unixgroup != NULL) {
1048 is_user = IDMAP_NO;
1049 unixname = *unixgroup;
1050 }
1051
1052 rc = unixname2dn(p, unixname, is_user, NULL, winname,
1053 windomain);
1054 if (rc != IDMAP_SUCCESS) {
1055 namemap_log(
1056 gettext("%s %s not found in native ldap."),
1057 is_user == IDMAP_YES ? "UNIX user" : "UNIX group",
1058 unixname);
1059 goto cleanup;
1060 }
1061 } else {
1062 rc = IDMAP_ERR_ARG;
1063 goto cleanup;
1064 }
1065
1066 cleanup:
1067 return (rc);
1068 }
1069