All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
rlm_chap.c
Go to the documentation of this file.
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: 5b03dbc6e949b305e5a33d81f1cd3ef199b271af $
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: 5b03dbc6e949b305e5a33d81f1cd3ef199b271af $")
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, 0, PW_CHAP_PASSWORD, TAG_ANY)) {
33  return RLM_MODULE_NOOP;
34  }
35 
36  if (fr_pair_find_by_num(request->config, 0, PW_AUTH_TYPE, 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,
57  REQUEST *request)
58 {
59  VALUE_PAIR *password, *chap;
60  uint8_t pass_str[MAX_STRING_LEN];
61 
62  if (!request->username) {
63  RWDEBUG("&request:User-Name attribute is required for authentication");
64  return RLM_MODULE_INVALID;
65  }
66 
67  chap = fr_pair_find_by_num(request->packet->vps, 0, PW_CHAP_PASSWORD, TAG_ANY);
68  if (!chap) {
69  REDEBUG("You set '&control:Auth-Type = CHAP' for a request that "
70  "does not contain a CHAP-Password attribute!");
71  return RLM_MODULE_INVALID;
72  }
73 
74  if (chap->vp_length == 0) {
75  REDEBUG("&request:CHAP-Password is empty");
76  return RLM_MODULE_INVALID;
77  }
78 
79  if (chap->vp_length != CHAP_VALUE_LENGTH + 1) {
80  REDEBUG("&request:CHAP-Password has invalid length");
81  return RLM_MODULE_INVALID;
82  }
83 
84  password = fr_pair_find_by_num(request->config, 0, PW_CLEARTEXT_PASSWORD, TAG_ANY);
85  if (password == NULL) {
86  if (fr_pair_find_by_num(request->config, 0, PW_USER_PASSWORD, TAG_ANY) != NULL){
87  REDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
88  REDEBUG("!!! Please update your configuration so that the \"known !!!");
89  REDEBUG("!!! good\" cleartext password is in Cleartext-Password, !!!");
90  REDEBUG("!!! and NOT in User-Password. !!!");
91  REDEBUG("!!! !!!");
92  REDEBUG("!!! Authentication will fail because of this. !!!");
93  REDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
94  }
95 
96  REDEBUG("&control:Cleartext-Password is required for authentication");
97  return RLM_MODULE_FAIL;
98  }
99 
100  fr_radius_encode_chap_password(pass_str, request->packet, chap->vp_octets[0], password);
101 
102  if (RDEBUG_ENABLED3) {
103  uint8_t const *p;
104  size_t length;
105  VALUE_PAIR *vp;
106  char buffer[CHAP_VALUE_LENGTH * 2 + 1];
107 
108  RDEBUG3("Comparing with \"known good\" &control:Cleartext-Password value \"%s\"",
109  password->vp_strvalue);
110 
111  vp = fr_pair_find_by_num(request->packet->vps, 0, PW_CHAP_CHALLENGE, TAG_ANY);
112  if (vp) {
113  RDEBUG2("Using challenge from &request:CHAP-Challenge");
114  p = vp->vp_octets;
115  length = vp->vp_length;
116  } else {
117  RDEBUG2("Using challenge from authenticator field");
118  p = request->packet->vector;
119  length = sizeof(request->packet->vector);
120  }
121 
122  fr_bin2hex(buffer, p, length);
123  RINDENT();
124  RDEBUG3("CHAP challenge : %s", buffer);
125 
126  fr_bin2hex(buffer, chap->vp_octets + 1, CHAP_VALUE_LENGTH);
127  RDEBUG3("Client sent : %s", buffer);
128 
129  fr_bin2hex(buffer, pass_str + 1, CHAP_VALUE_LENGTH);
130  RDEBUG3("We calculated : %s", buffer);
131  REXDENT();
132  } else {
133  RDEBUG2("Comparing with \"known good\" Cleartext-Password");
134  }
135 
136  if (fr_radius_digest_cmp(pass_str + 1, chap->vp_octets + 1, CHAP_VALUE_LENGTH) != 0) {
137  REDEBUG("Password comparison failed: password is incorrect");
138  return RLM_MODULE_REJECT;
139  }
140 
141  RDEBUG("CHAP user \"%s\" authenticated successfully", request->username->vp_strvalue);
142 
143  return RLM_MODULE_OK;
144 }
145 
146 
147 /*
148  * Access-Requests can have the CHAP-Challenge implicitly taken
149  * from the request authenticator. If the NAS has done that,
150  * then we need to copy the data to a real CHAP-Challenge
151  * attribute when proxying. Otherwise when we proxy the request,
152  * the new authenticator is different, and the CHAP calculations
153  * will fail.
154  */
155 static rlm_rcode_t CC_HINT(nonnull) mod_pre_proxy(UNUSED void *instance,
156  REQUEST *request)
157 {
158  VALUE_PAIR *vp;
159 
160  /*
161  * For Access-Requests, which have CHAP-Password,
162  * and no CHAP-Challenge, copy it over from the request.
163  */
164  if (request->packet->code != PW_CODE_ACCESS_REQUEST) return RLM_MODULE_NOOP;
165 
166  if (!fr_pair_find_by_num(request->proxy->vps, 0, PW_CHAP_PASSWORD, TAG_ANY)) return RLM_MODULE_NOOP;
167 
168  vp = radius_pair_create(request, &request->proxy->vps, PW_CHAP_CHALLENGE, 0);
169  if (!vp) return RLM_MODULE_FAIL;
170 
171  fr_pair_value_memcpy(vp, request->packet->vector, sizeof(request->packet->vector));
172 
173  return RLM_MODULE_OK;
174 }
175 
176 
177 /*
178  * The module name should be the only globally exported symbol.
179  * That is, everything else should be 'static'.
180  *
181  * If the module needs to temporarily modify it's instantiation
182  * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
183  * The server will then take care of ensuring that the module
184  * is single-threaded.
185  */
186 extern module_t rlm_chap;
187 module_t rlm_chap = {
189  .name = "chap",
190  .methods = {
193  [MOD_PRE_PROXY] = mod_pre_proxy
194  },
195 };
5 methods index for preproxy section.
Definition: modules.h:46
#define RINDENT()
Indent R* messages by one level.
Definition: log.h:265
#define RDEBUG_ENABLED3
True if request debug level 1-3 messages are enabled.
Definition: log.h:239
The module is OK, continue.
Definition: radiusd.h:91
Metadata exported by the module.
Definition: modules.h:134
VALUE_PAIR * radius_pair_create(TALLOC_CTX *ctx, VALUE_PAIR **vps, unsigned int attribute, unsigned int vendor)
Create a VALUE_PAIR and add it to a list of VALUE_PAIR s.
Definition: pair.c:704
static rlm_rcode_t mod_authorize(void *instance, REQUEST *request)
Handle authorization requests using Couchbase document data.
#define UNUSED
Definition: libradius.h:134
#define RLM_MODULE_INIT
Definition: modules.h:86
uint8_t length
Definition: proto_bfd.c:203
Definition: token.h:46
The module considers the request invalid.
Definition: radiusd.h:93
static rlm_rcode_t mod_authenticate(void *instance, REQUEST *request) CC_HINT(nonnull)
RFC2865 - Access-Request.
Definition: radius.h:92
#define pair_make_config(_a, _b, _c)
Definition: radiusd.h:547
static rlm_rcode_t CC_HINT(nonnull)
Definition: rlm_chap.c:30
int fr_radius_encode_chap_password(uint8_t *output, RADIUS_PACKET *packet, int id, VALUE_PAIR *password)
Immediately reject the request.
Definition: radiusd.h:89
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
0 methods index for authenticate section.
Definition: modules.h:41
#define REXDENT()
Exdent (unindent) R* messages by one level.
Definition: log.h:272
enum rlm_rcodes rlm_rcode_t
Return codes indicating the result of the module call.
#define RWDEBUG2(fmt,...)
Definition: log.h:252
module_t rlm_chap
Definition: rlm_chap.c:187
Module succeeded without doing anything.
Definition: radiusd.h:96
#define RDEBUG2(fmt,...)
Definition: log.h:244
uint64_t magic
Used to validate module struct.
Definition: modules.h:135
Module failed, don't reply.
Definition: radiusd.h:90
#define TAG_ANY
Definition: pair.h:191
#define REDEBUG(fmt,...)
Definition: log.h:254
int fr_radius_digest_cmp(uint8_t const *a, uint8_t const *b, size_t length)
Do a comparison of two authentication digests by comparing the FULL digest.
Definition: radius.c:578
VALUE_PAIR * fr_pair_find_by_num(VALUE_PAIR *head, unsigned int vendor, unsigned int attr, int8_t tag)
Find the pair with the matching attribute.
Definition: pair.c:639
#define CHAP_VALUE_LENGTH
Definition: libradius.h:119
#define MAX_STRING_LEN
Definition: libradius.h:120
#define RWDEBUG(fmt,...)
Definition: log.h:251
1 methods index for authorize section.
Definition: modules.h:42
#define RCSID(id)
Definition: build.h:135
#define RDEBUG(fmt,...)
Definition: log.h:243
size_t fr_bin2hex(char *hex, uint8_t const *bin, size_t inlen)
Convert binary data to a hex string.
Definition: misc.c:254
void fr_pair_value_memcpy(VALUE_PAIR *vp, uint8_t const *src, size_t len)
Copy data into an "octets" data type.
Definition: pair.c:1905
#define RDEBUG3(fmt,...)
Definition: log.h:245