Massively cleaned up #include's, so they're in a consistent
[freeradius.git] / src / modules / rlm_sim_files / rlm_sim_files.c
1 /*
2  * rlm_sim_files.c      authorization: Find a SIM user in the "simtriplets"
3  *                                     file.
4  *
5  * Version:     $Id$
6  *
7  *   This program is free software; you can redistribute it and/or modify
8  *   it under the terms of the GNU General Public License as published by
9  *   the Free Software Foundation; either version 2 of the License, or
10  *   (at your option) any later version.
11  *
12  *   This program is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with this program; if not, write to the Free Software
19  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  *
21  * Copyright 2004  Michael Richardson <mcr@sandelman.ottawa.on.ca>
22  * Copyright 2006  The FreeRADIUS server project
23  *
24  * (Adapted from rlm_files/rlm_files.c )
25  */
26
27 /*
28  * this is an authorization-only module that walks the file every time.
29  *
30  * this is an example of getting data for rlm_eap_sim from an external
31  * place.
32  *
33  * in a real system, this would be replaced with a lookup to the SS7
34  * network, but those interfaces are distinctly non-standard, and might
35  * even be totally proprietary
36  *
37  */
38
39 /* FILE FORMAT
40  *
41  *
42  * The triplets file contains records of the form:
43  *
44  * IMSI            RAND                             SRES     Kc
45  * 232420100000015,30000000000000000000000000000000,30112233,445566778899AABB
46  *
47  * there must be *three* entries for every IMSI for it to be considered valid.
48  *
49  * Lines starting with # are ignored.
50  *
51  * Conveniently, this file format is produced by XXXX.
52
53  *
54  */
55
56
57 #include        <freeradius-devel/ident.h>
58 RCSID("$Id$")
59
60 #include        <freeradius-devel/radiusd.h>
61 #include        <freeradius-devel/modules.h>
62
63 #include        <sys/stat.h>
64 #include        <ctype.h>
65 #include        <fcntl.h>
66 #include        <limits.h>
67
68 #include        "../rlm_eap/libeap/eap_sim.h"
69
70 struct sim_file_instance {
71         /* autz */
72         char *file;
73 };
74
75 static const CONF_PARSER module_config[] = {
76         { "simtriplets",        PW_TYPE_STRING_PTR,
77           offsetof(struct sim_file_instance, file),
78           NULL, "${raddbdir}/simtriplets.dat" },
79
80         { NULL, -1, 0, NULL, NULL }
81 };
82
83 /*
84  *      (Re-)read the "users" file into memory.
85  */
86 static int sim_file_instantiate(CONF_SECTION *conf, void **instance)
87 {
88         struct sim_file_instance *inst;
89
90         inst = rad_malloc(sizeof *inst);
91         if (!inst) {
92                 return -1;
93         }
94         memset(inst, 0, sizeof(*inst));
95
96         if (cf_section_parse(conf, inst, module_config) < 0) {
97                 free(inst);
98                 return -1;
99         }
100
101         *instance = inst;
102         return 0;
103 }
104
105 /*
106  *      Find the named user in the database.  Create the
107  *      set of attribute-value pairs to check and reply with
108  *      for this user from the database. The main code only
109  *      needs to check the password, the rest is done here.
110  */
111 static int sim_file_authorize(void *instance, REQUEST *request)
112 {
113         VALUE_PAIR      *namepair;
114         VALUE_PAIR      *reply_tmp;
115         const char      *name;
116         struct sim_file_instance *inst = instance;
117         VALUE_PAIR     **reply_pairs;
118         VALUE_PAIR     **config_pairs;
119         FILE            *triplets;
120         char             tripbuf[sizeof("232420100000015,30000000000000000000000000000000,30112233,445566778899AABB")*2];
121         char             imsi[128], chal[256], kc[128], sres[128];
122         int              imsicount;
123         int              fieldcount;
124         int lineno;
125
126         reply_pairs = &request->reply->vps;
127         config_pairs = &request->config_items;
128
129         /*
130          *      Grab the canonical user name.
131          */
132         namepair = request->username;
133         name = namepair ? (char *) namepair->vp_strvalue : "NONE";
134
135         triplets = fopen(inst->file, "r");
136
137         if(triplets == NULL) {
138                 radlog(L_ERR, "can not open %s: %s",
139                        inst->file, strerror(errno));
140                 return RLM_MODULE_NOTFOUND;
141         }
142
143         imsicount = 0;
144         lineno = 0;
145
146         while(fgets(tripbuf, sizeof(tripbuf), triplets) == tripbuf
147               && imsicount < 3)
148         {
149                 char *f;
150                 char *l;
151                 VALUE_PAIR *r, *k, *s;
152
153                 lineno++;
154                 if(tripbuf[0]=='#') continue;
155
156                 l = tripbuf;
157                 fieldcount = 0;
158                 chal[0]='0'; chal[1]='x';
159                 kc[0]='0';   kc[1]='x';
160                 sres[0]='0'; sres[1]='x';
161
162                 f = strsep(&l, ",");
163                 if(f)
164                 {
165                         imsi[0]='\0';
166                         strncat(imsi, f, sizeof(imsi));
167                         fieldcount++;
168                 }
169
170                 if(strcmp(imsi, name) != 0)
171                 {
172                         continue;
173                 }
174
175                 /* we found one */
176                 f = strsep(&l, ",");
177                 if(f)
178                 {
179                         chal[2]='\0';
180                         strncat(chal+2, f, sizeof(chal)-2);
181                         fieldcount++;
182                 }
183
184                 f = strsep(&l, ",");
185                 if(f)
186                 {
187                         sres[2]='\0';
188                         strncat(sres+2, f, sizeof(sres)-2);
189                         fieldcount++;
190                 }
191
192                 f = strsep(&l, ",\n");
193                 if(f)
194                 {
195                         kc[2]='\0';
196                         strncat(kc+2, f, sizeof(kc)-2);
197                         fieldcount++;
198                 }
199
200                 if(fieldcount != 4)
201                 {
202                         radlog(L_ERR, "invalid number of fields %d at line %d",
203                                fieldcount, lineno);
204                         /* complain about malformed line */
205                         continue;
206                 }
207
208
209                 r = paircreate(ATTRIBUTE_EAP_SIM_RAND1 + imsicount, PW_TYPE_OCTETS);
210                 r = pairparsevalue(r, chal);
211                 pairadd(reply_pairs, r);
212
213                 k = paircreate(ATTRIBUTE_EAP_SIM_KC1 + imsicount, PW_TYPE_OCTETS);
214                 k = pairparsevalue(k, kc);
215                 rad_assert(k != NULL);
216                 pairadd(reply_pairs, k);
217
218                 s = paircreate(ATTRIBUTE_EAP_SIM_SRES1 + imsicount, PW_TYPE_OCTETS);
219                 s = pairparsevalue(s, sres);
220                 pairadd(reply_pairs, s);
221
222                 imsicount++;
223         }
224         fclose(triplets);
225
226         if (imsicount < 3)
227         {
228                 DEBUG("rlm_sim_files: "
229                       "insufficient number of challenges for imsi %s: %d\n",
230                       name, imsicount);
231                 return RLM_MODULE_NOTFOUND;
232         }
233
234         DEBUG("rlm_sim_files: "
235               "authorized user/imsi %s\n", name);
236
237         /*
238          * EAP module will also grab based upon presence of EAP packet
239          * and it will add the Autz-Type entry.
240          */
241
242         if((reply_tmp = pairmake ("EAP-Type", "SIM", T_OP_EQ)))
243         {
244                 radlog(L_INFO, "rlm_sim_files: Adding EAP-Type: eap-sim");
245                 pairadd (config_pairs, reply_tmp);
246         }
247
248 #if 0
249         DEBUG("rlm_sim_files: saw config");
250         vp_printlist(stdout, *config_pairs);
251
252         DEBUG("rlm_sim_files: saw reply");
253         vp_printlist(stdout, *reply_pairs);
254 #endif
255
256         return RLM_MODULE_OK;
257 }
258
259
260 /*
261  *      Clean up.
262  */
263 static int sim_file_detach(void *instance)
264 {
265         struct sim_file_instance *inst = instance;
266
267         free(inst);
268         return 0;
269 }
270
271
272 /* globally exported name */
273 module_t rlm_sim_files = {
274         RLM_MODULE_INIT,
275         "sim_files",
276         0,                              /* type: reserved */
277         sim_file_instantiate,           /* instantiation */
278         sim_file_detach,                /* detach */
279         {
280                 NULL,                   /* authentication */
281                 sim_file_authorize,     /* authorization */
282                 NULL,                   /* preaccounting */
283                 NULL,                   /* accounting */
284                 NULL,                   /* checksimul */
285                 NULL,                   /* pre-proxy */
286                 NULL,                   /* post-proxy */
287                 NULL                    /* post-auth */
288         },
289 };
290