📄 radiusd.c
字号:
} /* * Loop where we spend the rest of our life. */ result = 0; memcpy ((char *) &savetime, (char *) &timeout, sizeof (struct timeval)); do { if (ddt != (FILE *) NULL && debug_flag <= 0) { fprintf (ddt, "Debug turned OFF\n"); if ((ddt == stderr) || (fileno(ddt) == STDERR_FILENO) || (fileno(ddt) == fileno(stderr))) { reset_stderr ("/dev/console", 1); } else { (void) fclose (ddt); } ddt = (FILE *) NULL; } /* Enable signal processing now */ sigprocmask (SIG_UNBLOCK, &signals, NULL);#ifdef USR_CCA /* Send out the resource query requests */ if (qry_init == FALSE && dns_done == TRUE) { qry_init = TRUE; rq_req_init (); if (!alarm_set || global_auth_q.q) { alarm (1); alarm_set++; } }#endif /* USR_CCA */ memcpy ((char *) &readfds, (char *) &select_mask, sizeof (readfds)); memcpy ((char *) &timeout, (char *) &savetime, sizeof (struct timeval)); selcnt = select (maxfd + 1, &readfds, NULL, NULL, selecttime); if (selcnt == 0) { logit (LOG_DAEMON, LOG_INFO, "%s: terminated by inactivity timeout (%ld secs.)", progname, timeout.tv_sec); sig_term (0); } if (selcnt < 0) { if (errno == EINTR) { continue; } logit (LOG_DAEMON, LOG_ALERT, "FATAL select: %s", get_errmsg ()); dumpcore = 1; abort (); } /* * Suspend signal processing while we do our stuff. * This is to prevent possible recursive calls to * nonreentrant functions. */ sigprocmask (SIG_BLOCK, &signals, NULL);/*#ifdef USR_CCA * Send out the resource query requests * if (qry_init == FALSE && dns_done == TRUE) { qry_init = TRUE; rq_req_init (); if (!alarm_set || global_auth_q.q) { alarm (1); alarm_set++; } }*//* #endif * USR_CCA */ for (i = 0; (aatv = sockfd_tv[i]) != NULL; i++) { time_t dummy_time; select_cur = time (&dummy_time); if (select_cur == (time_t) -1) { logit (LOG_DAEMON, LOG_ERR, "%s: time() error, #%d", func, errno); } if (FD_ISSET(aatv->sockfd, &readfds)) { len = sizeof (struct sockaddr_in); memset ((char *) &fromsin, '\0', len); result = recvfrom (aatv->sockfd, (char *) recv_buffer, (int) sizeof (recv_buffer) - MAX_SECRET_LENGTH, (int) 0, (struct sockaddr *) &fromsin, & len); if (result < 0) { if (errno == ECONNREFUSED) { result = 0; } else { break; } } if (result > 0) /* Handle received request */ { /* For some event.value to be filled */ /* in on return from AATV recv call */ event.state = ST_ANY; event.a.aatv = aatv; event.isproxy = 0; event.xstring[0] = '\0'; authreq = aatv->recv (aatv->sockfd, & fromsin, ntohl(fromsin.sin_addr.s_addr), result, & event); if (authreq != (AUTH_REQ *) NULL) { authreq->fsm_aatv = aatv; state_machine (event, authreq); /* Set alarm if a request is pending */ if (!alarm_set && (global_acct_q.q || global_auth_q.q)) { alarm (1); alarm_set++; } } } } if ((time (0) - select_cur) > select_max) { tofmaxdelay = time (0); select_max = tofmaxdelay - select_cur; } } } while (result >= 0); logit (LOG_DAEMON, LOG_ALERT, "%s: FATAL recvfrom: returned %d '%s'", func, result, get_errmsg ()); dumpcore = 1; abort ();} /* end of main () *//************************************************************************* * * Function: aatv_process_end * * Purpose: Start up next deferred request on a forking type AATV. * *************************************************************************/static voidaatv_process_end (aatv)AATV *aatv;{ u_char save_state; int evalue; PROC_ENT *pe; AUTH_REQ *authreq; char estring[sizeof (pe->estring)]; static char *func = "aatv_process_end"; dprintf(2, (LOG_DAEMON, LOG_DEBUG, "%s: entered", func)); /* Only applies for forking type AATVs. */ if (aatv == (AATV *) NULL || (aatv->aatvfunc_type != AA_FORK && aatv->aatvfunc_type != AA_FREPLY)) { return; } /* * See if AATV was at process maximum and * if we are able to de-queue anything. */ aatv->proc_cnt--; if (((pe = aatv->proc_q) == (PROC_ENT *) NULL) || (aatv->proc_cnt >= aatv->proc_max)) { return; } authreq = pe->authreq; dprintf(2, (LOG_DAEMON, LOG_DEBUG, "%s: proc_ent [%d '%s' '%s' %d '%s']", func, pe->state, (pe->fsm_aatv == (AATV *) NULL) ? (u_char *) "?" : pe->fsm_aatv->id, (pe->sub_aatv == (AATV *) NULL) ? (u_char *) "?" : pe->sub_aatv->id, pe->evalue, (pe->estring[0] == '\0') ? "?" : pe->estring)); /* Unlink proc_ent from the authreq. */ save_state = authreq->state; authreq->state = pe->state; authreq->fsm_aatv = pe->fsm_aatv; authreq->direct_aatv = pe->direct_aatv; evalue = pe->evalue; strncpy (estring, pe->estring, sizeof (estring)); dprintf(2, (LOG_DAEMON, LOG_DEBUG, "%s: invoking AATV '%s'", func, (pe->sub_aatv == (AATV *) NULL) ? (u_char *) "?" : pe->sub_aatv->id)); /* Unlink and free this proc_ent structure. */ authreq->proc_q = pe->next; free_proc_ent (pe); /* Now, process the de-queued request. */ call_action (aatv, authreq, evalue, estring); authreq->state = save_state; return;} /* end of aatv_process_end () *//************************************************************************* * * Function: acc_chal_action * * Purpose: Return EV_ACC_CHAL event for FSM purposes. * *************************************************************************/static intacc_chal_action (authreq, value, afpar)AUTH_REQ *authreq;int value;char *afpar;{ static char *func = "acc_chal_action"; dprintf(4, (LOG_DAEMON, LOG_DEBUG, "%s: entered", func)); return EV_ACC_CHAL;} /* end of acc_chal_action () *//************************************************************************* * * Function: authreq_dup_check * * Purpose: Determine if a authreq1 is a duplicate of authreq2. * * Returns: 0, if not a duplicate, * 1, if is a duplicate. * *************************************************************************/static intauthreq_dup_check (auth1, auth2, p_pw_vp1, p_pw1, p_why)AUTH_REQ *auth1; /* Authreq to check. */AUTH_REQ *auth2; /* Authreq to compare against. */VALUE_PAIR **p_pw_vp1; /* Password found in auth1 (if any) */char **p_pw1; /* Decrypted password found in auth1 (if any) */char **p_why; /* Message indicating why decision was made. */{ int vp_type; /* attribute type (string, etc.) */ DICT_ATTR *da; /* What dictionary entry it is. */ VALUE_PAIR *pw_vp1 = NULL_VP; /* Save password. */ VALUE_PAIR *pw_vp2 = NULL_VP; /* Save password. */ VALUE_PAIR *vp1; VALUE_PAIR *vp2; char *pw1 = *p_pw1; /* Saved password (if any) */ char pw2[AUTH_PASS_LEN + 1]; static char pw1_buff[AUTH_PASS_LEN + 1]; static char *func = "authreq_dup_check"; dprintf(2, (LOG_DAEMON, LOG_DEBUG, "%s: entered", func)); /* * If the packet types are different, * or the source IP address is different, * or the source UDP port is different, * or the lengths are different, then * it can not be a duplicate. */ if (auth1->code != auth2->code || /* Packet type */ auth1->ipaddr != auth2->ipaddr || /* Source IP address */ auth1->udp_port != auth2->udp_port || /* Source UDP port # */ auth1->rcv_len != auth2->rcv_len) /* Packet length */ { /* Definitely is NOT a duplicate. */ *p_why = "source, packet type or length different"; return (0); } /* * If the packet type, source IP address, * the source UDP port, the sequence number, * and the reply vector are the same, then * it is a duplicate. */ if (auth1->rep_id == auth2->rep_id) { if (memcmp (auth1->repvec, auth2->repvec, AUTH_VECTOR_LEN) == 0) { /* Definitely IS a duplicate. */ *p_why = "reply id and authenticating vector match"; return (1); } } /* * Packet type, source IP address, source UDP port, * and received length are all the same. Plus * either the sequence number or the authenticating * vector are different (or both). * * If the client is not a NAS (assume it's a PROXY), * presume that it will change the reply id and the * authenticating vector only for completely new * requests, nor for retransmissions. For instance, * the Merit AAA Server does NOT change the reply id * and the authenticating vector when it retransmits. * * However, allow some non-NAS clients to require the * more extensive checking by configuring "check_all" * in the "clients" file, if that proves necessary. */ if ((auth1->client->client_type & CE_NAS) == CE_NAS) /* came from NAS */ { /* * For some NAS vendors, the reply id and authenticating * vector are changed based on PPP exchanges, so if the * PPP client retransmits, everything is the same EXCEPT * the reply ID and vector. * * These requests need to be processed further by * comparing each and every attribute. The attribute * order is assumed to be preserved for these kinds of * re-transmissions. * * The default should be to do more extensive checking, * but some NAS vendors may not behave in this way. * Therefore, let the check be overridden by a configuration * in the "clients" file. */ if ((auth1->client->client_type & CE_NO_CHECK) == CE_NO_CHECK) { /* * The clients file indicates that PPP retransmissions * won't cause the reply id and authenticating vector * to be changed. * * Leave now, indicating that this is NOT a duplicate. */ *p_why = "new request (NAS, config)"; return (0); } /* Fall through to more extensive checking. */ } else /* was not from a NAS */ { if ((auth1->client->client_type & CE_CHECK_ALL) == 0) { *p_why = "new request (non-NAS, default)"; return (0); } } /* * EXTENSIVE, attribute by attribute checking. * * Still may be a duplicate, check all attributes to be sure. * * "vp1" is the current attribute/value pair from the * incoming request. * * "vp2" is the attribute/value pair from the request * which we are checking to see if it is a duplicate. */ for (vp1 = auth1->request, vp2 = auth2->request; (vp1 != NULL_VP) && (vp2 != NULL_VP); vp1 = vp1->next, vp2 = vp2->next) { /* * The lvalue of the attribute structure is the * data payload for the integer types and the * length of the string types. Since it is always * compared, check it here for effeciency. * * Check it first, because new, incoming requests * which are retransmissions of already enqueued * requests will probably have the same attributes * in the same order, differing only in their value(s). */ if (vp1->lvalue != vp2->lvalue) /* Definitely not duplicate. */ { *p_why = "not a dup (value/length)"; return (0); } /* Easy check for attribute and vendor_id match */ if (vp1->ap != vp2->ap) /* Definitely is not a duplicate. */ { *p_why = "not a dup (attr)"; return (0); } /* Compare tags, too. */ if (vp1->tag != vp2->tag) { *p_why = "not a dup (tags)"; return (0); } da = vp1->ap; /* Get dictionary entry */ vp_type = da->type; /* Attribute type (string, etc.) */ /* * If this attribute is not a string type, * then all the comparisons are done. * Attributes vp1 and vp2 are equal. */ if ((vp_type != PW_TYPE_STRING) && (vp_type != PW_TYPE_TAG_STR)#if defined(BINARY_FILTERS) && (vp_type != PW_TYPE_FILTER_BINARY)#endif /* BINARY_FILTERS */#if !defined(NO_EXTENDED_TYPES) && (vp_type != PW_TYPE_OCTETS) && (vp_type != PW_TYPE_VENDOR)#endif /* !defined(NO_EXTENDED_TYPES) */ ) { continue; /* Attributes vp1 and vp2 are equal. */ } /* * If this attribute is a User-Password, * then special case code handles it below. */ if ((vp1->attribute != PW_USER_PASSWORD) || (da->vendor_id != VC_RADIUS)) { /* Default string matching check. */ if (memcmp (vp1->strvalue, vp2->strvalue, vp1->lvalue) == 0) { /* * The request might be a duplicate * (if all the rest match, too.) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -