/* * radius.c * * Written by Michael Bretterklieber * Written by Brendan Bank */ #include "radius.h" #include "pptp.h" #include "pppoe.h" #include "chap.h" #include "ngfunc.h" #include #include #include #include /* Global variables */ static int RadiusSetCommand(int ac, char *av[], void *arg); static int RadiusAddServer (short request_type); static int RadiusInit(short request_type); static void RadiusClose(void); static const char * RadiusMPPEPolicyname(int policy); static const char * RadiusMPPETypesname(int types); /* compatibility functions until libradius has these builtin */ static int rad_demangle2(struct rad_handle *, const void *, size_t, u_char *); static int rad_demangle_mppe_key2(struct rad_handle *, const void *, size_t, u_char *, size_t *); /* Set menu options */ enum { SET_SERVER, SET_ME, SET_TIMEOUT, SET_RETRIES, SET_CONFIG, SET_UPDATE }; /* * GLOBAL VARIABLES */ const struct cmdtab RadiusSetCmds[] = { { "server [auth port] [acct port]", "Set radius server parameters" , RadiusSetCommand, NULL, (void *) SET_SERVER }, { "me ", "Set NAS IP address" , RadiusSetCommand, NULL, (void *) SET_ME }, { "timeout ", "Set timeout in seconds", RadiusSetCommand, NULL, (void *) SET_TIMEOUT }, { "retries <# retries>", "set number of retries", RadiusSetCommand, NULL, (void *) SET_RETRIES }, { "config ", "set path to config file for libradius", RadiusSetCommand, NULL, (void *) SET_CONFIG }, { "acct-update ", "set update interval", RadiusSetCommand, NULL, (void *) SET_UPDATE }, { NULL }, }; /* Set menu options */ static int RadiusSetCommand(int ac, char *av[], void *arg) { static char function[] = "RadiusSetCommand"; RadConf const conf = &bund->radius.conf; RadServe_Conf server; RadServe_Conf t_server; int val, count; /* Log(LG_RADIUS, ("[%s] %s: started", lnk->name, function)); */ if (ac == 0) return(-1); switch ((int) arg) { case SET_SERVER: if (ac > 4 || ac < 2) { return(-1); } count = 0; for ( t_server = conf->server ; t_server ; t_server = t_server->next) { count++; } if (count > RADIUS_MAX_SERVERS) { Log(LG_RADIUS, ("[%s] %s: cannot configure more than %d servers", lnk->name, function, RADIUS_MAX_SERVERS)); return (-1); } server = Malloc(MB_RADIUS, sizeof(*server)); server->auth_port = 1812; server->acct_port = 1813; server->next = NULL; if (strlen(av[0]) > 255) { Log(LG_ERR, ("Hostname too long!. > 255 char.")); return(-1); } if (strlen(av[1]) > 127) { Log(LG_ERR, ("Shared Secret too long! > 127 char.")); return(-1); } if (ac > 2 && atoi(av[2]) < 65535 && atoi(av[2]) > 1) { server->auth_port = atoi (av[2]); } else if ( ac > 2 ) { Log(LG_ERR, ("Auth Port number too high > 65535")); return(-1); } if (ac > 3 && atoi(av[3]) < 65535 && atoi(av[3]) > 1) { server->acct_port = atoi (av[3]); } else if ( ac > 3 ) { Log(LG_ERR, ("Acct Port number too high > 65535")); return(-1); } server->hostname = Malloc(MB_RADIUS, strlen(av[0]) + 1); server->sharedsecret = Malloc(MB_RADIUS, strlen(av[1]) + 1); sprintf(server->hostname, "%s" , av[0]); sprintf(server->sharedsecret, "%s" , av[1]); if (conf->server != NULL) server->next = conf->server; conf->server = server; break; case SET_ME: val = inet_aton(*av, &(conf->radius_me)); if (val == 0) Log(LG_ERR, ("Bad NAS address.")); break; case SET_TIMEOUT: val = atoi(*av); if (val <= 0) Log(LG_ERR, ("Timeout must be positive.")); else conf->radius_timeout = val; break; case SET_UPDATE: val = atoi(*av); if (val <= 0) Log(LG_ERR, ("Update interval must be positive.")); else conf->acct_update = val; break; case SET_RETRIES: val = atoi(*av); if (val <= 0) Log(LG_ERR, ("Retries must be positive.")); else conf->radius_retries = val; break; case SET_CONFIG: if (strlen(av[0]) > PATH_MAX) Log(LG_ERR, (" PATH_MAX exceeded for config file.")); else strcpy(conf->file, av[0]); break; default: assert(0); } return 0; } int RadiusInit(short request_type) { struct radius *rad = &bund->radius; RadiusClose(); if (request_type == RAD_ACCESS_REQUEST) { rad->radh = rad_open(); if (rad->radh == NULL) { Log(LG_RADIUS, ("[%s] RADIUS: rad_open failed", lnk->name)); return (RAD_NACK); } /* RAD_ACCOUNTING_REQUEST */ } else { rad->radh = rad_acct_open(); if (rad->radh == NULL) { Log(LG_RADIUS, ("[%s] RADIUS: rad_acct_open failed", lnk->name)); return (RAD_NACK); } } if (strlen(bund->radius.conf.file)) { Log(LG_RADIUS, ("[%s] RADIUS: using %s", lnk->name, bund->radius.conf.file)); if (rad_config(rad->radh, bund->radius.conf.file) != 0) { Log(LG_RADIUS, ("[%s] RADIUS: rad_config: %s", lnk->name, rad_strerror(rad->radh))); RadiusClose(); return (RAD_NACK); } } if (RadiusAddServer(request_type) == RAD_NACK) { RadiusClose(); return (RAD_NACK); } return RAD_ACK; } void RadiusClose(void) { struct radius *rad = &bund->radius; if (rad->radh != NULL) rad_close(rad->radh); rad->radh = NULL; } static int GetLinkID(void) { int port, i; port =- 1; for (i = 0; i < gNumLinks; i++) { if (gLinks[i] && gLinks[i]==lnk) { port = i; } } return port; }; void RadiusDown(void) { Log(LG_RADIUS, ("[%s] RADIUS: Down Event", lnk->name)); RadiusDestroy(); } void RadiusDestroy(void) { struct radius *rad = &bund->radius; struct radius_acl *acls, *acls1; RadiusClose(); free(rad->msdomain); rad->msdomain = NULL; free(rad->mschap_error); rad->mschap_error = NULL; free(rad->mschapv2resp); rad->mschapv2resp = NULL; free(rad->reply_message); rad->reply_message = NULL; acls = rad->acl_rule; while (acls != NULL) { acls1 = acls->next; free(acls); acls = acls1; }; acls = rad->acl_pipe; while (acls != NULL) { acls1 = acls->next; free(acls); acls = acls1; }; acls = rad->acl_queue; while (acls != NULL) { acls1 = acls->next; free(acls); acls = acls1; }; memset(rad, 0, sizeof(struct radius) - sizeof(struct radiusconf)); } int RadiusStart(short request_type) { static char function[] = "RadiusStart"; struct radius *rad = &bund->radius; char host[MAXHOSTNAMELEN]; struct in_addr *peer_ip; char *peeripname; u_char *peer_mac; char peermacname[18]; if (RadiusInit(request_type) == RAD_NACK) return RAD_NACK; if (gethostname(host, sizeof (host)) == -1) { Log(LG_RADIUS, ("[%s] RADIUS: %s: gethostname() failed", lnk->name, function)); return (RAD_NACK); } if (rad_create_request(rad->radh, request_type) == -1) { Log(LG_RADIUS, ("[%s] RADIUS: rad_create_request: %s", lnk->name, rad_strerror(rad->radh))); return (RAD_NACK); } if (rad_put_string(rad->radh, RAD_NAS_IDENTIFIER, host) == -1) { Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_string(host) failed %s", lnk->name, function, rad_strerror(rad->radh))); RadiusClose(); return (RAD_NACK); } if (rad->conf.radius_me.s_addr != 0) { if (rad_put_addr(rad->radh, RAD_NAS_IP_ADDRESS, rad->conf.radius_me) == -1) { Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_addr(RAD_NAS_IP_ADDRESS) failed %s", lnk->name, function, rad_strerror(rad->radh))); RadiusClose(); return (RAD_NACK); } } if (rad_put_int(rad->radh, RAD_NAS_PORT, GetLinkID()) == -1) { Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_int(RAD_NAS_PORT) failed %s", lnk->name, function, rad_strerror(rad->radh))); RadiusClose(); return (RAD_NACK); } if (rad_put_int(rad->radh, RAD_NAS_PORT_TYPE, RAD_VIRTUAL) == -1) { Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_int(RAD_NAS_PORT_TYPE) failed %s", lnk->name, function, rad_strerror(rad->radh))); RadiusClose(); return (RAD_NACK); } if (rad_put_int(rad->radh, RAD_SERVICE_TYPE, RAD_FRAMED) == -1) { Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_int(RAD_SERVICE_TYPE) failed %s", lnk->name, function, rad_strerror(rad->radh))); RadiusClose(); return (RAD_NACK); } if (rad_put_int(rad->radh, RAD_FRAMED_PROTOCOL, RAD_PPP) == -1) { Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_int(RAD_FRAMED_PROTOCOL) failed %s", lnk->name, function, rad_strerror(rad->radh))); RadiusClose(); return (RAD_NACK); } peer_ip = PptpGetPeerIp(); if (peer_ip != NULL && peer_ip->s_addr != 0) { peeripname = inet_ntoa(*peer_ip); if (peeripname != NULL) { if (rad_put_string(rad->radh, RAD_CALLING_STATION_ID, peeripname) == -1) { Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_string(RAD_CALLING_STATION_ID) failed %s", lnk->name, function, rad_strerror(rad->radh))); RadiusClose(); return (RAD_NACK); } } } peer_mac = PppoeGetPeerAddr(); if ((peer_mac != NULL) && ((peer_mac[0] != 0) || (peer_mac[1] != 0) || (peer_mac[2] != 0) || (peer_mac[3] !=0 ) || (peer_mac[4] != 0) || (peer_mac[5] != 0)) ) { snprintf(peermacname, sizeof(peermacname), "%02x%02x%02x%02x%02x%02x", peer_mac[0], peer_mac[1], peer_mac[2], peer_mac[3], peer_mac[4], peer_mac[5]); if (rad_put_string(rad->radh, RAD_CALLING_STATION_ID, peermacname) == -1) { Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_string(RAD_CALLING_STATION_ID) failed %s", lnk->name, function, rad_strerror(rad->radh))); RadiusClose(); return (RAD_NACK); } } return RAD_ACK; } int RadiusPutAuth(const char *name, const char *password, int passlen, const char *challenge, int challenge_size, u_char chapid, int auth_type) { static char function[] = "RadiusPutAuth"; struct radius *rad = &bund->radius; struct rad_chapvalue rad_chapval; struct rad_mschapvalue rad_mschapval; struct rad_mschapv2value rad_mschapv2val; struct mschapvalue *mschapval; struct mschapv2value *mschapv2val; if (name == NULL || password == NULL) { Log(LG_RADIUS, ("[%s] RADIUS: %s: name or password NULL", lnk->name, function)); return (RAD_NACK); } /* Remember authname */ strncpy(rad->authname, name, AUTH_MAX_AUTHNAME); if (rad_put_string(rad->radh, RAD_USER_NAME, name) == -1) { Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_string(username) failed %s", lnk->name, function, rad_strerror(rad->radh))); RadiusClose(); return (RAD_NACK); } /* Remember Auth-Type */ rad->auth_type = auth_type; switch (auth_type) { case CHAP_ALG_MSOFT: Log(LG_RADIUS, ("[%s] RADIUS: %s: RADIUS_CHAP (MSOFTv1) peer name: %s", lnk->name, function, name)); if (passlen != 49) { Log(LG_RADIUS, ("[%s] RADIUS: %s: RADIUS_CHAP (MSOFTv1) unrecognised key length %d/%d", lnk->name, function, passlen, 49)); RadiusClose(); return RAD_NACK; } if (rad_put_vendor_attr(rad->radh, RAD_VENDOR_MICROSOFT, RAD_MICROSOFT_MS_CHAP_CHALLENGE, challenge, challenge_size) == -1) { Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_vendor_attr(RAD_MICROSOFT_MS_CHAP_CHALLENGE) failed %s", lnk->name, function, rad_strerror(rad->radh))); RadiusClose(); return (RAD_NACK); } mschapval = (struct mschapvalue *)password; rad_mschapval.ident = chapid; rad_mschapval.flags = 0x01; memcpy(rad_mschapval.lm_response, mschapval->lmHash, 24); memcpy(rad_mschapval.nt_response, mschapval->ntHash, 24); if (rad_put_vendor_attr(rad->radh, RAD_VENDOR_MICROSOFT, RAD_MICROSOFT_MS_CHAP_RESPONSE, &rad_mschapval, sizeof rad_mschapval) == -1) { Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_vendor_attr(RAD_MICROSOFT_MS_CHAP_RESPONSE) failed %s", lnk->name, function, rad_strerror(rad->radh))); RadiusClose(); return (RAD_NACK); } break; case CHAP_ALG_MSOFTv2: Log(LG_RADIUS, ("[%s] RADIUS: %s: RADIUS_CHAP (MSOFTv2) peer name: %s", lnk->name, function, name)); if (rad_put_vendor_attr(rad->radh, RAD_VENDOR_MICROSOFT, RAD_MICROSOFT_MS_CHAP_CHALLENGE, challenge, challenge_size) == -1) { Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_vendor_attr(RAD_MICROSOFT_MS_CHAP_CHALLENGE) failed %s", lnk->name, function, rad_strerror(rad->radh))); RadiusClose(); return (RAD_NACK); } if (passlen != sizeof(*mschapv2val)) { Log(LG_RADIUS, ("[%s] RADIUS: %s: RADIUS_CHAP (MSOFTv2) unrecognised key length %d/%d", lnk->name, function, passlen, sizeof(*mschapv2val))); RadiusClose(); return RAD_NACK; } mschapv2val = (struct mschapv2value *)password; rad_mschapv2val.ident = chapid; rad_mschapv2val.flags = mschapv2val->flags; memcpy(rad_mschapv2val.response, mschapv2val->ntHash, sizeof rad_mschapv2val.response); memset(rad_mschapv2val.reserved, '\0', sizeof rad_mschapv2val.reserved); memcpy(rad_mschapv2val.pchallenge, mschapv2val->peerChal, sizeof rad_mschapv2val.pchallenge); if (rad_put_vendor_attr(rad->radh, RAD_VENDOR_MICROSOFT, RAD_MICROSOFT_MS_CHAP2_RESPONSE, &rad_mschapv2val, sizeof rad_mschapv2val) == -1) { Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_vendor_attr(RAD_MICROSOFT_MS_CHAP2_RESPONSE) failed %s", lnk->name, function, rad_strerror(rad->radh))); RadiusClose(); return (RAD_NACK); } break; case CHAP_ALG_MD5: /* Radius wants the CHAP Ident in the first byte of the CHAP-Password */ rad_chapval.ident = chapid; memcpy(rad_chapval.response, password, passlen); Log(LG_RADIUS, ("[%s] RADIUS: %s: RADIUS_CHAP (MD5) peer name: %s", lnk->name, function, name)); if (rad_put_attr(rad->radh, RAD_CHAP_PASSWORD, &rad_chapval, passlen + 1) == -1 || rad_put_attr(rad->radh, RAD_CHAP_CHALLENGE, challenge, challenge_size) == -1) { Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_string(password) failed %s", lnk->name, function, rad_strerror(rad->radh))); RadiusClose(); return (RAD_NACK); } break; case RADIUS_PAP: Log(LG_RADIUS, ("[%s] RADIUS: %s: RADIUS_PAP DEBUG: peer name: %s", lnk->name, function, name)); if (rad_put_string(rad->radh, RAD_USER_PASSWORD, password) == -1) { Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_string(password) failed %s", lnk->name, function, rad_strerror(rad->radh))); RadiusClose(); return (RAD_NACK); } break; default: Log(LG_RADIUS, ("[%s] RADIUS: %s: RADIUS auth type unkown", lnk->name, function)); RadiusClose(); return (RAD_NACK); break; } return RAD_ACK; } /* XXX mbretter: b0rked */ int RadiusPutChangePassword(const char *mschapvalue, int mschapvaluelen, u_char chapid, int chap_type) { static char function[] = "RadiusPutChangePassword"; struct radius *rad = &bund->radius; struct mschapv2value_cpw *mschapv2val_cpw; struct rad_mschapv2value_cpw rad_mschapv2val_cpw; struct rad_mschap_new_nt_pw new_nt_pw; int chunk; switch (chap_type) { case CHAP_ALG_MSOFT: Log(LG_RADIUS, ("[%s] RADIUS: %s: Password changing using MS-CHAPv1 not implemented", lnk->name, function)); return (RAD_NACK); break; case CHAP_ALG_MSOFTv2: mschapv2val_cpw = (struct mschapv2value_cpw *)mschapvalue; if (mschapvaluelen != sizeof(*mschapv2val_cpw)) { Log(LG_RADIUS, ("[%s] RADIUS: %s: RADIUS_CHAP (MSOFTv2) unrecognised key length %d/%d", lnk->name, function, mschapvaluelen, sizeof(*mschapv2val_cpw))); return RAD_NACK; } rad_mschapv2val_cpw.code = 7; rad_mschapv2val_cpw.ident = chapid; memcpy(rad_mschapv2val_cpw.encryptedHash, mschapv2val_cpw->encryptedHash, sizeof rad_mschapv2val_cpw.encryptedHash); memcpy(rad_mschapv2val_cpw.pchallenge, mschapv2val_cpw->peerChal, sizeof rad_mschapv2val_cpw.pchallenge); memset(rad_mschapv2val_cpw.reserved, '\0', sizeof rad_mschapv2val_cpw.reserved); memcpy(rad_mschapv2val_cpw.nt_response, mschapv2val_cpw->ntResponse, sizeof rad_mschapv2val_cpw.nt_response); memcpy(rad_mschapv2val_cpw.flags, mschapv2val_cpw->flags, sizeof rad_mschapv2val_cpw.flags); if (rad_put_vendor_attr(rad->radh, RAD_VENDOR_MICROSOFT, RAD_MICROSOFT_MS_CHAP2_PW, &rad_mschapv2val_cpw, sizeof rad_mschapv2val_cpw) == -1) { Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_vendor_attr(RAD_MICROSOFT_MS_CHAP2_PW) failed %s", lnk->name, function, rad_strerror(rad->radh))); RadiusClose(); return (RAD_NACK); } new_nt_pw.ident = chapid; for (chunk = 0; chunk < 4; chunk++) { new_nt_pw.chunk = chunk; printf("Chunk:%d\n",chunk); memcpy(new_nt_pw.data, &mschapv2val_cpw->encryptedPass[(sizeof new_nt_pw.data) * chunk], sizeof new_nt_pw.data); if (rad_put_vendor_attr(rad->radh, RAD_VENDOR_MICROSOFT, RAD_MICROSOFT_MS_CHAP_NT_ENC_PW, &new_nt_pw, sizeof new_nt_pw) == -1) { Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_vendor_attr(RAD_MICROSOFT_MS_CHAP_NT_ENC_PW) failed %s", lnk->name, function, rad_strerror(rad->radh))); RadiusClose(); return (RAD_NACK); } } break; default: Log(LG_RADIUS, ("[%s] RADIUS: %s: RADIUS auth type unkown", lnk->name, function)); RadiusClose(); return (RAD_NACK); break; } return RAD_ACK; } int RadiusSendRequest(void) { static char function[] = "RadiusSendRequest"; struct radius *rad = &bund->radius; struct timeval timelimit; struct timeval tv; int fd, n; #ifdef DEBUG Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_init_send_request ...", lnk->name, function)); #endif n = rad_init_send_request(rad->radh, &fd, &tv); if (n != 0) { Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_init_send_request failed: %d", lnk->name, function, n)); return RAD_NACK; } gettimeofday(&timelimit, NULL); timeradd(&tv, &timelimit, &timelimit); for ( ; ; ) { fd_set readfds; FD_ZERO(&readfds); FD_SET(fd, &readfds); #ifdef DEBUG Log(LG_RADIUS, ("[%s] RADIUS: %s: selecting ...", lnk->name, function)); #endif n = select(fd + 1, &readfds, NULL, NULL, &tv); if (n == -1) { Log(LG_RADIUS, ("[%s] RADIUS: %s: select failed: %s", lnk->name, function, strerror(errno))); return RAD_NACK; } if (!FD_ISSET(fd, &readfds)) { /* Compute a new timeout */ gettimeofday(&tv, NULL); timersub(&timelimit, &tv, &tv); if (tv.tv_sec > 0 || (tv.tv_sec == 0 && tv.tv_usec > 0)) /* Continue the select */ continue; } #ifdef DEBUG Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_continue_send_request ...", lnk->name, function)); #endif n = rad_continue_send_request(rad->radh, n, &fd, &tv); if (n != 0) break; gettimeofday(&timelimit, NULL); timeradd(&tv, &timelimit, &timelimit); } switch (n) { case RAD_ACCESS_ACCEPT: Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_ACCESS_ACCEPT for user %s", lnk->name, function, rad->authname)); rad->valid = 1; break; case RAD_ACCESS_REJECT: Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_ACCESS_REJECT for user %s", lnk->name, function, rad->authname)); rad->valid = 0; break; case RAD_ACCOUNTING_RESPONSE: Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_ACCOUNTING_RESPONSE for user %s", lnk->name, function, rad->authname)); return RAD_ACK; case -1: Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_send_request failed %s", lnk->name, function, rad_strerror(rad->radh))); RadiusClose(); return(RAD_NACK); break; default: Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_send_request: unexpected return value %s", lnk->name, function, rad_strerror(rad->radh))); RadiusClose(); return(RAD_NACK); } return RAD_ACK; } int RadiusPAPAuthenticate(const char *name, const char *password) { struct radius *rad = &bund->radius; RadiusDestroy(); if (RadiusStart(RAD_ACCESS_REQUEST) == RAD_NACK) return RAD_NACK; if (RadiusPutAuth(name, password, 0, NULL, NULL, 0, RADIUS_PAP) == RAD_NACK) return RAD_NACK; if (RadiusSendRequest() == RAD_NACK) return RAD_NACK; if (RadiusGetParams() == RAD_NACK) return RAD_NACK; if (rad->valid) { lnk->radius.authentic = 1; return RAD_ACK; } else { return RAD_NACK; } } int RadiusCHAPAuthenticate(const char *name, const char *password, int passlen, const char *challenge, int challenge_size, u_char chapid, int chap_type) { struct radius *rad = &bund->radius; RadiusDestroy(); if (RadiusStart(RAD_ACCESS_REQUEST) == RAD_NACK) return RAD_NACK; if (RadiusPutAuth(name, password, passlen, challenge, challenge_size, chapid, chap_type) == RAD_NACK) return RAD_NACK; if (RadiusSendRequest() == RAD_NACK) return RAD_NACK; if (RadiusGetParams() == RAD_NACK) return RAD_NACK; if (rad->valid) { lnk->radius.authentic = 1; return RAD_ACK; } else { return RAD_NACK; } } /* XXX mbretter: b0rked */ int RadiusMSCHAPChangePassword(const char *mschapvalue, int mschapvaluelen, const char *challenge, int challenge_size, u_char chapid, int chap_type) { static char function[] = "RadiusMSCHAPChangePassword"; struct radius *rad = &bund->radius; struct mschapv2value_cpw *mschapv2val_cpw; struct mschapv2value *mschapv2val; if (chap_type != CHAP_ALG_MSOFTv2) { Log(LG_RADIUS, ("[%s] RADIUS: %s: must use MS-CHAPv2 for changing passwords", lnk->name, function)); return RAD_NACK; } if (RadiusStart(RAD_ACCESS_REQUEST) == RAD_NACK) return RAD_NACK; mschapv2val_cpw = (struct mschapv2value_cpw *)mschapvalue; mschapv2val = (struct mschapv2value *)mschapv2val_cpw->encryptedHash; if (RadiusPutChangePassword(mschapvalue, mschapvaluelen, chapid, chap_type) == RAD_NACK) return RAD_NACK; if (RadiusPutAuth(rad->authname, (const char *)mschapv2val, sizeof *mschapv2val, challenge, challenge_size, chapid, chap_type) == RAD_NACK) return RAD_NACK; if (RadiusSendRequest() == RAD_NACK) return RAD_NACK; if (RadiusGetParams() == RAD_NACK) return RAD_NACK; if (rad->valid) { lnk->radius.authentic = 1; return RAD_ACK; } else { return RAD_NACK; } } int RadiusGetParams() { char function[] = "RadiusGetParams"; struct radius *rad = &bund->radius; int res,i,j; size_t len; const void *data; u_int32_t vendor; char *route; char *acl1,*acl2; struct radius_acl **acls, *acls1; struct ifaceroute r; struct in_range range; short got_mppe_keys = FALSE; while ((res = rad_get_attr(rad->radh, &data, &len)) > 0) { switch (res) { case RAD_FRAMED_IP_ADDRESS: rad->ip = rad_cvt_addr(data); Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_FRAMED_IP_ADDRESS: %s ", lnk->name, function, inet_ntoa(rad->ip))); break; case RAD_FRAMED_IP_NETMASK: rad->mask = rad_cvt_addr(data); Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_FRAMED_IP_NETMASK: %s ", lnk->name, function, inet_ntoa(rad->mask))); break; case RAD_FRAMED_ROUTE: route = rad_cvt_string(data,len); Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_FRAMED_ROUTE: %s ", lnk->name, function, route)); if (!ParseAddr(route, &range)) { Log(LG_ERR, ("route: bad route \"%s\"", route)); free(route); break; } free(route); r.netmask.s_addr = range.width ? htonl(~0 << (32 - range.width)) : 0; r.dest.s_addr = (range.ipaddr.s_addr & r.netmask.s_addr); j = 0; for (i=0;in_routes;i++) { if ((r.dest.s_addr==rad->routes[i].dest.s_addr)&&(r.netmask.s_addr==rad->routes[i].netmask.s_addr)) j=1; }; if (j==0) { rad->routes[rad->n_routes++] = r; }; break; case RAD_SESSION_TIMEOUT: rad->session_timeout = rad_cvt_int(data); Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_SESSION_TIMEOUT: %lu ", lnk->name, function, rad->session_timeout)); break; case RAD_IDLE_TIMEOUT: rad->idle_timeout = rad_cvt_int(data); Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_IDLE_TIMEOUT: %lu ", lnk->name, function, rad->idle_timeout)); break; case RAD_ACCT_INTERIM_INTERVAL: rad->interim_interval = rad_cvt_int(data); Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_ACCT_INTERIM_INTERVAL: %lu ", lnk->name, function, rad->interim_interval)); break; case RAD_FRAMED_MTU: rad->mtu = rad_cvt_int(data); if (rad->mtu < IFACE_MIN_MTU || rad->mtu > IFACE_MAX_MTU) { Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_FRAMED_MTU: invalid MTU: %lu ", lnk->name, function, rad->mtu)); rad->mtu = 0; break; } Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_FRAMED_MTU: %lu ", lnk->name, function, rad->mtu)); break; case RAD_FRAMED_COMPRESSION: rad->vj = rad_cvt_int(data) == 1 ? 1 : 0; Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_FRAMED_COMPRESSION: %d ", lnk->name, function, rad->vj)); break; case RAD_FRAMED_PROTOCOL: rad->protocol = rad_cvt_int(data); Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_FRAMED_PROTOCOL: %lu ", lnk->name, function, rad->protocol)); break; case RAD_SERVICE_TYPE: rad->service_type = rad_cvt_int(data); Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_FRAMED_PROTOCOL: %lu ", lnk->name, function, rad->service_type)); break; case RAD_CLASS: rad->class = rad_cvt_int(data); Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_CLASS: %lu ", lnk->name, function, rad->class)); break; case RAD_REPLY_MESSAGE: free(rad->reply_message); rad->reply_message = rad_cvt_string(data, len); Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_REPLY_MESSAGE: %s ", lnk->name, function, rad->reply_message)); break; case RAD_VENDOR_SPECIFIC: if ((res = rad_get_vendor_attr(&vendor, &data, &len)) == -1) { Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_get_vendor_attr failed: %s ", lnk->name, function, rad_strerror(rad->radh))); return RAD_NACK; } switch (vendor) { case RAD_VENDOR_MICROSOFT: switch (res) { case RAD_MICROSOFT_MS_CHAP_ERROR: /* there is a nullbyte on the first pos, don't know why */ if (((const char *)data)[0] == '\0') { ((const char *)data)++; len--; } free(rad->mschap_error); rad->mschap_error = rad_cvt_string(data, len); Log(LG_RADIUS, ("[%s] RADIUS: %s: MS-CHAP-Error: %s", lnk->name, function, rad->mschap_error)); rad->valid = 0; return RAD_NACK; break; /* this was taken from userland ppp */ case RAD_MICROSOFT_MS_CHAP2_SUCCESS: free(rad->mschapv2resp); if (len == 0) rad->mschapv2resp = NULL; else { if (len < 3 || ((const char *)data)[1] != '=') { /* * Only point at the String field if we don't think the * peer has misformatted the response. */ ((const char *)data)++; len--; } else Log(LG_RADIUS, ("[%s] RADIUS: %s: Warning: The MS-CHAP2-Success attribute is mis-formatted. Compensating", lnk->name, function)); if ((rad->mschapv2resp = rad_cvt_string((const char *)data, len)) == NULL) { Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_cvt_string failed: %s", lnk->name, function, rad_strerror(rad->radh))); return RAD_NACK; } Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_MICROSOFT_MS_CHAP2_SUCCESS: %s", lnk->name, function, rad->mschapv2resp)); } break; case RAD_MICROSOFT_MS_CHAP_DOMAIN: free(rad->msdomain); rad->msdomain = rad_cvt_string(data, len); Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_MICROSOFT_MS_CHAP_DOMAIN: %s", lnk->name, function, rad->msdomain)); break; /* MPPE Keys MS-CHAPv2 */ case RAD_MICROSOFT_MS_MPPE_RECV_KEY: got_mppe_keys = TRUE; Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_MICROSOFT_MS_MPPE_RECV_KEY", lnk->name, function)); rad_demangle_mppe_key2(rad->radh, data, len, rad->mppe.recvkey, &rad->mppe.recvkeylen); break; case RAD_MICROSOFT_MS_MPPE_SEND_KEY: got_mppe_keys = TRUE; Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_MICROSOFT_MS_MPPE_SEND_KEY", lnk->name, function)); rad_demangle_mppe_key2(rad->radh, data, len, rad->mppe.sendkey, &rad->mppe.sendkeylen); break; /* MPPE Keys MS-CHAPv1 */ case RAD_MICROSOFT_MS_CHAP_MPPE_KEYS: got_mppe_keys = TRUE; Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_MICROSOFT_MS_CHAP_MPPE_KEYS", lnk->name, function)); if (len != 32) { Log(LG_RADIUS, ("[%s] RADIUS: %s: Server returned garbage %d of expected %d Bytes", lnk->name, function, len, 32)); return RAD_NACK; } if (rad_demangle2(rad->radh, data, len, rad->mppe.lm_key) == -1) { Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_demangle failed: %s", lnk->name, function, rad_strerror(rad->radh))); return RAD_NACK; } break; case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_POLICY: rad->mppe.policy = rad_cvt_int(data); Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_MICROSOFT_MS_MPPE_ENCRYPTION_POLICY: %d (%s)", lnk->name, function, rad->mppe.policy, RadiusMPPEPolicyname(rad->mppe.policy))); break; case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_TYPES: rad->mppe.types = rad_cvt_int(data); Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_MICROSOFT_MS_MPPE_ENCRYPTION_TYPES: %d (%s)", lnk->name, function, rad->mppe.types, RadiusMPPETypesname(rad->mppe.types))); break; default: Log(LG_RADIUS, ("[%s] RADIUS: %s: Dropping MICROSOFT vendor specific attribute: %d ", lnk->name, function, res)); break; } case RAD_VENDOR_MPD: if (res == RAD_MPD_RULE) { acl2 = rad_cvt_string(data, len); Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_MPD_RULE: %s", lnk->name, function, acl2)); acls = &(rad->acl_rule); } else if (res == RAD_MPD_PIPE) { acl2 = rad_cvt_string(data, len); Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_MPD_PIPE: %s", lnk->name, function, acl2)); acls = &(rad->acl_pipe); } else if (res == RAD_MPD_QUEUE) { acl2 = rad_cvt_string(data, len); Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_MPD_QUEUE: %s", lnk->name, function, acl2)); acls = &(rad->acl_queue); } else { Log(LG_RADIUS, ("[%s] RADIUS: %s: Dropping MPD vendor specific attribute: %d ", lnk->name, function, res)); break; }; acl1 = strsep(&acl2,"="); i = atol(acl1); if (i <= 0) { Log(LG_RADIUS, ("[%s] RADIUS: %s: wrong acl number: %i", lnk->name, function,i)); free(acl1); break; }; if ((acl2 == NULL) && (acl2[0] == 0)) { Log(LG_RADIUS, ("[%s] RADIUS: %s: wrong acl", lnk->name, function)); free(acl1); break; }; acls1 = malloc(sizeof(struct radius_acl)); acls1->number = i; strncpy(acls1->rule,acl2,ACL_LEN); while ((*acls != NULL)&&((*acls)->number < i)) { acls = &((*acls)->next); }; if (*acls == NULL) { acls1->next = NULL; } else if ((*acls)->number == i) { Log(LG_RADIUS, ("[%s] RADIUS: %s: duplicate acl", lnk->name, function)); free(acl1); break; } else { acls1->next = *acls; }; *acls = acls1; free(acl1); break; default: Log(LG_RADIUS, ("[%s] RADIUS: %s: Dropping vendor %d attribute: %d ", lnk->name, function, vendor, res)); break; } break; default: Log(LG_RADIUS, ("[%s] RADIUS: %s: Dropping attribute: %d ", lnk->name, function, res)); break; } } /* sanity check, this happens when FreeRADIUS has no msoft-dictionary loaded */ if (rad->auth_type == CHAP_ALG_MSOFTv2 && rad->mschapv2resp == NULL) { Log(LG_RADIUS, ("[%s] RADIUS: %s: PANIC no MS-CHAPv2 response received", lnk->name, function)); return RAD_NACK; } /* MPPE allowed or required, but no MPPE keys returned */ /* print warning, because MPPE doesen't work */ if (!got_mppe_keys && rad->mppe.policy != MPPE_POLICY_NONE) { Log(LG_RADIUS, ("[%s] RADIUS: %s: WARNING no MPPE-Keys received, MPPE will not work", lnk->name, function)); } /* If no MPPE-Infos are returned by the RADIUS server, then allow all */ /* MSoft IAS sends no Infos if all MPPE-Types are enabled and if encryption is optional */ if (rad->mppe.policy == MPPE_POLICY_NONE && rad->mppe.types == MPPE_TYPE_0BIT && got_mppe_keys) { rad->mppe.policy = MPPE_POLICY_ALLOWED; rad->mppe.types = MPPE_TYPE_40BIT | MPPE_TYPE_128BIT | MPPE_TYPE_56BIT; Log(LG_RADIUS, ("[%s] RADIUS: %s: MPPE-Keys, but no MPPE-Infos received => allowing MPPE with all types", lnk->name, function)); } return RAD_ACK; } void RadiusAcctUpdate(void *a) { char function[] = "RadiusAcctUpdate"; Log(LG_RADIUS, ("[%s] RADIUS: %s: Sending Accounting Update", lnk->name, function)); TimerStop(&lnk->radius.radUpdate); RadiusAccount(RAD_UPDATE); TimerStart(&lnk->radius.radUpdate); } int RadiusAccount(short acct_type) { char function[] = "RadiusAccount"; struct radius *rad = &bund->radius; int authentic; /* if Radius-Auth wasn't used, then copy in authname */ if (!strlen(rad->authname)) strncpy(rad->authname, bund->peer_authname, AUTH_MAX_AUTHNAME); Log(LG_RADIUS, ("[%s] RADIUS: %s for: %s", lnk->name, function, rad->authname)); if (lnk->radius.authentic) { authentic = RAD_AUTH_RADIUS; } else { authentic = RAD_AUTH_LOCAL; } if (RadiusStart(RAD_ACCOUNTING_REQUEST) == RAD_NACK) return RAD_NACK; /* Grab some accounting data and initialize structure */ if (acct_type == RAD_START) { /* Generate a session ID */ snprintf(lnk->radius.session_id, RAD_ACCT_MAX_SESSIONID, "%ld-%s", time(NULL) % 10000000, lnk->name); /* The first accounting request generates the multi Session ID */ /* wich is the same for all links */ if (strlen(rad->multi_session_id) == 0) { snprintf(rad->multi_session_id, RAD_ACCT_MAX_SESSIONID, "%ld-%s", time(NULL) % 10000000, bund->name); } } if (rad_put_string(rad->radh, RAD_USER_NAME, lnk->peer_authname) != 0 || rad_put_addr(rad->radh, RAD_FRAMED_IP_ADDRESS, bund->ipcp.peer_addr)) { /*!= 0 || rad_put_addr(rad->radh, RAD_FRAMED_IP_NETMASK, ac->mask) != 0) {*/ Log(LG_RADIUS, ("[%s] RADIUS: %s: put (USER_NAME, FRAMED_IP_ADDRESS): %s", lnk->name, function, rad_strerror(rad->radh))); RadiusClose(); return RAD_NACK; } if (rad_put_int(rad->radh, RAD_ACCT_STATUS_TYPE, acct_type) != 0 || rad_put_string(rad->radh, RAD_ACCT_SESSION_ID, lnk->radius.session_id) != 0 || rad_put_string(rad->radh, RAD_ACCT_MULTI_SESSION_ID, rad->multi_session_id) != 0) { Log(LG_RADIUS, ("[%s] RADIUS: %s: put (STATUS_TYPE, SESSION_ID, MULTI_SESSION_ID): %s", lnk->name, function, rad_strerror(rad->radh))); RadiusClose(); return RAD_NACK; } if (rad_put_int(rad->radh, RAD_ACCT_LINK_COUNT, bund->n_links) != 0) { Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_int(RAD_ACCT_LINK_COUNT) failed: %s", lnk->name, function, rad_strerror(rad->radh))); RadiusClose(); return RAD_NACK; } if (rad_put_int(rad->radh, RAD_ACCT_AUTHENTIC, authentic) != 0) { Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_int(RAD_ACCT_AUTHENTIC) failed: %s", lnk->name, function, rad_strerror(rad->radh))); RadiusClose(); return RAD_NACK; } if (acct_type == RAD_STOP || acct_type == RAD_UPDATE) { if (acct_type == RAD_STOP) { int termCause = RAD_TERM_PORT_ERROR; if (lnk->downReason != NULL) { if (!strcmp(lnk->downReason, "")) { termCause = RAD_TERM_NAS_REQUEST; } else if (!strncmp(lnk->downReason, STR_PEER_DISC, strlen(STR_PEER_DISC))) { termCause = RAD_TERM_USER_REQUEST; } else if (!strncmp(lnk->downReason, STR_QUIT, strlen(STR_QUIT))) { termCause = RAD_TERM_ADMIN_REBOOT; } else if (!strncmp(lnk->downReason, STR_PORT_SHUTDOWN, strlen(STR_PORT_SHUTDOWN))) { termCause = RAD_TERM_NAS_REBOOT; } else if (!strncmp(lnk->downReason, STR_IDLE_TIMEOUT, strlen(STR_IDLE_TIMEOUT))) { termCause = RAD_TERM_IDLE_TIMEOUT; } else if (!strncmp(lnk->downReason, STR_SESSION_TIMEOUT, strlen(STR_SESSION_TIMEOUT))) { termCause = RAD_TERM_SESSION_TIMEOUT; } else if (!strncmp(lnk->downReason, STR_DROPPED, strlen(STR_DROPPED))) { termCause = RAD_TERM_LOST_CARRIER; } else if (!strncmp(lnk->downReason, STR_ECHO_TIMEOUT, strlen(STR_ECHO_TIMEOUT))) { termCause = RAD_TERM_LOST_SERVICE; } else if (!strncmp(lnk->downReason, STR_PROTO_ERR, strlen(STR_PROTO_ERR))) { termCause = RAD_TERM_SERVICE_UNAVAILABLE; } else if (!strncmp(lnk->downReason, STR_LOGIN_FAIL, strlen(STR_LOGIN_FAIL))) { termCause = RAD_TERM_USER_ERROR; }; Log(LG_RADIUS, ("[%s] RADIUS: Termination cause: %s, RADIUS: %d", lnk->name, lnk->downReason, termCause)); } if (rad_put_int(rad->radh, RAD_ACCT_TERMINATE_CAUSE, termCause) != 0) { Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_int(RAD_ACCT_TERMINATE_CAUSE) failed: %s", lnk->name, function, rad_strerror(rad->radh))); RadiusClose(); return RAD_NACK; } } if (rad_put_int(rad->radh, RAD_ACCT_SESSION_TIME, time(NULL) - lnk->bm.last_open) != 0) { Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_int(RAD_ACCT_SESSION_TIME) failed: %s", lnk->name, function, rad_strerror(rad->radh))); RadiusClose(); return RAD_NACK; } LinkUpdateStats(); if (rad_put_int(rad->radh, RAD_ACCT_INPUT_OCTETS, lnk->stats.recvOctets % MAX_U_INT32) != 0 || rad_put_int(rad->radh, RAD_ACCT_INPUT_PACKETS, lnk->stats.recvFrames) != 0 || rad_put_int(rad->radh, RAD_ACCT_OUTPUT_OCTETS, lnk->stats.xmitOctets % MAX_U_INT32) != 0 || rad_put_int(rad->radh, RAD_ACCT_OUTPUT_PACKETS, lnk->stats.xmitFrames) != 0 || rad_put_int(rad->radh, RAD_ACCT_INPUT_GIGAWORDS, lnk->stats.recvOctets / MAX_U_INT32) != 0 || rad_put_int(rad->radh, RAD_ACCT_OUTPUT_GIGAWORDS, lnk->stats.xmitOctets / MAX_U_INT32) != 0) { Log(LG_RADIUS, ("[%s] RADIUS: %s: put stats: %s", lnk->name, function, rad_strerror(rad->radh))); RadiusClose(); return RAD_NACK; } } Log(LG_RADIUS, ("[%s] RADIUS: %s: Sending accounting data (Type: %d)", lnk->name, function, acct_type)); if (RadiusSendRequest() == RAD_NACK) return RAD_NACK; return RAD_ACK; } int RadiusAddServer (short request_type) { RadConf const c = &bund->radius.conf; RadServe_Conf s; char function[] = "RadiusAddServer"; int i; struct radius *rad = &bund->radius; if (c->server == NULL) return (RAD_ACK); s = c->server; i = 1; while (s) { Log(LG_RADIUS, ("[%s] RADIUS: %s Adding %s", lnk->name, function, s->hostname)); if (request_type == RAD_ACCESS_REQUEST) { if (rad_add_server (rad->radh, s->hostname, s->auth_port, s->sharedsecret, c->radius_timeout, c->radius_retries) == -1) { Log(LG_RADIUS, ("[%s] RADIUS: %s error: %s", lnk->name, function, rad_strerror(rad->radh))); return (RAD_NACK); } } else { if (rad_add_server (rad->radh, s->hostname, s->acct_port, s->sharedsecret, c->radius_timeout, c->radius_retries) == -1) { Log(LG_RADIUS, ("[%s] RADIUS: %s error: %s", lnk->name, function, rad_strerror(rad->radh))); return (RAD_NACK); } } s = s->next; } return (RAD_ACK); } void RadiusSetAuth(AuthData auth) { char function[] = "RadiusSetAuth"; strncpy(auth->authname, bund->radius.authname, AUTH_MAX_AUTHNAME); if (Enabled(&bund->ipcp.conf.options, IPCP_CONF_RADIUSIP)) { Log(LG_RADIUS, ("[%s] RADIUS: %s: Trying to use IP-address from radius-server", lnk->name, function)); if (strcmp(inet_ntoa(bund->radius.ip), "255.255.255.255") == 0 || bund->radius.ip.s_addr == INADDR_ANY) { /* the peer can choose an address */ Log(LG_RADIUS, ("[%s] RADIUS: %s: server says that the peer can choose an address", lnk->name, function)); auth->range.ipaddr.s_addr = 0; auth->range.width = 0; auth->range_valid = 1; } else if (strcmp(inet_ntoa(bund->radius.ip), "255.255.255.254") == 0) { /* we should choose the ip */ Log(LG_RADIUS, ("[%s] RADIUS: %s: server says that we should choose an address", lnk->name, function)); auth->range_valid = 0; } else { /* or use IP from Radius-server */ Log(LG_RADIUS, ("[%s] RADIUS: %s: using this IP: %s", lnk->name, function, inet_ntoa(bund->radius.ip))); memcpy(&auth->range.ipaddr, &bund->radius.ip, sizeof(struct in_addr)); auth->range_valid = 1; auth->range.width = 32; } } } int RadStat(int ac, char *av[], void *arg) { RadConf const conf = &bund->radius.conf; RadServe_Conf server; struct radius *rad = &bund->radius; int i; printf("\tTimeout : %d\n", conf->radius_timeout); printf("\tRetries : %d\n", conf->radius_retries); printf("\tConfig-file : %s\n", conf->file); printf("\tMe (NAS-IP) : %s\n", inet_ntoa(conf->radius_me)); printf("\tAcct-Interval: %d\n", conf->acct_update); if (conf->server != NULL) { server = conf->server; i = 1; while (server) { printf("\t--------------- Radius Server %d ---------------\n", i); printf("\thostname : %s\n", server->hostname); printf("\tsecret : *********\n"); printf("\tauth port : %d\n", server->auth_port); printf("\tacct port : %d\n", server->acct_port); i++; server = server->next; } } printf("\t--------------- Radius Data ---------------\n"); printf("\tAuthenticated : %s\n", rad->valid ? "yes" : "no"); printf("\tAuthname : %s\n", rad->authname); printf("\tReply-message : %s\n", rad->reply_message == NULL ? "" : rad->reply_message); printf("\tIP : %s\n", inet_ntoa(rad->ip)); printf("\tMASK : %s\n", inet_ntoa(rad->mask)); printf("\tMTU : %lu\n", rad->mtu); printf("\tSession-timeout : %lu\n", rad->session_timeout); printf("\tIdle-timeout : %lu\n", rad->idle_timeout); printf("\tVJ : %d\n", rad->vj); printf("\tClass : %lu\n", rad->class); printf("\tProtocol : %lu\n", rad->protocol); printf("\tService-type : %lu\n", rad->service_type); printf("\tFilter-Id : %s\n", rad->filterid == NULL ? "" : rad->filterid); printf("\tAcct-SID : %s\n", lnk->radius.session_id); printf("\tAcct-MSID : %s\n", rad->multi_session_id); printf("\t--------------- Radius MSoft related Data ---------------\n"); printf("\tMPPE Types : %s\n", RadiusMPPETypesname(rad->mppe.types)); printf("\tMPPE Policy : %s\n", RadiusMPPEPolicyname(rad->mppe.policy)); printf("\tMS-Domain : %s\n", rad->msdomain == NULL ? "" : rad->msdomain); printf("\tMS-CHAP-Error : %s\n", rad->mschap_error == NULL ? "" : rad->mschap_error); printf("\tMS-CHAPv2-Response : %s\n", rad->mschapv2resp == NULL ? "" : rad->mschapv2resp); return (0); } static const char * RadiusMPPEPolicyname(int policy) { switch(policy) { case MPPE_POLICY_ALLOWED: return "Allowed"; case MPPE_POLICY_REQUIRED: return "Required"; case MPPE_POLICY_NONE: return "Not available"; default: return "Unknown Policy"; } } static const char * RadiusMPPETypesname(int types) { static char res[30]; memset(res, 0, sizeof res); if (types == 0) { sprintf(res, "no encryption required"); return res; } if (types & MPPE_TYPE_40BIT) sprintf (res, "40 "); if (types & MPPE_TYPE_56BIT) sprintf (&res[strlen(res)], "56 "); if (types & MPPE_TYPE_128BIT) sprintf (&res[strlen(res)], "128 "); if (strlen(res) == 0) { sprintf (res, "unknown types"); } else { sprintf (&res[strlen(res)], "bit"); } return res; } /* compatibility functions until libradius has these builtin */ static int rad_demangle2(struct rad_handle *h, const void *mangled, size_t mlen, u_char *demangled) { char function[] = "rad_demangle"; char R[AUTH_LEN]; const char *S; int i, Ppos; MD5_CTX Context; u_char b[16], *C; if ((mlen % 16 != 0) || (mlen > 128)) { Log(LG_RADIUS, ("[%s] RADIUS: %s: Cannot interpret mangled data of length %ld", lnk->name, function, (u_long)mlen)); return -1; } C = (u_char *)mangled; /* We need the shared secret as Salt */ S = rad_server_secret(h); /* We need the request authenticator */ if (rad_request_authenticator(h, R, sizeof R) != AUTH_LEN) { Log(LG_RADIUS, ("[%s] RADIUS: %s: Cannot obtain the RADIUS request authenticator", lnk->name, function)); return -1; } MD5Init(&Context); MD5Update(&Context, S, strlen(S)); MD5Update(&Context, R, AUTH_LEN); MD5Final(b, &Context); Ppos = 0; while (mlen) { mlen -= 16; for (i = 0; i < 16; i++) demangled[Ppos++] = C[i] ^ b[i]; if (mlen) { MD5Init(&Context); MD5Update(&Context, S, strlen(S)); MD5Update(&Context, C, 16); MD5Final(b, &Context); } C += 16; } return 0; } static int rad_demangle_mppe_key2(struct rad_handle *h, const void *mangled, size_t mlen, u_char *demangled, size_t *len) { char function[] = "rad_demangle_mppe_key"; char R[AUTH_LEN]; /* variable names as per rfc2548 */ const char *S; u_char b[16]; const u_char *A, *C; MD5_CTX Context; int Slen, i, Clen, Ppos; u_char *P; if (mlen % 16 != SALT_LEN) { Log(LG_RADIUS, ("[%s] RADIUS: %s: Cannot interpret mangled data of length %ld", lnk->name, function, (u_long)mlen)); return -1; } /* We need the RADIUS Request-Authenticator */ if (rad_request_authenticator(h, R, sizeof R) != AUTH_LEN) { Log(LG_RADIUS, ("[%s] RADIUS: %s: Cannot obtain the RADIUS request authenticator", lnk->name, function)); return -1; } A = (const u_char *)mangled; /* Salt comes first */ C = (const u_char *)mangled + SALT_LEN; /* Then the ciphertext */ Clen = mlen - SALT_LEN; S = rad_server_secret(h); /* We need the RADIUS secret */ Slen = strlen(S); P = alloca(Clen); /* We derive our plaintext */ MD5Init(&Context); MD5Update(&Context, S, Slen); MD5Update(&Context, R, AUTH_LEN); MD5Update(&Context, A, SALT_LEN); MD5Final(b, &Context); Ppos = 0; while (Clen) { Clen -= 16; for (i = 0; i < 16; i++) P[Ppos++] = C[i] ^ b[i]; if (Clen) { MD5Init(&Context); MD5Update(&Context, S, Slen); MD5Update(&Context, C, 16); MD5Final(b, &Context); } C += 16; } /* * The resulting plain text consists of a one-byte length, the text and * maybe some padding. */ *len = *P; if (*len > mlen - 1) { Log(LG_RADIUS, ("[%s] RADIUS: %s: Mangled data seems to be garbage %d %d", lnk->name, function, *len, mlen-1)); return -1; } if (*len > MPPE_KEY_LEN) { Log(LG_RADIUS, ("[%s] RADIUS: %s: Key to long (%d) for me max. %d", lnk->name, function, *len, MPPE_KEY_LEN)); return -1; } memcpy(demangled, P + 1, *len); return 0; }