📄 rlm_ldap.c
字号:
*/ group_name = rad_malloc((strlen(xlat_name) + 1 + 11) * sizeof(char)); sprintf(group_name,"%s-Ldap-Group",xlat_name); DEBUG("rlm_ldap: Creating new attribute %s",group_name); dict_addattr(group_name, 0, PW_TYPE_STRING, -1, flags); dattr = dict_attrbyname(group_name); if (dattr == NULL){ radlog(L_ERR, "rlm_ldap: Failed to create attribute %s",group_name); free(group_name); free(inst); /* FIXME: detach */ return -1; } DEBUG("rlm_ldap: Registering ldap_groupcmp for %s",group_name); paircompare_register(dattr->attr, PW_USER_NAME, ldap_groupcmp, inst); free(group_name); } else { xlat_name = cf_section_name1(conf); rad_assert(xlat_name != NULL); /* or all hell breaks loose */ } inst->xlat_name = strdup(xlat_name); DEBUG("rlm_ldap: Registering ldap_xlat with xlat_name %s",xlat_name); xlat_register(xlat_name,ldap_xlat,inst); /* * Over-ride set_auth_type if there's no Auth-Type of our name. * This automagically catches the case where LDAP is listed * in "authorize", but not "authenticate". */ if (inst->set_auth_type) { DICT_VALUE *dv = dict_valbyname(PW_AUTH_TYPE, xlat_name); if (!dv) { DEBUG2("rlm_ldap: Over-riding set_auth_type, as there is no module %s listed in the \"authenticate\" section.", xlat_name); inst->set_auth_type = 0; } } /* else no need to look up the value */#ifdef NOVELL /* * (LDAP_Instance, V1) attribute-value pair in the config * items list means that the 'authorize' method of the * instance 'V1' of the LDAP module has processed this * request. */ dict_addattr("LDAP-Instance", 0, PW_TYPE_STRING, -1, flags); /* * ('eDir-APC', '1') in config items list * Do not perform eDirectory account policy check (APC) * * ('eDir-APC', '2') in config items list * Perform eDirectory APC * * ('eDir-APC', '3') in config items list * eDirectory APC has been completed */ dict_addattr("eDir-APC", 0, PW_TYPE_STRING, -1, flags); /* * eDir-Auth-Option allows for a different NMAS Authentication method to be used instead of password */ dict_addattr("eDir-Auth-Option", 0, PW_TYPE_STRING, -1, flags);#endif if (inst->num_conns <= 0){ radlog(L_ERR, "rlm_ldap: Invalid ldap connections number passed."); free(inst); /* FIXME: detach */ return -1; } inst->conns = malloc(sizeof(*(inst->conns))*inst->num_conns); if (inst->conns == NULL){ radlog(L_ERR, "rlm_ldap: Could not allocate memory. Aborting."); free(inst); /* FIXME: detach */ return -1; } for(i = 0; i < inst->num_conns; i++){ inst->conns[i].bound = 0; inst->conns[i].locked = 0; inst->conns[i].failed_conns = 0; inst->conns[i].ld = NULL; pthread_mutex_init(&inst->conns[i].mutex, NULL); }#ifdef NOVELL /* * 'inst->apc_conns' is a separate connection pool to be * used for performing eDirectory account policy check in * the 'postauth' method. This avoids changing the * (RADIUS server) credentials associated with the * 'inst->conns' connection pool. */ inst->apc_conns = malloc(sizeof(*(inst->apc_conns))*inst->num_conns); if (inst->apc_conns == NULL){ radlog(L_ERR, "rlm_ldap: Could not allocate memory. Aborting."); free(inst); /* FIXME: detach */ return -1; } for(i = 0; i < inst->num_conns; i++){ inst->apc_conns[i].bound = 0; inst->apc_conns[i].locked = 0; inst->apc_conns[i].failed_conns = 0; inst->apc_conns[i].ld = NULL; pthread_mutex_init(&inst->apc_conns[i].mutex, NULL); }#endif if (read_mappings(inst) != 0) { radlog(L_ERR, "rlm_ldap: Reading dictionary mappings from file %s failed", inst->dictionary_mapping); free(inst); /* FIXME: detach */ return -1; } if ((inst->check_item_map == NULL) && (inst->reply_item_map == NULL)) { radlog(L_ERR, "rlm_ldap: dictionary mappings file %s did not contain any mappings", inst->dictionary_mapping); free(inst); /* FIXME: detach */ return -1; } pair = inst->check_item_map; while(pair != NULL){ atts_num++; pair = pair->next; } check_map_num = (atts_num - 1); pair = inst->reply_item_map; while(pair != NULL){ atts_num++; pair = pair->next; } reply_map_num = (atts_num - 1); if (inst->profile_attr) atts_num++; if (inst->passwd_attr) atts_num++; if (inst->access_attr) atts_num++;#ifdef NOVELL atts_num++; /* eDirectory Authentication Option attribute */#endif inst->atts = (char **)malloc(sizeof(char *)*(atts_num + 1)); if (inst->atts == NULL){ radlog(L_ERR, "rlm_ldap: Could not allocate memory. Aborting."); free(inst); /* FIXME: detach */ return -1; } pair = inst->check_item_map; if (pair == NULL) pair = inst->reply_item_map;#ifdef NOVELL for(i=0;i<atts_num - 1;i++){#else for(i=0;i<atts_num;i++){#endif if (i <= check_map_num ){ inst->atts[i] = pair->attr; if (i == check_map_num) pair = inst->reply_item_map; else pair = pair->next; } else if (i <= reply_map_num){ inst->atts[i] = pair->attr; pair = pair->next; } else{ if (inst->profile_attr && !att_map[0]){ inst->atts[i] = inst->profile_attr; att_map[0] = 1; } else if (inst->passwd_attr && !att_map[1]){ inst->atts[i] = inst->passwd_attr; att_map[1] = 1; } else if (inst->access_attr && !att_map[2]){ inst->atts[i] = inst->access_attr; att_map[2] = 1; } } }#ifdef NOVELL inst->atts[atts_num - 1] = "sasdefaultloginsequence";#endif 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]; char radiusAttribute[MAX_LINE_LEN], ldapAttribute[MAX_LINE_LEN]; int linenumber; FR_TOKEN operator; char opstring[MAX_LINE_LEN]; /* 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: %s", filename, strerror(errno)); return -1; /* error */ } /* * read file line by line. Note that if line length * exceeds 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 %s", itemType, radiusAttribute, ldapAttribute, opstring); if (token_count <= 0) /* no tokens */ continue; if ((token_count < 3) || (token_count > 4)) { radlog(L_ERR, "rlm_ldap: Skipping %s line %i: %s", filename, linenumber, buf); radlog(L_ERR, "rlm_ldap: Expected 3 to 4 tokens " "(Item type, RADIUS Attribute and LDAP Attribute) but found only %i", token_count); continue; } if (token_count == 3) { operator = T_OP_INVALID; /* use defaults */ } else { ptr = opstring; operator = gettoken(&ptr, buf, sizeof(buf)); if ((operator < T_OP_ADD) || (operator > T_OP_CMP_EQ)) { radlog(L_ERR, "rlm_ldap: file %s: skipping line %i: unknown or invalid operator %s", filename, linenumber, opstring); continue; } } /* create new TLDAP_RADIUS list node */ pair = rad_malloc(sizeof(*pair)); pair->attr = strdup(ldapAttribute); pair->radius_attr = strdup(radiusAttribute); pair->operator = operator; 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; struct timeval tv; *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)) == 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; } tv.tv_sec = inst->timeout; tv.tv_usec = 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, &tv, 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_FILTER_ERROR: radlog(L_ERR, "rlm_ldap: ldap_search() failed: Bad search filter: %s",filter); 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 size_t ldap_escape_func(char *out, size_t outlen, const char *in){ size_t len = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -