📄 rlm_ldap.c
字号:
}/***************************************************************************** * * Function: rlm_ldap_authenticate * * Purpose: Check the user's password against ldap database * *****************************************************************************/static int ldap_authenticate(void *instance, REQUEST * request){ LDAP *ld_user; LDAPMessage *result, *msg; ldap_instance *inst = instance; char *user_dn, *attrs[] = {"uid", NULL}; char filter[MAX_FILTER_STR_LEN]; char basedn[MAX_FILTER_STR_LEN]; int res; VALUE_PAIR *vp_user_dn; VALUE_PAIR *module_fmsg_vp; char module_fmsg[MAX_STRING_LEN]; LDAP_CONN *conn; int conn_id = -1;#ifdef NOVELL char *err = NULL;#endif DEBUG("rlm_ldap: - authenticate"); /* * Ensure that we're being passed a plain-text password, and not * anything else. */ if (!request->username) { radlog(L_AUTH, "rlm_ldap: Attribute \"User-Name\" is required for authentication.\n"); return RLM_MODULE_INVALID; } if (!request->password){ radlog(L_AUTH, "rlm_ldap: Attribute \"User-Password\" is required for authentication."); DEBUG2(" You seem to have set \"Auth-Type := LDAP\" somewhere."); DEBUG2(" THAT CONFIGURATION IS WRONG. DELETE IT."); DEBUG2(" YOU ARE PREVENTING THE SERVER FROM WORKING PROPERLY."); return RLM_MODULE_INVALID; } if(request->password->attribute != PW_USER_PASSWORD) { radlog(L_AUTH, "rlm_ldap: Attribute \"User-Password\" is required for authentication. Cannot use \"%s\".", request->password->name); return RLM_MODULE_INVALID; } if (request->password->length == 0) { snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: empty password supplied"); module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ); pairadd(&request->packet->vps, module_fmsg_vp); return RLM_MODULE_INVALID; } /* * Check that we don't have any failed connections. If we do there's no real need * of runing. Also give it another chance if we have a lot of failed connections. */ if (inst->failed_conns > MAX_FAILED_CONNS_END) inst->failed_conns = 0; if (inst->failed_conns > MAX_FAILED_CONNS_START){ inst->failed_conns++; return RLM_MODULE_FAIL; } DEBUG("rlm_ldap: login attempt by \"%s\" with password \"%s\"", request->username->vp_strvalue, request->password->vp_strvalue); while ((vp_user_dn = pairfind(request->config_items, PW_LDAP_USERDN)) == NULL) { if (!radius_xlat(filter, sizeof(filter), inst->filter, request, ldap_escape_func)) { radlog (L_ERR, "rlm_ldap: unable to create filter.\n"); return RLM_MODULE_INVALID; } if (!radius_xlat(basedn, sizeof(basedn), inst->basedn, request, ldap_escape_func)) { radlog (L_ERR, "rlm_ldap: unable to create basedn.\n"); return RLM_MODULE_INVALID; } if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){ radlog(L_ERR, "rlm_ldap: All ldap connections are in use"); return RLM_MODULE_FAIL; } if ((res = perform_search(instance, conn, basedn, LDAP_SCOPE_SUBTREE, filter, attrs, &result)) != RLM_MODULE_OK) { if (res == RLM_MODULE_NOTFOUND){ snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: User not found"); module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ); pairadd(&request->packet->vps, module_fmsg_vp); } ldap_release_conn(conn_id,inst->conns); return (res); } if ((msg = ldap_first_entry(conn->ld, result)) == NULL) { ldap_msgfree(result); ldap_release_conn(conn_id,inst->conns); return RLM_MODULE_FAIL; } if ((user_dn = ldap_get_dn(conn->ld, msg)) == NULL) { DEBUG("rlm_ldap: ldap_get_dn() failed"); ldap_msgfree(result); ldap_release_conn(conn_id,inst->conns); return RLM_MODULE_FAIL; } ldap_release_conn(conn_id,inst->conns); pairadd(&request->config_items, pairmake("Ldap-UserDn", user_dn, T_OP_EQ)); ldap_memfree(user_dn); ldap_msgfree(result); } user_dn = vp_user_dn->vp_strvalue; DEBUG("rlm_ldap: user DN: %s", user_dn);#ifndef NOVELL ld_user = ldap_connect(instance, user_dn, request->password->vp_strvalue, 1, &res, NULL);#else /* Don't perform eDirectory APC again after attempting to bind here. */ { int apc_attr; DICT_ATTR *dattr; VALUE_PAIR *vp_apc; VALUE_PAIR *vp_auth_opt, *vp_state; int auth_opt_attr; char seq[256]; char host_ipaddr[32]; LDAP_CONN *conn1; int auth_state = -1; char *challenge = NULL; int challenge_len = MAX_CHALLENGE_LEN; char *state = NULL; dattr = dict_attrbyname("eDir-APC"); apc_attr = dattr->attr; vp_apc = pairfind(request->config_items, apc_attr); if(vp_apc && vp_apc->vp_strvalue[0] == '2') vp_apc->vp_strvalue[0] = '3'; res = 0; dattr = dict_attrbyname("eDir-Auth-Option"); auth_opt_attr = dattr->attr; vp_auth_opt = pairfind(request->config_items, auth_opt_attr); if(vp_auth_opt ) { DEBUG("rlm_ldap: ldap auth option = %s", vp_auth_opt->vp_strvalue); strncpy(seq, vp_auth_opt->vp_strvalue, vp_auth_opt->length); seq[vp_auth_opt->length] = '\0'; if( strcmp(seq, "<No Default>") ){ /* Get the client IP address to check for packet validity */ inet_ntop(AF_INET, &request->packet->src_ipaddr, host_ipaddr, sizeof(host_ipaddr)); /* challenge variable is used to receive the challenge from the * Token method (if any) and also to send the state attribute * in case the request packet is a reply to a challenge */ challenge = rad_malloc(MAX_CHALLENGE_LEN); /* If state attribute present in request it is a reply to challenge. */ if((vp_state = pairfind(request->packet->vps, PW_STATE))!= NULL ){ DEBUG("rlm_ldap: Response to Access-Challenge"); strncpy(challenge, vp_state->vp_strvalue, sizeof(challenge)); challenge_len = vp_state->length; challenge[challenge_len] = 0; auth_state = -2; } if ((conn_id = ldap_get_conn(inst->conns, &conn1, inst)) == -1){ radlog(L_ERR, "rlm_ldap: All ldap connections are in use"); res = RLM_MODULE_FAIL; } if(!conn1){ radlog(L_ERR, "rlm_ldap: NULL connection handle passed"); return RLM_MODULE_FAIL; } if (conn1->failed_conns > MAX_FAILED_CONNS_START){ conn1->failed_conns++; if (conn1->failed_conns >= MAX_FAILED_CONNS_END){ conn1->failed_conns = MAX_FAILED_CONNS_RESTART; conn1->bound = 0; } }retry: if (!conn1->bound || conn1->ld == NULL) { DEBUG2("rlm_ldap: attempting LDAP reconnection"); if (conn1->ld){ DEBUG2("rlm_ldap: closing existing LDAP connection"); ldap_unbind_s(conn1->ld); } if ((conn1->ld = ldap_connect(instance, inst->login,inst->password, 0, &res, NULL)) == NULL) { radlog(L_ERR, "rlm_ldap: (re)connection attempt failed"); conn1->failed_conns++; return (RLM_MODULE_FAIL); } conn1->bound = 1; conn1->failed_conns = 0; } DEBUG("rlm_ldap: Performing NMAS Authentication for user: %s, seq: %s \n", user_dn,seq); res = radLdapXtnNMASAuth(conn1->ld, user_dn, request->password->vp_strvalue, seq, host_ipaddr, &challenge_len, challenge, &auth_state ); switch(res){ case LDAP_SUCCESS: ldap_release_conn(conn_id,inst->conns); if ( auth_state == -1) res = RLM_MODULE_FAIL; if ( auth_state != REQUEST_CHALLENGED){ if (auth_state == REQUEST_ACCEPTED){ DEBUG("rlm_ldap: user %s authenticated succesfully",request->username->vp_strvalue); res = RLM_MODULE_OK; }else if(auth_state == REQUEST_REJECTED){ DEBUG("rlm_ldap: user %s authentication failed",request->username->vp_strvalue); res = RLM_MODULE_REJECT; } }else{ /* Request challenged. Generate Reply-Message attribute with challenge data */ pairadd(&request->reply->vps,pairmake("Reply-Message", challenge, T_OP_EQ)); /* Generate state attribute */ state = rad_malloc(MAX_CHALLENGE_LEN); (void) sprintf(state, "%s%s", challenge, challenge); vp_state = paircreate(PW_STATE, PW_TYPE_OCTETS); memcpy(vp_state->vp_strvalue, state, strlen(state)); vp_state->length = strlen(state); pairadd(&request->reply->vps, vp_state); free(state); /* Mark the packet as a Acceess-Challenge Packet */ request->reply->code = PW_ACCESS_CHALLENGE; DEBUG("rlm_ldap: Sending Access-Challenge."); res = RLM_MODULE_HANDLED; } if(challenge) free(challenge); return res; case LDAP_SERVER_DOWN: radlog(L_ERR, "rlm_ldap: nmas authentication failed: LDAP connection lost."); conn->failed_conns++; if (conn->failed_conns <= MAX_FAILED_CONNS_START){ radlog(L_INFO, "rlm_ldap: Attempting reconnect"); conn->bound = 0; goto retry; } if(challenge) free(challenge); return RLM_MODULE_FAIL; default: ldap_release_conn(conn_id,inst->conns); if(challenge) free(challenge); return RLM_MODULE_FAIL; } } } } ld_user = ldap_connect(instance, user_dn, request->password->vp_strvalue, 1, &res, &err); if(err != NULL){ /* 'err' contains the LDAP connection error description */ DEBUG("rlm_ldap: %s", err); pairadd(&request->reply->vps, pairmake("Reply-Message", err, T_OP_EQ)); ldap_memfree((void *)err); }#endif if (ld_user == NULL){ if (res == RLM_MODULE_REJECT){ inst->failed_conns = 0; snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Bind as user failed"); module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ); pairadd(&request->packet->vps, module_fmsg_vp); } if (res == RLM_MODULE_FAIL){ DEBUG("rlm_ldap: ldap_connect() failed"); inst->failed_conns++; } return (res); } DEBUG("rlm_ldap: user %s authenticated succesfully", request->username->vp_strvalue); ldap_unbind_s(ld_user); inst->failed_conns = 0; return RLM_MODULE_OK;}#ifdef NOVELL/***************************************************************************** * * Function: rlm_ldap_postauth * * Purpose: Perform eDirectory account policy check and failed-login reporting * to eDirectory. * *****************************************************************************/static int ldap_postauth(void *instance, REQUEST * request){ int res = RLM_MODULE_FAIL; int inst_attr, apc_attr; char password[UNIVERSAL_PASS_LEN]; ldap_instance *inst = instance; LDAP_CONN *conn; VALUE_PAIR *vp_inst, *vp_apc; DICT_ATTR *dattr; dattr = dict_attrbyname("LDAP-Instance"); inst_attr = dattr->attr; dattr = dict_attrbyname("eDir-APC"); apc_attr = dattr->attr; vp_inst = pairfind(request->config_items, inst_attr); /* * Check if the password in the config items list is the user's UP which has * been read in the authorize method of this instance of the LDAP module. */ if((vp_inst == NULL) || strcmp(vp_inst->vp_strvalue, inst->xlat_name)) return RLM_MODULE_NOOP; vp_apc = pairfind(request->config_items, apc_attr); switch(vp_apc->vp_strvalue[0]){ case '1': /* Account policy check not enabled */ case '3': /* Account policy check has been completed */ res = RLM_MODULE_NOOP; break; case '2': { int err, conn_id = -1; char *error_msg = NULL; VALUE_PAIR *vp_fdn, *vp_pwd; DICT_ATTR *da; if (request->reply->code == PW_AUTHENTICATION_REJECT) { /* Bind to eDirectory as the RADIUS user with a wrong password. */ vp_pwd = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD); strcpy(password, vp_pwd->vp_strvalue); if (strlen(password) > 0) { if (password[0] != 'a') { password[0] = 'a'; } else { password[0] = 'b'; } } else { strcpy(password, "dummy_password"); } res = RLM_MODULE_REJECT; } else { /* Bind to eDirectory as the RADIUS user using the user's UP */ vp_pwd = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD); if (vp_pwd == NULL) { DEBUG("rlm_ldap: User's Universal Password not in config items list."); return RLM_MODULE_FAIL; } strcpy(password, vp_pwd->vp_strvalue); } if ((da = dict_attrbyname("Ldap-UserDn")) == NULL) { DEBUG("rlm_ldap: Attribute for user FDN not found in dictionary. Unable to proceed"); return RLM_MODULE_FAIL; } vp_fdn = pairfind(request->config_items, da->attr); if (vp_fdn == NULL) { DEBUG("rlm_ldap: User's FQDN not in config items list."); return RLM_MODULE_FAIL; } if ((conn_id = ldap_get_conn(inst->apc_conns, &conn, inst)) == -1){ radlog(L_ERR, "rlm_ldap: All ldap connections are in use"); return RLM_MODULE_FAIL; } /* * If there is an existing LDAP * connection to the directory, * bind over it. Otherwise, * establish a new connection. */ postauth_reconnect: 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, (char *)vp_fdn->vp_strvalue, password, 0, &res, &error_msg)) == NULL) { radlog(L_ERR, "rlm_ldap: eDirectory account policy check failed."); if (error_msg != NULL) { DEBUG("rlm_ldap: %s", error_msg); pairadd(&request->reply->vps, pairmake("Reply-Message", error_msg, T_OP_EQ)); ldap_memfree((void *)error_msg); } vp_apc->vp_strvalue[0] = '3'; ldap_release_conn(conn_id, inst->apc_conns); return RLM_MODULE_REJECT; } conn->bound = 1; } else if((err = ldap_simple_bind_s(conn->ld, (char *)vp_fdn->vp_strvalue, password)) != LDAP_SUCCESS) { if (err == LDAP_SERVER_DOWN) { conn->bound = 0; goto postauth_reconnect; } DEBUG("rlm_ldap: eDirectory account policy check failed."); l
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -