Remove libradius.h from the top of the standard header list.
[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
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47
48 #include "radiusd.h"
49 #include "modules.h"
50 #include "md5.h"
51
52 #define HASH_LEN 100
53
54 static const char *ns_mta_hextab = "0123456789abcdef";
55
56 /*
57  *  Smaller & faster than snprintf("%x");
58  */
59 static void ns_mta_hexify(char *buffer, char *str, int len)
60 {
61   char *pch = str;
62   char ch;
63   int i;
64
65   for(i = 0;i < len; i ++) {
66     ch = pch[i];
67     buffer[2*i] = ns_mta_hextab[(ch>>4) & 15];
68     buffer[2*i + 1] = ns_mta_hextab[ch & 15];
69   }
70   return;
71 }
72
73 /*
74  *      Do the hash.
75  */
76 static char *ns_mta_hash_alg(char *buffer, const char *salt, const char *passwd)
77 {
78   MD5_CTX context;
79   char saltstr[2048];
80   unsigned char digest[16];
81
82   snprintf(saltstr, sizeof(saltstr), "%s%c%s%c%s",salt, 89, passwd, 247, salt);
83
84   MD5Init(&context);
85   MD5Update(&context,(unsigned char *)saltstr,strlen(saltstr));
86   MD5Final(digest,&context);
87   ns_mta_hexify(buffer,(char*)digest,16);
88   buffer[32] = '\0';
89   return(buffer);
90 }
91
92 /*
93  *  Take the clear
94  */
95 static int ns_mta_md5_pass(const char *clear, const char *encrypted)
96 {
97   char hashed[HASH_LEN];
98   char salt[33];
99
100   if (!(strlen(encrypted) == 64)) {
101     DEBUG2("NS-MTA-MD5 hash not 64 bytes");
102     return -1;
103   }
104
105   memcpy(salt, &encrypted[32], 32);
106   salt[32] = 0;
107   ns_mta_hash_alg(hashed, salt, clear);
108   memcpy(&hashed[32], salt, 33);
109
110   if (strcasecmp(hashed,encrypted) == 0) {
111     return 0;
112   }
113
114   return -1;
115 }
116
117 /*
118  *  Validate User-Name / Passwd
119  */
120 static int module_auth(void *instance, REQUEST *request)
121 {
122         VALUE_PAIR *md5_password;
123
124         /*
125          *      We can only authenticate user requests which HAVE
126          *      a User-Password attribute.
127          */
128         if (!request->password) {
129                 radlog(L_AUTH, "rlm_ns_mta_md5: Attribute \"User-Password\" is required for authentication.");
130                 return RLM_MODULE_INVALID;
131         }
132
133         /*
134          *  Ensure that we're being passed a plain-text password,
135          *  and not anything else.
136          */
137         if (request->password->attribute != PW_PASSWORD) {
138                 radlog(L_AUTH, "rlm_ns_mta_md5: Attribute \"User-Password\" is required for authentication.  Cannot use \"%s\".", request->password->name);
139                 return RLM_MODULE_INVALID;
140         }
141
142         /*
143          *  Find the MD5 encrypted password
144          */
145         md5_password = pairfind(request->config_items, PW_NS_MTA_MD5_PASSWORD);
146         if (!md5_password) {
147                 radlog(L_AUTH, "rlm_ns_mta_md5: Cannot find NS-MTA-MD5-Password attribute.");
148                 return RLM_MODULE_INVALID;
149         }
150
151         /*
152          *  Check their password against the encrypted one.
153          */
154         if (ns_mta_md5_pass(request->password->strvalue,
155                             md5_password->strvalue) < 0) {
156                 return RLM_MODULE_REJECT;
157         }
158
159         return RLM_MODULE_OK;
160 }
161
162 module_t rlm_ns_mta_md5 = {
163   "NS-MTA-MD5",
164   0,                            /* type: reserved */
165   NULL,                         /* initialize */
166   NULL,                         /* instantiation */
167   {
168           module_auth,          /* authenticate */
169           NULL,                 /* authorize */
170           NULL,                 /* pre-accounting */
171           NULL,                 /* accounting */
172           NULL,                 /* checksimul */
173           NULL,                 /* pre-proxy */
174           NULL,                 /* post-proxy */
175           NULL                  /* post-auth */
176   },
177   NULL,                         /* detach */
178   NULL,                         /* destroy */
179 };