e88e90d75561701822838c8e9124d35ecaf756c7
[freeradius.git] / src / modules / rlm_example / rlm_example.c
1 /*
2  * rlm_example.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 2000  The FreeRADIUS server project
21  * Copyright 2000  your name <your address>
22  */
23
24 #include <freeradius-devel/autoconf.h>
25
26 #include <stdio.h>
27 #include <stdlib.h>
28
29 #include <freeradius-devel/radiusd.h>
30 #include <freeradius-devel/modules.h>
31 #include <freeradius-devel/conffile.h>
32
33 static const char rcsid[] = "$Id$";
34
35 /*
36  *      Define a structure for our module configuration.
37  *
38  *      These variables do not need to be in a structure, but it's
39  *      a lot cleaner to do so, and a pointer to the structure can
40  *      be used as the instance handle.
41  */
42 typedef struct rlm_example_t {
43         int             boolean;
44         int             value;
45         char            *string;
46         uint32_t        ipaddr;
47 } rlm_example_t;
48
49 /*
50  *      A mapping of configuration file names to internal variables.
51  *
52  *      Note that the string is dynamically allocated, so it MUST
53  *      be freed.  When the configuration file parse re-reads the string,
54  *      it free's the old one, and strdup's the new one, placing the pointer
55  *      to the strdup'd string into 'config.string'.  This gets around
56  *      buffer over-flows.
57  */
58 static const CONF_PARSER module_config[] = {
59   { "integer", PW_TYPE_INTEGER,    offsetof(rlm_example_t,value), NULL,   "1" },
60   { "boolean", PW_TYPE_BOOLEAN,    offsetof(rlm_example_t,boolean), NULL, "no"},
61   { "string",  PW_TYPE_STRING_PTR, offsetof(rlm_example_t,string), NULL,  NULL},
62   { "ipaddr",  PW_TYPE_IPADDR,     offsetof(rlm_example_t,ipaddr), NULL,  "*" },
63
64   { NULL, -1, 0, NULL, NULL }           /* end the list */
65 };
66
67
68 /*
69  *      Do any per-module initialization that is separate to each
70  *      configured instance of the module.  e.g. set up connections
71  *      to external databases, read configuration files, set up
72  *      dictionary entries, etc.
73  *
74  *      If configuration information is given in the config section
75  *      that must be referenced in later calls, store a handle to it
76  *      in *instance otherwise put a null pointer there.
77  */
78 static int example_instantiate(CONF_SECTION *conf, void **instance)
79 {
80         rlm_example_t *data;
81
82         /*
83          *      Set up a storage area for instance data
84          */
85         data = rad_malloc(sizeof(*data));
86         if (!data) {
87                 return -1;
88         }
89         memset(data, 0, sizeof(*data));
90
91         /*
92          *      If the configuration parameters can't be parsed, then
93          *      fail.
94          */
95         if (cf_section_parse(conf, data, module_config) < 0) {
96                 free(data);
97                 return -1;
98         }
99
100         *instance = data;
101
102         return 0;
103 }
104
105 /*
106  *      Find the named user in this modules database.  Create the set
107  *      of attribute-value pairs to check and reply with for this user
108  *      from the database. The authentication code only needs to check
109  *      the password, the rest is done here.
110  */
111 static int example_authorize(void *instance, REQUEST *request)
112 {
113         VALUE_PAIR *state;
114         VALUE_PAIR *reply;
115
116         /* quiet the compiler */
117         instance = instance;
118         request = request;
119
120         /*
121          *  Look for the 'state' attribute.
122          */
123         state =  pairfind(request->packet->vps, PW_STATE);
124         if (state != NULL) {
125                 DEBUG("rlm_example: Found reply to access challenge");
126                 return RLM_MODULE_OK;
127         }
128
129         /*
130          *  Create the challenge, and add it to the reply.
131          */
132         reply = pairmake("Reply-Message", "This is a challenge", T_OP_EQ);
133         pairadd(&request->reply->vps, reply);
134         state = pairmake("State", "0", T_OP_EQ);
135         pairadd(&request->reply->vps, state);
136
137         /*
138          *  Mark the packet as an Access-Challenge packet.
139          *
140          *  The server will take care of sending it to the user.
141          */
142         request->reply->code = PW_ACCESS_CHALLENGE;
143         DEBUG("rlm_example: Sending Access-Challenge.");
144
145         return RLM_MODULE_HANDLED;
146 }
147
148 /*
149  *      Authenticate the user with the given password.
150  */
151 static int example_authenticate(void *instance, REQUEST *request)
152 {
153         /* quiet the compiler */
154         instance = instance;
155         request = request;
156
157         return RLM_MODULE_OK;
158 }
159
160 /*
161  *      Massage the request before recording it or proxying it
162  */
163 static int example_preacct(void *instance, REQUEST *request)
164 {
165         /* quiet the compiler */
166         instance = instance;
167         request = request;
168
169         return RLM_MODULE_OK;
170 }
171
172 /*
173  *      Write accounting information to this modules database.
174  */
175 static int example_accounting(void *instance, REQUEST *request)
176 {
177         /* quiet the compiler */
178         instance = instance;
179         request = request;
180
181         return RLM_MODULE_OK;
182 }
183
184 /*
185  *      See if a user is already logged in. Sets request->simul_count to the
186  *      current session count for this user and sets request->simul_mpp to 2
187  *      if it looks like a multilink attempt based on the requested IP
188  *      address, otherwise leaves request->simul_mpp alone.
189  *
190  *      Check twice. If on the first pass the user exceeds his
191  *      max. number of logins, do a second pass and validate all
192  *      logins by querying the terminal server (using eg. SNMP).
193  */
194 static int example_checksimul(void *instance, REQUEST *request)
195 {
196   instance = instance;
197
198   request->simul_count=0;
199
200   return RLM_MODULE_OK;
201 }
202
203 static int example_detach(void *instance)
204 {
205         free(((struct rlm_example_t *)instance)->string);
206         free(instance);
207         return 0;
208 }
209
210 /*
211  *      The module name should be the only globally exported symbol.
212  *      That is, everything else should be 'static'.
213  *
214  *      If the module needs to temporarily modify it's instantiation
215  *      data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
216  *      The server will then take care of ensuring that the module
217  *      is single-threaded.
218  */
219 module_t rlm_example = {
220         RLM_MODULE_INIT,
221         "example",
222         RLM_TYPE_THREAD_SAFE,           /* type */
223         example_instantiate,            /* instantiation */
224         example_detach,                 /* detach */
225         {
226                 example_authenticate,   /* authentication */
227                 example_authorize,      /* authorization */
228                 example_preacct,        /* preaccounting */
229                 example_accounting,     /* accounting */
230                 example_checksimul,     /* checksimul */
231                 NULL,                   /* pre-proxy */
232                 NULL,                   /* post-proxy */
233                 NULL                    /* post-auth */
234         },
235 };