Delete trailing whitespace.
[freeradius.git] / src / modules / rlm_pap / rlm_pap.c
1 /*
2  * rlm_pap.c
3  *
4  * Version:  $Id$
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2001,2006  The FreeRADIUS server project
21  * Copyright 2001  Kostas Kalevras <kkalev@noc.ntua.gr>
22  */
23
24 #include <freeradius-devel/ident.h>
25 RCSID("$Id$")
26
27 #include <freeradius-devel/radiusd.h>
28 #include <freeradius-devel/modules.h>
29
30 #include <ctype.h>
31
32 #include "../../include/md5.h"
33 #include "../../include/sha1.h"
34
35 #define PAP_ENC_INVALID -1
36 #define PAP_ENC_CLEAR           0
37 #define PAP_ENC_CRYPT           1
38 #define PAP_ENC_MD5             2
39 #define PAP_ENC_SHA1            3
40 #define PAP_ENC_NT              4
41 #define PAP_ENC_LM              5
42 #define PAP_ENC_SMD5            6
43 #define PAP_ENC_SSHA            7
44 #define PAP_ENC_NS_MTA_MD5      8
45 #define PAP_ENC_AUTO            9
46 #define PAP_MAX_ENC             9
47
48
49 /*
50  *      Define a structure for our module configuration.
51  *
52  *      These variables do not need to be in a structure, but it's
53  *      a lot cleaner to do so, and a pointer to the structure can
54  *      be used as the instance handle.
55  */
56 typedef struct rlm_pap_t {
57         const char *name;       /* CONF_SECTION->name, not strdup'd */
58         char *scheme;  /* password encryption scheme */
59         int sch;
60         char norm_passwd;
61         int auto_header;
62         int auth_type;
63 } rlm_pap_t;
64
65 /*
66  *      A mapping of configuration file names to internal variables.
67  *
68  *      Note that the string is dynamically allocated, so it MUST
69  *      be freed.  When the configuration file parse re-reads the string,
70  *      it free's the old one, and strdup's the new one, placing the pointer
71  *      to the strdup'd string into 'config.string'.  This gets around
72  *      buffer over-flows.
73  */
74 static const CONF_PARSER module_config[] = {
75         { "encryption_scheme", PW_TYPE_STRING_PTR, offsetof(rlm_pap_t,scheme), NULL, "auto" },
76         { "auto_header", PW_TYPE_BOOLEAN, offsetof(rlm_pap_t,auto_header), NULL, "no" },
77         { NULL, -1, 0, NULL, NULL }
78 };
79
80 static const LRAD_NAME_NUMBER schemes[] = {
81         { "clear", PAP_ENC_CLEAR },
82         { "crypt", PAP_ENC_CRYPT },
83         { "md5", PAP_ENC_MD5 },
84         { "sha1", PAP_ENC_SHA1 },
85         { "nt", PAP_ENC_NT },
86         { "lm", PAP_ENC_LM },
87         { "smd5", PAP_ENC_SMD5 },
88         { "ssha", PAP_ENC_SSHA },
89         { "auto", PAP_ENC_AUTO },
90         { NULL, PAP_ENC_INVALID }
91 };
92
93
94 /*
95  *      For auto-header discovery.
96  */
97 static const LRAD_NAME_NUMBER header_names[] = {
98         { "{clear}",    PW_CLEARTEXT_PASSWORD },
99         { "{cleartext}", PW_CLEARTEXT_PASSWORD },
100         { "{md5}",      PW_MD5_PASSWORD },
101         { "{smd5}",     PW_SMD5_PASSWORD },
102         { "{crypt}",    PW_CRYPT_PASSWORD },
103         { "{sha}",      PW_SHA_PASSWORD },
104         { "{ssha}",     PW_SSHA_PASSWORD },
105         { "{nt}",       PW_NT_PASSWORD },
106         { "{x-nthash}", PW_NT_PASSWORD },
107         { "{ns-mta-md5}", PW_NS_MTA_MD5_PASSWORD },
108         { NULL, 0 }
109 };
110
111
112 static int pap_detach(void *instance)
113 {
114         rlm_pap_t *inst = (rlm_pap_t *) instance;
115
116         free(inst);
117
118         return 0;
119 }
120
121
122 static int pap_instantiate(CONF_SECTION *conf, void **instance)
123 {
124         rlm_pap_t *inst;
125         DICT_VALUE *dval;
126
127         /*
128          *      Set up a storage area for instance data
129          */
130         inst = rad_malloc(sizeof(*inst));
131         if (!inst) {
132                 return -1;
133         }
134         memset(inst, 0, sizeof(*inst));
135
136         /*
137          *      If the configuration parameters can't be parsed, then
138          *      fail.
139          */
140         if (cf_section_parse(conf, inst, module_config) < 0) {
141                 pap_detach(inst);
142                 return -1;
143         }
144         if (inst->scheme == NULL || strlen(inst->scheme) == 0){
145                 radlog(L_ERR, "rlm_pap: No scheme defined");
146                 pap_detach(inst);
147                 return -1;
148         }
149
150         inst->sch = lrad_str2int(schemes, inst->scheme, PAP_ENC_INVALID);
151         if (inst->sch == PAP_ENC_INVALID) {
152                 radlog(L_ERR, "rlm_pap: Unknown scheme \"%s\"", inst->scheme);
153                 pap_detach(inst);
154                 return -1;
155         }
156
157         inst->name = cf_section_name2(conf);
158         if (!inst->name) {
159                 inst->name = cf_section_name1(conf);
160         }
161
162         dval = dict_valbyname(PW_AUTH_TYPE, inst->name);
163         if (dval) {
164                 inst->auth_type = dval->value;
165         } else {
166                 inst->auth_type = 0;
167         }
168
169         *instance = inst;
170
171         return 0;
172 }
173
174
175 /*
176  *      Decode one base64 chunk
177  */
178 static int decode_it(const char *src, uint8_t *dst)
179 {
180         int i;
181         unsigned int x = 0;
182
183         for(i = 0; i < 4; i++) {
184                 if (src[i] >= 'A' && src[i] <= 'Z')
185                         x = (x << 6) + (unsigned int)(src[i] - 'A' + 0);
186                 else if (src[i] >= 'a' && src[i] <= 'z')
187                          x = (x << 6) + (unsigned int)(src[i] - 'a' + 26);
188                 else if(src[i] >= '0' && src[i] <= '9')
189                          x = (x << 6) + (unsigned int)(src[i] - '0' + 52);
190                 else if(src[i] == '+')
191                         x = (x << 6) + 62;
192                 else if (src[i] == '/')
193                         x = (x << 6) + 63;
194                 else if (src[i] == '=')
195                         x = (x << 6);
196                 else return 0;
197         }
198
199         dst[2] = (unsigned char)(x & 255); x >>= 8;
200         dst[1] = (unsigned char)(x & 255); x >>= 8;
201         dst[0] = (unsigned char)(x & 255); x >>= 8;
202
203         return 1;
204 }
205
206
207 /*
208  *      Base64 decoding.
209  */
210 static int base64_decode (const char *src, uint8_t *dst)
211 {
212         int length, equals;
213         int i, num;
214         char last[3];
215
216         length = equals = 0;
217         while (src[length] && src[length] != '=') length++;
218
219         while (src[length + equals] == '=') equals++;
220
221         num = (length + equals) / 4;
222
223         for (i = 0; i < num - 1; i++) {
224                 if (!decode_it(src, dst)) return 0;
225                 src += 4;
226                 dst += 3;
227         }
228
229         decode_it(src, last);
230         for (i = 0; i < (3 - equals); i++) {
231                 dst[i] = last[i];
232         }
233
234         return (num * 3) - equals;
235 }
236
237
238 /*
239  *      Hex or base64 or bin auto-discovery.
240  */
241 static void normify(VALUE_PAIR *vp, int min_length)
242 {
243         int decoded;
244         char buffer[64];
245
246         if ((size_t) min_length >= sizeof(buffer)) return; /* paranoia */
247
248         /*
249          *      Hex encoding.
250          */
251         if (vp->length >= (2 * min_length)) {
252                 decoded = lrad_hex2bin(vp->vp_octets, buffer, vp->length >> 1);
253                 if (decoded == (vp->length >> 1)) {
254                         DEBUG2("rlm_pap: Normalizing %s from hex encoding", vp->name);
255                         memcpy(vp->vp_octets, buffer, decoded);
256                         vp->length = decoded;
257                         return;
258                 }
259         }
260
261         /*
262          *      Base 64 encoding.  It's at least 4/3 the original size,
263          *      and we want to avoid division...
264          */
265         if ((vp->length * 3) >= ((min_length * 4))) {
266                 decoded = base64_decode(vp->vp_octets, buffer);
267                 if (decoded >= min_length) {
268                         DEBUG2("rlm_pap: Normalizing %s from base64 encoding", vp->name);
269                         memcpy(vp->vp_octets, buffer, decoded);
270                         vp->length = decoded;
271                         return;
272                 }
273         }
274
275         /*
276          *      Else unknown encoding, or already binary.  Leave it.
277          */
278 }
279
280
281 /*
282  *      Authorize the user for PAP authentication.
283  *
284  *      This isn't strictly necessary, but it does make the
285  *      server simpler to configure.
286  */
287 static int pap_authorize(void *instance, REQUEST *request)
288 {
289         rlm_pap_t *inst = instance;
290         int auth_type = FALSE;
291         int found_pw = FALSE;
292         VALUE_PAIR *vp, *next;
293
294         for (vp = request->config_items; vp != NULL; vp = next) {
295                 next = vp->next;
296
297                 switch (vp->attribute) {
298                 case PW_USER_PASSWORD: /* deprecated */
299                         found_pw = TRUE;
300
301                         /*
302                          *      Look for '{foo}', and use them
303                          */
304                         if (!inst->auto_header ||
305                             (vp->vp_strvalue[0] != '{')) {
306                                 break;
307                         }
308                         /* FALL-THROUGH */
309
310                 case PW_PASSWORD_WITH_HEADER: /* preferred */
311                 {
312                         int attr;
313                         uint8_t *p, *q;
314                         char buffer[64];
315                         VALUE_PAIR *new_vp;
316
317                         found_pw = TRUE;
318                         q = vp->vp_strvalue;
319                         p = strchr(q + 1, '}');
320                         if (!p) {
321                                 /*
322                                  *      FIXME: Turn it into a
323                                  *      cleartext-password, unless it,
324                                  *      or user-password already
325                                  *      exists.
326                                  */
327                                 break;
328                         }
329
330                         if ((size_t) (p - q) > sizeof(buffer)) break;
331
332                         memcpy(buffer, q, p - q + 1);
333                         buffer[p - q + 1] = '\0';
334
335                         attr = lrad_str2int(header_names, buffer, 0);
336                         if (!attr) {
337                                 DEBUG2("rlm_pap: Found unknown header {%s}: Not doing anything", buffer);
338                                 break;
339                         }
340
341                         new_vp = radius_paircreate(request,
342                                                    &request->config_items,
343                                                    attr, PW_TYPE_STRING);
344                         strcpy(new_vp->vp_strvalue, p + 1);/* bounds OK */
345                         new_vp->length = strlen(new_vp->vp_strvalue);
346
347                         /*
348                          *      May be old-style User-Password with header.
349                          *      We've found the header & created the proper
350                          *      attribute, so we should delete the old
351                          *      User-Password here.
352                          */
353                         pairdelete(&request->config_items, PW_USER_PASSWORD);
354                 }
355                         break;
356
357                 case PW_CLEARTEXT_PASSWORD:
358                 case PW_CRYPT_PASSWORD:
359                 case PW_NS_MTA_MD5_PASSWORD:
360                         found_pw = TRUE;
361                         break;  /* don't touch these */
362
363                 case PW_MD5_PASSWORD:
364                 case PW_SMD5_PASSWORD:
365                 case PW_NT_PASSWORD:
366                 case PW_LM_PASSWORD:
367                         normify(vp, 16); /* ensure it's in the right format */
368                         found_pw = TRUE;
369                         break;
370
371                 case PW_SHA_PASSWORD:
372                 case PW_SSHA_PASSWORD:
373                         normify(vp, 20); /* ensure it's in the right format */
374                         found_pw = TRUE;
375                         break;
376
377                         /*
378                          *      If it's proxied somewhere, don't complain
379                          *      about not having passwords or Auth-Type.
380                          */
381                 case PW_PROXY_TO_REALM:
382                 {
383                         REALM *realm = realm_find(vp->vp_strvalue);
384                         if (realm && !realm->auth_pool) {
385                                 return RLM_MODULE_NOOP;
386                         }
387                         break;
388                 }
389
390                 case PW_AUTH_TYPE:
391                         auth_type = TRUE;
392
393                         /*
394                          *      Auth-Type := Accept
395                          *      Auth-Type := Reject
396                          */
397                         if ((vp->vp_integer == 254) ||
398                             (vp->vp_integer == 4)) {
399                             found_pw = 1;
400                         }
401                         break;
402
403                 default:
404                         break;  /* ignore it */
405
406                 }
407         }
408
409         /*
410          *      Print helpful warnings if there was no password.
411          */
412         if (!found_pw) {
413                 /*
414                  *      Likely going to be proxied.  Avoid printing
415                  *      warning message.
416                  */
417                 if (pairfind(request->config_items, PW_REALM) ||
418                     (pairfind(request->config_items, PW_PROXY_TO_REALM))) {
419                         return RLM_MODULE_NOOP;
420                 }
421
422                 /*
423                  *      The TLS types don't need passwords.
424                  */
425                 vp = pairfind(request->packet->vps, PW_EAP_TYPE);
426                 if (vp &&
427                     ((vp->vp_integer == 13) || /* EAP-TLS */
428                      (vp->vp_integer == 21) || /* EAP-TTLS */
429                      (vp->vp_integer == 25))) { /* PEAP */
430                         return RLM_MODULE_NOOP;
431                 }
432
433                 DEBUG("rlm_pap: WARNING! No \"known good\" password found for the user.  Authentication may fail because of this.");
434                 return RLM_MODULE_NOOP;
435         }
436
437         /*
438          *      Don't touch existing Auth-Types.
439          */
440         if (auth_type) {
441                 DEBUG2("rlm_pap: Found existing Auth-Type, not changing it.");
442                 return RLM_MODULE_NOOP;
443         }
444
445         /*
446          *      Can't do PAP if there's no password.
447          */
448         if (!request->password ||
449             (request->password->attribute != PW_USER_PASSWORD)) {
450                 /*
451                  *      Don't print out debugging messages if we know
452                  *      they're useless.
453                  */
454                 if (request->packet->code == PW_ACCESS_CHALLENGE) {
455                         return RLM_MODULE_NOOP;
456                 }
457
458                 DEBUG2("rlm_pap: No clear-text password in the request.  Not performing PAP.");
459                 return RLM_MODULE_NOOP;
460         }
461
462         if (inst->auth_type) {
463                 vp = radius_paircreate(request, &request->config_items,
464                                        PW_AUTH_TYPE, PW_TYPE_INTEGER);
465                 vp->vp_integer = inst->auth_type;
466         }
467
468         return RLM_MODULE_UPDATED;
469 }
470
471
472 /*
473  *      Authenticate the user via one of any well-known password.
474  */
475 static int pap_authenticate(void *instance, REQUEST *request)
476 {
477         rlm_pap_t *inst = instance;
478         VALUE_PAIR *vp;
479         VALUE_PAIR *module_fmsg_vp;
480         char module_fmsg[MAX_STRING_LEN];
481         MD5_CTX md5_context;
482         SHA1_CTX sha1_context;
483         uint8_t digest[40];
484         char buff[MAX_STRING_LEN];
485         char buff2[MAX_STRING_LEN + 50];
486         int scheme = PAP_ENC_INVALID;
487
488         if (!request->password){
489                 radlog(L_AUTH, "rlm_pap: Attribute \"Password\" is required for authentication.");
490                 return RLM_MODULE_INVALID;
491         }
492
493         /*
494          *      Clear-text passwords are the only ones we support.
495          */
496         if (request->password->attribute != PW_USER_PASSWORD) {
497                 radlog(L_AUTH, "rlm_pap: Attribute \"User-Password\" is required for authentication. Cannot use \"%s\".", request->password->name);
498                 return RLM_MODULE_INVALID;
499         }
500
501         /*
502          *      The user MUST supply a non-zero-length password.
503          */
504         if (request->password->length == 0) {
505                 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: empty password supplied");
506                 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
507                 pairadd(&request->packet->vps, module_fmsg_vp);
508                 return RLM_MODULE_INVALID;
509         }
510
511         DEBUG("rlm_pap: login attempt with password %s",
512               request->password->vp_strvalue);
513
514         /*
515          *      First, auto-detect passwords, by attribute in the
516          *      config items.
517          */
518         if (inst->sch == PAP_ENC_AUTO) {
519                 for (vp = request->config_items; vp != NULL; vp = vp->next) {
520                         switch (vp->attribute) {
521                         case PW_USER_PASSWORD: /* deprecated */
522                         case PW_CLEARTEXT_PASSWORD: /* preferred */
523                                 goto do_clear;
524
525                         case PW_CRYPT_PASSWORD:
526                                 goto do_crypt;
527
528                         case PW_MD5_PASSWORD:
529                                 goto do_md5;
530
531                         case PW_SHA_PASSWORD:
532                                 goto do_sha;
533
534                         case PW_NT_PASSWORD:
535                                 goto do_nt;
536
537                         case PW_LM_PASSWORD:
538                                 goto do_lm;
539
540                         case PW_SMD5_PASSWORD:
541                                 goto do_smd5;
542
543                         case PW_SSHA_PASSWORD:
544                                 goto do_ssha;
545
546                         case PW_NS_MTA_MD5_PASSWORD:
547                                 goto do_ns_mta_md5;
548
549                         default:
550                                 break;  /* ignore it */
551
552                         }
553                 }
554
555         fail:
556                 DEBUG("rlm_pap: No password configured for the user.  Cannot do authentication");
557                 return RLM_MODULE_FAIL;
558
559         } else {
560                 vp = NULL;
561
562                 if (inst->sch == PAP_ENC_CRYPT) {
563                         vp = pairfind(request->config_items, PW_CRYPT_PASSWORD);
564                 }
565
566                 /*
567                  *      Old-style: all passwords are in User-Password.
568                  */
569                 if (!vp) {
570                         vp = pairfind(request->config_items, PW_USER_PASSWORD);
571                         if (!vp) goto fail;
572                 }
573         }
574
575         /*
576          *      Now that we've decided what to do, go do it.
577          */
578         switch (scheme) {
579         case PAP_ENC_CLEAR:
580         do_clear:
581                 DEBUG("rlm_pap: Using clear text password.");
582                 if (strcmp((char *) vp->vp_strvalue,
583                            (char *) request->password->vp_strvalue) != 0){
584                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: CLEAR TEXT password check failed");
585                         goto make_msg;
586                 }
587         done:
588                 DEBUG("rlm_pap: User authenticated successfully");
589                 return RLM_MODULE_OK;
590                 break;
591
592         case PAP_ENC_CRYPT:
593         do_crypt:
594                 DEBUG("rlm_pap: Using CRYPT encryption.");
595                 if (lrad_crypt_check((char *) request->password->vp_strvalue,
596                                      (char *) vp->vp_strvalue) != 0) {
597                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: CRYPT password check failed");
598                         goto make_msg;
599                 }
600                 goto done;
601                 break;
602
603         case PW_MD5_PASSWORD:
604         do_md5:
605                 DEBUG("rlm_pap: Using MD5 encryption.");
606
607                 normify(vp, 16);
608                 if (vp->length != 16) {
609                 DEBUG("rlm_pap: Configured MD5 password has incorrect length");
610                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: Configured MD5 password has incorrect length");
611                         goto make_msg;
612                 }
613
614                 MD5Init(&md5_context);
615                 MD5Update(&md5_context, request->password->vp_strvalue,
616                           request->password->length);
617                 MD5Final(digest, &md5_context);
618                 if (memcmp(digest, vp->vp_octets, vp->length) != 0) {
619                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: MD5 password check failed");
620                         goto make_msg;
621                 }
622                 goto done;
623                 break;
624
625         case PW_SMD5_PASSWORD:
626         do_smd5:
627                 DEBUG("rlm_pap: Using SMD5 encryption.");
628
629                 normify(vp, 16);
630                 if (vp->length <= 16) {
631                         DEBUG("rlm_pap: Configured SMD5 password has incorrect length");
632                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: Configured SMD5 password has incorrect length");
633                         goto make_msg;
634                 }
635
636                 MD5Init(&md5_context);
637                 MD5Update(&md5_context, request->password->vp_strvalue,
638                           request->password->length);
639                 MD5Update(&md5_context, &vp->vp_octets[16], vp->length - 16);
640                 MD5Final(digest, &md5_context);
641
642                 /*
643                  *      Compare only the MD5 hash results, not the salt.
644                  */
645                 if (memcmp(digest, vp->vp_octets, 16) != 0) {
646                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: SMD5 password check failed");
647                         goto make_msg;
648                 }
649                 goto done;
650                 break;
651
652         case PW_SHA_PASSWORD:
653         do_sha:
654                 DEBUG("rlm_pap: Using SHA1 encryption.");
655
656                 normify(vp, 20);
657                 if (vp->length != 20) {
658                         DEBUG("rlm_pap: Configured SHA1 password has incorrect length");
659                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: Configured SHA1 password has incorrect length");
660                         goto make_msg;
661                 }
662
663                 SHA1Init(&sha1_context);
664                 SHA1Update(&sha1_context, request->password->vp_strvalue,
665                            request->password->length);
666                 SHA1Final(digest,&sha1_context);
667                 if (memcmp(digest, vp->vp_octets, vp->length) != 0) {
668                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: SHA1 password check failed");
669                         goto make_msg;
670                 }
671                 goto done;
672                 break;
673
674         case PW_SSHA_PASSWORD:
675         do_ssha:
676                 DEBUG("rlm_pap: Using SSHA encryption.");
677
678                 normify(vp, 20);
679                 if (vp->length <= 20) {
680                         DEBUG("rlm_pap: Configured SSHA password has incorrect length");
681                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: Configured SHA password has incorrect length");
682                         goto make_msg;
683                 }
684
685
686                 SHA1Init(&sha1_context);
687                 SHA1Update(&sha1_context, request->password->vp_strvalue,
688                            request->password->length);
689                 SHA1Update(&sha1_context, &vp->vp_octets[20], vp->length - 20);
690                 SHA1Final(digest,&sha1_context);
691                 if (memcmp(digest, vp->vp_octets, 20) != 0) {
692                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: SSHA password check failed");
693                         goto make_msg;
694                 }
695                 goto done;
696                 break;
697
698         case PW_NT_PASSWORD:
699         do_nt:
700                 DEBUG("rlm_pap: Using NT encryption.");
701
702                 normify(vp, 16);
703                 if (vp->length != 16) {
704                         DEBUG("rlm_pap: Configured NT-Password has incorrect length");
705                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: Configured NT-Password has incorrect length");
706                         goto make_msg;
707                 }
708
709                 sprintf(buff2,"%%{mschap:NT-Hash %s}",
710                         request->password->vp_strvalue);
711                 if (!radius_xlat(digest,sizeof(digest),buff2,request,NULL)){
712                         DEBUG("rlm_pap: mschap xlat failed");
713                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: mschap xlat failed");
714                         goto make_msg;
715                 }
716                 if ((lrad_hex2bin(digest, digest, 16) != vp->length) ||
717                     (memcmp(digest, vp->vp_octets, vp->length) != 0)) {
718                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: NT password check failed");
719                         goto make_msg;
720                 }
721                 goto done;
722                 break;
723
724         case PW_LM_PASSWORD:
725         do_lm:
726                 DEBUG("rlm_pap: Using LM encryption.");
727
728                 normify(vp, 16);
729                 if (vp->length != 16) {
730                         DEBUG("rlm_pap: Configured LM-Password has incorrect length");
731                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: Configured LM-Password has incorrect length");
732                         goto make_msg;
733                 }
734                 sprintf(buff2,"%%{mschap:LM-Hash %s}",
735                         request->password->vp_strvalue);
736                 if (!radius_xlat(digest,sizeof(digest),buff2,request,NULL)){
737                         DEBUG("rlm_pap: mschap xlat failed");
738                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: mschap xlat failed");
739                         goto make_msg;
740                 }
741                 if ((lrad_hex2bin(digest, digest, 16) != vp->length) ||
742                     (memcmp(digest, vp->vp_octets, vp->length) != 0)) {
743                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: LM password check failed");
744                 make_msg:
745                         DEBUG("rlm_pap: Passwords don't match");
746                         module_fmsg_vp = pairmake("Module-Failure-Message",
747                                                   module_fmsg, T_OP_EQ);
748                         pairadd(&request->packet->vps, module_fmsg_vp);
749                         return RLM_MODULE_REJECT;
750                 }
751                 goto done;
752                 break;
753
754         case PAP_ENC_NS_MTA_MD5:
755         do_ns_mta_md5:
756                 DEBUG("rlm_pap: Using NT-MTA-MD5 password");
757
758                 if (vp->length != 64) {
759                         DEBUG("rlm_pap: Configured NS-MTA-MD5-Password has incorrect length");
760                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: Configured NS-MTA-MD5-Password has incorrect length");
761                         goto make_msg;
762                 }
763
764                 /*
765                  *      Sanity check the value of NS-MTA-MD5-Password
766                  */
767                 if (lrad_hex2bin(vp->vp_octets, buff, 32) != 16) {
768                         DEBUG("rlm_pap: Configured NS-MTA-MD5-Password has invalid value");
769                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: Configured NS-MTA-MD5-Password has invalid value");
770                         goto make_msg;
771                 }
772
773                 /*
774                  *      Ensure we don't have buffer overflows.
775                  *
776                  *      This really: sizeof(buff) - 2 - 2*32 - strlen(passwd)
777                  */
778                 if (strlen(request->password->vp_strvalue) >= (sizeof(buff2) - 2 - 2 * 32)) {
779                         DEBUG("rlm_pap: Configured password is too long");
780                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: password is too long");
781                         goto make_msg;
782                 }
783
784                 /*
785                  *      Set up the algorithm.
786                  */
787                 {
788                         char *p = buff2;
789
790                         memcpy(p, &vp->vp_octets[32], 32);
791                         p += 32;
792                         *(p++) = 89;
793                         strcpy(p, request->password->vp_strvalue);
794                         p += strlen(p);
795                         *(p++) = 247;
796                         memcpy(p, &vp->vp_octets[32], 32);
797                         p += 32;
798
799                         MD5Init(&md5_context);
800                         MD5Update(&md5_context, buff2, p - buff2);
801                         MD5Final(digest, &md5_context);
802                 }
803                 if (memcmp(digest, buff, 16) != 0) {
804                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: NS-MTA-MD5 password check failed");
805                         goto make_msg;
806                 }
807                 goto done;
808
809         default:
810                 break;
811         }
812
813         DEBUG("rlm_pap: No password configured for the user.  Cannot do authentication");
814         return RLM_MODULE_FAIL;
815 }
816
817
818 /*
819  *      The module name should be the only globally exported symbol.
820  *      That is, everything else should be 'static'.
821  *
822  *      If the module needs to temporarily modify it's instantiation
823  *      data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
824  *      The server will then take care of ensuring that the module
825  *      is single-threaded.
826  */
827 module_t rlm_pap = {
828         RLM_MODULE_INIT,
829         "PAP",
830         0,                              /* type */
831         pap_instantiate,                /* instantiation */
832         pap_detach,                     /* detach */
833         {
834                 pap_authenticate,       /* authentication */
835                 pap_authorize,          /* authorization */
836                 NULL,                   /* preaccounting */
837                 NULL,                   /* accounting */
838                 NULL,                   /* checksimul */
839                 NULL,                   /* pre-proxy */
840                 NULL,                   /* post-proxy */
841                 NULL                    /* post-auth */
842         },
843 };