X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=src%2Fmodules%2Frlm_mschap%2Frlm_mschap.c;h=62d45ac7d6ea0eca0d63480caa80ac2b51966d4b;hb=2fa3d061ecd55e12a7fcb1ba7b7684dc5161ef84;hp=218fdb73bf6f2a4a3f11a11478ff83717a8997c2;hpb=726cb64b814169a913e117a8f59028e4139adcaa;p=freeradius.git diff --git a/src/modules/rlm_mschap/rlm_mschap.c b/src/modules/rlm_mschap/rlm_mschap.c index 218fdb7..62d45ac 100644 --- a/src/modules/rlm_mschap/rlm_mschap.c +++ b/src/modules/rlm_mschap/rlm_mschap.c @@ -15,85 +15,30 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * - * Copyright 2000,2001 The FreeRADIUS server project - */ - - -/* - * mschap.c MS-CHAP module - * - * This implements MS-CHAP, as described in RFC 2548 - * - * http://www.freeradius.org/rfc/rfc2548.txt - * - */ - -/* - * If you have any questions on NTLM (Samba) passwords - * support, LM authentication and MS-CHAP v2 support - * please contact - * - * Vladimir Dubrovin vlad@sandy.ru - * aka - * ZARAZA 3APA3A@security.nnov.ru + * Copyright 2000,2001,2006 The FreeRADIUS server project */ /* MPPE support from Takahiro Wagatsuma */ -#include "autoconf.h" -#include "libradius.h" - -#include -#include -#include -#include +#include +RCSID("$Id$") -#include "radiusd.h" -#include "modules.h" +#include +#include +#include +#include +#include -#include "md4.h" -#include "md5.h" -#include "sha1.h" -#include "rad_assert.h" +#include +#include "mschap.h" #include "smbdes.h" -static const char rcsid[] = "$Id$"; - -static const char *letters = "0123456789ABCDEF"; - -/* - * hex2bin converts hexadecimal strings into binary - */ -static int hex2bin (const char *szHex, unsigned char* szBin, int len) -{ - char * c1, * c2; - int i; - - for (i = 0; i < len; i++) { - if( !(c1 = memchr(letters, toupper((int) szHex[i << 1]), 16)) || - !(c2 = memchr(letters, toupper((int) szHex[(i << 1) + 1]), 16))) - break; - szBin[i] = ((c1-letters)<<4) + (c2-letters); - } - return i; -} - -/* - * bin2hex creates hexadecimal presentation - * of binary data - */ -static void bin2hex (const unsigned char *szBin, char *szHex, int len) -{ - int i; - for (i = 0; i < len; i++) { - szHex[i<<1] = letters[szBin[i] >> 4]; - szHex[(i<<1) + 1] = letters[szBin[i] & 0x0F]; - } -} - +#ifdef __APPLE__ +extern int od_mschap_auth(REQUEST *request, VALUE_PAIR *challenge, VALUE_PAIR * usernamepair); +#endif /* Allowable account control bits */ #define ACB_DISABLED 0x0001 /* 1 = User account disabled */ @@ -183,113 +128,18 @@ static int pdb_decode_acct_ctrl(const char *p) } -/* - * ntpwdhash converts Unicode password to 16-byte NT hash - * with MD4 - */ -static void ntpwdhash (unsigned char *szHash, const char *szPassword) -{ - char szUnicodePass[513]; - int nPasswordLen; - int i; - - /* - * NT passwords are unicode. Convert plain text password - * to unicode by inserting a zero every other byte - */ - nPasswordLen = strlen(szPassword); - for (i = 0; i < nPasswordLen; i++) { - szUnicodePass[i << 1] = szPassword[i]; - szUnicodePass[(i << 1) + 1] = 0; - } - - /* Encrypt Unicode password to a 16-byte MD4 hash */ - md4_calc(szHash, szUnicodePass, (nPasswordLen<<1) ); -} - - -/* - * challenge_hash() is used by mschap2() and auth_response() - * implements RFC2759 ChallengeHash() - * generates 64 bit challenge - */ -static void challenge_hash( const char *peer_challenge, - const char *auth_challenge, - const char *user_name, char *challenge ) -{ - SHA1_CTX Context; - unsigned char hash[20]; - - SHA1Init(&Context); - SHA1Update(&Context, peer_challenge, 16); - SHA1Update(&Context, auth_challenge, 16); - SHA1Update(&Context, user_name, strlen(user_name)); - SHA1Final(hash, &Context); - memcpy(challenge, hash, 8); -} - -/* - * auth_response() generates MS-CHAP v2 SUCCESS response - * according to RFC 2759 GenerateAuthenticatorResponse() - * returns 42-octet response string - */ -static void auth_response(const char *username, - const unsigned char *nt_hash_hash, - unsigned char *ntresponse, - char *peer_challenge, char *auth_challenge, - char *response) -{ - SHA1_CTX Context; - const unsigned char magic1[39] = - {0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65, - 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67, - 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74}; - - const unsigned char magic2[41] = - {0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, - 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F, - 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E, - 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F, - 0x6E}; - - char challenge[8]; - unsigned char digest[20]; - - SHA1Init(&Context); - SHA1Update(&Context, nt_hash_hash, 16); - SHA1Update(&Context, ntresponse, 24); - SHA1Update(&Context, magic1, 39); - SHA1Final(digest, &Context); - challenge_hash(peer_challenge, auth_challenge, username, challenge); - SHA1Init(&Context); - SHA1Update(&Context, digest, 20); - SHA1Update(&Context, challenge, 8); - SHA1Update(&Context, magic2, 41); - SHA1Final(digest, &Context); - - /* - * Encode the value of 'Digest' as "S=" followed by - * 40 ASCII hexadecimal digits and return it in - * AuthenticatorResponse. - * For example, - * "S=0123456789ABCDEF0123456789ABCDEF01234567" - */ - response[0] = 'S'; - response[1] = '='; - bin2hex(digest, response + 2, 20); -} - - typedef struct rlm_mschap_t { int use_mppe; int require_encryption; int require_strong; int with_ntdomain_hack; /* this should be in another module */ char *passwd_file; - char *xlat_name; + const char *xlat_name; char *ntlm_auth; - char *auth_type; + const char *auth_type; +#ifdef __APPLE__ + int open_directory; +#endif } rlm_mschap_t; @@ -299,18 +149,18 @@ typedef struct rlm_mschap_t { * Pulls NT-Response, LM-Response, or Challenge from MSCHAP * attributes. */ -static int mschap_xlat(void *instance, REQUEST *request, +static size_t mschap_xlat(void *instance, REQUEST *request, char *fmt, char *out, size_t outlen, RADIUS_ESCAPE_STRING func) { - int i, data_len; + size_t i, data_len; uint8_t *data = NULL; - uint8_t buffer[8]; + uint8_t buffer[32]; VALUE_PAIR *user_name; VALUE_PAIR *chap_challenge, *response; rlm_mschap_t *inst = instance; - chap_challenge = response = NULL; + response = NULL; func = func; /* -Wunused */ @@ -318,11 +168,12 @@ static int mschap_xlat(void *instance, REQUEST *request, * Challenge means MS-CHAPv1 challenge, or * hash of MS-CHAPv2 challenge, and peer challenge. */ - if (strcasecmp(fmt, "Challenge") == 0) { + if (strncasecmp(fmt, "Challenge", 9) == 0) { chap_challenge = pairfind(request->packet->vps, - PW_MSCHAP_CHALLENGE); + PW_MSCHAP_CHALLENGE, + VENDORPEC_MICROSOFT); if (!chap_challenge) { - DEBUG2(" rlm_mschap: No MS-CHAP-Challenge in the request."); + RDEBUG2("No MS-CHAP-Challenge in the request."); return 0; } @@ -331,8 +182,9 @@ static int mschap_xlat(void *instance, REQUEST *request, * for MS-CHAPv2 */ if (chap_challenge->length == 8) { - DEBUG2(" mschap1: %02x", chap_challenge->strvalue[0]); - data = chap_challenge->strvalue; + RDEBUG2(" mschap1: %02x", + chap_challenge->vp_octets[0]); + data = chap_challenge->vp_octets; data_len = 8; /* @@ -340,43 +192,73 @@ static int mschap_xlat(void *instance, REQUEST *request, * for MS-CHAPv2. */ } else if (chap_challenge->length == 16) { + VALUE_PAIR *name_attr, *response_name; char *username_string; - DEBUG2(" mschap2: %02x", chap_challenge->strvalue[0]); + RDEBUG2(" mschap2: %02x", chap_challenge->vp_octets[0]); response = pairfind(request->packet->vps, - PW_MSCHAP2_RESPONSE); + PW_MSCHAP2_RESPONSE, + VENDORPEC_MICROSOFT); if (!response) { - DEBUG2(" rlm_mschap: MS-CHAP2-Response is required to calculate MS-CHAPv1 challenge."); + RDEBUG2("MS-CHAP2-Response is required to calculate MS-CHAPv1 challenge."); return 0; } /* + * FIXME: Much of this is copied from + * below. We should put it into a + * separate function. + */ + + /* * Responses are 50 octets. */ if (response->length < 50) { - radlog(L_AUTH, "rlm_mschap: MS-CHAP-Response has the wrong format."); + radlog_request(L_AUTH, 0, request, "MS-CHAP-Response has the wrong format."); return 0; } user_name = pairfind(request->packet->vps, - PW_USER_NAME); + PW_USER_NAME, 0); if (!user_name) { - DEBUG2(" rlm_mschap: User-Name is required to calculateMS-CHAPv1 Challenge."); + RDEBUG2("User-Name is required to calculate MS-CHAPv1 Challenge."); return 0; } + /* + * Check for MS-CHAP-User-Name and if found, use it + * to construct the MSCHAPv1 challenge. This is + * set by rlm_eap_mschap to the MS-CHAP Response + * packet Name field. + * + * We prefer this to the User-Name in the + * packet. + */ + response_name = pairfind(request->packet->vps, PW_MS_CHAP_USER_NAME, 0); + if (response_name) { + name_attr = response_name; + } else { + name_attr = user_name; + } + /* * with_ntdomain_hack moved here, too. */ - if ((username_string = strchr(user_name->strvalue, '\\')) != NULL) { + if ((username_string = strchr(name_attr->vp_strvalue, '\\')) != NULL) { if (inst->with_ntdomain_hack) { username_string++; } else { - DEBUG2(" rlm_mschap: NT Domain delimeter found, should we have enabled with_ntdomain_hack?"); - username_string = user_name->strvalue; + RDEBUG2("NT Domain delimeter found, should we have enabled with_ntdomain_hack?"); + username_string = name_attr->vp_strvalue; } } else { - username_string = user_name->strvalue; + username_string = name_attr->vp_strvalue; + } + + if (response_name && + ((user_name->length != response_name->length) || + (strncasecmp(user_name->vp_strvalue, response_name->vp_strvalue, user_name->length) != 0))) { + RDEBUG("WARNING: User-Name (%s) is not the same as MS-CHAP Name (%s) from EAP-MSCHAPv2", user_name->vp_strvalue, response_name->vp_strvalue); } /* @@ -384,27 +266,30 @@ static int mschap_xlat(void *instance, REQUEST *request, * from the MS-CHAPv2 peer challenge, * our challenge, and the user name. */ - challenge_hash(response->strvalue + 2, - chap_challenge->strvalue, + RDEBUG2("Creating challenge hash with username: %s", + username_string); + mschap_challenge_hash(response->vp_octets + 2, + chap_challenge->vp_octets, username_string, buffer); data = buffer; data_len = 8; } else { - DEBUG2(" rlm_mschap: Invalid MS-CHAP challenge length"); + RDEBUG2("Invalid MS-CHAP challenge length"); return 0; } - + /* * Get the MS-CHAPv1 response, or the MS-CHAPv2 * response. */ - } else if (strcasecmp(fmt, "NT-Response") == 0) { + } else if (strncasecmp(fmt, "NT-Response", 11) == 0) { response = pairfind(request->packet->vps, - PW_MSCHAP_RESPONSE); + PW_MSCHAP_RESPONSE, VENDORPEC_MICROSOFT); if (!response) response = pairfind(request->packet->vps, - PW_MSCHAP2_RESPONSE); + PW_MSCHAP2_RESPONSE, + VENDORPEC_MICROSOFT); if (!response) { - DEBUG2(" rlm_mschap: No MS-CHAP-Response or MS-CHAP2-Response was found in the request."); + RDEBUG2("No MS-CHAP-Response or MS-CHAP2-Response was found in the request."); return 0; } @@ -413,8 +298,8 @@ static int mschap_xlat(void *instance, REQUEST *request, * if the second octet says so. */ if ((response->attribute == PW_MSCHAP_RESPONSE) && - ((response->strvalue[1] & 0x01) == 0)) { - DEBUG2(" rlm_mschap: No NT-Response in MS-CHAP-Response"); + ((response->vp_octets[1] & 0x01) == 0)) { + RDEBUG2("No NT-Response in MS-CHAP-Response"); return 0; } @@ -423,18 +308,18 @@ static int mschap_xlat(void *instance, REQUEST *request, * the NT-Response at the same offset, and are * the same length. */ - data = response->strvalue + 26; + data = response->vp_octets + 26; data_len = 24; - + /* * LM-Response is deprecated, and exists only * in MS-CHAPv1, and not often there. */ - } else if (strcasecmp(fmt, "LM-Response") == 0) { + } else if (strncasecmp(fmt, "LM-Response", 11) == 0) { response = pairfind(request->packet->vps, - PW_MSCHAP_RESPONSE); + PW_MSCHAP_RESPONSE, VENDORPEC_MICROSOFT); if (!response) { - DEBUG2(" rlm_mschap: No MS-CHAP-Response was found in the request."); + RDEBUG2("No MS-CHAP-Response was found in the request."); return 0; } @@ -442,40 +327,40 @@ static int mschap_xlat(void *instance, REQUEST *request, * For MS-CHAPv1, the NT-Response exists only * if the second octet says so. */ - if ((response->strvalue[1] & 0x01) != 0) { - DEBUG2(" rlm_mschap: No LM-Response in MS-CHAP-Response"); + if ((response->vp_octets[1] & 0x01) != 0) { + RDEBUG2("No LM-Response in MS-CHAP-Response"); return 0; } - data = response->strvalue + 2; + data = response->vp_octets + 2; data_len = 24; /* * Pull the NT-Domain out of the User-Name, if it exists. */ - } else if (strcasecmp(fmt, "NT-Domain") == 0) { + } else if (strncasecmp(fmt, "NT-Domain", 9) == 0) { char *p, *q; - user_name = pairfind(request->packet->vps, PW_USER_NAME); + user_name = pairfind(request->packet->vps, PW_USER_NAME, 0); if (!user_name) { - DEBUG2(" rlm_mschap: No User-Name was found in the request."); + RDEBUG2("No User-Name was found in the request."); return 0; } - + /* * First check to see if this is a host/ style User-Name * (a la Kerberos host principal) */ - if (strncmp(user_name->strvalue, "host/", 5) == 0) { + if (strncmp(user_name->vp_strvalue, "host/", 5) == 0) { /* * If we're getting a User-Name formatted in this way, * it's likely due to PEAP. The Windows Domain will be * the first domain component following the hostname, * or the machine name itself if only a hostname is supplied */ - p = strchr(user_name->strvalue, '.'); + p = strchr(user_name->vp_strvalue, '.'); if (!p) { - DEBUG2(" rlm_mschap: setting NT-Domain to same as machine name"); - strNcpy(out, user_name->strvalue + 5, outlen); + RDEBUG2("setting NT-Domain to same as machine name"); + strlcpy(out, user_name->vp_strvalue + 5, outlen); } else { p++; /* skip the period */ q = strchr(p, '.'); @@ -484,13 +369,13 @@ static int mschap_xlat(void *instance, REQUEST *request, * only if another period was found */ if (q) *q = '\0'; - strNcpy(out, p, outlen); + strlcpy(out, p, outlen); if (q) *q = '.'; } } else { - p = strchr(user_name->strvalue, '\\'); + p = strchr(user_name->vp_strvalue, '\\'); if (!p) { - DEBUG2(" rlm_mschap: No NT-Domain was found in the User-Name."); + RDEBUG2("No NT-Domain was found in the User-Name."); return 0; } @@ -498,7 +383,7 @@ static int mschap_xlat(void *instance, REQUEST *request, * Hack. This is simpler than the alternatives. */ *p = '\0'; - strNcpy(out, user_name->strvalue, outlen); + strlcpy(out, user_name->vp_strvalue, outlen); *p = '\\'; } @@ -507,20 +392,20 @@ static int mschap_xlat(void *instance, REQUEST *request, /* * Pull the User-Name out of the User-Name... */ - } else if (strcasecmp(fmt, "User-Name") == 0) { + } else if (strncasecmp(fmt, "User-Name", 9) == 0) { char *p; - user_name = pairfind(request->packet->vps, PW_USER_NAME); + user_name = pairfind(request->packet->vps, PW_USER_NAME, 0); if (!user_name) { - DEBUG2(" rlm_mschap: No User-Name was found in the request."); + RDEBUG2("No User-Name was found in the request."); return 0; } - + /* * First check to see if this is a host/ style User-Name * (a la Kerberos host principal) */ - if (strncmp(user_name->strvalue, "host/", 5) == 0) { + if (strncmp(user_name->vp_strvalue, "host/", 5) == 0) { /* * If we're getting a User-Name formatted in this way, * it's likely due to PEAP. When authenticating this against @@ -531,28 +416,78 @@ static int mschap_xlat(void *instance, REQUEST *request, * from that point to the first period into a string and appending * a $ to the end. */ - p = strchr(user_name->strvalue, '.'); + p = strchr(user_name->vp_strvalue, '.'); /* * use the same hack as above * only if a period was found */ if (p) *p = '\0'; - snprintf(out, outlen, "%s$", user_name->strvalue + 5); + snprintf(out, outlen, "%s$", user_name->vp_strvalue + 5); if (p) *p = '.'; } else { - p = strchr(user_name->strvalue, '\\'); + p = strchr(user_name->vp_strvalue, '\\'); if (p) { p++; /* skip the backslash */ } else { - p = user_name->strvalue; /* use the whole User-Name */ + p = user_name->vp_strvalue; /* use the whole User-Name */ } - strNcpy(out, p, outlen); + strlcpy(out, p, outlen); } return strlen(out); + /* + * Return the NT-Hash of the passed string + */ + } else if (strncasecmp(fmt, "NT-Hash ", 8) == 0) { + char *p; + char buf2[1024]; + + p = fmt + 8; /* 7 is the length of 'NT-Hash' */ + if ((p == '\0') || (outlen <= 32)) + return 0; + + while (isspace(*p)) p++; + + if (!radius_xlat(buf2, sizeof(buf2),p,request,NULL)) { + RDEBUG("xlat failed"); + *buffer = '\0'; + return 0; + } + + mschap_ntpwdhash(buffer,buf2); + + fr_bin2hex(buffer, out, 16); + out[32] = '\0'; + RDEBUG("NT-Hash of %s = %s", buf2, out); + return 32; + + /* + * Return the LM-Hash of the passed string + */ + } else if (strncasecmp(fmt, "LM-Hash ", 8) == 0) { + char *p; + char buf2[1024]; + + p = fmt + 8; /* 7 is the length of 'LM-Hash' */ + if ((p == '\0') || (outlen <= 32)) + return 0; + + while (isspace(*p)) p++; + + if (!radius_xlat(buf2, sizeof(buf2),p,request,NULL)) { + RDEBUG("xlat failed"); + *buffer = '\0'; + return 0; + } + + smbdes_lmpwdhash(buf2, buffer); + fr_bin2hex(buffer, out, 16); + out[32] = '\0'; + RDEBUG("LM-Hash of %s = %s", buf2, out); + return 32; } else { - DEBUG2(" rlm_mschap: Unknown expansion string \"%s\"", + RDEBUG2("Unknown expansion string \"%s\"", fmt); return 0; } @@ -563,7 +498,7 @@ static int mschap_xlat(void *instance, REQUEST *request, * Didn't set anything: this is bad. */ if (!data) { - DEBUG2(" rlm_mschap: Failed to do anything intelligent"); + RDEBUG2("Failed to do anything intelligent"); return 0; } @@ -575,18 +510,18 @@ static int mschap_xlat(void *instance, REQUEST *request, } /* - * + * */ for (i = 0; i < data_len; i++) { sprintf(out + (2 * i), "%02x", data[i]); } out[data_len * 2] = '\0'; - + return data_len * 2; } -static CONF_PARSER module_config[] = { +static const CONF_PARSER module_config[] = { /* * Cache the password by default. */ @@ -602,6 +537,10 @@ static CONF_PARSER module_config[] = { offsetof(rlm_mschap_t, passwd_file), NULL, NULL }, { "ntlm_auth", PW_TYPE_STRING_PTR, offsetof(rlm_mschap_t, ntlm_auth), NULL, NULL }, +#ifdef __APPLE__ + { "use_open_directory", PW_TYPE_BOOLEAN, + offsetof(rlm_mschap_t,open_directory), NULL, "yes" }, +#endif { NULL, -1, 0, NULL, NULL } /* end the list */ }; @@ -612,8 +551,6 @@ static CONF_PARSER module_config[] = { */ static int mschap_detach(void *instance){ #define inst ((rlm_mschap_t *)instance) - free(inst->passwd_file); - free(inst->ntlm_auth); if (inst->xlat_name) { xlat_unregister(inst->xlat_name, mschap_xlat); free(inst->xlat_name); @@ -629,7 +566,6 @@ static int mschap_detach(void *instance){ */ static int mschap_instantiate(CONF_SECTION *conf, void **instance) { - const char *xlat_name; rlm_mschap_t *inst; inst = *instance = rad_malloc(sizeof(*inst)); @@ -658,19 +594,18 @@ static int mschap_instantiate(CONF_SECTION *conf, void **instance) /* * Create the dynamic translation. */ - xlat_name = cf_section_name2(conf); - if (xlat_name == NULL) - xlat_name = cf_section_name1(conf); - if (xlat_name){ - inst->xlat_name = strdup(xlat_name); - xlat_register(xlat_name, mschap_xlat, inst); - } + inst->xlat_name = cf_section_name2(conf); + if (!inst->xlat_name) inst->xlat_name = cf_section_name1(conf); + inst->xlat_name = strdup(inst->xlat_name); + xlat_register(inst->xlat_name, mschap_xlat, inst); /* * For backwards compatibility */ - if (!dict_valbyname(PW_AUTH_TYPE, inst->xlat_name)) { + if (!dict_valbyname(PW_AUTH_TYPE, 0, inst->xlat_name)) { inst->auth_type = "MS-CHAP"; + } else { + inst->auth_type = inst->xlat_name; } return 0; @@ -680,18 +615,18 @@ static int mschap_instantiate(CONF_SECTION *conf, void **instance) * add_reply() adds either MS-CHAP2-Success or MS-CHAP-Error * attribute to reply packet */ -static void add_reply(VALUE_PAIR** vp, unsigned char ident, +void mschap_add_reply(REQUEST *request, VALUE_PAIR** vp, unsigned char ident, const char* name, const char* value, int len) { VALUE_PAIR *reply_attr; reply_attr = pairmake(name, "", T_OP_EQ); if (!reply_attr) { - DEBUG(" rlm_mschap: Failed to create attribute %s: %s\n", name, librad_errstr); + RDEBUG("Failed to create attribute %s: %s\n", name, fr_strerror()); return; } - reply_attr->strvalue[0] = ident; - memcpy(reply_attr->strvalue + 1, value, len); + reply_attr->vp_octets[0] = ident; + memcpy(reply_attr->vp_octets + 1, value, len); reply_attr->length = len + 1; pairadd(vp, reply_attr); } @@ -699,19 +634,18 @@ static void add_reply(VALUE_PAIR** vp, unsigned char ident, /* * Add MPPE attributes to the reply. */ -static void mppe_add_reply(VALUE_PAIR **vp, - const char* name, const char* value, int len) +static void mppe_add_reply(REQUEST *request, + const char* name, const uint8_t * value, int len) { - VALUE_PAIR *reply_attr; - reply_attr = pairmake(name, "", T_OP_EQ); - if (!reply_attr) { - DEBUG("rlm_mschap: mppe_add_reply failed to create attribute %s: %s\n", name, librad_errstr); + VALUE_PAIR *vp; + vp = radius_pairmake(request, &request->reply->vps, name, "", T_OP_EQ); + if (!vp) { + RDEBUG("rlm_mschap: mppe_add_reply failed to create attribute %s: %s\n", name, fr_strerror()); return; } - memcpy(reply_attr->strvalue, value, len); - reply_attr->length = len; - pairadd(vp, reply_attr); + memcpy(vp->vp_octets, value, len); + vp->length = len; } @@ -725,35 +659,9 @@ static void mppe_add_reply(VALUE_PAIR **vp, static int do_mschap(rlm_mschap_t *inst, REQUEST *request, VALUE_PAIR *password, uint8_t *challenge, uint8_t *response, - uint8_t *nthashhash) + uint8_t *nthashhash, int do_ntlm_auth) { - int do_ntlm_auth = 0; uint8_t calculated[24]; - VALUE_PAIR *vp = NULL; - - /* - * If we have ntlm_auth configured, use it unless told - * otherwise - */ - if (inst->ntlm_auth) do_ntlm_auth = 1; - - /* - * If we have an ntlm_auth configuration, then we may - * want to use it. - */ - vp = pairfind(request->config_items, - PW_MS_CHAP_USE_NTLM_AUTH); - if (vp) do_ntlm_auth = vp->lvalue; - - /* - * No ntlm_auth configured, attribute to tell us to - * use it exists, and we're told to use it. We don't - * know what to do... - */ - if (!inst->ntlm_auth && do_ntlm_auth) { - DEBUG2(" rlm_mschap: Asked to use ntlm_auth, but it was not configured in the mschap{} section."); - return -1; - } /* * Do normal authentication. @@ -763,22 +671,22 @@ static int do_mschap(rlm_mschap_t *inst, * No password: can't do authentication. */ if (!password) { - DEBUG2(" rlm_mschap: FAILED: No NT/LM-Password. Cannot perform authentication."); + RDEBUG2("FAILED: No NT/LM-Password. Cannot perform authentication."); return -1; } - - smbdes_mschap(password->strvalue, challenge, calculated); + + smbdes_mschap(password->vp_strvalue, challenge, calculated); if (memcmp(response, calculated, 24) != 0) { return -1; } - + /* * If the password exists, and is an NT-Password, * then calculate the hash of the NT hash. Doing this * here minimizes work for later. */ if (password && (password->attribute == PW_NT_PASSWORD)) { - md4_calc(nthashhash, password->strvalue, 16); + fr_md4_calc(nthashhash, password->vp_octets, 16); } else { memset(nthashhash, 0, 16); } @@ -789,29 +697,31 @@ static int do_mschap(rlm_mschap_t *inst, memset(nthashhash, 0, 16); /* - * Run the program, and expect that we get 16 + * Run the program, and expect that we get 16 */ result = radius_exec_program(inst->ntlm_auth, request, TRUE, /* wait */ buffer, sizeof(buffer), - NULL, NULL); + NULL, NULL, 1); if (result != 0) { char *p; - - DEBUG2(" rlm_mschap: External script failed."); + VALUE_PAIR *vp = NULL; + + RDEBUG2("External script failed."); vp = pairmake("Module-Failure-Message", "", T_OP_EQ); if (!vp) { - radlog(L_ERR, "No memory"); - return -1; + radlog_request(L_ERR, 0, request, "No memory to allocate Module-Failure-Message"); + return RLM_MODULE_FAIL; } p = strchr(buffer, '\n'); if (p) *p = '\0'; - snprintf(vp->strvalue, sizeof(vp->strvalue), - "rlm_mschap: %s", buffer); - vp->length = strlen(vp->strvalue); - pairadd(&request->packet->vps, vp); + snprintf(vp->vp_strvalue, sizeof(vp->vp_strvalue), + "%s: External script says %s", + inst->xlat_name, buffer); + vp->length = strlen(vp->vp_strvalue); + pairadd(&request->request->vps, vp); return -1; } @@ -822,7 +732,7 @@ static int do_mschap(rlm_mschap_t *inst, * NT_KEY: 000102030405060708090a0b0c0d0e0f */ if (memcmp(buffer, "NT_KEY: ", 8) != 0) { - DEBUG2(" rlm_mschap: Invalid output from ntlm_auth: expecting NT_KEY"); + RDEBUG2("Invalid output from ntlm_auth: expecting NT_KEY"); return -1; } @@ -831,15 +741,15 @@ static int do_mschap(rlm_mschap_t *inst, * with an LF at the end. */ if (strlen(buffer + 8) < 32) { - DEBUG2(" rlm_mschap: Invalid output from ntlm_auth: NT_KEY has unexpected length"); + RDEBUG2("Invalid output from ntlm_auth: NT_KEY has unexpected length"); return -1; } /* * Update the NT hash hash, from the NT key. */ - if (hex2bin(buffer + 8, nthashhash, 16) != 16) { - DEBUG2(" rlm_mschap: Invalid output from ntlm_auth: NT_KEY has non-hex values"); + if (fr_hex2bin(buffer + 8, nthashhash, 16) != 16) { + RDEBUG2("Invalid output from ntlm_auth: NT_KEY has non-hex values"); return -1; } } @@ -895,13 +805,13 @@ static void mppe_GetMasterKey(uint8_t *nt_hashhash,uint8_t *nt_response, uint8_t *masterkey) { uint8_t digest[20]; - SHA1_CTX Context; + fr_SHA1_CTX Context; - SHA1Init(&Context); - SHA1Update(&Context,nt_hashhash,16); - SHA1Update(&Context,nt_response,24); - SHA1Update(&Context,magic1,27); - SHA1Final(digest,&Context); + fr_SHA1Init(&Context); + fr_SHA1Update(&Context,nt_hashhash,16); + fr_SHA1Update(&Context,nt_response,24); + fr_SHA1Update(&Context,magic1,27); + fr_SHA1Final(digest,&Context); memcpy(masterkey,digest,16); } @@ -912,7 +822,7 @@ static void mppe_GetAsymmetricStartKey(uint8_t *masterkey,uint8_t *sesskey, { uint8_t digest[20]; const uint8_t *s; - SHA1_CTX Context; + fr_SHA1_CTX Context; memset(digest,0,20); @@ -922,12 +832,12 @@ static void mppe_GetAsymmetricStartKey(uint8_t *masterkey,uint8_t *sesskey, s = magic2; } - SHA1Init(&Context); - SHA1Update(&Context,masterkey,16); - SHA1Update(&Context,SHSpad1,40); - SHA1Update(&Context,s,84); - SHA1Update(&Context,SHSpad2,40); - SHA1Final(digest,&Context); + fr_SHA1Init(&Context); + fr_SHA1Update(&Context,masterkey,16); + fr_SHA1Update(&Context,SHSpad1,40); + fr_SHA1Update(&Context,s,84); + fr_SHA1Update(&Context,SHSpad2,40); + fr_SHA1Final(digest,&Context); memcpy(sesskey,digest,keylen); } @@ -974,38 +884,47 @@ static void mppe_chap2_gen_keys128(uint8_t *nt_hashhash,uint8_t *response, static int mschap_authorize(void * instance, REQUEST *request) { #define inst ((rlm_mschap_t *)instance) - VALUE_PAIR *challenge = NULL; - VALUE_PAIR *response = NULL; - VALUE_PAIR *vp; + VALUE_PAIR *challenge = NULL, *response = NULL; - challenge = pairfind(request->packet->vps, PW_MSCHAP_CHALLENGE); + challenge = pairfind(request->packet->vps, + PW_MSCHAP_CHALLENGE, + VENDORPEC_MICROSOFT); if (!challenge) { return RLM_MODULE_NOOP; } - response = pairfind(request->packet->vps, PW_MSCHAP_RESPONSE); + response = pairfind(request->packet->vps, + PW_MSCHAP_RESPONSE, + VENDORPEC_MICROSOFT); if (!response) - response = pairfind(request->packet->vps, PW_MSCHAP2_RESPONSE); + response = pairfind(request->packet->vps, + PW_MSCHAP2_RESPONSE, + VENDORPEC_MICROSOFT); /* * Nothing we recognize. Don't do anything. */ if (!response) { - DEBUG2(" rlm_mschap: Found MS-CHAP-Challenge, but no MS-CHAP-Response."); + RDEBUG2("Found MS-CHAP-Challenge, but no MS-CHAP-Response."); return RLM_MODULE_NOOP; } - DEBUG2(" rlm_mschap: Found MS-CHAP attributes. Setting 'Auth-Type = %s'", inst->xlat_name); + if (pairfind(request->config_items, PW_AUTH_TYPE, 0)) { + RDEBUG2("WARNING: Auth-Type already set. Not setting to MS-CHAP"); + return RLM_MODULE_NOOP; + } + + RDEBUG2("Found MS-CHAP attributes. Setting 'Auth-Type = %s'", inst->xlat_name); /* * Set Auth-Type to MS-CHAP. The authentication code * will take care of turning clear-text passwords into * NT/LM passwords. */ - vp = pairmake("Auth-Type", inst->auth_type, T_OP_EQ); - if (!vp) return RLM_MODULE_FAIL; - pairmove(&request->config_items, &vp); - pairfree(&vp); /* may be NULL */ + if (!radius_pairmake(request, &request->config_items, + "Auth-Type", inst->auth_type, T_OP_EQ)) { + return RLM_MODULE_FAIL; + } return RLM_MODULE_OK; #undef inst @@ -1020,7 +939,7 @@ static int mschap_authorize(void * instance, REQUEST *request) * * If PW_SMB_ACCOUNT_CTRL is not set to ACB_PWNOTREQ we must have * one of: - * PAP: PW_PASSWORD or + * PAP: PW_USER_PASSWORD or * MS-CHAP: PW_MSCHAP_CHALLENGE and PW_MSCHAP_RESPONSE or * MS-CHAP2: PW_MSCHAP_CHALLENGE and PW_MSCHAP2_RESPONSE * In case of password mismatch or locked account we MAY return @@ -1036,24 +955,44 @@ static int mschap_authenticate(void * instance, REQUEST *request) VALUE_PAIR *password = NULL; VALUE_PAIR *lm_password, *nt_password, *smb_ctrl; VALUE_PAIR *username; - VALUE_PAIR *reply_attr; uint8_t nthashhash[16]; - uint8_t msch2resp[42]; + char msch2resp[42]; char *username_string; int chap = 0; + int do_ntlm_auth; + + /* + * If we have ntlm_auth configured, use it unless told + * otherwise + */ + do_ntlm_auth = (inst->ntlm_auth != NULL); + + /* + * If we have an ntlm_auth configuration, then we may + * want to suppress it. + */ + if (do_ntlm_auth) { + VALUE_PAIR *vp = pairfind(request->config_items, + PW_MS_CHAP_USE_NTLM_AUTH, 0); + if (vp) do_ntlm_auth = vp->vp_integer; + } /* * Find the SMB-Account-Ctrl attribute, or the * SMB-Account-Ctrl-Text attribute. */ - smb_ctrl = pairfind(request->config_items, PW_SMB_ACCOUNT_CTRL); + smb_ctrl = pairfind(request->config_items, PW_SMB_ACCOUNT_CTRL, 0); if (!smb_ctrl) { password = pairfind(request->config_items, - PW_SMB_ACCOUNT_CTRL_TEXT); + PW_SMB_ACCOUNT_CTRL_TEXT, 0); if (password) { - smb_ctrl = pairmake("SMB-Account-CTRL", "0", T_OP_SET); - pairadd(&request->config_items, smb_ctrl); - smb_ctrl->lvalue = pdb_decode_acct_ctrl(password->strvalue); + smb_ctrl = radius_pairmake(request, + &request->config_items, + "SMB-Account-CTRL", "0", + T_OP_SET); + if (smb_ctrl) { + smb_ctrl->vp_integer = pdb_decode_acct_ctrl(password->vp_strvalue); + } } } @@ -1065,8 +1004,8 @@ static int mschap_authenticate(void * instance, REQUEST *request) /* * Password is not required. */ - if ((smb_ctrl->lvalue & ACB_PWNOTREQ) != 0) { - DEBUG2(" rlm_mschap: SMB-Account-Ctrl says no password is required."); + if ((smb_ctrl->vp_integer & ACB_PWNOTREQ) != 0) { + RDEBUG2("SMB-Account-Ctrl says no password is required."); return RLM_MODULE_OK; } } @@ -1074,84 +1013,89 @@ static int mschap_authenticate(void * instance, REQUEST *request) /* * Decide how to get the passwords. */ - password = pairfind(request->config_items, PW_PASSWORD); + password = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0); /* * We need an LM-Password. */ - lm_password = pairfind(request->config_items, PW_LM_PASSWORD); + lm_password = pairfind(request->config_items, PW_LM_PASSWORD, 0); if (lm_password) { /* * Allow raw octets. */ if ((lm_password->length == 16) || ((lm_password->length == 32) && - (hex2bin(lm_password->strvalue, - lm_password->strvalue, 16) == 16))) { - DEBUG2(" rlm_mschap: Found LM-Password"); + (fr_hex2bin(lm_password->vp_strvalue, + lm_password->vp_octets, 16) == 16))) { + RDEBUG2("Found LM-Password"); lm_password->length = 16; } else { - radlog(L_ERR, "rlm_mschap: Invalid LM-Password"); + radlog_request(L_ERR, 0, request, "Invalid LM-Password"); lm_password = NULL; } } else if (!password) { - DEBUG2(" rlm_mschap: No User-Password configured. Cannot create LM-Password."); + if (!do_ntlm_auth) RDEBUG2("No Cleartext-Password configured. Cannot create LM-Password."); - } else { /* there is a configured User-Password */ - lm_password = pairmake("LM-Password", "", T_OP_EQ); + } else { /* there is a configured Cleartext-Password */ + lm_password = radius_pairmake(request, &request->config_items, + "LM-Password", "", T_OP_EQ); if (!lm_password) { - radlog(L_ERR, "No memory"); + radlog_request(L_ERR, 0, request, "No memory"); } else { - smbdes_lmpwdhash(password->strvalue, - lm_password->strvalue); + smbdes_lmpwdhash(password->vp_strvalue, + lm_password->vp_octets); lm_password->length = 16; - pairadd(&request->config_items, lm_password); } } /* * We need an NT-Password. */ - nt_password = pairfind(request->config_items, PW_NT_PASSWORD); + nt_password = pairfind(request->config_items, PW_NT_PASSWORD, 0); if (nt_password) { if ((nt_password->length == 16) || ((nt_password->length == 32) && - (hex2bin(nt_password->strvalue, - nt_password->strvalue, 16) == 16))) { - DEBUG2(" rlm_mschap: Found NT-Password"); + (fr_hex2bin(nt_password->vp_strvalue, + nt_password->vp_octets, 16) == 16))) { + RDEBUG2("Found NT-Password"); nt_password->length = 16; } else { - radlog(L_ERR, "rlm_mschap: Invalid NT-Password"); + radlog_request(L_ERR, 0, request, "Invalid NT-Password"); nt_password = NULL; } } else if (!password) { - DEBUG2(" rlm_mschap: No User-Password configured. Cannot create NT-Password."); + if (!do_ntlm_auth) RDEBUG2("No Cleartext-Password configured. Cannot create NT-Password."); - } else { /* there is a configured User-Password */ - nt_password = pairmake("NT-Password", "", T_OP_EQ); + } else { /* there is a configured Cleartext-Password */ + nt_password = radius_pairmake(request, &request->config_items, + "NT-Password", "", T_OP_EQ); if (!nt_password) { - radlog(L_ERR, "No memory"); + radlog_request(L_ERR, 0, request, "No memory"); return RLM_MODULE_FAIL; } else { - ntpwdhash(nt_password->strvalue, password->strvalue); + mschap_ntpwdhash(nt_password->vp_octets, + password->vp_strvalue); nt_password->length = 16; - pairadd(&request->config_items, nt_password); } } - challenge = pairfind(request->packet->vps, PW_MSCHAP_CHALLENGE); + challenge = pairfind(request->packet->vps, + PW_MSCHAP_CHALLENGE, + VENDORPEC_MICROSOFT); if (!challenge) { - DEBUG2(" rlm_mschap: No MS-CHAP-Challenge in the request"); + RDEBUG("ERROR: You set 'Auth-Type = MS-CHAP' for a request that does not contain any MS-CHAP attributes!"); return RLM_MODULE_REJECT; } /* * We also require an MS-CHAP-Response. */ - response = pairfind(request->packet->vps, PW_MSCHAP_RESPONSE); + response = pairfind(request->packet->vps, + PW_MSCHAP_RESPONSE, + VENDORPEC_MICROSOFT); /* * MS-CHAP-Response, means MS-CHAPv1 @@ -1163,7 +1107,7 @@ static int mschap_authenticate(void * instance, REQUEST *request) * MS-CHAPv1 challenges are 8 octets. */ if (challenge->length < 8) { - radlog(L_AUTH, "rlm_mschap: MS-CHAP-Challenge has the wrong format."); + radlog_request(L_AUTH, 0, request, "MS-CHAP-Challenge has the wrong format."); return RLM_MODULE_INVALID; } @@ -1171,7 +1115,7 @@ static int mschap_authenticate(void * instance, REQUEST *request) * Responses are 50 octets. */ if (response->length < 50) { - radlog(L_AUTH, "rlm_mschap: MS-CHAP-Response has the wrong format."); + radlog_request(L_AUTH, 0, request, "MS-CHAP-Response has the wrong format."); return RLM_MODULE_INVALID; } @@ -1179,12 +1123,12 @@ static int mschap_authenticate(void * instance, REQUEST *request) * We are doing MS-CHAP. Calculate the MS-CHAP * response */ - if (response->strvalue[1] & 0x01) { - DEBUG2(" rlm_mschap: Told to do MS-CHAPv1 with NT-Password"); + if (response->vp_octets[1] & 0x01) { + RDEBUG2("Told to do MS-CHAPv1 with NT-Password"); password = nt_password; offset = 26; } else { - DEBUG2(" rlm_mschap: Told to do MS-CHAPv1 with LM-Password"); + RDEBUG2("Told to do MS-CHAPv1 with LM-Password"); password = lm_password; offset = 2; } @@ -1192,24 +1136,27 @@ static int mschap_authenticate(void * instance, REQUEST *request) /* * Do the MS-CHAP authentication. */ - if (do_mschap(inst, request, password, challenge->strvalue, - response->strvalue + offset, nthashhash) < 0) { - DEBUG2(" rlm_mschap: MS-CHAP-Response is incorrect."); - add_reply(&request->reply->vps, *response->strvalue, - "MS-CHAP-Error", "E=691 R=1", 9); + if (do_mschap(inst, request, password, challenge->vp_octets, + response->vp_octets + offset, nthashhash, + do_ntlm_auth) < 0) { + RDEBUG2("MS-CHAP-Response is incorrect."); + mschap_add_reply(request, &request->reply->vps, + *response->vp_octets, + "MS-CHAP-Error", "E=691 R=1", 9); return RLM_MODULE_REJECT; } chap = 1; - } else if ((response = pairfind(request->packet->vps, PW_MSCHAP2_RESPONSE)) != NULL) { + } else if ((response = pairfind(request->packet->vps, PW_MSCHAP2_RESPONSE, VENDORPEC_MICROSOFT)) != NULL) { uint8_t mschapv1_challenge[16]; + VALUE_PAIR *name_attr, *response_name; /* * MS-CHAPv2 challenges are 16 octets. */ if (challenge->length < 16) { - radlog(L_AUTH, "rlm_mschap: MS-CHAP-Challenge has the wrong format."); + radlog_request(L_AUTH, 0, request, "MS-CHAP-Challenge has the wrong format."); return RLM_MODULE_INVALID; } @@ -1217,34 +1164,73 @@ static int mschap_authenticate(void * instance, REQUEST *request) * Responses are 50 octets. */ if (response->length < 50) { - radlog(L_AUTH, "rlm_mschap: MS-CHAP-Response has the wrong format."); + radlog_request(L_AUTH, 0, request, "MS-CHAP-Response has the wrong format."); return RLM_MODULE_INVALID; } /* * We also require a User-Name */ - username = pairfind(request->packet->vps, PW_USER_NAME); + username = pairfind(request->packet->vps, PW_USER_NAME, 0); if (!username) { - radlog(L_AUTH, "rlm_mschap: We require a User-Name for MS-CHAPv2"); + radlog_request(L_AUTH, 0, request, "We require a User-Name for MS-CHAPv2"); return RLM_MODULE_INVALID; } - /* - * with_ntdomain_hack moved here + * Check for MS-CHAP-User-Name and if found, use it + * to construct the MSCHAPv1 challenge. This is + * set by rlm_eap_mschap to the MS-CHAP Response + * packet Name field. + * + * We prefer this to the User-Name in the + * packet. */ - if ((username_string = strchr(username->strvalue, '\\')) != NULL) { - if (inst->with_ntdomain_hack) { - username_string++; + response_name = pairfind(request->packet->vps, PW_MS_CHAP_USER_NAME, 0); + if (response_name) { + name_attr = response_name; + } else { + name_attr = username; + } + + /* + * with_ntdomain_hack moved here, too. + */ + if ((username_string = strchr(name_attr->vp_strvalue, '\\')) != NULL) { + if (inst->with_ntdomain_hack) { + username_string++; } else { - DEBUG2(" rlm_mschap: NT Domain delimeter found, should we have enabled with_ntdomain_hack?"); - username_string = username->strvalue; + RDEBUG2("NT Domain delimeter found, should we have enabled with_ntdomain_hack?"); + username_string = name_attr->vp_strvalue; } } else { - username_string = username->strvalue; + username_string = name_attr->vp_strvalue; + } + + if (response_name && + ((username->length != response_name->length) || + (strncasecmp(username->vp_strvalue, response_name->vp_strvalue, username->length) != 0))) { + RDEBUG("ERROR: User-Name (%s) is not the same as MS-CHAP Name (%s) from EAP-MSCHAPv2", username->vp_strvalue, response_name->vp_strvalue); + return RLM_MODULE_REJECT; } +#ifdef __APPLE__ + /* + * No "known good" NT-Password attribute. Try to do + * OpenDirectory authentication. + * + * If OD determines the user is an AD user it will return noop, which + * indicates the auth process should continue directly to AD. + * Otherwise OD will determine auth success/fail. + */ + if (!nt_password && inst->open_directory) { + RDEBUG2("No NT-Password configured. Trying OpenDirectory Authentication."); + int odStatus = od_mschap_auth(request, challenge, username); + if (odStatus != RLM_MODULE_NOOP) { + return odStatus; + } + } +#endif /* * The old "mschapv2" function has been moved to * here. @@ -1252,40 +1238,38 @@ static int mschap_authenticate(void * instance, REQUEST *request) * MS-CHAPv2 takes some additional data to create an * MS-CHAPv1 challenge, and then does MS-CHAPv1. */ - challenge_hash(response->strvalue + 2, /* peer challenge */ - challenge->strvalue, /* our challenge */ + RDEBUG2("Creating challenge hash with username: %s", + username_string); + mschap_challenge_hash(response->vp_octets + 2, /* peer challenge */ + challenge->vp_octets, /* our challenge */ username_string, /* user name */ mschapv1_challenge); /* resulting challenge */ - - DEBUG2(" rlm_mschap: Told to do MS-CHAPv2 for %s with NT-Password", + + RDEBUG2("Told to do MS-CHAPv2 for %s with NT-Password", username_string); if (do_mschap(inst, request, nt_password, mschapv1_challenge, - response->strvalue + 26, nthashhash) < 0) { - DEBUG2(" rlm_mschap: FAILED: MS-CHAP2-Response is incorrect"); - add_reply(&request->reply->vps, *response->strvalue, - "MS-CHAP-Error", "E=691 R=1", 9); + response->vp_octets + 26, nthashhash, + do_ntlm_auth) < 0) { + RDEBUG2("FAILED: MS-CHAP2-Response is incorrect"); + mschap_add_reply(request, &request->reply->vps, + *response->vp_octets, + "MS-CHAP-Error", "E=691 R=1", 9); return RLM_MODULE_REJECT; } - /* - * Get the NT-hash-hash, if necessary - */ - if (nt_password) { - } - - auth_response(username_string, /* without the domain */ + mschap_auth_response(username_string, /* without the domain */ nthashhash, /* nt-hash-hash */ - response->strvalue + 26, /* peer response */ - response->strvalue + 2, /* peer challenge */ - challenge->strvalue, /* our challenge */ + response->vp_octets + 26, /* peer response */ + response->vp_octets + 2, /* peer challenge */ + challenge->vp_octets, /* our challenge */ msch2resp); /* calculated MPPE key */ - add_reply( &request->reply->vps, *response->strvalue, - "MS-CHAP2-Success", msch2resp, 42); + mschap_add_reply(request, &request->reply->vps, *response->vp_octets, + "MS-CHAP2-Success", msch2resp, 42); chap = 2; } else { /* Neither CHAPv1 or CHAPv2 response: die */ - radlog(L_AUTH, "rlm_mschap: No MS-CHAP response found"); + RDEBUG("ERROR: You set 'Auth-Type = MS-CHAP' for a request that does not contain any MS-CHAP attributes!"); return RLM_MODULE_INVALID; } @@ -1301,21 +1285,23 @@ static int mschap_authenticate(void * instance, REQUEST *request) * They're found, but they don't exist, so we * return 'not found'. */ - if (((smb_ctrl->lvalue & ACB_DISABLED) != 0) || - ((smb_ctrl->lvalue & ACB_NORMAL) == 0)) { - DEBUG2(" rlm_mschap: SMB-Account-Ctrl says that the account is disabled, or is not a normal account."); - add_reply( &request->reply->vps, *response->strvalue, - "MS-CHAP-Error", "E=691 R=1", 9); + if (((smb_ctrl->vp_integer & ACB_DISABLED) != 0) || + ((smb_ctrl->vp_integer & ACB_NORMAL) == 0)) { + RDEBUG2("SMB-Account-Ctrl says that the account is disabled, or is not a normal account."); + mschap_add_reply(request, &request->reply->vps, + *response->vp_octets, + "MS-CHAP-Error", "E=691 R=1", 9); return RLM_MODULE_NOTFOUND; } /* * User is locked out. */ - if ((smb_ctrl->lvalue & ACB_AUTOLOCK) != 0) { - DEBUG2(" rlm_mschap: SMB-Account-Ctrl says that the account is locked out."); - add_reply( &request->reply->vps, *response->strvalue, - "MS-CHAP-Error", "E=647 R=0", 9); + if ((smb_ctrl->vp_integer & ACB_AUTOLOCK) != 0) { + RDEBUG2("SMB-Account-Ctrl says that the account is locked out."); + mschap_add_reply(request, &request->reply->vps, + *response->vp_octets, + "MS-CHAP-Error", "E=647 R=0", 9); return RLM_MODULE_USERLOCK; } } @@ -1326,10 +1312,10 @@ static int mschap_authenticate(void * instance, REQUEST *request) uint8_t mppe_recvkey[34]; if (chap == 1){ - DEBUG2("rlm_mschap: adding MS-CHAPv1 MPPE keys"); + RDEBUG2("adding MS-CHAPv1 MPPE keys"); memset(mppe_sendkey, 0, 32); if (lm_password) { - memcpy(mppe_sendkey, lm_password->strvalue, 8); + memcpy(mppe_sendkey, lm_password->vp_octets, 8); } /* @@ -1346,34 +1332,31 @@ static int mschap_authenticate(void * instance, REQUEST *request) */ memcpy(mppe_sendkey + 8, nthashhash, 16); - mppe_add_reply(&request->reply->vps, + mppe_add_reply(request, "MS-CHAP-MPPE-Keys", mppe_sendkey, 32); } else if (chap == 2) { - DEBUG2("rlm_mschap: adding MS-CHAPv2 MPPE keys"); + RDEBUG2("adding MS-CHAPv2 MPPE keys"); mppe_chap2_gen_keys128(nthashhash, - response->strvalue + 26, + response->vp_octets + 26, mppe_sendkey, mppe_recvkey); - - mppe_add_reply(&request->reply->vps, + + mppe_add_reply(request, "MS-MPPE-Recv-Key", mppe_recvkey, 16); - mppe_add_reply(&request->reply->vps, + mppe_add_reply(request, "MS-MPPE-Send-Key", mppe_sendkey, 16); } - reply_attr = pairmake("MS-MPPE-Encryption-Policy", - (inst->require_encryption)? "0x00000002":"0x00000001", - T_OP_EQ); - rad_assert(reply_attr != NULL); - pairadd(&request->reply->vps, reply_attr); - reply_attr = pairmake("MS-MPPE-Encryption-Types", - (inst->require_strong)? "0x00000004":"0x00000006", - T_OP_EQ); - rad_assert(reply_attr != NULL); - pairadd(&request->reply->vps, reply_attr); - + radius_pairmake(request, &request->reply->vps, + "MS-MPPE-Encryption-Policy", + (inst->require_encryption)? "0x00000002":"0x00000001", + T_OP_EQ); + radius_pairmake(request, &request->reply->vps, + "MS-MPPE-Encryption-Types", + (inst->require_strong)? "0x00000004":"0x00000006", + T_OP_EQ); } /* else we weren't asked to use MPPE */ return RLM_MODULE_OK; @@ -1381,20 +1364,19 @@ static int mschap_authenticate(void * instance, REQUEST *request) } module_t rlm_mschap = { - "MS-CHAP", - RLM_TYPE_THREAD_SAFE, /* type */ - NULL, /* initialize */ - mschap_instantiate, /* instantiation */ - { - mschap_authenticate, /* authenticate */ - mschap_authorize, /* authorize */ - NULL, /* pre-accounting */ - NULL, /* accounting */ - NULL, /* checksimul */ - NULL, /* pre-proxy */ - NULL, /* post-proxy */ - NULL /* post-auth */ - }, - mschap_detach, /* detach */ - NULL, /* destroy */ + RLM_MODULE_INIT, + "MS-CHAP", + RLM_TYPE_THREAD_SAFE, /* type */ + mschap_instantiate, /* instantiation */ + mschap_detach, /* detach */ + { + mschap_authenticate, /* authenticate */ + mschap_authorize, /* authorize */ + NULL, /* pre-accounting */ + NULL, /* accounting */ + NULL, /* checksimul */ + NULL, /* pre-proxy */ + NULL, /* post-proxy */ + NULL /* post-auth */ + }, };