Added -C command-line option, documentation, debug messages,
[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)) {
42                 return RLM_MODULE_NOOP;
43         }
44
45         if (pairfind(request->config_items, PW_AUTHTYPE) != NULL) {
46                 DEBUG2("  rlm_chap: WARNING: Auth-Type already set.  Not setting to CHAP");
47                 return RLM_MODULE_NOOP;
48         }
49
50         DEBUG("  rlm_chap: 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(L_AUTH, "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);
80         if (!chap) {
81                 radlog(L_AUTH, "rlm_chap: Attribute \"CHAP-Password\" is required for authentication.");
82                 return RLM_MODULE_INVALID;
83         }
84
85         if (chap->length == 0) {
86                 radlog(L_ERR, "rlm_chap: empty password supplied");
87                 return RLM_MODULE_INVALID;
88         }
89
90         if (chap->length != CHAP_VALUE_LENGTH + 1) {
91                 radlog(L_ERR, "rlm_chap: password supplied has wrong length");
92                 return RLM_MODULE_INVALID;
93         }
94
95         /*
96          *      Don't print out the CHAP password here.  It's binary crap.
97          */
98         DEBUG("  rlm_chap: login attempt by \"%s\" with CHAP password",
99                 request->username->vp_strvalue);
100
101         if ((passwd_item = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD)) == NULL){
102           DEBUG("  rlm_chap: Cleartext-Password is required for authentication");
103                 snprintf(module_fmsg, sizeof(module_fmsg),
104                          "rlm_chap: Clear text password not available");
105                 module_fmsg_vp = pairmake("Module-Failure-Message",
106                                           module_fmsg, T_OP_EQ);
107                 pairadd(&request->packet->vps, module_fmsg_vp);
108                 return RLM_MODULE_INVALID;
109         }
110
111         DEBUG("  rlm_chap: Using clear text password \"%s\" for user %s authentication.",
112               passwd_item->vp_strvalue, request->username->vp_strvalue);
113
114         rad_chap_encode(request->packet,pass_str,
115                         chap->vp_octets[0],passwd_item);
116
117         if (memcmp(pass_str + 1, chap->vp_octets + 1,
118                    CHAP_VALUE_LENGTH) != 0){
119                 DEBUG("  rlm_chap: Password check failed");
120                 snprintf(module_fmsg, sizeof(module_fmsg),
121                          "rlm_chap: Wrong user password");
122                 module_fmsg_vp = pairmake("Module-Failure-Message",
123                                           module_fmsg, T_OP_EQ);
124                 pairadd(&request->packet->vps, module_fmsg_vp);
125                 return RLM_MODULE_REJECT;
126         }
127
128         DEBUG("  rlm_chap: chap user %s authenticated succesfully",
129               request->username->vp_strvalue);
130
131         return RLM_MODULE_OK;
132 }
133
134 /*
135  *      The module name should be the only globally exported symbol.
136  *      That is, everything else should be 'static'.
137  *
138  *      If the module needs to temporarily modify it's instantiation
139  *      data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
140  *      The server will then take care of ensuring that the module
141  *      is single-threaded.
142  */
143 module_t rlm_chap = {
144          RLM_MODULE_INIT,
145         "CHAP",
146         RLM_TYPE_CHECK_CONFIG_SAFE,     /* type */
147         NULL,                           /* instantiation */
148         NULL,                           /* detach */
149         {
150                 chap_authenticate,      /* authentication */
151                 chap_authorize,         /* authorization */
152                 NULL,                   /* preaccounting */
153                 NULL,                   /* accounting */
154                 NULL,                   /* checksimul */
155                 NULL,                   /* pre-proxy */
156                 NULL,                   /* post-proxy */
157                 NULL                    /* post-auth */
158         },
159 };