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) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
24 */
25
26 #include <stdio.h>
27 #include <sys/types.h>
28 #include <stdlib.h>
29 #include <libintl.h>
30 #include <ctype.h>
31 #include <syslog.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 #include <unistd.h>
35 #include <string.h>
36 #include <strings.h>
37 #include <priv.h>
38
39 #include "ns_sldap.h"
40 #include "ns_internal.h"
41 #include "ns_cache_door.h"
42 #include "ns_connmgmt.h"
43
3578
3579 /* Return 0 if no more cookies left otherwise 1 */
3580 return ((batch->nactive > 0) ? 1 : 0);
3581 }
3582
3583
3584 /*
3585 * Process all the active cookies in the batch and when none
3586 * remains finalize the batch.
3587 */
3588 int
3589 __ns_ldap_list_batch_end(ns_ldap_list_batch_t *batch)
3590 {
3591 int rc = NS_LDAP_SUCCESS;
3592 while (__ns_ldap_list_batch_process(batch, &rc) > 0)
3593 ;
3594 __ns_ldap_list_batch_release(batch);
3595 return (rc);
3596 }
3597
3598 /*
3599 * find_domainname performs one or more LDAP searches to
3600 * find the value of the nisdomain attribute associated with
3601 * the input DN (with no retry).
3602 */
3603
3604 static int
3605 find_domainname(const char *dn, char **domainname, const ns_cred_t *cred,
3606 ns_ldap_error_t **errorp, ns_conn_user_t *conn_user)
3607 {
3608
3609 ns_ldap_cookie_t *cookie;
3610 ns_ldap_search_desc_t **sdlist;
3611 ns_ldap_search_desc_t *dptr;
3612 int rc;
3613 char **value;
3614 int flags = 0;
3615
3616 *domainname = NULL;
3617 *errorp = NULL;
3618
3619 /* Initialize State machine cookie */
3620 cookie = init_search_state_machine();
3621 if (cookie == NULL) {
3622 return (NS_LDAP_MEMORY);
3623 }
3624 cookie->conn_user = conn_user;
3625
3626 /* see if need to follow referrals */
3627 rc = __s_api_toFollowReferrals(flags,
3628 &cookie->followRef, errorp);
3629 if (rc != NS_LDAP_SUCCESS) {
3630 delete_search_cookie(cookie);
3631 return (rc);
3632 }
3633
3634 /* Create default service Desc */
3635 sdlist = (ns_ldap_search_desc_t **)calloc(2,
3636 sizeof (ns_ldap_search_desc_t *));
3637 if (sdlist == NULL) {
3638 delete_search_cookie(cookie);
3639 cookie = NULL;
3640 return (NS_LDAP_MEMORY);
3641 }
3642 dptr = (ns_ldap_search_desc_t *)
3643 calloc(1, sizeof (ns_ldap_search_desc_t));
3644 if (dptr == NULL) {
3645 free(sdlist);
3646 delete_search_cookie(cookie);
3647 cookie = NULL;
3648 return (NS_LDAP_MEMORY);
3649 }
3650 sdlist[0] = dptr;
3651
3652 /* search base is dn */
3653 dptr->basedn = strdup(dn);
3654
3655 /* search scope is base */
3656 dptr->scope = NS_LDAP_SCOPE_BASE;
3657
3658 /* search filter is "nisdomain=*" */
3659 dptr->filter = strdup(_NIS_FILTER);
3660
3661 cookie->sdlist = sdlist;
3662 cookie->i_filter = strdup(dptr->filter);
3663 cookie->i_attr = nis_domain_attrs;
3664 cookie->i_auth = cred;
3665 cookie->i_flags = 0;
3666
3667 /* Process search */
3668 rc = search_state_machine(cookie, INIT, 0);
3669
3670 /* Copy domain name if found */
3671 rc = cookie->err_rc;
3672 if (rc != NS_LDAP_SUCCESS) {
3673 if (conn_user != NULL && conn_user->ns_error != NULL) {
3674 *errorp = conn_user->ns_error;
3675 conn_user->ns_error = NULL;
3676 } else {
3677 *errorp = cookie->errorp;
3678 }
3679 }
3680 if (cookie->result == NULL)
3681 rc = NS_LDAP_NOTFOUND;
3682 if (rc == NS_LDAP_SUCCESS) {
3683 value = __ns_ldap_getAttr(cookie->result->entry,
3684 _NIS_DOMAIN);
3685 if (value[0])
3686 *domainname = strdup(value[0]);
3687 else
3688 rc = NS_LDAP_NOTFOUND;
3689 }
3690 if (cookie->result != NULL)
3691 (void) __ns_ldap_freeResult(&cookie->result);
3692 cookie->errorp = NULL;
3693 delete_search_cookie(cookie);
3694 cookie = NULL;
3695 return (rc);
3696 }
3697
3698 /*
3699 * __s_api_find_domainname performs one or more LDAP searches to
3700 * find the value of the nisdomain attribute associated with
3701 * the input DN (with retry).
3702 */
3703
3704 static int
3705 __s_api_find_domainname(const char *dn, char **domainname,
3706 const ns_cred_t *cred, ns_ldap_error_t **errorp)
3707 {
3708 ns_conn_user_t *cu = NULL;
3709 int try_cnt = 0;
3710 int rc = NS_LDAP_SUCCESS;
3711
3712 for (;;) {
3713 if (__s_api_setup_retry_search(&cu, NS_CONN_USER_SEARCH,
3714 &try_cnt, &rc, errorp) == 0)
4222 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, strdup(errstr),
4223 NS_LDAP_MEMORY);
4224 return (NS_LDAP_INTERNAL);
4225 }
4226
4227 value = __ns_ldap_getAttr(result->entry, "dn");
4228 *userDN = strdup(value[0]);
4229 (void) __ns_ldap_freeResult(&result);
4230 result = NULL;
4231 return (NS_LDAP_SUCCESS);
4232 }
4233
4234 #define _P_UID "uid"
4235 static const char *dn2uid_attrs[] = {
4236 _P_CN,
4237 _P_UID,
4238 (char *)NULL
4239 };
4240
4241 int
4242 __ns_ldap_dn2uid(const char *dn, char **userID, const ns_cred_t *cred,
4243 ns_ldap_error_t **errorp)
4244 {
4245 ns_ldap_result_t *result = NULL;
4246 char *filter, *userdata;
4247 char errstr[MAXERROR];
4248 char **value;
4249 int rc = 0;
4250 size_t len;
4251
4252 *errorp = NULL;
4253 *userID = NULL;
4254 if ((dn == NULL) || (dn[0] == '\0'))
4255 return (NS_LDAP_INVALID_PARAM);
4256
4257 len = strlen(UIDDNFILTER) + strlen(dn) + 1;
4258 filter = malloc(len);
4259 if (filter == NULL) {
4260 return (NS_LDAP_MEMORY);
4261 }
4262 (void) snprintf(filter, len, UIDDNFILTER, dn);
4263
4264 len = strlen(UIDDNFILTER_SSD) + strlen(dn) + 1;
4265 userdata = malloc(len);
4266 if (userdata == NULL) {
4267 free(filter);
4268 return (NS_LDAP_MEMORY);
4269 }
4270 (void) snprintf(userdata, len, UIDDNFILTER_SSD, dn);
4271
4272 /*
4273 * Unlike uid2dn, we DO want attribute mapping, so that
4274 * "uid" is mapped to/from samAccountName, for example.
4275 */
4276 rc = __ns_ldap_list("passwd", filter,
4277 __s_api_merge_SSD_filter,
4278 dn2uid_attrs, cred, 0,
4279 &result, errorp, NULL,
4280 userdata);
4281 free(filter);
4282 filter = NULL;
4283 free(userdata);
4284 userdata = NULL;
4285 if (rc != NS_LDAP_SUCCESS)
4286 goto out;
4287
4288 if (result->entries_count > 1) {
4289 (void) sprintf(errstr,
4290 gettext("Too many entries are returned for %s"), dn);
4291 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, strdup(errstr),
4292 NS_LDAP_MEMORY);
4293 rc = NS_LDAP_INTERNAL;
4294 goto out;
4295 }
4296
4297 value = __ns_ldap_getAttr(result->entry, _P_UID);
4298 if (value == NULL || value[0] == NULL) {
4299 rc = NS_LDAP_NOTFOUND;
4300 goto out;
4301 }
4302
4303 *userID = strdup(value[0]);
4304 rc = NS_LDAP_SUCCESS;
4305
4306 out:
4307 (void) __ns_ldap_freeResult(&result);
4308 result = NULL;
4309 return (rc);
4310 }
4311
4312 int
4313 __ns_ldap_host2dn(const char *host, const char *domain, char **hostDN,
4314 const ns_cred_t *cred, ns_ldap_error_t **errorp)
4315 {
4316 ns_ldap_result_t *result = NULL;
4317 char *filter, *userdata;
4318 char errstr[MAXERROR];
4319 char **value;
4320 int rc;
4321 size_t len;
4322
4323 /*
4324 * XXX
4325 * the domain parameter needs to be used in case domain is not local,
4326 * if this routine is to support multi domain setups, it needs lots
4327 * of work...
4328 */
|
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) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
24 * Copyright 2020 Joyent, Inc.
25 */
26
27 #include <stdio.h>
28 #include <sys/types.h>
29 #include <stdlib.h>
30 #include <libintl.h>
31 #include <ctype.h>
32 #include <syslog.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <string.h>
37 #include <strings.h>
38 #include <priv.h>
39
40 #include "ns_sldap.h"
41 #include "ns_internal.h"
42 #include "ns_cache_door.h"
43 #include "ns_connmgmt.h"
44
3579
3580 /* Return 0 if no more cookies left otherwise 1 */
3581 return ((batch->nactive > 0) ? 1 : 0);
3582 }
3583
3584
3585 /*
3586 * Process all the active cookies in the batch and when none
3587 * remains finalize the batch.
3588 */
3589 int
3590 __ns_ldap_list_batch_end(ns_ldap_list_batch_t *batch)
3591 {
3592 int rc = NS_LDAP_SUCCESS;
3593 while (__ns_ldap_list_batch_process(batch, &rc) > 0)
3594 ;
3595 __ns_ldap_list_batch_release(batch);
3596 return (rc);
3597 }
3598
3599 typedef struct lookup_data {
3600 const char *lkd_dn;
3601 const char *lkd_service;
3602 const char *lkd_filter;
3603 const ns_cred_t *lkd_cred;
3604 ns_conn_user_t *lkd_user;
3605 } lookup_data_t;
3606
3607 /*
3608 * This creates a service search descriptor that can be used to
3609 * retrieve a specific DN by using the DN as the basedn with a search
3610 * scope of 'base'. We don't use any service SSDs in this instance since
3611 * they are intended to search specific locations/subtrees and filter the
3612 * results, while here we are wanting to retrieve a specific entry.
3613 */
3614 static int
3615 lookup_create_ssd(lookup_data_t *dn_data, ns_ldap_search_desc_t **descpp)
3616 {
3617 ns_ldap_search_desc_t *dptr;
3618
3619 *descpp = NULL;
3620
3621 dptr = calloc(1, sizeof (ns_ldap_search_desc_t));
3622 if (dptr == NULL)
3623 return (NS_LDAP_MEMORY);
3624
3625 dptr->basedn = strdup(dn_data->lkd_dn);
3626 dptr->scope = NS_LDAP_SCOPE_BASE;
3627 dptr->filter = strdup(UIDFILTER);
3628
3629 if (dptr->basedn == NULL || dptr->filter == NULL) {
3630 __ns_ldap_freeASearchDesc(dptr);
3631 return (NS_LDAP_MEMORY);
3632 }
3633
3634 *descpp = dptr;
3635 return (NS_LDAP_SUCCESS);
3636 }
3637
3638 static int
3639 lookup_dn(lookup_data_t *dn_data, const char **attrs,
3640 ns_ldap_result_t **resultp, ns_ldap_error_t **errorp)
3641 {
3642 ns_ldap_cookie_t *cookie;
3643 int rc = 0;
3644 int flags = 0;
3645
3646 *errorp = NULL;
3647 *resultp = NULL;
3648
3649 if (dn_data == NULL || dn_data->lkd_dn == NULL ||
3650 dn_data->lkd_dn[0] == '\0' || dn_data->lkd_filter == NULL)
3651 return (NS_LDAP_INVALID_PARAM);
3652
3653 cookie = init_search_state_machine();
3654 if (cookie == NULL)
3655 return (NS_LDAP_MEMORY);
3656
3657 rc = __s_api_toFollowReferrals(flags, &cookie->followRef, errorp);
3658 if (rc != NS_LDAP_SUCCESS)
3659 goto out;
3660
3661 /* 1 for SSD, 1 for terminating NULL */
3662 cookie->sdlist = calloc(2, sizeof (ns_ldap_search_desc_t *));
3663 if (cookie->sdlist == NULL) {
3664 rc = NS_LDAP_MEMORY;
3665 goto out;
3666 }
3667
3668 rc = lookup_create_ssd(dn_data, &cookie->sdlist[0]);
3669 if (rc != NS_LDAP_SUCCESS)
3670 goto out;
3671
3672 if (dn_data->lkd_service != NULL) {
3673 /*
3674 * If a service was specified, set that on the cookie so
3675 * that search_state_machine() will properly map
3676 * attributes and objectclasses.
3677 */
3678 cookie->service = strdup(dn_data->lkd_service);
3679 if (cookie->service == NULL) {
3680 rc = NS_LDAP_MEMORY;
3681 goto out;
3682 }
3683 }
3684
3685 cookie->i_attr = attrs;
3686 cookie->i_auth = dn_data->lkd_cred;
3687 cookie->i_flags = 0;
3688 cookie->i_filter = strdup(dn_data->lkd_filter);
3689 if (cookie->i_filter == NULL) {
3690 rc = NS_LDAP_MEMORY;
3691 goto out;
3692 }
3693
3694 /*
3695 * Actually perform the search. The return value is only used when
3696 * iterating through multiple results. Since we are searching with
3697 * a scope of base, we will always get at most one result entry,
3698 * we ignore the return value and look at err_rc to determine if
3699 * there were any errors.
3700 */
3701 (void) search_state_machine(cookie, INIT, 0);
3702 rc = cookie->err_rc;
3703
3704 if (rc != NS_LDAP_SUCCESS) {
3705 ns_conn_user_t *user = dn_data->lkd_user;
3706
3707 if (user != NULL && user->ns_error != NULL) {
3708 *errorp = user->ns_error;
3709 user->ns_error = NULL;
3710 } else {
3711 *errorp = cookie->errorp;
3712 cookie->errorp = NULL;
3713 }
3714 } else if (cookie->result != NULL) {
3715 *resultp = cookie->result;
3716 cookie->result = NULL;
3717 } else {
3718 rc = NS_LDAP_NOTFOUND;
3719 }
3720
3721 out:
3722 delete_search_cookie(cookie);
3723 return (rc);
3724 }
3725
3726 /*
3727 * find_domainname performs one or more LDAP searches to
3728 * find the value of the nisdomain attribute associated with
3729 * the input DN (with no retry).
3730 */
3731
3732 static int
3733 find_domainname(const char *dn, char **domainname, const ns_cred_t *cred,
3734 ns_ldap_error_t **errorp, ns_conn_user_t *conn_user)
3735 {
3736 lookup_data_t ldata;
3737 ns_ldap_result_t *result;
3738 char **value;
3739 int rc;
3740
3741 *domainname = NULL;
3742 *errorp = NULL;
3743
3744 ldata.lkd_dn = dn;
3745 ldata.lkd_service = NULL;
3746 ldata.lkd_filter = _NIS_FILTER;
3747 ldata.lkd_cred = cred;
3748 ldata.lkd_user = conn_user;
3749
3750 rc = lookup_dn(&ldata, nis_domain_attrs, &result, errorp);
3751 if (rc != NS_LDAP_SUCCESS)
3752 return (rc);
3753
3754 value = __ns_ldap_getAttr(result->entry, _NIS_DOMAIN);
3755
3756 if (value != NULL && value[0] != NULL) {
3757 *domainname = strdup(value[0]);
3758 if (*domainname == NULL)
3759 rc = NS_LDAP_MEMORY;
3760 } else {
3761 rc = NS_LDAP_NOTFOUND;
3762 }
3763
3764 (void) __ns_ldap_freeResult(&result);
3765 return (rc);
3766 }
3767
3768 /*
3769 * __s_api_find_domainname performs one or more LDAP searches to
3770 * find the value of the nisdomain attribute associated with
3771 * the input DN (with retry).
3772 */
3773
3774 static int
3775 __s_api_find_domainname(const char *dn, char **domainname,
3776 const ns_cred_t *cred, ns_ldap_error_t **errorp)
3777 {
3778 ns_conn_user_t *cu = NULL;
3779 int try_cnt = 0;
3780 int rc = NS_LDAP_SUCCESS;
3781
3782 for (;;) {
3783 if (__s_api_setup_retry_search(&cu, NS_CONN_USER_SEARCH,
3784 &try_cnt, &rc, errorp) == 0)
4292 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, strdup(errstr),
4293 NS_LDAP_MEMORY);
4294 return (NS_LDAP_INTERNAL);
4295 }
4296
4297 value = __ns_ldap_getAttr(result->entry, "dn");
4298 *userDN = strdup(value[0]);
4299 (void) __ns_ldap_freeResult(&result);
4300 result = NULL;
4301 return (NS_LDAP_SUCCESS);
4302 }
4303
4304 #define _P_UID "uid"
4305 static const char *dn2uid_attrs[] = {
4306 _P_CN,
4307 _P_UID,
4308 (char *)NULL
4309 };
4310
4311 int
4312 __ns_ldap_dn2uid(const char *dn, char **userIDp, const ns_cred_t *cred,
4313 ns_ldap_error_t **errorp)
4314 {
4315 lookup_data_t ldata;
4316 ns_ldap_result_t *result;
4317 char **value;
4318 int rc;
4319
4320 *errorp = NULL;
4321 *userIDp = NULL;
4322 if ((dn == NULL) || (dn[0] == '\0'))
4323 return (NS_LDAP_INVALID_PARAM);
4324
4325 /*
4326 * Many LDAP servers do not support using the dn in a search
4327 * filter. As a result, we unfortunately cannot use __ns_ldap_list()
4328 * to lookup the DN. Instead we perform a search with the baseDN
4329 * being the DN we are looking for with a scope of 'base' to
4330 * return the entry, as this should be supported by all LDAP servers.
4331 */
4332 ldata.lkd_dn = dn;
4333
4334 /*
4335 * Since we are looking up a user account by its DN, use the attribute
4336 * and objectclass mappings (if present) for the passwd service.
4337 */
4338 ldata.lkd_service = "passwd";
4339 ldata.lkd_filter = UIDDNFILTER;
4340 ldata.lkd_cred = cred;
4341 ldata.lkd_user = NULL;
4342
4343 rc = lookup_dn(&ldata, dn2uid_attrs, &result, errorp);
4344 if (rc != NS_LDAP_SUCCESS)
4345 return (rc);
4346
4347 value = __ns_ldap_getAttr(result->entry, _P_UID);
4348 if (value != NULL && value[0] != NULL) {
4349 *userIDp = strdup(value[0]);
4350 if (*userIDp == NULL)
4351 rc = NS_LDAP_MEMORY;
4352 } else {
4353 rc = NS_LDAP_NOTFOUND;
4354 }
4355
4356 (void) __ns_ldap_freeResult(&result);
4357 return (rc);
4358 }
4359
4360 int
4361 __ns_ldap_host2dn(const char *host, const char *domain, char **hostDN,
4362 const ns_cred_t *cred, ns_ldap_error_t **errorp)
4363 {
4364 ns_ldap_result_t *result = NULL;
4365 char *filter, *userdata;
4366 char errstr[MAXERROR];
4367 char **value;
4368 int rc;
4369 size_t len;
4370
4371 /*
4372 * XXX
4373 * the domain parameter needs to be used in case domain is not local,
4374 * if this routine is to support multi domain setups, it needs lots
4375 * of work...
4376 */
|