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.
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.
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
20 * Copyright 2001,2006 The FreeRADIUS server project
21 * Copyright 2001 Kostas Kalevras <kkalev@noc.ntua.gr>
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
28 #include <freeradius-devel/ident.h>
31 #include <freeradius-devel/radiusd.h>
32 #include <freeradius-devel/modules.h>
34 static int chap_authorize(void *instance, REQUEST *request)
37 /* quiet the compiler */
41 if (!pairfind(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY)) {
42 return RLM_MODULE_NOOP;
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;
50 RDEBUG("Setting 'Auth-Type := CHAP'");
51 pairadd(&request->config_items,
52 pairmake("Auth-Type", "CHAP", T_OP_EQ));
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.
63 static int chap_authenticate(void *instance, REQUEST *request)
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];
70 /* quiet the compiler */
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;
79 chap = pairfind(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY);
81 RDEBUG("ERROR: You set 'Auth-Type = CHAP' for a request that does not contain a CHAP-Password attribute!");
82 return RLM_MODULE_INVALID;
85 if (chap->length == 0) {
86 RDEBUG("ERROR: CHAP-Password is empty");
87 return RLM_MODULE_INVALID;
90 if (chap->length != CHAP_VALUE_LENGTH + 1) {
91 RDEBUG("ERROR: CHAP-Password has invalid length");
92 return RLM_MODULE_INVALID;
96 * Don't print out the CHAP password here. It's binary crap.
98 RDEBUG("login attempt by \"%s\" with CHAP password",
99 request->username->vp_strvalue);
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. !!!");
108 RDEBUG("!!! Authentication will fail because of this. !!!");
109 RDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
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;
120 RDEBUG("Using clear text password \"%s\" for user %s authentication.",
121 passwd_item->vp_strvalue, request->username->vp_strvalue);
123 rad_chap_encode(request->packet,pass_str,
124 chap->vp_octets[0],passwd_item);
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;
137 RDEBUG("chap user %s authenticated succesfully",
138 request->username->vp_strvalue);
140 return RLM_MODULE_OK;
144 * The module name should be the only globally exported symbol.
145 * That is, everything else should be 'static'.
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.
152 module_t rlm_chap = {
155 RLM_TYPE_CHECK_CONFIG_SAFE, /* type */
156 NULL, /* instantiation */
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 */