Add support for tags to remaining functions in lib/valuepair.c
[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/radiusd.h>
32 #include <freeradius-devel/modules.h>
33
34 static int chap_authorize(void *instance, REQUEST *request)
35 {
36
37         /* quiet the compiler */
38         instance = instance;
39         request = request;
40
41         if (!pairfind(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY)) {
42                 return RLM_MODULE_NOOP;
43         }
44
45         if (pairfind(request->config_items, PW_AUTHTYPE, 0, TAG_ANY) != NULL) {
46                 RDEBUG2("WARNING: Auth-Type already set.  Not setting to CHAP");
47                 return RLM_MODULE_NOOP;
48         }
49
50         RDEBUG("Setting 'Auth-Type := CHAP'");
51         pairadd(&request->config_items,
52                 pairmake("Auth-Type", "CHAP", T_OP_EQ));
53         return RLM_MODULE_OK;
54 }
55
56
57 /*
58  *      Find the named user in this modules database.  Create the set
59  *      of attribute-value pairs to check and reply with for this user
60  *      from the database. The authentication code only needs to check
61  *      the password, the rest is done here.
62  */
63 static int chap_authenticate(void *instance, REQUEST *request)
64 {
65         VALUE_PAIR *passwd_item, *chap;
66         uint8_t pass_str[MAX_STRING_LEN];
67         VALUE_PAIR *module_fmsg_vp;
68         char module_fmsg[MAX_STRING_LEN];
69
70         /* quiet the compiler */
71         instance = instance;
72         request = request;
73
74         if (!request->username) {
75                 radlog_request(L_AUTH, 0, request, "rlm_chap: Attribute \"User-Name\" is required for authentication.\n");
76                 return RLM_MODULE_INVALID;
77         }
78
79         chap = pairfind(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY);
80         if (!chap) {
81                 RDEBUG("ERROR: You set 'Auth-Type = CHAP' for a request that does not contain a CHAP-Password attribute!");
82                 return RLM_MODULE_INVALID;
83         }
84
85         if (chap->length == 0) {
86                 RDEBUG("ERROR: CHAP-Password is empty");
87                 return RLM_MODULE_INVALID;
88         }
89
90         if (chap->length != CHAP_VALUE_LENGTH + 1) {
91                 RDEBUG("ERROR: CHAP-Password has invalid length");
92                 return RLM_MODULE_INVALID;
93         }
94
95         /*
96          *      Don't print out the CHAP password here.  It's binary crap.
97          */
98         RDEBUG("login attempt by \"%s\" with CHAP password",
99                 request->username->vp_strvalue);
100
101         if ((passwd_item = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY)) == NULL){
102                 if ((passwd_item = pairfind(request->config_items, PW_USER_PASSWORD, 0, TAG_ANY)) != NULL){
103                         RDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
104                         RDEBUG("!!! Please update your configuration so that the \"known !!!");
105                         RDEBUG("!!! good\" clear text password is in Cleartext-Password, !!!");
106                         RDEBUG("!!! and NOT in User-Password.                           !!!");
107                         RDEBUG("!!!                                                     !!!");
108                         RDEBUG("!!! Authentication will fail because of this.           !!!");
109                         RDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
110                 }
111                 RDEBUG("Cleartext-Password is required for authentication");
112                 snprintf(module_fmsg, sizeof(module_fmsg),
113                          "rlm_chap: Clear text password not available");
114                 module_fmsg_vp = pairmake("Module-Failure-Message",
115                                           module_fmsg, T_OP_EQ);
116                 pairadd(&request->packet->vps, module_fmsg_vp);
117                 return RLM_MODULE_INVALID;
118         }
119
120         RDEBUG("Using clear text password \"%s\" for user %s authentication.",
121               passwd_item->vp_strvalue, request->username->vp_strvalue);
122
123         rad_chap_encode(request->packet,pass_str,
124                         chap->vp_octets[0],passwd_item);
125
126         if (rad_digest_cmp(pass_str + 1, chap->vp_octets + 1,
127                            CHAP_VALUE_LENGTH) != 0) {
128                 RDEBUG("Password check failed");
129                 snprintf(module_fmsg, sizeof(module_fmsg),
130                          "rlm_chap: Wrong user password");
131                 module_fmsg_vp = pairmake("Module-Failure-Message",
132                                           module_fmsg, T_OP_EQ);
133                 pairadd(&request->packet->vps, module_fmsg_vp);
134                 return RLM_MODULE_REJECT;
135         }
136
137         RDEBUG("chap user %s authenticated succesfully",
138               request->username->vp_strvalue);
139
140         return RLM_MODULE_OK;
141 }
142
143 /*
144  *      The module name should be the only globally exported symbol.
145  *      That is, everything else should be 'static'.
146  *
147  *      If the module needs to temporarily modify it's instantiation
148  *      data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
149  *      The server will then take care of ensuring that the module
150  *      is single-threaded.
151  */
152 module_t rlm_chap = {
153          RLM_MODULE_INIT,
154         "CHAP",
155         RLM_TYPE_CHECK_CONFIG_SAFE,     /* type */
156         NULL,                           /* instantiation */
157         NULL,                           /* detach */
158         {
159                 chap_authenticate,      /* authentication */
160                 chap_authorize,         /* authorization */
161                 NULL,                   /* preaccounting */
162                 NULL,                   /* accounting */
163                 NULL,                   /* checksimul */
164                 NULL,                   /* pre-proxy */
165                 NULL,                   /* post-proxy */
166                 NULL                    /* post-auth */
167         },
168 };