./scripts/min-includes +n <files listed here>
[freeradius.git] / src / modules / rlm_chap / rlm_chap.c
1 /*
2  * rlm_chap.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  The FreeRADIUS server project
21  * Copyright 2001  Kostas Kalevras <kkalev@noc.ntua.gr>
22  *
23  * Nov 03 2001, Kostas Kalevras <kkalev@noc.ntua.gr>
24  * - Added authorize() function to set Auth-Type if Chap-Password exists
25  * - Added module messages when rejecting user
26  */
27
28 #include <freeradius-devel/autoconf.h>
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include <freeradius-devel/radiusd.h>
35 #include <freeradius-devel/modules.h>
36
37 static const char rcsid[] = "$Id$";
38
39 static int chap_authorize(void *instance, REQUEST *request)
40 {
41
42         /* quiet the compiler */
43         instance = instance;
44         request = request;
45
46         if (!request->password ||
47             request->password->attribute != PW_CHAP_PASSWORD) {
48                 return RLM_MODULE_NOOP;
49         }
50
51         if (pairfind(request->config_items, PW_AUTHTYPE) != NULL) {
52                 DEBUG2("  rlm_chap: WARNING: Auth-Type already set.  Not setting to CHAP");
53                 return RLM_MODULE_NOOP;
54         }
55
56         DEBUG("  rlm_chap: Setting 'Auth-Type := CHAP'");
57         pairadd(&request->config_items,
58                 pairmake("Auth-Type", "CHAP", T_OP_EQ));
59         return RLM_MODULE_OK;
60 }
61
62
63 /*
64  *      Find the named user in this modules database.  Create the set
65  *      of attribute-value pairs to check and reply with for this user
66  *      from the database. The authentication code only needs to check
67  *      the password, the rest is done here.
68  */
69 static int chap_authenticate(void *instance, REQUEST *request)
70 {
71         VALUE_PAIR *passwd_item;
72         uint8_t pass_str[MAX_STRING_LEN];
73         VALUE_PAIR *module_fmsg_vp;
74         char module_fmsg[MAX_STRING_LEN];
75
76         /* quiet the compiler */
77         instance = instance;
78         request = request;
79
80         if (!request->username) {
81                 radlog(L_AUTH, "rlm_chap: Attribute \"User-Name\" is required for authentication.\n");
82                 return RLM_MODULE_INVALID;
83         }
84
85         if (!request->password) {
86                 radlog(L_AUTH, "rlm_chap: Attribute \"CHAP-Password\" is required for authentication.");
87                 return RLM_MODULE_INVALID;
88         }
89
90         if (request->password->attribute != PW_CHAP_PASSWORD) {
91                 radlog(L_AUTH, "rlm_chap: Attribute \"CHAP-Password\" is required for authentication. Cannot use \"%s\".", request->password->name);
92                 return RLM_MODULE_INVALID;
93         }
94
95         if (request->password->length == 0) {
96                 radlog(L_ERR, "rlm_chap: empty password supplied");
97                 return RLM_MODULE_INVALID;
98         }
99
100         if (request->password->length != CHAP_VALUE_LENGTH + 1) {
101                 radlog(L_ERR, "rlm_chap: password supplied has wrong length");
102                 return RLM_MODULE_INVALID;
103         }
104
105         /*
106          *      Don't print out the CHAP password here.  It's binary crap.
107          */
108         DEBUG("  rlm_chap: login attempt by \"%s\" with CHAP password",
109                 request->username->vp_strvalue);
110
111         if ((passwd_item = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD)) == NULL){
112           DEBUG("  rlm_chap: Cleartext-Password is required for authentication");
113                 snprintf(module_fmsg, sizeof(module_fmsg),
114                          "rlm_chap: Clear text password not available");
115                 module_fmsg_vp = pairmake("Module-Failure-Message",
116                                           module_fmsg, T_OP_EQ);
117                 pairadd(&request->packet->vps, module_fmsg_vp);
118                 return RLM_MODULE_INVALID;
119         }
120
121         DEBUG("  rlm_chap: Using clear text password %s for user %s authentication.",
122               passwd_item->vp_strvalue, request->username->vp_strvalue);
123
124         rad_chap_encode(request->packet,pass_str,
125                         request->password->vp_octets[0],passwd_item);
126
127         if (memcmp(pass_str + 1, request->password->vp_octets + 1,
128                    CHAP_VALUE_LENGTH) != 0){
129                 DEBUG("  rlm_chap: Pasword check failed");
130                 snprintf(module_fmsg, sizeof(module_fmsg),
131                          "rlm_chap: Wrong user password");
132                 module_fmsg_vp = pairmake("Module-Failure-Message",
133                                           module_fmsg, T_OP_EQ);
134                 pairadd(&request->packet->vps, module_fmsg_vp);
135                 return RLM_MODULE_REJECT;
136         }
137
138         DEBUG("  rlm_chap: chap user %s authenticated succesfully",
139               request->username->vp_strvalue);
140
141         return RLM_MODULE_OK;
142 }
143
144 /*
145  *      The module name should be the only globally exported symbol.
146  *      That is, everything else should be 'static'.
147  *
148  *      If the module needs to temporarily modify it's instantiation
149  *      data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
150  *      The server will then take care of ensuring that the module
151  *      is single-threaded.
152  */
153 module_t rlm_chap = {
154          RLM_MODULE_INIT,
155         "CHAP",
156         0,                              /* type */
157         NULL,                           /* instantiation */
158         NULL,                           /* detach */
159         {
160                 chap_authenticate,      /* authentication */
161                 chap_authorize,         /* authorization */
162                 NULL,                   /* preaccounting */
163                 NULL,                   /* accounting */
164                 NULL,                   /* checksimul */
165                 NULL,                   /* pre-proxy */
166                 NULL,                   /* post-proxy */
167                 NULL                    /* post-auth */
168         },
169 };