use new RCSID macro to prevent Id keyword from being optimized out
[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/autoconf.h>
61
62 #include        <sys/stat.h>
63
64 #include        <stdlib.h>
65 #include        <string.h>
66 #include        <netdb.h>
67 #include        <ctype.h>
68 #include        <fcntl.h>
69 #include        <limits.h>
70
71 #include        <freeradius-devel/radiusd.h>
72 #include        <freeradius-devel/modules.h>
73 #include        "../rlm_eap/libeap/eap_sim.h"
74
75 struct sim_file_instance {
76         /* autz */
77         char *file;
78 };
79
80 static const CONF_PARSER module_config[] = {
81         { "simtriplets",        PW_TYPE_STRING_PTR,
82           offsetof(struct sim_file_instance, file),
83           NULL, "${raddbdir}/simtriplets.dat" },
84
85         { NULL, -1, 0, NULL, NULL }
86 };
87
88 /*
89  *      (Re-)read the "users" file into memory.
90  */
91 static int sim_file_instantiate(CONF_SECTION *conf, void **instance)
92 {
93         struct sim_file_instance *inst;
94
95         inst = rad_malloc(sizeof *inst);
96         if (!inst) {
97                 return -1;
98         }
99         memset(inst, 0, sizeof(*inst));
100
101         if (cf_section_parse(conf, inst, module_config) < 0) {
102                 free(inst);
103                 return -1;
104         }
105
106         *instance = inst;
107         return 0;
108 }
109
110 /*
111  *      Find the named user in the database.  Create the
112  *      set of attribute-value pairs to check and reply with
113  *      for this user from the database. The main code only
114  *      needs to check the password, the rest is done here.
115  */
116 static int sim_file_authorize(void *instance, REQUEST *request)
117 {
118         VALUE_PAIR      *namepair;
119         VALUE_PAIR      *reply_tmp;
120         const char      *name;
121         struct sim_file_instance *inst = instance;
122         VALUE_PAIR     **reply_pairs;
123         VALUE_PAIR     **config_pairs;
124         FILE            *triplets;
125         char             tripbuf[sizeof("232420100000015,30000000000000000000000000000000,30112233,445566778899AABB")*2];
126         char             imsi[128], chal[256], kc[128], sres[128];
127         int              imsicount;
128         int              fieldcount;
129         int lineno;
130
131         reply_pairs = &request->reply->vps;
132         config_pairs = &request->config_items;
133
134         /*
135          *      Grab the canonical user name.
136          */
137         namepair = request->username;
138         name = namepair ? (char *) namepair->vp_strvalue : "NONE";
139
140         triplets = fopen(inst->file, "r");
141
142         if(triplets == NULL) {
143                 radlog(L_ERR, "can not open %s: %s",
144                        inst->file, strerror(errno));
145                 return RLM_MODULE_NOTFOUND;
146         }
147
148         imsicount = 0;
149         lineno = 0;
150
151         while(fgets(tripbuf, sizeof(tripbuf), triplets) == tripbuf
152               && imsicount < 3)
153         {
154                 char *f;
155                 char *l;
156                 VALUE_PAIR *r, *k, *s;
157
158                 lineno++;
159                 if(tripbuf[0]=='#') continue;
160
161                 l = tripbuf;
162                 fieldcount = 0;
163                 chal[0]='0'; chal[1]='x';
164                 kc[0]='0';   kc[1]='x';
165                 sres[0]='0'; sres[1]='x';
166
167                 f = strsep(&l, ",");
168                 if(f)
169                 {
170                         imsi[0]='\0';
171                         strncat(imsi, f, sizeof(imsi));
172                         fieldcount++;
173                 }
174
175                 if(strcmp(imsi, name) != 0)
176                 {
177                         continue;
178                 }
179
180                 /* we found one */
181                 f = strsep(&l, ",");
182                 if(f)
183                 {
184                         chal[2]='\0';
185                         strncat(chal+2, f, sizeof(chal)-2);
186                         fieldcount++;
187                 }
188
189                 f = strsep(&l, ",");
190                 if(f)
191                 {
192                         sres[2]='\0';
193                         strncat(sres+2, f, sizeof(sres)-2);
194                         fieldcount++;
195                 }
196
197                 f = strsep(&l, ",\n");
198                 if(f)
199                 {
200                         kc[2]='\0';
201                         strncat(kc+2, f, sizeof(kc)-2);
202                         fieldcount++;
203                 }
204
205                 if(fieldcount != 4)
206                 {
207                         radlog(L_ERR, "invalid number of fields %d at line %d",
208                                fieldcount, lineno);
209                         /* complain about malformed line */
210                         continue;
211                 }
212
213
214                 r = paircreate(ATTRIBUTE_EAP_SIM_RAND1 + imsicount, PW_TYPE_OCTETS);
215                 r = pairparsevalue(r, chal);
216                 pairadd(reply_pairs, r);
217
218                 k = paircreate(ATTRIBUTE_EAP_SIM_KC1 + imsicount, PW_TYPE_OCTETS);
219                 k = pairparsevalue(k, kc);
220                 rad_assert(k != NULL);
221                 pairadd(reply_pairs, k);
222
223                 s = paircreate(ATTRIBUTE_EAP_SIM_SRES1 + imsicount, PW_TYPE_OCTETS);
224                 s = pairparsevalue(s, sres);
225                 pairadd(reply_pairs, s);
226
227                 imsicount++;
228         }
229         fclose(triplets);
230
231         if (imsicount < 3)
232         {
233                 DEBUG("rlm_sim_files: "
234                       "insufficient number of challenges for imsi %s: %d\n",
235                       name, imsicount);
236                 return RLM_MODULE_NOTFOUND;
237         }
238
239         DEBUG("rlm_sim_files: "
240               "authorized user/imsi %s\n", name);
241
242         /*
243          * EAP module will also grab based upon presence of EAP packet
244          * and it will add the Autz-Type entry.
245          */
246
247         if((reply_tmp = pairmake ("EAP-Type", "SIM", T_OP_EQ)))
248         {
249                 radlog(L_INFO, "rlm_sim_files: Adding EAP-Type: eap-sim");
250                 pairadd (config_pairs, reply_tmp);
251         }
252
253 #if 0
254         DEBUG("rlm_sim_files: saw config");
255         vp_printlist(stdout, *config_pairs);
256
257         DEBUG("rlm_sim_files: saw reply");
258         vp_printlist(stdout, *reply_pairs);
259 #endif
260
261         return RLM_MODULE_OK;
262 }
263
264
265 /*
266  *      Clean up.
267  */
268 static int sim_file_detach(void *instance)
269 {
270         struct sim_file_instance *inst = instance;
271
272         free(inst);
273         return 0;
274 }
275
276
277 /* globally exported name */
278 module_t rlm_sim_files = {
279         RLM_MODULE_INIT,
280         "sim_files",
281         0,                              /* type: reserved */
282         sim_file_instantiate,           /* instantiation */
283         sim_file_detach,                /* detach */
284         {
285                 NULL,                   /* authentication */
286                 sim_file_authorize,     /* authorization */
287                 NULL,                   /* preaccounting */
288                 NULL,                   /* accounting */
289                 NULL,                   /* checksimul */
290                 NULL,                   /* pre-proxy */
291                 NULL,                   /* post-proxy */
292                 NULL                    /* post-auth */
293         },
294 };
295