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