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