import from HEAD:
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * Copyright 2001  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 "autoconf.h"
29 #include "libradius.h"
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include "radiusd.h"
36 #include "modules.h"
37 #include "conffile.h"
38
39 static const char rcsid[] = "$Id$";
40
41 static int chap_authorize(void *instance, REQUEST *request)
42 {
43
44         /* quiet the compiler */
45         instance = instance;
46         request = request;
47
48         if (!request->password ||
49             request->password->attribute != PW_CHAP_PASSWORD) {
50                 return RLM_MODULE_NOOP;
51         }
52
53         if (pairfind(request->config_items, PW_AUTHTYPE) != NULL) {
54                 DEBUG2("  rlm_chap: WARNING: Auth-Type already set.  Not setting to CHAP");
55                 return RLM_MODULE_NOOP;
56         }
57
58         DEBUG("  rlm_chap: Setting 'Auth-Type := CHAP'");
59         pairadd(&request->config_items,
60                 pairmake("Auth-Type", "CHAP", T_OP_EQ));
61         return RLM_MODULE_OK;
62 }
63
64
65 /*
66  *      Find the named user in this modules database.  Create the set
67  *      of attribute-value pairs to check and reply with for this user
68  *      from the database. The authentication code only needs to check
69  *      the password, the rest is done here.
70  */
71 static int chap_authenticate(void *instance, REQUEST *request)
72 {
73         VALUE_PAIR *passwd_item;
74         char pass_str[MAX_STRING_LEN];
75         VALUE_PAIR *module_fmsg_vp;
76         char module_fmsg[MAX_STRING_LEN];
77
78         /* quiet the compiler */
79         instance = instance;
80         request = request;
81
82         if (!request->username) {
83                 radlog(L_AUTH, "rlm_chap: Attribute \"User-Name\" is required for authentication.\n");
84                 return RLM_MODULE_INVALID;
85         }
86
87         if (!request->password) {
88                 radlog(L_AUTH, "rlm_chap: Attribute \"CHAP-Password\" is required for authentication.");
89                 return RLM_MODULE_INVALID;
90         }
91
92         if (request->password->attribute != PW_CHAP_PASSWORD) {
93                 radlog(L_AUTH, "rlm_chap: Attribute \"CHAP-Password\" is required for authentication. Cannot use \"%s\".", request->password->name);
94                 return RLM_MODULE_INVALID;
95         }
96
97         if (request->password->length == 0) {
98                 radlog(L_ERR, "rlm_chap: empty password supplied");
99                 return RLM_MODULE_INVALID;
100         }
101
102         /*
103          *      Don't print out the CHAP password here.  It's binary crap.
104          */
105         DEBUG("  rlm_chap: login attempt by \"%s\" with CHAP password",
106                 request->username->strvalue);
107
108         if ((passwd_item = pairfind(request->config_items, PW_PASSWORD)) == NULL){
109                 DEBUG("  rlm_chap: Could not find clear text password for user %s",request->username->strvalue);
110                 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_chap: Clear text password not available");
111                 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
112                 pairadd(&request->packet->vps, module_fmsg_vp);
113                 return RLM_MODULE_INVALID;
114         }
115
116         DEBUG("  rlm_chap: Using clear text password \"%s\" for user %s authentication.",
117               passwd_item->strvalue, request->username->strvalue);
118
119         rad_chap_encode(request->packet,pass_str,request->password->strvalue[0],passwd_item);
120
121         if (memcmp(pass_str+1,request->password->strvalue+1,CHAP_VALUE_LENGTH) != 0){
122                 DEBUG("  rlm_chap: Password check failed");
123                 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_chap: Wrong user password");
124                 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
125                 pairadd(&request->packet->vps, module_fmsg_vp);
126                 return RLM_MODULE_REJECT;
127         }
128
129         DEBUG("  rlm_chap: chap user %s authenticated succesfully",request->username->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         "CHAP",
145         0,                              /* type */
146         NULL,                           /* initialization */
147         NULL,                           /* instantiation */
148         {
149                 chap_authenticate,      /* authentication */
150                 chap_authorize,         /* authorization */
151                 NULL,                   /* preaccounting */
152                 NULL,                   /* accounting */
153                 NULL,                   /* checksimul */
154                 NULL,                   /* pre-proxy */
155                 NULL,                   /* post-proxy */
156                 NULL                    /* post-auth */
157         },
158         NULL,                           /* detach */
159         NULL,                           /* destroy */
160 };