📄 radius.c
字号:
u_char *p = cpassword; if (response_len != MS_CHAP2_RESPONSE_LEN) return 0; *p++ = id; /* The idiots use a different field order in RADIUS than PPP */ memcpy(p, rmd->Flags, sizeof(rmd->Flags)); p += sizeof(rmd->Flags); memcpy(p, rmd->PeerChallenge, sizeof(rmd->PeerChallenge)); p += sizeof(rmd->PeerChallenge); memcpy(p, rmd->Reserved, sizeof(rmd->Reserved)); p += sizeof(rmd->Reserved); memcpy(p, rmd->NTResp, sizeof(rmd->NTResp)); rc_avpair_add(&send, PW_MS_CHAP_CHALLENGE, challenge, challenge_len, VENDOR_MICROSOFT); rc_avpair_add(&send, PW_MS_CHAP2_RESPONSE, cpassword, MS_CHAP2_RESPONSE_LEN + 1, VENDOR_MICROSOFT); break; }#endif } if (*remote_number) { rc_avpair_add(&send, PW_CALLING_STATION_ID, remote_number, 0, VENDOR_NONE); } else if (ipparam) rc_avpair_add(&send, PW_CALLING_STATION_ID, ipparam, 0, VENDOR_NONE); /* Add user specified vp's */ if (rstate.avp) rc_avpair_insert(&send, NULL, rc_avpair_copy(rstate.avp)); /* * make authentication with RADIUS server */ if (rstate.authserver) { result = rc_auth_using_server(rstate.authserver, rstate.client_port, send, &received, radius_msg, req_info); } else { result = rc_auth(rstate.client_port, send, &received, radius_msg, req_info); } if (result == OK_RC) { if (!rstate.done_chap_once) { if (radius_setparams(received, radius_msg, req_info, digest, challenge, message, message_space) < 0) { error("%s", radius_msg); result = ERROR_RC; } else { rstate.done_chap_once = 1; } } } rc_avpair_free(received); rc_avpair_free (send); return (result == OK_RC);}/*********************************************************************** %FUNCTION: make_username_realm* %ARGUMENTS:* user -- the user given to pppd* %RETURNS:* Nothing* %DESCRIPTION:* Copies user into rstate.user. If it lacks a realm (no "@domain" part),* then the default realm from the radiusclient config file is added.***********************************************************************/static voidmake_username_realm(char *user){ char *default_realm; if ( user != NULL ) { strlcpy(rstate.user, user, sizeof(rstate.user)); } else { rstate.user[0] = 0; } default_realm = rc_conf_str("default_realm"); if (!strchr(rstate.user, '@') && default_realm && (*default_realm != '\0')) { strlcat(rstate.user, "@", sizeof(rstate.user)); strlcat(rstate.user, default_realm, sizeof(rstate.user)); }}/*********************************************************************** %FUNCTION: radius_setparams* %ARGUMENTS:* vp -- received value-pairs* msg -- buffer in which to place error message. Holds up to BUF_LEN chars* %RETURNS:* >= 0 on success; -1 on failure* %DESCRIPTION:* Parses attributes sent by RADIUS server and sets them in pppd.***********************************************************************/static intradius_setparams(VALUE_PAIR *vp, char *msg, REQUEST_INFO *req_info, struct chap_digest_type *digest, unsigned char *challenge, char *message, int message_space){ u_int32_t remote; int ms_chap2_success = 0;#ifdef MPPE int mppe_enc_keys = 0; /* whether or not these were received */ int mppe_enc_policy = 0; int mppe_enc_types = 0;#endif /* Send RADIUS attributes to anyone else who might be interested */ if (radius_attributes_hook) { (*radius_attributes_hook)(vp); } /* * service type (if not framed then quit), * new IP address (RADIUS can define static IP for some users), */ while (vp) { if (vp->vendorcode == VENDOR_NONE) { switch (vp->attribute) { case PW_SERVICE_TYPE: /* check for service type */ /* if not FRAMED then exit */ if (vp->lvalue != PW_FRAMED) { slprintf(msg, BUF_LEN, "RADIUS: wrong service type %ld for %s", vp->lvalue, rstate.user); return -1; } break; case PW_FRAMED_PROTOCOL: /* check for framed protocol type */ /* if not PPP then also exit */ if (vp->lvalue != PW_PPP) { slprintf(msg, BUF_LEN, "RADIUS: wrong framed protocol %ld for %s", vp->lvalue, rstate.user); return -1; } break; case PW_SESSION_TIMEOUT: /* Session timeout */ maxconnect = vp->lvalue; break;#ifdef MAXOCTETS case PW_SESSION_OCTETS_LIMIT: /* Session traffic limit */ maxoctets = vp->lvalue; break; case PW_OCTETS_DIRECTION: /* Session traffic limit direction check */ maxoctets_dir = ( vp->lvalue > 4 ) ? 0 : vp->lvalue ; break;#endif case PW_ACCT_INTERIM_INTERVAL: /* Send accounting updates every few seconds */ rstate.acct_interim_interval = vp->lvalue; /* RFC says it MUST NOT be less than 60 seconds */ /* We use "0" to signify not sending updates */ if (rstate.acct_interim_interval && rstate.acct_interim_interval < 60) { rstate.acct_interim_interval = 60; } break; case PW_FRAMED_IP_ADDRESS: /* seting up remote IP addresses */ remote = vp->lvalue; if (remote == 0xffffffff) { /* 0xffffffff means user should be allowed to select one */ rstate.any_ip_addr_ok = 1; } else if (remote != 0xfffffffe) { /* 0xfffffffe means NAS should select an ip address */ remote = htonl(vp->lvalue); if (bad_ip_adrs (remote)) { slprintf(msg, BUF_LEN, "RADIUS: bad remote IP address %I for %s", remote, rstate.user); return -1; } rstate.choose_ip = 1; rstate.ip_addr = remote; } break; case PW_CLASS: /* Save Class attribute to pass it in accounting request */ if (vp->lvalue <= MAXCLASSLEN) { rstate.class_len=vp->lvalue; memcpy(rstate.class, vp->strvalue, rstate.class_len); } /* else too big for our buffer - ignore it */ break; }#ifdef CHAPMS } else if (vp->vendorcode == VENDOR_MICROSOFT) { switch (vp->attribute) { case PW_MS_CHAP2_SUCCESS: if ((vp->lvalue != 43) || strncmp(vp->strvalue + 1, "S=", 2)) { slprintf(msg,BUF_LEN,"RADIUS: bad MS-CHAP2-Success packet"); return -1; } if (message != NULL) strlcpy(message, vp->strvalue + 1, message_space); ms_chap2_success = 1; break;#ifdef MPPE case PW_MS_CHAP_MPPE_KEYS: if (radius_setmppekeys(vp, req_info, challenge) < 0) { slprintf(msg, BUF_LEN, "RADIUS: bad MS-CHAP-MPPE-Keys attribute"); return -1; } mppe_enc_keys = 1; break; case PW_MS_MPPE_SEND_KEY: case PW_MS_MPPE_RECV_KEY: if (radius_setmppekeys2(vp, req_info) < 0) { slprintf(msg, BUF_LEN, "RADIUS: bad MS-MPPE-%s-Key attribute", (vp->attribute == PW_MS_MPPE_SEND_KEY)? "Send": "Recv"); return -1; } mppe_enc_keys = 1; break; case PW_MS_MPPE_ENCRYPTION_POLICY: mppe_enc_policy = vp->lvalue; /* save for later */ break; case PW_MS_MPPE_ENCRYPTION_TYPES: mppe_enc_types = vp->lvalue; /* save for later */ break;#endif /* MPPE */#if 0 case PW_MS_PRIMARY_DNS_SERVER: case PW_MS_SECONDARY_DNS_SERVER: case PW_MS_PRIMARY_NBNS_SERVER: case PW_MS_SECONDARY_NBNS_SERVER: break;#endif }#endif /* CHAPMS */ } vp = vp->next; } /* Require a valid MS-CHAP2-SUCCESS for MS-CHAPv2 auth */ if (digest && (digest->code == CHAP_MICROSOFT_V2) && !ms_chap2_success) return -1;#ifdef MPPE /* * Require both policy and key attributes to indicate a valid key. * Note that if the policy value was '0' we don't set the key! */ if (mppe_enc_policy && mppe_enc_keys) { mppe_keys_set = 1; /* Set/modify allowed encryption types. */ if (mppe_enc_types) set_mppe_enc_types(mppe_enc_policy, mppe_enc_types); }#endif return 0;}#ifdef MPPE/*********************************************************************** %FUNCTION: radius_setmppekeys* %ARGUMENTS:* vp -- value pair holding MS-CHAP-MPPE-KEYS attribute* req_info -- radius request information used for encryption* %RETURNS:* >= 0 on success; -1 on failure* %DESCRIPTION:* Decrypt the "key" provided by the RADIUS server for MPPE encryption.* See RFC 2548.***********************************************************************/static intradius_setmppekeys(VALUE_PAIR *vp, REQUEST_INFO *req_info, unsigned char *challenge){ int i; MD5_CTX Context; u_char plain[32]; u_char buf[16]; if (vp->lvalue != 32) { error("RADIUS: Incorrect attribute length (%d) for MS-CHAP-MPPE-Keys", vp->lvalue); return -1; } memcpy(plain, vp->strvalue, sizeof(plain)); MD5_Init(&Context); MD5_Update(&Context, req_info->secret, strlen(req_info->secret)); MD5_Update(&Context, req_info->request_vector, AUTH_VECTOR_LEN); MD5_Final(buf, &Context); for (i = 0; i < 16; i++) plain[i] ^= buf[i]; MD5_Init(&Context); MD5_Update(&Context, req_info->secret, strlen(req_info->secret)); MD5_Update(&Context, vp->strvalue, 16); MD5_Final(buf, &Context); for(i = 0; i < 16; i++) plain[i + 16] ^= buf[i]; /* * Annoying. The "key" returned is just the NTPasswordHashHash, which * the NAS (us) doesn't need; we only need the start key. So we have * to generate the start key, sigh. NB: We do not support the LM-Key. */ mppe_set_keys(challenge, &plain[8]); return 0; }/*********************************************************************** %FUNCTION: radius_setmppekeys2* %ARGUMENTS:* vp -- value pair holding MS-MPPE-SEND-KEY or MS-MPPE-RECV-KEY attribute* req_info -- radius request information used for encryption* %RETURNS:* >= 0 on success; -1 on failure* %DESCRIPTION:* Decrypt the key provided by the RADIUS server for MPPE encryption.* See RFC 2548.***********************************************************************/static intradius_setmppekeys2(VALUE_PAIR *vp, REQUEST_INFO *req_info){ int i; MD5_CTX Context; u_char *salt = vp->strvalue; u_char *crypt = vp->strvalue + 2; u_char plain[32]; u_char buf[MD5_HASH_SIZE]; char *type = "Send"; if (vp->attribute == PW_MS_MPPE_RECV_KEY) type = "Recv"; if (vp->lvalue != 34) { error("RADIUS: Incorrect attribute length (%d) for MS-MPPE-%s-Key", vp->lvalue, type); return -1; } if ((salt[0] & 0x80) == 0) { error("RADIUS: Illegal salt value for MS-MPPE-%s-Key attribute", type); return -1; } memcpy(plain, crypt, 32); MD5_Init(&Context); MD5_Update(&Context, req_info->secret, strlen(req_info->secret)); MD5_Update(&Context, req_info->request_vector, AUTH_VECTOR_LEN); MD5_Update(&Context, salt, 2); MD5_Final(buf, &Context); for (i = 0; i < 16; i++) plain[i] ^= buf[i]; if (plain[0] != sizeof(mppe_send_key) /* 16 */) { error("RADIUS: Incorrect key length (%d) for MS-MPPE-%s-Key attribute", (int) plain[0], type); return -1; } MD5_Init(&Context); MD5_Update(&Context, req_info->secret, strlen(req_info->secret)); MD5_Update(&Context, crypt, 16); MD5_Final(buf, &Context); plain[16] ^= buf[0]; /* only need the first byte */ if (vp->attribute == PW_MS_MPPE_SEND_KEY) memcpy(mppe_send_key, plain + 1, 16); else memcpy(mppe_recv_key, plain + 1, 16); return 0;}#endif /* MPPE *//*********************************************************************** %FUNCTION: radius_acct_start* %ARGUMENTS:* None* %RETURNS:* Nothing* %DESCRIPTION:* Sends a "start" accounting message to the RADIUS server.***********************************************************************/static voidradius_acct_start(void){ UINT4 av_type; int result; VALUE_PAIR *send = NULL; ipcp_options *ho = &ipcp_hisoptions[0]; u_int32_t hisaddr; if (!rstate.initialized) { return; } rstate.start_time = time(NULL); strncpy(rstate.session_id, rc_mksid(), sizeof(rstate.session_id)); rc_avpair_add(&send, PW_ACCT_SESSION_ID, rstate.session_id, 0, VENDOR_NONE); rc_avpair_add(&send, PW_USER_NAME, rstate.user, 0, VENDOR_NONE); if (rstate.class_len > 0) rc_avpair_add(&send, PW_CLASS,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -