📄 rlm_ldap.c
字号:
att_map[1] = 1; } else if (inst->access_attr && !att_map[2]){ inst->atts[i] = inst->access_attr; att_map[2] = 1; } } } inst->atts[atts_num] = NULL; DEBUG("conns: %p",inst->conns); *instance = inst; return 0;}/* * read_mappings(...) reads a ldap<->radius mappings file to inst->reply_item_map and inst->check_item_map */#define MAX_LINE_LEN 160#define GENERIC_ATTRIBUTE_ID "$GENERIC$"static intread_mappings(ldap_instance* inst){ FILE* mapfile; char *filename; /* all buffers are of MAX_LINE_LEN so we can use sscanf without being afraid of buffer overflows */ char buf[MAX_LINE_LEN], itemType[MAX_LINE_LEN], radiusAttribute[MAX_LINE_LEN], ldapAttribute[MAX_LINE_LEN]; int linenumber; /* open the mappings file for reading */ filename = inst->dictionary_mapping; DEBUG("rlm_ldap: reading ldap<->radius mappings from file %s", filename); mapfile = fopen(filename, "r"); if (mapfile == NULL) { radlog(L_ERR, "rlm_ldap: Opening file %s failed", filename); return -1; /* error */ } /* read file line by line. Note that if line length exceed MAX_LINE_LEN, line numbers will be mixed up */ linenumber = 0; while (fgets(buf, sizeof buf, mapfile)!=NULL) { char* ptr; int token_count; TLDAP_RADIUS* pair; linenumber++; /* strip comments */ ptr = strchr(buf, '#'); if (ptr) *ptr = 0; /* empty line */ if (buf[0] == 0) continue; /* extract tokens from the string */ token_count = sscanf(buf, "%s %s %s", itemType, radiusAttribute, ldapAttribute); if (token_count <= 0) /* no tokens */ continue; if (token_count != 3) { radlog(L_ERR, "rlm_ldap: Skipping %s line %i: %s", filename, linenumber, buf); radlog(L_ERR, "rlm_ldap: Expected 3 tokens " "(Item type, RADIUS Attribute and LDAP Attribute) but found only %i", token_count); continue; } /* create new TLDAP_RADIUS list node */ pair = rad_malloc(sizeof(TLDAP_RADIUS)); pair->attr = strdup(ldapAttribute); pair->radius_attr = strdup(radiusAttribute); if ( (pair->attr == NULL) || (pair->radius_attr == NULL) ) { radlog(L_ERR, "rlm_ldap: Out of memory"); if (pair->attr) free(pair->attr); if (pair->radius_attr) free(pair->radius_attr); free(pair); fclose(mapfile); return -1; } /* push node to correct list */ if (strcasecmp(itemType, "checkItem") == 0) { pair->next = inst->check_item_map; inst->check_item_map = pair; } else if (strcasecmp(itemType, "replyItem") == 0) { pair->next = inst->reply_item_map; inst->reply_item_map = pair; } else { radlog(L_ERR, "rlm_ldap: file %s: skipping line %i: unknown itemType %s", filename, linenumber, itemType); free(pair->attr); free(pair->radius_attr); free(pair); continue; } DEBUG("rlm_ldap: LDAP %s mapped to RADIUS %s", pair->attr, pair->radius_attr); } fclose(mapfile); return 0; /* success */}static int perform_search(void *instance, LDAP_CONN *conn, char *search_basedn, int scope, char *filter, char **attrs, LDAPMessage ** result){ int res = RLM_MODULE_OK; int ldap_errno = 0; ldap_instance *inst = instance; int search_retry = 0; *result = NULL; if (!conn){ radlog(L_ERR, "rlm_ldap: NULL connection handle passed"); return RLM_MODULE_FAIL; } if (conn->failed_conns > MAX_FAILED_CONNS_START){ conn->failed_conns++; if (conn->failed_conns >= MAX_FAILED_CONNS_END){ conn->failed_conns = MAX_FAILED_CONNS_RESTART; conn->bound = 0; } }retry: if (!conn->bound || conn->ld == NULL) { DEBUG2("rlm_ldap: attempting LDAP reconnection"); if (conn->ld){ DEBUG2("rlm_ldap: closing existing LDAP connection"); ldap_unbind_s(conn->ld); } if ((conn->ld = ldap_connect(instance, inst->login, inst->password, 0, &res)) == NULL) { radlog(L_ERR, "rlm_ldap: (re)connection attempt failed"); if (search_retry == 0) conn->failed_conns++; return (RLM_MODULE_FAIL); } conn->bound = 1; conn->failed_conns = 0; } DEBUG2("rlm_ldap: performing search in %s, with filter %s", search_basedn ? search_basedn : "(null)" , filter); switch (ldap_search_st(conn->ld, search_basedn, scope, filter, attrs, 0, &(inst->timeout), result)) { case LDAP_SUCCESS: case LDAP_NO_SUCH_OBJECT: break; case LDAP_SERVER_DOWN: radlog(L_ERR, "rlm_ldap: ldap_search() failed: LDAP connection lost."); conn->failed_conns++; if (search_retry == 0){ if (conn->failed_conns <= MAX_FAILED_CONNS_START){ radlog(L_INFO, "rlm_ldap: Attempting reconnect"); search_retry = 1; conn->bound = 0; ldap_msgfree(*result); goto retry; } } ldap_msgfree(*result); return RLM_MODULE_FAIL; case LDAP_INSUFFICIENT_ACCESS: radlog(L_ERR, "rlm_ldap: ldap_search() failed: Insufficient access. Check the identity and password configuration directives."); ldap_msgfree(*result); return RLM_MODULE_FAIL; case LDAP_TIMEOUT: radlog(L_ERR, "rlm_ldap: ldap_search() failed: Timed out while waiting for server to respond. Please increase the timeout."); ldap_msgfree(*result); return RLM_MODULE_FAIL; case LDAP_TIMELIMIT_EXCEEDED: case LDAP_BUSY: case LDAP_UNAVAILABLE: /* We don't need to reconnect in these cases so we don't set conn->bound */ ldap_get_option(conn->ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno); radlog(L_ERR, "rlm_ldap: ldap_search() failed: %s", ldap_err2string(ldap_errno)); ldap_msgfree(*result); return (RLM_MODULE_FAIL); default: ldap_get_option(conn->ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno); radlog(L_ERR, "rlm_ldap: ldap_search() failed: %s", ldap_err2string(ldap_errno)); conn->bound = 0; ldap_msgfree(*result); return (RLM_MODULE_FAIL); } if ((ldap_count_entries(conn->ld, *result)) != 1) { DEBUG("rlm_ldap: object not found or got ambiguous search result"); res = RLM_MODULE_NOTFOUND; ldap_msgfree(*result); } return res;}/* * Translate the LDAP queries. */static int ldap_escape_func(char *out, int outlen, const char *in){ int len = 0; while (in[0]) { /* * Only one byte left. */ if (outlen <= 1) { break; } if (strchr("*", *in)) { in++; outlen--; continue; } /* * Else it's a nice character. */ *out = *in; out++; in++; outlen--; len++; } *out = '\0'; return len;}/* * ldap_groupcmp(). Implement the Ldap-Group == "group" filter */static int ldap_groupcmp(void *instance, REQUEST *req, VALUE_PAIR *request, VALUE_PAIR *check, VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs){ char filter[MAX_FILTER_STR_LEN]; char gr_filter[MAX_FILTER_STR_LEN]; int res; LDAPMessage *result = NULL; LDAPMessage *msg = NULL; char basedn[MAX_FILTER_STR_LEN]; char *attrs[] = {"dn",NULL}; char **vals; ldap_instance *inst = instance; char *group_attrs[] = {inst->groupmemb_attr,NULL}; LDAP_CONN *conn; int conn_id = -1; VALUE_PAIR *vp_user_dn; VALUE_PAIR **request_pairs; request_pairs = &req->packet->vps; DEBUG("rlm_ldap: Entering ldap_groupcmp()"); if (check->strvalue == NULL || check->length == 0){ DEBUG("rlm_ldap::ldap_groupcmp: Illegal group name"); return 1; } if (req == NULL){ DEBUG("rlm_ldap::ldap_groupcmp: NULL request"); return 1; } if (!radius_xlat(basedn, sizeof(basedn), inst->basedn, req, NULL)) { DEBUG("rlm_ldap::ldap_groupcmp: unable to create basedn."); return 1; } while((vp_user_dn = pairfind(*request_pairs, PW_LDAP_USERDN)) == NULL){ char *user_dn = NULL; if (!radius_xlat(filter, sizeof(filter), inst->filter, req, ldap_escape_func)){ DEBUG("rlm_ldap::ldap_groupcmp: unable to create filter"); return 1; } if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){ radlog(L_ERR, "rlm_ldap: All ldap connections are in use"); return 1; } if ((res = perform_search(inst, conn, basedn, LDAP_SCOPE_SUBTREE, filter, attrs, &result)) != RLM_MODULE_OK){ DEBUG("rlm_ldap::ldap_groupcmp: search failed"); ldap_release_conn(conn_id,inst->conns); return 1; } if ((msg = ldap_first_entry(conn->ld, result)) == NULL) { DEBUG("rlm_ldap::ldap_groupcmp: ldap_first_entry() failed"); ldap_release_conn(conn_id,inst->conns); ldap_msgfree(result); return 1; } if ((user_dn = ldap_get_dn(conn->ld, msg)) == NULL) { DEBUG("rlm_ldap:ldap_groupcmp:: ldap_get_dn() failed"); ldap_release_conn(conn_id,inst->conns); ldap_msgfree(result); return 1; } ldap_release_conn(conn_id,inst->conns); /* * Adding new attribute containing DN for LDAP object associated with * given username */ pairadd(request_pairs, pairmake("Ldap-UserDn", user_dn, T_OP_EQ)); ldap_memfree(user_dn); ldap_msgfree(result); } if(!radius_xlat(gr_filter, sizeof(gr_filter), inst->groupmemb_filt, req, NULL)){ DEBUG("rlm_ldap::ldap_groupcmp: unable to create filter."); return 1; } if (strchr((char *)check->strvalue,',') != NULL) { /* This looks like a DN */ snprintf(filter,sizeof(filter), "%s",gr_filter); snprintf(basedn,sizeof(basedn), "%s",(char *)check->strvalue); } else snprintf(filter,sizeof(filter), "(&(%s=%s)%s)",inst->groupname_attr,(char *)check->strvalue,gr_filter); if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){ radlog(L_ERR, "rlm_ldap: All ldap connections are in use"); return 1; } if ((res = perform_search(inst, conn, basedn, LDAP_SCOPE_SUBTREE, filter, attrs, &result)) == RLM_MODULE_OK){ DEBUG("rlm_ldap::ldap_groupcmp: User found in group %s", (char *)check->strvalue); ldap_msgfree(result); ldap_release_conn(conn_id,inst->conns); return 0; } ldap_release_conn(conn_id,inst->conns); if (res != RLM_MODULE_NOTFOUND ) { DEBUG("rlm_ldap::ldap_groupcmp: Search returned error"); return 1; } if (inst->groupmemb_attr == NULL){ /* search returned NOTFOUND and searching for membership * using user object attributes is not specified in config * file */ DEBUG("rlm_ldap::ldap_groupcmp: Group %s not found or user is not a member.",(char *)check->strvalue); return 1; } snprintf(filter,sizeof(filter), "(objectclass=*)"); if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){ radlog(L_ERR, "rlm_ldap: Add ldap connections are in use"); return 1; } if ((res = perform_search(inst, conn, vp_user_dn->strvalue, LDAP_SCOPE_BASE, filter, group_attrs,&result)) != RLM_MODULE_OK){ DEBUG("rlm_ldap::ldap_groupcmp: Search returned error"); ldap_release_conn(conn_id, inst->conns); return 1; } if ((msg = ldap_first_entry(conn->ld, result)) == NULL) { DEBUG("rlm_ldap::ldap_groupcmp: ldap_first_entry() failed"); ldap_release_conn(conn_id,inst->conns); ldap_msgfree(result); return 1; } if ((vals = ldap_get_values(conn->ld, msg, inst->groupmemb_attr)) != NULL) { unsigned int i = 0; char found = 0; for (;i < ldap_count_values(vals);i++){ if (strchr(vals[i],',') != NULL){ /* This looks like a DN */ LDAPMessage *gr_result = NULL; snprintf(filter,sizeof(filter), "(%s=%s)", inst->groupname_attr, (char *)check->strvalue); if ((res = perform_search(inst, conn, vals[i], LDAP_SCOPE_BASE, filter, attrs, &gr_result)) != RLM_MODULE_OK){ if (res != RLM_MODULE_NOTFOUND){ DEBUG("rlm_ldap::ldap_groupcmp: \ Search returned error"); ldap_value_free(vals); ldap_msgfree(result); ldap_release_conn(conn_id,inst->conns); return 1; } } else { ldap_msgfree(gr_result); found = 1; break; } } else { if (strcmp(vals[i],(char *)check->strvalue) == 0){ found = 1; break; } } } ldap_value_free(vals); ldap_msgfree(result); if (found == 0){ DEBUG("rlm_ldap::groupcmp: Group %s not found \ or user not a member", (char *)check->strvalue); ldap_release_conn(conn_id,inst->conns); return 1; } } else { DEBUG("rlm_ldap::ldap_groupcmp: ldap_get_values() failed"); ldap_msgfree(result); ldap_release_conn(conn_id,inst->conns); return 1; } DEBUG("rlm_ldap::ldap_groupcmp: User found in group %s",(char *)check->strvalue); ldap_release_conn(conn_id,inst->conns); return 0;}/* * ldap_xlat()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -