UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2013 Olaf Wintermann. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #ifdef __gnu_linux__ 30 #define _GNU_SOURCE 31 #endif 32 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <sys/time.h> 37 38 #include <cx/utils.h> 39 #include <cx/hash_map.h> 40 #include <cx/printf.h> 41 42 #include "../util/util.h" 43 44 #include "ldap_auth.h" 45 #include "ldap_resource.h" 46 47 static cxstring ws_ldap_default_uid_attr[] = { 48 CX_STR("uid") 49 }; 50 51 static cxstring ws_ldap_default_member_attr[] = { 52 CX_STR("member"), 53 CX_STR("uniqueMember") 54 }; 55 56 static LDAPConfig ws_ldap_default_config = { 57 NULL, // resource 58 NULL, // basedn 59 NULL, // binddn 60 NULL, // bindpw 61 "(&(objectclass=inetorgperson)(|(cn=%s)(uid=%s)))", // userSearchFilter 62 ws_ldap_default_uid_attr, // uidAttributes 63 1, // numUidAttributes 64 "(&(|(objectclass=groupOfNames)(objectclass=groupOfUniqueNames))(cn=%s))", // groupSearchFilter 65 ws_ldap_default_member_attr, // memberAttributes 66 2, // numMemberAttributes 67 WS_LDAP_GROUP_MEMBER_DN, // groupMemberType 68 TRUE, // enableGroups 69 FALSE // userNameIsDN 70 }; 71 72 // TODO: AD 73 static cxstring ws_ad_default_uid_attr[] = { 74 CX_STR("uid") 75 }; 76 77 static cxstring ws_ad_default_member_attr[] = { 78 CX_STR("member"), 79 CX_STR("uniqueMember") 80 }; 81 82 static LDAPConfig ws_ldap_ad_config = { 83 NULL, // resource 84 NULL, // basedn 85 NULL, // binddn 86 NULL, // bindpw 87 "(&(objectclass=inetorgperson)(|(cn=%s)(uid=%s)))", // userSearchFilter 88 ws_ad_default_uid_attr, // uidAttributes 89 1, // numUidAttributes 90 "", // groupSearchFilter 91 ws_ad_default_member_attr, // memberAttributes 92 2, // numMemberAttributes 93 WS_LDAP_GROUP_MEMBER_DN, // groupMemberType 94 TRUE, // enableGroups 95 FALSE // userNameIsDN 96 }; 97 98 static cxstring ws_posix_default_uid_attr[] = { 99 CX_STR("uid") 100 }; 101 102 static cxstring ws_posix_default_member_attr[] = { 103 CX_STR("memberUid") 104 }; 105 106 static LDAPConfig ws_ldap_posix_config = { 107 NULL, // resource 108 NULL, // basedn 109 NULL, // binddn 110 NULL, // bindpw 111 "(&(objectclass=posixAccount)(uid=%s))", // userSearchFilter 112 ws_posix_default_uid_attr, // uidAttributes 113 1, // numUidAttributes 114 "(&(objectclass=posixGroup)(cn=%s))", // groupSearchFilter 115 ws_posix_default_member_attr, // memberAttributes 116 1, // numMemberAttributes 117 WS_LDAP_GROUP_MEMBER_UID, // groupMemberType 118 TRUE, // enableGroups 119 FALSE // userNameIsDN 120 }; 121 122 AuthDB* create_ldap_authdb(ServerConfiguration *cfg, const char *name, ConfigNode *node) { 123 LDAPAuthDB *authdb = cxMalloc(cfg->a, sizeof(LDAPAuthDB)); 124 if(!authdb) { 125 return NULL; 126 } 127 authdb->authdb.name = pool_strdup(cfg->pool, name); 128 if(!authdb->authdb.name) { 129 return NULL; 130 } 131 authdb->authdb.get_user = ldap_get_user; 132 authdb->authdb.use_cache = 0; // TODO: enable caching when cache actually works 133 134 // initialize default ldap config 135 cxstring dirtype = serverconfig_object_directive_value(node, cx_str("DirectoryType")); 136 LDAPConfig *default_config; 137 if(!dirtype.ptr) { 138 default_config = &ws_ldap_default_config; 139 } else if(!cx_strcmp(dirtype, cx_str("ldap"))) { 140 default_config = &ws_ldap_default_config; 141 } else if(!cx_strcmp(dirtype, cx_str("posix"))) { 142 default_config = &ws_ldap_posix_config; 143 } else if(!cx_strcmp(dirtype, cx_str("ad"))) { 144 default_config = &ws_ldap_ad_config; 145 } else { 146 log_ereport(LOG_FAILURE, "cannot create ldap authdb %s: unknown directory type %s", name, dirtype.ptr); 147 } 148 memcpy(&authdb->config, default_config, sizeof(LDAPConfig)); 149 150 // custom config 151 cxstring resource = serverconfig_object_directive_value(node, cx_str("Resource")); 152 cxstring basedn = serverconfig_object_directive_value(node, cx_str("Basedn")); 153 cxstring binddn = serverconfig_object_directive_value(node, cx_str("Binddn")); 154 cxstring bindpw = serverconfig_object_directive_value(node, cx_str("Bindpw")); 155 cxstring userSearchFilter = serverconfig_object_directive_value(node, cx_str("UserSearchFilter")); 156 cxstring uidAttributes = serverconfig_object_directive_value(node, cx_str("UidAttributes")); 157 cxstring groupSearchFilter = serverconfig_object_directive_value(node, cx_str("GroupSearchFilter")); 158 cxstring memberAttributes = serverconfig_object_directive_value(node, cx_str("MemberAttributes")); 159 cxstring memberType = serverconfig_object_directive_value(node, cx_str("MemberType")); 160 cxstring enableGroups = serverconfig_object_directive_value(node, cx_str("EnableGroups")); 161 cxstring userNameIsDn = serverconfig_object_directive_value(node, cx_str("UserNameIsDn")); 162 163 if(!resource.ptr) { 164 // implicitly create a resource pool for this authdb 165 cxmutstr respool_name = cx_asprintf_a(cfg->a, "_authdb_%s", name); 166 if(!respool_name.ptr) { 167 return NULL; 168 } 169 log_ereport( 170 LOG_INFORM, 171 "ldap authdb %s: no resource specified: create resource pool %s", 172 name, 173 respool_name.ptr); 174 if(resourcepool_new(cfg, cx_str("ldap"), cx_strcast(respool_name), node)) { 175 log_ereport( 176 LOG_FAILURE, 177 "ldap authdb %s: cannot create ldap resource pool", 178 name); 179 return NULL; 180 } 181 authdb->config.resource = respool_name.ptr; 182 } else { 183 authdb->config.resource = cx_strdup_a(cfg->a, resource).ptr; 184 if(!authdb->config.resource) return NULL; 185 } 186 187 if(!basedn.ptr) { 188 log_ereport(LOG_FAILURE, "ldap authdb %s: basedn is required", name); 189 return NULL; 190 } 191 authdb->config.basedn = cx_strdup_a(cfg->a, basedn).ptr; 192 if(!authdb->config.basedn) return NULL; 193 194 // optional config 195 if(binddn.ptr) { 196 if(!bindpw.ptr) { 197 log_ereport(LOG_FAILURE, "ldap authdb %s: binddn specified, but no bindpw", name); 198 return NULL; 199 } 200 201 authdb->config.binddn = cx_strdup_a(cfg->a, binddn).ptr; 202 authdb->config.bindpw = cx_strdup_a(cfg->a, bindpw).ptr; 203 204 if(!authdb->config.binddn || !authdb->config.bindpw) { 205 return NULL; 206 } 207 } 208 209 210 if(userSearchFilter.ptr) { 211 authdb->config.userSearchFilter = cx_strdup_a(cfg->a, userSearchFilter).ptr; 212 } 213 if(uidAttributes.ptr) { 214 cxmutstr uidAttributesCopy = cx_strdup_a(cfg->a, uidAttributes); 215 if(uidAttributesCopy.ptr) { 216 authdb->config.numUidAttributes = cx_strsplit_a( 217 cfg->a, 218 cx_strcast(uidAttributesCopy), 219 cx_str(","), 220 1024, 221 &authdb->config.uidAttributes); 222 } 223 } 224 if(groupSearchFilter.ptr) { 225 authdb->config.groupSearchFilter = groupSearchFilter.ptr; 226 } 227 if(memberAttributes.ptr) { 228 cxmutstr memberAttributesCopy = cx_strdup_a(cfg->a, memberAttributes); 229 if(memberAttributesCopy.ptr) { 230 authdb->config.numMemberAttributes = cx_strsplit_a( 231 cfg->a, 232 cx_strcast(memberAttributesCopy), 233 cx_str(","), 234 1024, 235 &authdb->config.memberAttributes); 236 } 237 } 238 if(memberType.ptr) { 239 if(!cx_strcmp(memberType, cx_str("dn"))) { 240 authdb->config.groupMemberType = WS_LDAP_GROUP_MEMBER_DN; 241 } else if(!cx_strcmp(memberType, cx_str("uid"))) { 242 authdb->config.groupMemberType = WS_LDAP_GROUP_MEMBER_UID; 243 } else { 244 log_ereport(LOG_FAILURE, "ldap authdb %s: unknown MemberType %s", name, memberType.ptr); 245 return NULL; 246 } 247 } 248 if(enableGroups.ptr) { 249 authdb->config.enableGroups = util_getboolean_s(enableGroups, FALSE); 250 } 251 if(userNameIsDn.ptr) { 252 authdb->config.userNameIsDN = util_getboolean_s(userNameIsDn, FALSE); 253 } 254 255 256 // initialize group cache 257 authdb->groups.first = NULL; 258 authdb->groups.last = NULL; 259 authdb->groups.map = cxHashMapCreate(cfg->a, CX_STORE_POINTERS, 32); 260 if(!authdb->groups.map) { 261 return NULL; 262 } 263 264 log_ereport(LOG_INFORM, "create authdb name=%s type=ldap resource=%s", name, resource.ptr); 265 266 return (AuthDB*) authdb; 267 } 268 269 LDAP* get_ldap_session(Session *sn, Request *rq, LDAPAuthDB *authdb) { 270 ResourceData *res = resourcepool_lookup(sn, rq, authdb->config.resource, 0); 271 if(!res) { 272 log_ereport(LOG_FAILURE, "AuthDB %s: cannot get resource %s", authdb->authdb.name, authdb->config.resource); 273 return NULL; 274 } 275 276 LDAP *ldap = res->data; 277 278 if(authdb->config.binddn) { 279 struct berval *server_cred; 280 int r = ws_ldap_bind(ldap, authdb->config.binddn, authdb->config.bindpw, &server_cred); 281 if(r != LDAP_SUCCESS) { 282 log_ereport(LOG_FAILURE, "AuthDB %s: bind to %s failed: %s", authdb->config.binddn, ldap_err2string(r)); 283 resourcepool_free(sn, rq, res); 284 return NULL; 285 } 286 } 287 288 return ldap; 289 } 290 291 static LDAPUser* ldap_msg_to_user( 292 Session *sn, 293 Request *rq, 294 LDAPAuthDB *authdb, 295 LDAP *ldap, 296 LDAPMessage *msg) 297 { 298 CxAllocator *a = pool_allocator(sn->pool); 299 300 LDAPUser *user = pool_malloc(sn->pool, sizeof(LDAPUser)); 301 if(!user) { 302 return NULL; 303 } 304 305 // get dn 306 char *ldap_dn = ldap_get_dn(ldap, msg); 307 if(!ldap_dn) { 308 return NULL; 309 } 310 char *dn = pool_strdup(sn->pool, ldap_dn); 311 ldap_memfree(ldap_dn); 312 if(!dn) { 313 return NULL; 314 } 315 316 // get uid 317 char *uid = NULL; 318 319 // values of configured UidAttributes 320 size_t numUidAttributes = authdb->config.numUidAttributes; 321 cxmutstr *uid_values = pool_calloc(sn->pool, authdb->config.numUidAttributes, sizeof(cxmutstr)); 322 if(!uid_values) { 323 return NULL; 324 } 325 326 327 BerElement *ber = NULL; 328 char *attribute = ldap_first_attribute(ldap, msg, &ber); 329 while(attribute) { 330 cxstring attr = cx_str(attribute); 331 for(int i=0;i<numUidAttributes;i++) { 332 // check if the attribute is one of the uid attributes 333 if(!uid_values[i].ptr && !cx_strcmp(attr, authdb->config.uidAttributes[i])) { 334 // copy value to uid_values 335 struct berval **values = ldap_get_values_len(ldap, msg, attribute); 336 if(values) { 337 int count = ldap_count_values_len(values); 338 if(count > 0) { 339 cxstring attr_val = cx_strn(values[0]->bv_val, values[0]->bv_len); 340 uid_values[i] = cx_strdup_a(a, attr_val); 341 } else { 342 log_ereport(LOG_FAILURE, "ldap user: dn: %s attribute %s: no values", dn, attribute); 343 } 344 ldap_value_free_len(values); 345 } 346 } 347 } 348 349 if(uid_values[0].ptr) { 350 // if we found a value for the first attribute, we can use that 351 break; 352 } 353 354 ldap_memfree(attribute); 355 attribute = ldap_next_attribute(ldap, msg, ber); 356 } 357 if(ber) { 358 ber_free(ber, 0); 359 } 360 361 362 363 // use first value as uid 364 for(int i=0;i<numUidAttributes;i++) { 365 if(uid_values[i].ptr) { 366 if(!uid) { 367 uid = uid_values[i].ptr; 368 } else { 369 cxFree(a, uid_values[i].ptr); 370 } 371 } 372 } 373 pool_free(sn->pool, uid_values); 374 375 // get user name 376 char *username; 377 if(authdb->config.userNameIsDN) { 378 username = dn; 379 } else { 380 username = uid; 381 } 382 383 if(!username) { 384 return NULL; 385 } 386 387 user->authdb = authdb; 388 user->user.verify_password = ldap_user_verify_password; 389 user->user.check_group = ldap_user_check_group; 390 user->user.free = ldap_user_free; 391 user->user.name = username; 392 user->sn = sn; 393 user->rq = rq; 394 395 // TODO: get uid/gid from ldap 396 user->user.uid = -1; 397 user->user.gid = -1; 398 399 user->ldap = ldap; 400 user->userdn = dn; 401 user->uid_attr = uid; 402 403 return user; 404 } 405 406 User* ldap_get_user(AuthDB *db, Session *sn, Request *rq, const char *username) { 407 LDAPAuthDB *authdb = (LDAPAuthDB*) db; 408 LDAPConfig *config = &authdb->config; 409 CxAllocator *a = pool_allocator(sn->pool); 410 411 LDAP *ld = get_ldap_session(sn, rq, authdb); 412 if (ld == NULL) { 413 return NULL; 414 } 415 416 // get the user dn 417 cxstring userSearch = cx_str(config->userSearchFilter); 418 cxmutstr filter = cx_strreplace_a(a, userSearch, cx_str("%s"), cx_str(username)); 419 if(!filter.ptr) { 420 return NULL; 421 } 422 423 log_ereport(LOG_DEBUG, "ldap_get_user: filter: %s", filter.ptr); 424 425 LDAPMessage *result; 426 struct timeval timeout; 427 timeout.tv_sec = 8; // TODO: add config parameter for timeout 428 timeout.tv_usec = 0; 429 int r = ldap_search_ext_s( 430 ld, 431 config->basedn, 432 LDAP_SCOPE_SUBTREE, 433 filter.ptr, 434 NULL, 435 0, 436 NULL, // server controls 437 NULL, // client controls 438 &timeout, 439 2, // size limit 440 &result); 441 cxFree(a, filter.ptr); 442 if(r != LDAP_SUCCESS) { 443 if(result) { 444 ldap_msgfree(result); 445 } 446 log_ereport(LOG_FAILURE, "ldap_get_user: search failed: %s", ldap_err2string(r)); 447 return NULL; 448 } 449 if(!result) { 450 // not sure if this can happen 451 log_ereport(LOG_FAILURE, "ldap_get_user: search failed: no result"); 452 return NULL; 453 } 454 455 LDAPMessage *msg = ldap_first_entry(ld, result); 456 LDAPUser *user = NULL; 457 if(msg) { 458 if(ldap_count_entries(ld, msg) > 1) { 459 log_ereport(LOG_FAILURE, "ldap_get_user: more than one search result"); 460 } else { 461 user = ldap_msg_to_user(sn, rq, authdb, ld, msg); 462 } 463 } 464 ldap_msgfree(result); 465 466 return (User*)user; 467 } 468 469 470 static int is_member_attribute(LDAPAuthDB *auth, const char *attribute) { 471 LDAPConfig *config = &auth->config; 472 cxstring attr = cx_str(attribute); 473 for(int i=0;i<config->numMemberAttributes;i++) { 474 if(!cx_strcmp(config->memberAttributes[i], attr)) { 475 return 1; 476 } 477 } 478 return 0; 479 } 480 481 static int group_add_member(LDAPGroup *group, LDAP *ldap, LDAPMessage *msg, char *attribute) { 482 struct berval **values = ldap_get_values_len(ldap, msg, attribute); 483 int ret = 0; 484 if(values) { 485 int count = ldap_count_values_len(values); 486 for(int i=0;i<count;i++) { 487 cxstring memberValue = cx_strn(values[i]->bv_val, values[i]->bv_len); 488 CxHashKey key = cx_hash_key(memberValue.ptr, memberValue.length); 489 char *g_member = cxMapGet(group->members, key); 490 if(!g_member) { 491 cxmutstr member = cx_strdup_a(group->members->allocator, memberValue); 492 if(!member.ptr) { 493 ret = 1; 494 break; 495 } 496 if(cxMapPut(group->members, key, member.ptr)) { 497 ret = 1; 498 break; 499 } 500 } 501 } 502 ldap_value_free_len(values); 503 } 504 return ret; 505 } 506 507 static LDAPGroup* ldap_msg_to_group( 508 Session *sn, 509 Request *rq, 510 LDAPAuthDB *authdb, 511 LDAP *ldap, 512 LDAPMessage *msg, 513 const char *group_name) 514 { 515 CxAllocator *a = pool_allocator(sn->pool); 516 517 LDAPGroup *group = pool_malloc(sn->pool, sizeof(LDAPGroup)); 518 if(!group) { 519 return NULL; 520 } 521 group->members = cxHashMapCreate(a, CX_STORE_POINTERS, 32); 522 if(!group->members) { 523 pool_free(sn->pool, group); 524 return NULL; 525 } 526 group->name = pool_strdup(sn->pool, group_name); 527 528 BerElement *ber = NULL; 529 char *attribute = ldap_first_attribute(ldap, msg, &ber); 530 while(attribute) { 531 if(is_member_attribute(authdb, attribute)) { 532 if(group_add_member(group, ldap, msg, attribute)) { 533 // OOM 534 ldap_memfree(attribute); 535 // free at least some memory 536 cxMapDestroy(group->members); 537 pool_free(sn->pool, group); 538 group = NULL; 539 break; 540 } 541 } 542 543 ldap_memfree(attribute); 544 attribute = ldap_next_attribute(ldap, msg, ber); 545 } 546 if(ber) { 547 ber_free(ber, 0); 548 } 549 550 return group; 551 } 552 553 LDAPGroup* ldap_get_group(Session *sn, Request *rq, LDAPAuthDB *authdb, const char *group) { 554 LDAPConfig *config = &authdb->config; 555 CxAllocator *a = pool_allocator(sn->pool); 556 557 LDAP *ld = get_ldap_session(sn, rq, authdb); 558 if (ld == NULL) { 559 return NULL; 560 } 561 562 // if userNameIsDN is true, group will be the full group dn and we 563 // don't need to search with a filter, to get the entry 564 char *filterStr; 565 const char *basedn; 566 int scope; 567 if(config->userNameIsDN) { 568 filterStr = NULL; 569 basedn = group; 570 scope = LDAP_SCOPE_BASE; 571 } else { 572 cxstring groupSearch = cx_str(config->groupSearchFilter); 573 cxmutstr filter = cx_strreplace_a(a, groupSearch, cx_str("%s"), cx_str(group)); 574 if(!filter.ptr) { 575 return NULL; 576 } 577 filterStr = filter.ptr; 578 basedn = config->basedn; 579 scope = LDAP_SCOPE_SUBTREE; 580 } 581 582 log_ereport(LOG_DEBUG, "ldap_get_group: basedn: %s filter: %s", basedn, filterStr); 583 584 LDAPMessage *result; 585 struct timeval timeout; 586 timeout.tv_sec = 8; 587 timeout.tv_usec = 0; 588 int r = ldap_search_ext_s( 589 ld, 590 basedn, 591 scope, 592 filterStr, 593 NULL, 594 0, 595 NULL, // server controls 596 NULL, // client controls 597 &timeout, 598 2, // size limit 599 &result); 600 if(filterStr) { 601 cxFree(a, filterStr); 602 } 603 604 if (r != LDAP_SUCCESS) { 605 if(result) { 606 ldap_msgfree(result); 607 } 608 log_ereport(LOG_FAILURE, "ldap_get_group %s: search failed: %s", group, ldap_err2string(r)); 609 return NULL; 610 } 611 612 LDAPMessage *msg = ldap_first_entry(ld, result); 613 LDAPGroup *wsgroup = NULL; 614 if(msg) { 615 if(ldap_count_entries(ld, msg) > 1) { 616 log_ereport(LOG_FAILURE, "ldap_get_user: more than one search result"); 617 } else { 618 wsgroup = ldap_msg_to_group(sn, rq, authdb, ld, msg, group); 619 } 620 } 621 ldap_msgfree(result); 622 623 return wsgroup; 624 } 625 626 int ldap_user_verify_password(User *u, const char *password) { 627 LDAPUser *user = (LDAPUser*)u; 628 629 struct berval cred; 630 cred.bv_val = (char*)password; 631 cred.bv_len = strlen(password); 632 struct berval *server_cred; 633 int r = ldap_sasl_bind_s( 634 user->ldap, 635 user->userdn, 636 LDAP_SASL_SIMPLE, 637 &cred, 638 NULL, 639 NULL, 640 &server_cred); 641 if(r == LDAP_SUCCESS) { 642 log_ereport(LOG_VERBOSE, "ldap user %s password ok", user->userdn); 643 return 1; 644 } else { 645 log_ereport(LOG_VERBOSE, "ldap user %s password not ok", user->userdn); 646 return 0; 647 } 648 } 649 650 int ldap_user_check_group(User *u, const char *group_str) { 651 LDAPUser *user = (LDAPUser*)u; 652 LDAPAuthDB *authdb = user->authdb; 653 if(!authdb->config.enableGroups) { 654 log_ereport( 655 LOG_DEBUG, 656 "ldap_user_check_group: authdb %s: groups disabled", 657 authdb->authdb.name); 658 return 0; 659 } 660 661 int ret = 0; 662 LDAPGroup *group = ldap_get_group(user->sn, user->rq, authdb, group_str); 663 if(group) { 664 const char *usr = authdb->config.groupMemberType == WS_LDAP_GROUP_MEMBER_DN ? user->userdn : user->uid_attr; 665 char *member = cxMapGet(group->members, cx_hash_key_str(usr)); 666 if(member) { 667 ret = 1; 668 } 669 } 670 671 return ret; 672 } 673 674 void ldap_user_free(User *u) { 675 LDAPUser *user = (LDAPUser*)u; 676 pool_free(user->sn->pool, user->userdn); 677 pool_free(user->sn->pool, user->uid_attr); 678 pool_free(user->sn->pool, user); 679 } 680