📄 auth.c
字号:
} /* * Challenges are punted back to the NAS * without any further processing. */ if (request->proxy_reply->code == PW_ACCESS_CHALLENGE) { request->reply->code = PW_ACCESS_CHALLENGE; return RLM_MODULE_HANDLED; } /* * Reply of ACCEPT means accept, ALL other * replies mean reject. This is fail-safe. */ if (request->proxy_reply->code == PW_AUTHENTICATION_ACK) tmp->lvalue = PW_AUTHTYPE_ACCEPT; else tmp->lvalue = PW_AUTHTYPE_REJECT; pairadd(&request->config_items, tmp); /* * If it's an Access-Reject, then do NOT do any * authorization or authentication. They're being * rejected, so we minimize the amount of work * done by the server, by rejecting them here. */ if ((request->proxy_reply->code != PW_AUTHENTICATION_ACK) && (request->proxy_reply->code != PW_ACCESS_CHALLENGE)) { rad_authlog("Login incorrect (Home Server says so)", request, 0); request->reply->code = PW_AUTHENTICATION_REJECT; rad_postauth_reject(request); return RLM_MODULE_REJECT; } } /* * Get the username from the request. * * Note that namepair MAY be NULL, in which case there * is no User-Name attribute in the request. */ namepair = request->username; /* * Look for, and cache, passwords. */ if (!request->password) { request->password = pairfind(request->packet->vps, PW_PASSWORD); } /* * Discover which password we want to use. */ auth_item = request->password; if (auth_item) { password = (const char *)auth_item->strvalue; } else { /* * Maybe there's a CHAP-Password? */ if ((auth_item = pairfind(request->packet->vps, PW_CHAP_PASSWORD)) != NULL) { password = "<CHAP-PASSWORD>"; } else { /* * No password we recognize. */ password = "<NO-PASSWORD>"; } } request->password = auth_item; /* * Get the user's authorization information from the database */autz_redo: r = module_authorize(autz_type, request); if (r != RLM_MODULE_NOTFOUND && r != RLM_MODULE_NOOP && r != RLM_MODULE_OK && r != RLM_MODULE_UPDATED) { if (r != RLM_MODULE_FAIL && r != RLM_MODULE_HANDLED) { if ((module_msg = pairfind(request->packet->vps, PW_MODULE_FAILURE_MESSAGE)) != NULL){ char msg[MAX_STRING_LEN+16]; snprintf(msg, sizeof(msg), "Invalid user (%s)", module_msg->strvalue); rad_authlog(msg,request,0); } else { rad_authlog("Invalid user", request, 0); } request->reply->code = PW_AUTHENTICATION_REJECT; } return r; } if (!autz_retry){ VALUE_PAIR *autz_type_item = NULL; autz_type_item = pairfind(request->config_items, PW_AUTZ_TYPE); if (autz_type_item){ autz_type = autz_type_item->lvalue; autz_retry = 1; goto autz_redo; } } /* * If we haven't already proxied the packet, then check * to see if we should. Maybe one of the authorize * modules has decided that a proxy should be used. If * so, get out of here and send the packet. */ if ((request->proxy == NULL) && ((tmp = pairfind(request->config_items, PW_PROXY_TO_REALM)) != NULL)) { REALM *realm; /* * Catch users who set Proxy-To-Realm to a LOCAL * realm (sigh). */ realm = realm_find(tmp->strvalue, 0); if (realm && (realm->ipaddr == htonl(INADDR_NONE))) { DEBUG2(" WARNING: You set Proxy-To-Realm = %s, but it is a LOCAL realm! Cancelling invalid proxy request.", realm->realm); } else { /* * Don't authenticate, as the request is * proxied. */ return RLM_MODULE_OK; } } /* * Perhaps there is a Stripped-User-Name now. */ namepair = request->username; /* * Validate the user */ do { if ((result = check_expiration(request)) < 0) break; result = rad_check_password(request); if (result > 0) { /* don't reply! */ return RLM_MODULE_HANDLED; } } while(0); /* * Failed to validate the user. * * We PRESUME that the code which failed will clean up * request->reply->vps, to be ONLY the reply items it * wants to send back. */ if (result < 0) { DEBUG2("auth: Failed to validate the user."); request->reply->code = PW_AUTHENTICATION_REJECT; if ((module_msg = pairfind(request->packet->vps,PW_MODULE_FAILURE_MESSAGE)) != NULL){ char msg[MAX_STRING_LEN+19]; snprintf(msg, sizeof(msg), "Login incorrect (%s)", module_msg->strvalue); rad_authlog(msg, request, 0); } else { rad_authlog("Login incorrect", request, 0); } /* double check: maybe the secret is wrong? */ if ((debug_flag > 1) && (auth_item != NULL) && (auth_item->attribute == PW_PASSWORD)) { u_char *p; p = auth_item->strvalue; while (*p != '\0') { if (!isprint((int) *p)) { log_debug(" WARNING: Unprintable characters in the password.\n\t Double-check the shared secret on the server and the NAS!"); break; } p++; } } } if (result >= 0 && (check_item = pairfind(request->config_items, PW_SIMULTANEOUS_USE)) != NULL) { VALUE_PAIR *session_type; int sess_type = 0; session_type = pairfind(request->config_items, PW_SESSION_TYPE); if (session_type) sess_type = session_type->lvalue; /* * User authenticated O.K. Now we have to check * for the Simultaneous-Use parameter. */ if (namepair && (r = module_checksimul(sess_type,request, check_item->lvalue)) != 0) { char mpp_ok = 0; if (r == 2){ /* Multilink attempt. Check if port-limit > simultaneous-use */ VALUE_PAIR *port_limit; if ((port_limit = pairfind(request->reply->vps, PW_PORT_LIMIT)) != NULL && port_limit->lvalue > check_item->lvalue){ DEBUG2("main auth: MPP is OK"); mpp_ok = 1; } } if (!mpp_ok){ if (check_item->lvalue > 1) { snprintf(umsg, sizeof(umsg), "\r\nYou are already logged in %d times - access denied\r\n\n", (int)check_item->lvalue); user_msg = umsg; } else { user_msg = "\r\nYou are already logged in - access denied\r\n\n"; } request->reply->code = PW_AUTHENTICATION_REJECT; /* * They're trying to log in too many times. * Remove ALL reply attributes. */ pairfree(&request->reply->vps); tmp = pairmake("Reply-Message", user_msg, T_OP_SET); request->reply->vps = tmp; snprintf(logstr, sizeof(logstr), "Multiple logins (max %d) %s", check_item->lvalue, r == 2 ? "[MPP attempt]" : ""); rad_authlog(logstr, request, 1); result = -1; } } } if (result >= 0 && (check_item = pairfind(request->config_items, PW_LOGIN_TIME)) != NULL) { /* * Authentication is OK. Now see if this * user may login at this time of the day. */ r = timestr_match((char *)check_item->strvalue, request->timestamp); if (r == 0) { /* unlimited */ /* * Do nothing: login-time is OK. */ /* * Session-Timeout needs to be at least * 60 seconds, some terminal servers * ignore smaller values. */ } else if (r < 60) { /* * User called outside allowed time interval. */ result = -1; user_msg = "You are calling outside your allowed timespan\r\n"; request->reply->code = PW_AUTHENTICATION_REJECT; pairfree(&request->reply->vps); tmp = pairmake("Reply-Message", user_msg, T_OP_SET); request->reply->vps = tmp; snprintf(logstr, sizeof(logstr), "Outside allowed timespan (time allowed %s)", check_item->strvalue); rad_authlog(logstr, request, 1); } else if (r > 0) { /* * User is allowed, but set Session-Timeout. */ if ((reply_item = pairfind(request->reply->vps, PW_SESSION_TIMEOUT)) != NULL) { if (reply_item->lvalue > (unsigned) r) reply_item->lvalue = r; } else { if ((reply_item = paircreate( PW_SESSION_TIMEOUT, PW_TYPE_INTEGER)) == NULL) { radlog(L_ERR|L_CONS, "no memory"); exit(1); } reply_item->lvalue = r; pairadd(&request->reply->vps, reply_item); } } } /* * Result should be >= 0 here - if not, it means the user * is rejected, so we just process post-auth and return. */ if (result < 0) { rad_postauth_reject(request); return RLM_MODULE_REJECT; } /* * We might need this later. The 'password' string * is NOT used anywhere below here, except for logging, * so it should be safe... */ if ((auth_item != NULL) && (auth_item->attribute == PW_CHAP_PASSWORD)) { password = "CHAP-Password"; } /* * Add the port number to the Framed-IP-Address if * vp->addport is set. */ if (((tmp = pairfind(request->reply->vps, PW_FRAMED_IP_ADDRESS)) != NULL) && (tmp->flags.addport != 0)) { VALUE_PAIR *vpPortId; /* * Find the NAS port ID. */ if ((vpPortId = pairfind(request->packet->vps, PW_NAS_PORT)) != NULL) { unsigned long tvalue = ntohl(tmp->lvalue); tmp->lvalue = htonl(tvalue + vpPortId->lvalue); tmp->flags.addport = 0; ip_ntoa(tmp->strvalue, tmp->lvalue); } else { DEBUG2("WARNING: No NAS-Port attribute in request. CANNOT return a Framed-IP-Address + NAS-Port.\n"); pairdelete(&request->reply->vps, PW_FRAMED_IP_ADDRESS); } } /* * See if we need to execute a program. * FIXME: somehow cache this info, and only execute the * program when we receive an Accounting-START packet. * Only at that time we know dynamic IP etc. */ exec_program = NULL; exec_wait = 0; if ((auth_item = pairfind(request->reply->vps, PW_EXEC_PROGRAM)) != NULL) { exec_wait = 0; exec_program = strdup((char *)auth_item->strvalue); pairdelete(&request->reply->vps, PW_EXEC_PROGRAM); } if ((auth_item = pairfind(request->reply->vps, PW_EXEC_PROGRAM_WAIT)) != NULL) { exec_wait = 1; exec_program = strdup((char *)auth_item->strvalue); pairdelete(&request->reply->vps, PW_EXEC_PROGRAM_WAIT); } /* * Hack - allow % expansion in certain value strings. * This is nice for certain Exec-Program programs. */ seen_callback_id = 0; if ((auth_item = pairfind(request->reply->vps, PW_CALLBACK_ID)) != NULL) { seen_callback_id = 1; radius_xlat(buf, sizeof(auth_item->strvalue), (char *)auth_item->strvalue, request, NULL); strNcpy((char *)auth_item->strvalue, buf, sizeof(auth_item->strvalue)); auth_item->length = strlen((char *)auth_item->strvalue); } /* * If we want to exec a program, but wait for it, * do it first before sending the reply. */ if (exec_program && exec_wait) { r = radius_exec_program(exec_program, request, exec_wait, umsg, sizeof(umsg), request->packet->vps, &tmp); free(exec_program); exec_program = NULL; /* * Always add the value-pairs to the reply. */ pairmove(&request->reply->vps, &tmp); pairfree(&tmp); if (r != 0) { /* * Error. radius_exec_program() returns -1 on * fork/exec errors, or >0 if the exec'ed program * had a non-zero exit status. */ if (umsg[0] == '\0') { user_msg = "\r\nAccess denied (external check failed)."; } else { user_msg = &umsg[0]; } request->reply->code = PW_AUTHENTICATION_REJECT; tmp = pairmake("Reply-Message", user_msg, T_OP_SET); pairadd(&request->reply->vps, tmp); rad_authlog("Login incorrect (external check failed)", request, 0); rad_postauth_reject(request); return RLM_MODULE_REJECT; } } /* * Delete "normal" A/V pairs when using callback. * * FIXME: This is stupid. The portmaster should accept * these settings instead of insisting on using a * dialout location. * * FIXME2: Move this into the above exec thingy? * (if you knew how I use the exec_wait, you'd understand). */ if (seen_callback_id) { pairdelete(&request->reply->vps, PW_FRAMED_PROTOCOL); pairdelete(&request->reply->vps, PW_FRAMED_IP_ADDRESS); pairdelete(&request->reply->vps, PW_FRAMED_IP_NETMASK); pairdelete(&request->reply->vps, PW_FRAMED_ROUTE); pairdelete(&request->reply->vps, PW_FRAMED_MTU); pairdelete(&request->reply->vps, PW_FRAMED_COMPRESSION); pairdelete(&request->reply->vps, PW_FILTER_ID); pairdelete(&request->reply->vps, PW_PORT_LIMIT); pairdelete(&request->reply->vps, PW_CALLBACK_NUMBER); } /* * Filter (possibly multiple) Reply-Message attributes * through radius_xlat, modifying them in place. */ if (user_msg == NULL) { reply_item = pairfind(request->reply->vps, PW_REPLY_MESSAGE); while (reply_item) { radius_xlat(buf, sizeof(reply_item->strvalue), (char *)reply_item->strvalue, request, NULL); strNcpy((char *)reply_item->strvalue, buf, sizeof(reply_item->strvalue)); reply_item->length = strlen((char *)reply_item->strvalue); user_msg = NULL; reply_item = pairfind(reply_item->next, PW_REPLY_MESSAGE); } } /* * Set the reply to Access-Accept, if it hasn't already * been set to something. (i.e. Access-Challenge) */ if (request->reply->code == 0) request->reply->code = PW_AUTHENTICATION_ACK; if ((module_msg = pairfind(request->packet->vps,PW_MODULE_SUCCESS_MESSAGE)) != NULL){ char msg[MAX_STRING_LEN+12]; snprintf(msg, sizeof(msg), "Login OK (%s)", module_msg->strvalue); rad_authlog(msg, request, 1); } else { rad_authlog("Login OK", request, 1); } if (exec_program && !exec_wait) { /* * No need to check the exit status here. */ radius_exec_program(exec_program, request, exec_wait, NULL, 0, request->packet->vps, NULL); } if (exec_program) free(exec_program); result = rad_postauth(request); return result;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -