quiet some compiler warnings
[freeradius.git] / src / modules / rlm_policy / rlm_policy.c
1 /*
2  * rlm_policy.c         Implements a policy language
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 2004  Alan DeKok <aland@ox.org>
21  * Copyright 2006  The FreeRADIUS server project
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 #include "rlm_policy.h"
31
32 /*
33  *      A mapping of configuration file names to internal variables.
34  *
35  *      Note that the string is dynamically allocated, so it MUST
36  *      be freed.  When the configuration file parse re-reads the string,
37  *      it free's the old one, and strdup's the new one, placing the pointer
38  *      to the strdup'd string into 'config.string'.  This gets around
39  *      buffer over-flows.
40  */
41 static const CONF_PARSER module_config[] = {
42   { "filename",  PW_TYPE_FILENAME,
43     offsetof(rlm_policy_t,filename), NULL,  "${confdir}/policy.txt"},
44
45   { NULL, -1, 0, NULL, NULL }           /* end the list */
46 };
47
48
49 /*
50  *      Callbacks for red-black trees.
51  */
52 static int policyname_cmp(const void *a, const void *b)
53 {
54         return strcmp(((const policy_named_t *)a)->name,
55                       ((const policy_named_t *)b)->name);
56 }
57
58
59 /*
60  *      Detach a policy.
61  */
62 static int policy_detach(void *instance)
63 {
64         rlm_policy_t *inst = instance;
65
66         if (inst->policies) rbtree_free(inst->policies);
67         free(instance);
68         return 0;
69 }
70
71 /*
72  *      Do any per-module initialization that is separate to each
73  *      configured instance of the module.  e.g. set up connections
74  *      to external databases, read configuration files, set up
75  *      dictionary entries, etc.
76  *
77  *      If configuration information is given in the config section
78  *      that must be referenced in later calls, store a handle to it
79  *      in *instance otherwise put a null pointer there.
80  */
81 static int policy_instantiate(CONF_SECTION *conf, void **instance)
82 {
83         rlm_policy_t *inst;
84
85         /*
86          *      Set up a storage area for instance data
87          */
88         inst = rad_malloc(sizeof(*inst));
89         if (!inst) {
90                 return -1;
91         }
92         memset(inst, 0, sizeof(*inst));
93
94         /*
95          *      If the configuration parameters can't be parsed, then
96          *      fail.
97          */
98         if (cf_section_parse(conf, inst, module_config) < 0) {
99                 policy_detach(inst);
100                 return -1;
101         }
102
103         inst->policies = rbtree_create(policyname_cmp,
104                                        (void (*)(void *)) rlm_policy_free_item,
105                                        0);
106         if (!inst->policies) {
107                 policy_detach(inst);
108                 return -1;
109         }
110
111         /*
112          *      Parse the policy from the file.
113          */
114         if (!rlm_policy_parse(inst->policies, inst->filename)) {
115                 policy_detach(inst);
116                 return -1;
117         }
118
119         *instance = inst;
120
121         return 0;
122 }
123
124
125 /*
126  *      Insert a named policy into a list.
127  */
128 int rlm_policy_insert(rbtree_t *head, policy_named_t *policy)
129 {
130         if (!rbtree_insert(head, policy)) {
131                 return 0;
132         }
133
134         return 1;
135 }
136
137
138 /*
139  *      Find a named policy
140  */
141 policy_named_t *rlm_policy_find(rbtree_t *head, const char *name)
142 {
143         policy_named_t mypolicy;
144
145         mypolicy.name = name;
146
147         return rbtree_finddata(head, &mypolicy);
148 }
149
150
151 /*
152  *      Find the named user in this modules database.  Create the set
153  *      of attribute-value pairs to check and reply with for this user
154  *      from the database. The authentication code only needs to check
155  *      the password, the rest is done here.
156  */
157 static int policy_authorize(void *instance, REQUEST *request)
158 {
159         return rlm_policy_evaluate((rlm_policy_t *) instance, request,
160                                    "authorize");
161 }
162
163
164 static int policy_preacct(void *instance, REQUEST *request)
165 {
166         return rlm_policy_evaluate((rlm_policy_t *) instance, request,
167                                    "preacct");
168 }
169
170 static int policy_accounting(void *instance, REQUEST *request)
171 {
172         return rlm_policy_evaluate((rlm_policy_t *) instance, request,
173                                    "accounting");
174 }
175
176 static int policy_post_auth(void *instance, REQUEST *request)
177 {
178         return rlm_policy_evaluate((rlm_policy_t *) instance, request,
179                                    "post-auth");
180 }
181
182 static int policy_pre_proxy(void *instance, REQUEST *request)
183 {
184         return rlm_policy_evaluate((rlm_policy_t *) instance, request,
185                                    "pre-proxy");
186 }
187
188 static int policy_post_proxy(void *instance, REQUEST *request)
189 {
190         return rlm_policy_evaluate((rlm_policy_t *) instance, request,
191                                    "post-proxy");
192 }
193
194 #ifdef WITH_COA
195 static int policy_recv_coa(void *instance, REQUEST *request)
196 {
197         return rlm_policy_evaluate((rlm_policy_t *) instance, request,
198                                    "recv-coa");
199 }
200 static int policy_send_coa(void *instance, REQUEST *request)
201 {
202         return rlm_policy_evaluate((rlm_policy_t *) instance, request,
203                                    "send-coa");
204 }
205 #endif
206
207 /*
208  *      The "free" functions are here, for no particular reason.
209  */
210 void rlm_policy_free_item(policy_item_t *item)
211 {
212         while (item) {
213                 policy_item_t *next = item->next;
214
215                 switch (item->type) {
216                 default:
217                 case POLICY_TYPE_BAD:
218                         break;
219
220                 case POLICY_TYPE_ASSIGNMENT:
221                         {
222                                 policy_assignment_t *this;
223
224                                 this = (policy_assignment_t *) item;
225                                 if (this->lhs) free(this->lhs);
226                                 if (this->rhs) free(this->rhs);
227                         }
228                         break;
229
230                 case POLICY_TYPE_CONDITIONAL:
231                         {
232                                 policy_condition_t *this;
233
234                                 this = (policy_condition_t *) item;
235                                 if (this->lhs) free(this->lhs);
236                                 if (this->rhs) free(this->rhs);
237
238                                 if (this->child) {
239                                         rlm_policy_free_item(this->child);
240                                         this->child = NULL;
241                                 }
242                         }
243                         break;
244
245                 case POLICY_TYPE_IF:
246                         {
247                                 policy_if_t *this;
248
249                                 this = (policy_if_t *) item;
250                                 if (this->condition) {
251                                         rlm_policy_free_item(this->condition);
252                                         this->condition = NULL;
253                                 }
254                                 if (this->if_true) {
255                                         rlm_policy_free_item(this->if_true);
256                                         this->if_true = NULL;
257                                 }
258                                 if (this->if_false) {
259                                         rlm_policy_free_item(this->if_false);
260                                         this->if_false = NULL;
261                                 }
262                         }
263                         break;
264
265                 case POLICY_TYPE_ATTRIBUTE_LIST:
266                         {
267                                 policy_attributes_t *this;
268
269                                 this = (policy_attributes_t *) item;
270                                 rlm_policy_free_item(this->attributes);
271                         }
272                         break;
273
274                 case POLICY_TYPE_NAMED_POLICY:
275                         {
276                                 policy_named_t *this;
277
278                                 this = (policy_named_t *) item;
279                                 rad_assert(this->name != NULL);
280                                 free((void *) this->name);
281                                 rlm_policy_free_item(this->policy);
282                         }
283                         break;
284
285                 case POLICY_TYPE_CALL:
286                         {
287                                 policy_call_t *this;
288
289                                 this = (policy_call_t *) item;
290                                 free((void *) this->name);
291                         }
292                         break;
293
294                 case POLICY_TYPE_RETURN:
295                         break;  /* do nothing */
296
297                 case POLICY_TYPE_MODULE:
298                         {
299                                 policy_module_t *this;
300
301                                 this = (policy_module_t *) item;
302                                 if (this->cs) cf_section_free(&this->cs);
303                                 if (this->mc) modcallable_free(&this->mc);
304                         }
305                         break;
306                 } /* switch over type */
307                 item->next = NULL; /* for debugging & sanity checks */
308                 item->type = POLICY_TYPE_BAD;
309                 free(item);
310
311                 item = next;
312         }
313 }
314
315
316 /*
317  *      The module name should be the only globally exported symbol.
318  *      That is, everything else should be 'static'.
319  *
320  *      If the module needs to temporarily modify it's instantiation
321  *      data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
322  *      The server will then take care of ensuring that the module
323  *      is single-threaded.
324  */
325 module_t rlm_policy = {
326         RLM_MODULE_INIT,
327         "policy",
328         RLM_TYPE_CHECK_CONFIG_SAFE | RLM_TYPE_HUP_SAFE,         /* type */
329         policy_instantiate,             /* instantiation */
330         policy_detach,                  /* detach */
331         {
332                 NULL,                   /* authentication */
333                 policy_authorize,       /* authorization */
334                 policy_preacct,         /* preaccounting */
335                 policy_accounting,      /* accounting */
336                 NULL,                   /* checksimul */
337                 policy_pre_proxy,       /* pre-proxy */
338                 policy_post_proxy,      /* post-proxy */
339                 policy_post_auth        /* post-auth */
340 #ifdef WITH_COA
341                 , policy_recv_coa,
342                 policy_send_coa
343 #endif
344         },
345 };