Merge tag 'release_3_0_12' into branch moonshot-fr-3.0.12-upgrade.
[freeradius.git] / src / modules / rlm_chap / rlm_chap.c
1 /*
2  *   This program is is free software; you can redistribute it and/or modify
3  *   it under the terms of the GNU General Public License as published by
4  *   the Free Software Foundation; either version 2 of the License, or (at
5  *   your option) any later version.
6  *
7  *   This program is distributed in the hope that it will be useful,
8  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *   GNU General Public License for more details.
11  *
12  *   You should have received a copy of the GNU General Public License
13  *   along with this program; if not, write to the Free Software
14  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16
17 /**
18  * $Id$
19  * @file rlm_chap.c
20  * @brief Process chap authentication requests.
21  *
22  * @copyright 2001,2006  The FreeRADIUS server project
23  * @copyright 2001  Kostas Kalevras <kkalev@noc.ntua.gr>
24  */
25 RCSID("$Id$")
26
27 #include <freeradius-devel/radiusd.h>
28 #include <freeradius-devel/modules.h>
29
30 static rlm_rcode_t CC_HINT(nonnull) mod_authorize(UNUSED void *instance, REQUEST *request)
31 {
32         if (!fr_pair_find_by_num(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY)) {
33                 return RLM_MODULE_NOOP;
34         }
35
36         if (fr_pair_find_by_num(request->config, PW_AUTH_TYPE, 0, TAG_ANY) != NULL) {
37                 RWDEBUG2("&control:Auth-Type already set.  Not setting to CHAP");
38                 return RLM_MODULE_NOOP;
39         }
40
41         RINDENT();
42         RDEBUG("&control:Auth-Type := CHAP");
43         REXDENT();
44         pair_make_config("Auth-Type", "CHAP", T_OP_EQ);
45
46         return RLM_MODULE_OK;
47 }
48
49
50 /*
51  *      Find the named user in this modules database.  Create the set
52  *      of attribute-value pairs to check and reply with for this user
53  *      from the database. The authentication code only needs to check
54  *      the password, the rest is done here.
55  */
56 static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(UNUSED void *instance, REQUEST *request)
57 {
58         VALUE_PAIR *password, *chap;
59         uint8_t pass_str[MAX_STRING_LEN];
60
61         if (!request->username) {
62                 REDEBUG("&request:User-Name attribute is required for authentication");
63                 return RLM_MODULE_INVALID;
64         }
65
66         chap = fr_pair_find_by_num(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY);
67         if (!chap) {
68                 REDEBUG("You set '&control:Auth-Type = CHAP' for a request that "
69                         "does not contain a CHAP-Password attribute!");
70                 return RLM_MODULE_INVALID;
71         }
72
73         if (chap->vp_length == 0) {
74                 REDEBUG("&request:CHAP-Password is empty");
75                 return RLM_MODULE_INVALID;
76         }
77
78         if (chap->vp_length != CHAP_VALUE_LENGTH + 1) {
79                 REDEBUG("&request:CHAP-Password has invalid length");
80                 return RLM_MODULE_INVALID;
81         }
82
83         password = fr_pair_find_by_num(request->config, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY);
84         if (password == NULL) {
85                 if (fr_pair_find_by_num(request->config, PW_USER_PASSWORD, 0, TAG_ANY) != NULL){
86                         REDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
87                         REDEBUG("!!! Please update your configuration so that the \"known !!!");
88                         REDEBUG("!!! good\" cleartext password is in Cleartext-Password,  !!!");
89                         REDEBUG("!!! and NOT in User-Password.                            !!!");
90                         REDEBUG("!!!                                                      !!!");
91                         REDEBUG("!!! Authentication will fail because of this.            !!!");
92                         REDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
93                 }
94
95                 REDEBUG("&control:Cleartext-Password is required for authentication");
96                 return RLM_MODULE_FAIL;
97         }
98
99         rad_chap_encode(request->packet, pass_str, chap->vp_octets[0], password);
100
101         if (RDEBUG_ENABLED3) {
102                 uint8_t const *p;
103                 size_t length;
104                 VALUE_PAIR *vp;
105                 char buffer[CHAP_VALUE_LENGTH * 2 + 1];
106
107                 RDEBUG3("Comparing with \"known good\" &control:Cleartext-Password value \"%s\"",
108                         password->vp_strvalue);
109
110                 vp = fr_pair_find_by_num(request->packet->vps, PW_CHAP_CHALLENGE, 0, TAG_ANY);
111                 if (vp) {
112                         RDEBUG2("Using challenge from &request:CHAP-Challenge");
113                         p = vp->vp_octets;
114                         length = vp->vp_length;
115                 } else {
116                         RDEBUG2("Using challenge from authenticator field");
117                         p = request->packet->vector;
118                         length = sizeof(request->packet->vector);
119                 }
120
121                 fr_bin2hex(buffer, p, length);
122                 RINDENT();
123                 RDEBUG3("CHAP challenge : %s", buffer);
124
125                 fr_bin2hex(buffer, chap->vp_octets + 1, CHAP_VALUE_LENGTH);
126                 RDEBUG3("Client sent    : %s", buffer);
127
128                 fr_bin2hex(buffer, pass_str + 1, CHAP_VALUE_LENGTH);
129                 RDEBUG3("We calculated  : %s", buffer);
130                 REXDENT();
131         } else {
132                 RDEBUG2("Comparing with \"known good\" Cleartext-Password");
133         }
134
135         if (rad_digest_cmp(pass_str + 1, chap->vp_octets + 1, CHAP_VALUE_LENGTH) != 0) {
136                 REDEBUG("Password comparison failed: password is incorrect");
137                 return RLM_MODULE_REJECT;
138         }
139
140         RDEBUG("CHAP user \"%s\" authenticated successfully", request->username->vp_strvalue);
141
142         return RLM_MODULE_OK;
143 }
144
145 /*
146  *      The module name should be the only globally exported symbol.
147  *      That is, everything else should be 'static'.
148  *
149  *      If the module needs to temporarily modify it's instantiation
150  *      data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
151  *      The server will then take care of ensuring that the module
152  *      is single-threaded.
153  */
154 extern module_t rlm_chap;
155 module_t rlm_chap = {
156         .magic          = RLM_MODULE_INIT,
157         .name           = "chap",
158         .methods = {
159                 [MOD_AUTHENTICATE]      = mod_authenticate,
160                 [MOD_AUTHORIZE]         = mod_authorize,
161         },
162 };