port fix from branch_1_1
[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,2006  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/ident.h>
29 RCSID("$Id$")
30
31 #include <freeradius-devel/autoconf.h>
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include <freeradius-devel/radiusd.h>
38 #include <freeradius-devel/modules.h>
39
40 static int chap_authorize(void *instance, REQUEST *request)
41 {
42
43         /* quiet the compiler */
44         instance = instance;
45         request = request;
46
47         if (!pairfind(request->packet->vps, 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, *chap;
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         chap = pairfind(request->packet->vps, PW_CHAP_PASSWORD);
86         if (!chap) {
87                 radlog(L_AUTH, "rlm_chap: Attribute \"CHAP-Password\" is required for authentication.");
88                 return RLM_MODULE_INVALID;
89         }
90
91         if (chap->length == 0) {
92                 radlog(L_ERR, "rlm_chap: empty password supplied");
93                 return RLM_MODULE_INVALID;
94         }
95
96         if (chap->length != CHAP_VALUE_LENGTH + 1) {
97                 radlog(L_ERR, "rlm_chap: password supplied has wrong length");
98                 return RLM_MODULE_INVALID;
99         }
100
101         /*
102          *      Don't print out the CHAP password here.  It's binary crap.
103          */
104         DEBUG("  rlm_chap: login attempt by \"%s\" with CHAP password",
105                 request->username->vp_strvalue);
106
107         if ((passwd_item = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD)) == NULL){
108           DEBUG("  rlm_chap: Cleartext-Password is required for authentication");
109                 snprintf(module_fmsg, sizeof(module_fmsg),
110                          "rlm_chap: Clear text password not available");
111                 module_fmsg_vp = pairmake("Module-Failure-Message",
112                                           module_fmsg, T_OP_EQ);
113                 pairadd(&request->packet->vps, module_fmsg_vp);
114                 return RLM_MODULE_INVALID;
115         }
116
117         DEBUG("  rlm_chap: Using clear text password \"%s\" for user %s authentication.",
118               passwd_item->vp_strvalue, request->username->vp_strvalue);
119
120         rad_chap_encode(request->packet,pass_str,
121                         chap->vp_octets[0],passwd_item);
122
123         if (memcmp(pass_str + 1, chap->vp_octets + 1,
124                    CHAP_VALUE_LENGTH) != 0){
125                 DEBUG("  rlm_chap: Password check failed");
126                 snprintf(module_fmsg, sizeof(module_fmsg),
127                          "rlm_chap: Wrong user password");
128                 module_fmsg_vp = pairmake("Module-Failure-Message",
129                                           module_fmsg, T_OP_EQ);
130                 pairadd(&request->packet->vps, module_fmsg_vp);
131                 return RLM_MODULE_REJECT;
132         }
133
134         DEBUG("  rlm_chap: chap user %s authenticated succesfully",
135               request->username->vp_strvalue);
136
137         return RLM_MODULE_OK;
138 }
139
140 /*
141  *      The module name should be the only globally exported symbol.
142  *      That is, everything else should be 'static'.
143  *
144  *      If the module needs to temporarily modify it's instantiation
145  *      data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
146  *      The server will then take care of ensuring that the module
147  *      is single-threaded.
148  */
149 module_t rlm_chap = {
150          RLM_MODULE_INIT,
151         "CHAP",
152         0,                              /* type */
153         NULL,                           /* instantiation */
154         NULL,                           /* detach */
155         {
156                 chap_authenticate,      /* authentication */
157                 chap_authorize,         /* authorization */
158                 NULL,                   /* preaccounting */
159                 NULL,                   /* accounting */
160                 NULL,                   /* checksimul */
161                 NULL,                   /* pre-proxy */
162                 NULL,                   /* post-proxy */
163                 NULL                    /* post-auth */
164         },
165 };