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