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