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: d0f3292ff0ec5fac9051ac18da04411abcef90a7 $
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: d0f3292ff0ec5fac9051ac18da04411abcef90a7 $")
26
27 #include <freeradius-devel/radiusd.h>
28 #include <freeradius-devel/modules.h>
29
CC_HINT(nonnull)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 */
CC_HINT(nonnull)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[MAX_STRING_LEN * 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 };
163