bug-fix for nesting
[freeradius.git] / src / modules / rlm_ns_mta_md5 / rlm_ns_mta_md5.c
1 /*
2  * rlm_ns_mta_md5.c     Functions to authenticate using NS-MTA-MD5 passwords.
3  *              Taken from the hacks for qmail located at nrg4u.com
4  *              by Andre Oppermann.
5  *
6  *              NS-MTA-MD5 passwords are 64 byte strings, the first  
7  *              32 bytes being the password hash and the last 32 bytes 
8  *              the salt.  The clear text password and the salt are MD5 
9  *              hashed[1].  If the resulting hash concatenated with the salt
10  *              are equivalent to the original NS-MTA-MD5 password the 
11  *              password is correct. 
12  *
13  *              [1] Read the source for details.
14  *
15  *              bob Auth-Type := NS-MTA-MD5, NS-MTA-MD5-Password := "f8b4eac9f051a61eebe266f9c29a193626d8eb25c2598c55c8874260b24eb435"
16  *                  Reply-Message = "NS-MTA-MD5 is working!"
17  *              password = "testpass".
18  *
19  *  Version:    $Id$
20  *
21  *   This program is free software; you can redistribute it and/or modify
22  *   it under the terms of the GNU General Public License as published by
23  *   the Free Software Foundation; either version 2 of the License, or
24  *   (at your option) any later version.
25  *
26  *   This program is distributed in the hope that it will be useful,
27  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
28  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
29  *   GNU General Public License for more details.
30  *
31  *   You should have received a copy of the GNU General Public License
32  *   along with this program; if not, write to the Free Software
33  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
34  *
35  * Copyright 2000  The FreeRADIUS server project
36  * Copyright 2000  Andre Oppermann
37  */
38
39
40 static const char rcsid[] = "$Id$";
41
42 #include "autoconf.h"
43 #include "libradius.h"
44
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48
49 #include "radiusd.h"
50 #include "modules.h"
51 #include "md5.h"
52
53 #define HASH_LEN 100
54
55 static const char *ns_mta_hextab = "0123456789abcdef";
56
57 /*
58  *  Smaller & faster than snprintf("%x");
59  */
60 static void ns_mta_hexify(char *buffer, char *str, int len)
61 {
62   char *pch = str;
63   char ch;
64   int i;
65
66   for(i = 0;i < len; i ++) {
67     ch = pch[i];
68     buffer[2*i] = ns_mta_hextab[(ch>>4) & 15];
69     buffer[2*i + 1] = ns_mta_hextab[ch & 15];
70   }
71   return;
72 }
73
74 /*
75  *      Do the hash.
76  */
77 static char *ns_mta_hash_alg(char *buffer, const char *salt, const char *passwd)
78 {
79   MD5_CTX context;
80   char saltstr[2048];
81   unsigned char digest[16];
82
83   snprintf(saltstr, sizeof(saltstr), "%s%c%s%c%s",salt, 89, passwd, 247, salt);
84
85   MD5Init(&context);
86   MD5Update(&context,(unsigned char *)saltstr,strlen(saltstr));
87   MD5Final(digest,&context);
88   ns_mta_hexify(buffer,(char*)digest,16);
89   buffer[32] = '\0';
90   return(buffer);
91 }
92
93 /*
94  *  Take the clear
95  */
96 static int ns_mta_md5_pass(const char *clear, const char *encrypted)
97 {
98   char hashed[HASH_LEN];
99   char salt[33];
100
101   if (!(strlen(encrypted) == 64)) {
102     DEBUG2("NS-MTA-MD5 hash not 64 bytes");
103     return -1;
104   }
105
106   memcpy(salt, &encrypted[32], 32);
107   salt[32] = 0;
108   ns_mta_hash_alg(hashed, salt, clear);
109   memcpy(&hashed[32], salt, 33);
110
111   if (strcasecmp(hashed,encrypted) == 0) {
112     return 0;
113   }
114
115   return -1;
116 }
117
118 /*
119  *  Validate User-Name / Passwd
120  */
121 static int module_auth(void *instance, REQUEST *request)
122 {
123         VALUE_PAIR *md5_password;
124         
125         /*
126          *      We can only authenticate user requests which HAVE
127          *      a Password attribute.
128          */
129         if (!request->password) {
130                 radlog(L_AUTH, "rlm_ns_m5a_md5: Attribute \"Password\" is required for authentication.");
131                 return RLM_MODULE_INVALID;
132         }
133
134         /*
135          *  Ensure that we're being passed a plain-text password,
136          *  and not anything else.
137          */
138         if (request->password->attribute != PW_PASSWORD) {
139                 radlog(L_AUTH, "rlm_ns_mta_md5: Attribute \"Password\" is required for authentication.  Cannot use \"%s\".", request->password->name);
140                 return RLM_MODULE_INVALID;
141         }
142
143         /*
144          *  Find the MD5 encrypted password
145          */
146         md5_password = pairfind(request->config_items, PW_NS_MTA_MD5_PASSWORD);
147         if (!md5_password) {
148                 radlog(L_AUTH, "rlm_ns_mta_md5: Cannot find NS-MTA-MD5-Password attribute.");
149                 return RLM_MODULE_INVALID;
150         }
151
152         /*
153          *  Check their password against the encrypted one.
154          */
155         if (ns_mta_md5_pass(request->password->strvalue,
156                             md5_password->strvalue) < 0) {
157                 return RLM_MODULE_REJECT;
158         }
159
160         return RLM_MODULE_OK;
161 }
162
163 module_t rlm_ns_mta_md5 = {
164   "NS-MTA-MD5",
165   0,                            /* type: reserved */
166   NULL,                         /* initialize */
167   NULL,                         /* instantiation */
168   NULL,                         /* authorize */
169   module_auth,                  /* authenticate */
170   NULL,                         /* pre-accounting */
171   NULL,                         /* accounting */
172   NULL,                         /* checksimul */
173   NULL,                         /* detach */
174   NULL,                         /* destroy */
175 };