📄 radiusd.c
字号:
/* fork our child */ cleanup_pid = -1; rad_spawned_child_pid = fork(); if(rad_spawned_child_pid < 0) { log_err("system error: fork failed with error %d for request from %s\n", errno,req2strp(authreq)); reqfree(authreq,"rad_spawn_child"); return; } if(rad_spawned_child_pid == 0) { /* This is the child, it should go ahead and respond */ child_authenticate(authreq, activefd); exit(0); } /* Register the Child */ authreq->child_pid = rad_spawned_child_pid; /* * If cleanup_pid is not -1, then we received a SIGCHLD between * the time we forked and the time we got here, so clean up after it */ if(cleanup_pid != -1) { clean_child(cleanup_pid); cleanup_pid = -1; }}void clean_child(int pid){ AUTH_REQ *curreq; curreq = first_request; while(curreq != (AUTH_REQ *)NULL) { if(curreq->child_pid == pid) { curreq->child_pid = -1; curreq->timestamp = (UINT4)time((time_t *)NULL); return; } curreq = curreq->next; } cleanup_pid = (int)pid; return;}void sig_cleanup(int sig){ int status; pid_t pid; for (;;) { pid = waitpid((pid_t)-1,&status,WNOHANG); signal(SIGCHLD, sig_cleanup); if (pid <= 0) return;#if defined (aix) kill(pid, SIGKILL);#endif if(pid == acct_pid) { sig_fatal(100); } clean_child(pid); }}/************************************************************************* * * Function: child_authenticate * * Purpose: Process and reply to an authentication request * *************************************************************************/void child_authenticate(AUTH_REQ *authreq,int activefd){#ifdef SMARTCARD key_t msg_key; int msg_id; int length; struct sockaddr_in *sin; msg_key = RADIUS_MSG_KEY(getpid());#endif /* SMARTCARD */ for (;;) { if (rad_authenticate(authreq, activefd) == 0) { break; }#ifdef SMARTCARD if ((msg_id = msgget(msg_key, IPC_CREAT | 0600)) == -1) { log_err("child_authenticate: msgget for key %x for id %d returned error: %s\n", msg_key, msg_id, strerror(errno)); break; } if ((length = msgrcv(msg_id, recv_buffer, sizeof recv_buffer - sizeof(long), 0, 0)) == -1) { log_err("child_authenticate: msgrcv for msgid %d returned error: %s\n", msg_id, strerror(errno)); break; } if (msgctl(msg_id, IPC_RMID, 0) == -1) { log_err("child_authenticate: msgctl for msgid %d returned error: %s\n", msg_id, strerror(errno)); } sin = (struct sockaddr_in *) &rad_saremote; authreq = radrecv( ntohl(sin->sin_addr.s_addr), ntohs(sin->sin_port), authreq->secret, recv_buffer, length);#else /* not SMARTCARD */ break;#endif /* not SMARTCARD */ }}/************************************************************************* * * Function: rad_authenticate * * Purpose: Process and reply to an authentication request * *************************************************************************/int rad_authenticate(AUTH_REQ *authreq,int activefd){ USER_FILE user_desc; VALUE_PAIR *attr; VALUE_PAIR *auth_item; VALUE_PAIR *callpair; VALUE_PAIR *challenge; VALUE_PAIR *check_item; VALUE_PAIR *password_item; VALUE_PAIR *user_check; VALUE_PAIR *user_reply; char auth_name[AUTH_STRING_LEN + 2]; char callfrom[ID_LENGTH]; char pw_digest[16]; char string[AUTH_STRING_LEN + 20 + 2]; char umsg[AUTH_STRING_LEN + 2]; char *encpw; char *ptr; char *user_msg; char *pass; int authtype; int chlen; int result; int retval; int speed; /* The username was placed in authreq->name by handle_proxy */ if(strlen(authreq->name) <= (size_t)0) { log_err("auth: access-request from %s ignored; no user name\n", req2strp(authreq)); reqfree(authreq,"rad_authenticate"); return(0); }#ifdef VPORTS if (vports_flag == 1) { switch(vp_check_req(authreq)) { case VP_RET_REJECT: send_reject(authreq, (char *)NULL, activefd); reqfree(authreq,"rad_authenticate"); return(0); break; case VP_RET_ACCEPT: send_accept(authreq, (VALUE_PAIR *)NULL, (char *)NULL, activefd); reqfree(authreq,"rad_authenticate"); return(0); break; case VP_RET_IGNORE: default: break; }}#endif /* VPORTS */ /* calculate the MD5 Password Digest */ calc_digest((u_char*)pw_digest, authreq, (u_char*)authreq->secret); /* * If the request is processing a menu, service it here. */ if((attr = get_attribute(authreq->request, PW_STATE)) != (VALUE_PAIR *)NULL && strncmp(attr->strvalue, "MENU=", 5) == 0){ process_menu(authreq, activefd, pw_digest); return(0); } callpair = get_attribute(authreq->request, PW_CALLING); if (callpair == (VALUE_PAIR *)NULL || callpair->lvalue > 20) { callfrom[0] = '\0'; } else { snprintf(callfrom,(size_t)ID_LENGTH," at %s",callpair->strvalue); } /* * Open the user table */ user_desc = user_open(); if(user_desc.gdbm == NULL && user_desc.flat == NULL) { reqfree(authreq,"rad_authenticate"); return(0); } for (;;) { /* Get the user from the database */ if ((result = user_find(authreq->name, auth_name, &user_check, &user_reply, user_desc)) != 0) { log_err("auth: access-request from %s denied for unknown user \"%s\"%s\n", req2strp(authreq), authreq->name, callfrom); send_reject(authreq, (char *)NULL, activefd); reqfree(authreq,"rad_authenticate"); user_close(user_desc); return(0); } /* Validate the user */ /* Look for matching check items */ password_item = (VALUE_PAIR *)NULL; authtype = PW_AUTHTYPE_NONE; user_msg = (char *)NULL; check_item = user_check; result = allow_user(authreq->name); if (result != 0) { result = deny_user(authreq->name); if (result != 0) { log_err("auth: denied connection for '%s' (listed in '%s/%s')", authreq->name,radius_dir, (result==-2)?"denyusers":"stopusers"); } } while(result == 0 && check_item != (VALUE_PAIR *)NULL) { auth_item = get_attribute(authreq->request, check_item->attribute); switch(check_item->attribute) { case PW_PREFIX: case PW_SUFFIX: break; case PW_EXPIRATION: /* * Check expiration date if we are * doing password aging. */#if defined(SHADOW_EXPIRATION) if (!strncasecmp(check_item->strvalue,"SHADOW", 6)) retval = shadow_expired(authreq->name); else#endif retval = pw_expired(check_item->lvalue); if(retval < 0) { result = -2; snprintf(umsg,sizeof(umsg),"Password Has Expired\r\n"); user_msg = umsg; log_err("auth: Password expired for '%s'\n",authreq->name); } else { if(retval > 0) { snprintf(umsg,(size_t)(AUTH_STRING_LEN)+2,"Password Will Expire in %d Days\r\n", retval); user_msg = umsg; log_err("auth: Password for '%s' will expire in %d days\n", retval); } } break; case PW_PASSWORD: if(strcmp(check_item->strvalue, "UNIX") == 0) { authtype = PW_AUTHTYPE_UNIX; } else { authtype = PW_AUTHTYPE_LOCAL; password_item = check_item; } break; case PW_AUTHTYPE: authtype = check_item->lvalue; break; case PW_GROUP: if(!unix_group(auth_name, check_item->strvalue)) { result = -1; } break; case PW_CRYPT_PASSWORD: authtype = PW_AUTHTYPE_CRYPT; password_item = check_item; break; /** FIXME This is a problem for Yard. Connect-Info or Connect-Info-Old are often not used by non-Livingston boxes, so this check item is unuseful. Ascend and USR boxes uses their VSAs to register connection speed. Cisco too. Not RFC compliant at this moment.**/ case PW_CONNECT_RATE: auth_item = get_attribute(authreq->request, PW_CONNECT_INFO); if (auth_item != (VALUE_PAIR *)NULL) { if ( sscanf(auth_item->strvalue,"%d/%*d%*s",&speed)==1|| (speed=atoi(auth_item->strvalue)) ) if ( speed>check_item->lvalue ) result=-1; } else { auth_item = get_attribute(authreq->request, PW_CONNECT_INFO_OLD); if (auth_item != (VALUE_PAIR *)NULL) { speed = atoi(auth_item->strvalue); if (speed > check_item->lvalue) result=-1; } } break;#if defined(PAM) && defined(HAVE_LIBPAM) case PW_PAM_AUTH: pam_auth = check_item->strvalue; break;#endif case PW_LOGINS: retval = check_logins(auth_name, check_item->lvalue); if (retval != 0) { result = -2; snprintf(umsg,(size_t)(AUTH_STRING_LEN+2),"Too many logins - max %d\r\n",(unsigned int)check_item->lvalue); user_msg = umsg; log_err("Too many logins for '%s' (max %d)\n",authreq->name,(unsigned int)check_item->lvalue); } break; case PW_MAXDTIME: retval = check_maxtime(auth_name,check_item->lvalue,DAY_LIMIT); if (retval != 0) { result = -2; snprintf(umsg,sizeof(umsg),"Total on-line daily time expired (%d hours)\r\n",(unsigned int)check_item->lvalue); user_msg = umsg; log_err("Total on-line daily time expired (%d hours) for '%s'\n", (unsigned int)check_item->lvalue, authreq->name); } break; case PW_MAXMTIME: retval = check_maxtime(auth_name,check_item->lvalue,MONTH_LIMIT); if (retval != 0) { result = -2; snprintf(umsg,sizeof(umsg),"Total on-line time expired (%d hours)\r\n", (unsigned int)check_item->lvalue); user_msg = umsg; log_err("Total on-line time expired (%d hours) for '%s'\n", (unsigned int)check_item->lvalue, authreq->name); } break; case PW_MAXYTIME: retval = check_maxtime(auth_name,check_item->lvalue,YEAR_LIMIT); if (retval != 0) { result = -2; snprintf(umsg,sizeof(umsg),"Total on-line yearly time expired (%d hours)\r\n", (unsigned int)check_item->lvalue); user_msg = umsg; log_err("Total on-line yearly time expired (%d hours) for '%s'\n", (unsigned int)check_item->lvalue, authreq->name); } break; case PW_TIME: retval = allowed_time(check_item->strvalue); if (retval != 0) { result = -2; snprintf(umsg,sizeof(umsg),"Not allowed to login at this time\r\n"); user_msg = umsg; log_err( "Not allowed to login at this time for '%s'\n",authreq->name ); } break; case PW_MAXDTRAFFIC: retval = check_maxtraffic(auth_name,check_item->lvalue,DAY_LIMIT); if (retval != 0) { result = -2; snprintf(umsg,sizeof(umsg),"Maximum allowed daily traffic size reached (%d KB)\r\n",(unsigned int)check_item->lvalue); user_msg=umsg; log_err("Maximum allowed daily traffic size reached (%dKB) for '%s'\r\n", (unsigned int)check_item->lvalue, authreq->name); } break; case PW_MAXMTRAFFIC: retval = check_maxtraffic(auth_name,check_item->lvalue,MONTH_LIMIT); if (retval != 0) { result = -2; snprintf(umsg,sizeof(umsg),"Maximum allowed monthly traffic size reached (%d KB)\r\n", (unsigned int)check_item->lvalue); user_msg=umsg; log_err("Maximum allowed monthly traffic size reached (%d KB) for '%s'\r\n", (unsigned int)check_item->lvalue, authreq->name); } break; case PW_MAXYTRAFFIC: retval = check_maxtraffic(auth_name,check_item->lvalue,YEAR_LIMIT); if (retval != 0) { result = -2; snprintf(umsg,sizeof(umsg),"Maximum allowed yearly traffic size reached (%d KB)\r\n", (unsigned int)check_item->lvalue); user_msg=umsg; log_err("Maximum allowed yearly traffic size reached (%d KB) for '%s'\r\n", (unsigned int)check_item->lvalue, authreq->name); } break; default: if(auth_item == (VALUE_PAIR *)NULL) { result = -1; break; } switch(check_item->type) { case PW_TYPE_STRING: if(strcmp(check_item->strvalue, auth_item->strvalue) != 0) { result = -1; } break; case PW_TYPE_INTEGER: case PW_TYPE_IPADDR: if(check_item->lvalue != auth_item->lvalue) { result = -1; } break; default: result = -1; break; } break; } check_item = check_item->next; } if (result != -1) { break; } pairfree(user_check,"rad_authenticate"); pairfree(user_reply,"rad_authenticate"); } user_close(user_desc); /* * At this point we have validated all normal comparisons * for the user. All that is left is the actual authentication. * Authentication will be done based on the authentication type * previously specified. */ if(result == 0) { /* * Decrypt the password in the request. */ pass = decrypt_password(authreq,authreq->secret); if (pass != (char *)NULL) { strncpy(string,pass,AUTH_STRING_LEN); string[AUTH_STRING_LEN] = '\0'; /* always null-term */ } else { string[0] = '\0'; } switch(authtype) { case PW_AUTHTYPE_LOCAL: /* * The local authentication type supports normal * password comparison and the Three-Way CHAP. */ if (password_item == (VALUE_PAIR *)NULL) { log_err("Warning: entry for user \"%s\" is missing Password check item\n",authreq->name); result = -1; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -