New build path variable
[freeradius.git] / src / modules / rlm_ippool / rlm_ippool_tool.c
1 /*
2  * rlm_ippool_tool.c
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 2003,2006  FreeRADIUS Project, http://www.freeradius.org/
21  * Copyright 2003  Edwin Groothuis, edwin@mavetju.org
22  * Permission from Edwin Groothuis for release under GPL is archived here:
23  * http://lists.cistron.nl/archives/freeradius-devel/2003/09/frm00247.html
24  *
25  */
26
27 /*
28  The original license follows. This license applies to the tarball at
29  http://www.mavetju.org/unix/general.php
30
31  Copyright 2003 by Edwin Groothuis, edwin@mavetju.org
32  All rights reserved.
33
34  Redistribution and use in source and binary forms, with or without
35  modification, are permitted provided that the following conditions
36  are met:
37  1. Redistributions of source code must retain the above copyright
38     notice, this list of conditions and the following disclaimer.
39  2. Redistributions in binary form must reproduce the above copyright
40     notice, this list of conditions and the following disclaimer in the
41     documentation and/or other materials provided with the distribution.
42
43  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
44  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
47  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53  SUCH DAMAGE.
54 */
55
56 #include <freeradius-devel/ident.h>
57 RCSID("$Id$")
58
59 #include <freeradius-devel/libradius.h>
60 #include <fcntl.h>
61 #include <gdbm.h>
62 #include "../../include/md5.h"
63
64 int active=0;
65
66 int aflag=0;
67 int cflag=0;
68 int rflag=0;
69 int vflag=0;
70 int nflag=0;
71 int oflag=0;
72 int uflag=0;
73
74 typedef struct ippool_info {
75     uint32_t        ipaddr;
76     char            active;
77     char            cli[32];
78         char                    extra;
79 } ippool_info;
80
81
82 #define MAX_NAS_NAME_SIZE 64
83 typedef struct old_ippool_key {
84     char nas[MAX_NAS_NAME_SIZE];
85     unsigned int port;
86 } old_ippool_key;
87 typedef struct ippool_key {
88     char key[16];
89 } ippool_key;
90
91 #define MATCH_IP(ip1,ip2) ((ip1)==NULL || strcmp((ip1),(ip2))==0)
92 #define MATCH_ACTIVE(info) ((info).active==1 || !aflag)
93
94 void addip(char *sessiondbname,char *indexdbname,char *ipaddress, char* NASname, char*NASport,int old);
95 void viewdb(char *sessiondbname,char *indexdbname,char *ipaddress, int old);
96 void tonewformat(char *sessiondbname,char *newsessiondbname);
97 void usage(char *argv0);
98
99 void addip(char *sessiondbname,char *indexdbname,char *ipaddress, char* NASname, char*NASport, int old) {
100     GDBM_FILE sessiondb;
101     GDBM_FILE indexdb;
102     datum key_datum,data_datum,save_datum;
103         datum nextkey;
104     ippool_key key;
105     old_ippool_key old_key;
106     ippool_info entry;
107     struct in_addr ipaddr;
108     uint8_t key_str[17];
109     char hex_str[35];
110     int num=0;
111         int mppp=0;
112     int mode=GDBM_WRITER;
113     signed int rcode;
114         int delete = 0;
115         int port;
116         int extra = 0;
117         int found = 0;
118
119     sessiondb=gdbm_open(sessiondbname,512,mode,0,NULL);
120     indexdb=gdbm_open(indexdbname,512,mode,0,NULL);
121
122         if (inet_aton(ipaddress, &ipaddr) == 0)
123         {
124                 printf("rlm_ippool_tool: Unable to convert IP address '%s'\n", ipaddress);
125                 return;
126         }
127
128     if (sessiondb==NULL)
129         {
130                 printf("rlm_ippool_tool: Unable to open DB '%s'\n", sessiondbname);
131                 return;
132         }
133
134     if (indexdb==NULL)
135         {
136                 printf("rlm_ippool_tool: Unable to open DB '%s'\n", indexdbname);
137                 return;
138         }
139
140         port = strtoul(NASport,NULL,0);
141
142         /* Basically from rlm_ippool.c */
143
144         if (old){
145                 strlcpy(old_key.nas,NASname,sizeof(old_key.nas));
146                 old_key.port = port;
147                 key_datum.dptr = (char *) &old_key;
148                 key_datum.dsize = sizeof(old_ippool_key);
149         }
150         else{
151                 char md5_input_str[MAX_STRING_LEN];
152                 FR_MD5_CTX md5_context;
153
154                 snprintf(md5_input_str,MAX_STRING_LEN, "%s %s",NASname,NASport);
155                 fr_MD5Init(&md5_context);
156                 fr_MD5Update(&md5_context, md5_input_str, strlen(md5_input_str));
157                 fr_MD5Final(key_str, &md5_context);
158                 memcpy(key.key,key_str,16);
159                 fr_bin2hex(key_str,hex_str,16);
160                 hex_str[32] = '\0';
161                 key_datum.dptr = (char *) &key;
162                 key_datum.dsize = sizeof(ippool_key);
163         }
164
165
166         data_datum = gdbm_fetch(sessiondb, key_datum);
167         if (data_datum.dptr != NULL){
168                 found = 1;
169                 memcpy(&entry,data_datum.dptr, sizeof(ippool_info));
170                 free(data_datum.dptr);
171                 if (entry.active){
172                         if (old)
173                                 printf("rlm_ippool_tool: Deleting stale entry for ip/port %s/%u",
174                                         ipaddress, port);
175                         else
176                                 printf("rlm_ippool_tool: Deleting stale entry for key: '%s'",hex_str);
177                         entry.active = 0;
178                         save_datum.dptr = key_datum.dptr;
179                         save_datum.dsize = key_datum.dsize;
180
181                         data_datum.dptr = (char*) &entry;
182                         data_datum.dsize = sizeof(ippool_info);
183
184                         rcode = gdbm_store(sessiondb, key_datum, data_datum, GDBM_REPLACE);
185                         if (rcode < 0) {
186                                 printf("rlm_ippool_tool: Failed storing data to %s: %s\n",
187                                         sessiondbname, gdbm_strerror(gdbm_errno));
188                                 gdbm_close(indexdb);
189                                 gdbm_close(sessiondb);
190                                 return;
191                         }
192
193                         key_datum.dptr = (char *) &entry.ipaddr;
194                         key_datum.dsize = sizeof(uint32_t);
195                         data_datum = gdbm_fetch(indexdb, key_datum);
196                         if (data_datum.dptr != NULL) {
197                                 memcpy(&num, data_datum.dptr, sizeof(int));
198                                 free(data_datum.dptr);
199                                 if (num > 0) {
200                                         num--;
201                                         data_datum.dptr = (char *) &num;
202                                         data_datum.dsize = sizeof(int);
203                                         rcode = gdbm_store(indexdb, key_datum, data_datum, GDBM_REPLACE);
204                                         if (rcode < 0) {
205                                                 printf("rlm_ippool_tool: Failed storing data to %s: %s\n",
206                                                         indexdbname, gdbm_strerror(gdbm_errno));
207                                                 gdbm_close(indexdb);
208                                                 gdbm_close(sessiondb);
209                                                 return;
210                                         }
211                                         if (num > 0 && entry.extra == 1) {
212                                                 gdbm_delete(sessiondb, save_datum);
213                                         }
214                                 }
215                         }
216                 }
217         }
218         key_datum.dptr = NULL;
219
220         if (key_datum.dptr == NULL) {
221                 key_datum = gdbm_firstkey(sessiondb);
222                 while (key_datum.dptr) {
223                         data_datum = gdbm_fetch(sessiondb, key_datum);
224                         if (data_datum.dptr != NULL) {
225                                 memcpy(&entry, data_datum.dptr, sizeof(ippool_info));
226                                 free(data_datum.dptr);
227
228                                 if (entry.active == 0 && entry.ipaddr == ipaddr.s_addr) {
229                                         datum tmp;
230                                         tmp.dptr = (char *) &entry.ipaddr;
231                                         tmp.dsize = sizeof(uint32_t);
232                                         data_datum = gdbm_fetch(indexdb, tmp);
233                                         if (data_datum.dptr){
234                                                 memcpy(&num, data_datum.dptr, sizeof(int));
235                                                 free(data_datum.dptr);
236                                                 if (num == 0){
237                                                         delete = 1;
238                                                         break;
239                                                 }
240                                         } else {
241                                                 delete = 1;
242                                                 break;
243                                         }
244                                 }
245                         }
246                         nextkey = gdbm_nextkey(sessiondb, key_datum);
247                         free(key_datum.dptr);
248                         key_datum = nextkey;
249                 }
250         }
251
252         if (key_datum.dptr){
253                 if (found && ! mppp){
254                         datum key_datum_tmp,data_datum_tmp;
255                         old_ippool_key old_key_tmp;
256                         ippool_key key_tmp;
257                         if (old){
258                                 strlcpy(old_key_tmp.nas,NASname,
259                                         sizeof(old_key_tmp.nas));
260                                 old_key_tmp.port=port;
261                                 key_datum_tmp.dptr = (char *) &old_key_tmp;
262                                 key_datum_tmp.dsize = sizeof(old_ippool_key);
263                         }
264                         else{
265                                 memcpy(key_tmp.key,key_str,16);
266                                 key_datum_tmp.dptr = (char *) &key_tmp;
267                                 key_datum_tmp.dsize = sizeof(ippool_key);
268                         }
269                         data_datum_tmp = gdbm_fetch(sessiondb, key_datum_tmp);
270                         if (data_datum_tmp.dptr != NULL) {
271                                 rcode = gdbm_store(sessiondb, key_datum, data_datum_tmp, GDBM_REPLACE);
272                                 if (rcode < 0) {
273                                         printf("rlm_ippool_tool: Failed storing data to %s: %s\n",
274                                                 sessiondbname, gdbm_strerror(gdbm_errno));
275                                                 gdbm_close(indexdb);
276                                                 gdbm_close(sessiondb);
277                                         return;
278                                 }
279                                 free(data_datum_tmp.dptr);
280                         }
281                 } else {
282                         if (delete)
283                                 gdbm_delete(sessiondb, key_datum);
284                         else {
285                                 if (mppp)
286                                         extra = 1;
287 #if 0
288                                 if (!mppp)
289                                         printf("Error in if statements!!!\n");
290 #endif
291                         }
292                 }
293                 free(key_datum.dptr);
294                 entry.active=1;
295                 if (extra)
296                         entry.extra=1;
297                 data_datum.dptr = (char *) &entry;
298                 data_datum.dsize = sizeof(ippool_info);
299
300                 if (old){
301                         strlcpy(old_key.nas,NASname,sizeof(old_key.nas));
302                         old_key.port = port;
303                         key_datum.dptr = (char *) &old_key;
304                         key_datum.dsize = sizeof(old_ippool_key);
305                         printf("rlm_ippool_tool: Allocating ip to nas/port: %s/%u\n",old_key.nas,old_key.port);
306                 }
307                 else{
308                         memcpy(key.key,key_str,16);
309                         key_datum.dptr = (char *) &key;
310                         key_datum.dsize = sizeof(ippool_key);
311                         printf("rlm_ippool_tool: Allocating ip to key: '%s'\n",hex_str);
312                 }
313                 rcode = gdbm_store(sessiondb, key_datum, data_datum, GDBM_REPLACE);
314                 if (rcode < 0) {
315                         printf("rlm_ippool_tool: Failed storing data to %s: %s\n",
316                                 sessiondbname, gdbm_strerror(gdbm_errno));
317                         gdbm_close(indexdb);
318                         gdbm_close(sessiondb);
319                         return;
320                 }
321
322                 /* Increase the ip index count */
323                 key_datum.dptr = (char *) &entry.ipaddr;
324                 key_datum.dsize = sizeof(uint32_t);
325                 data_datum = gdbm_fetch(indexdb, key_datum);
326                 if (data_datum.dptr){
327                         memcpy(&num,data_datum.dptr,sizeof(int));
328                         free(data_datum.dptr);
329                 } else
330                         num = 0;
331                 num++;
332                 printf("rlm_ippool_tool: num: %d\n",num);
333                 data_datum.dptr = (char *) &num;
334                 data_datum.dsize = sizeof(int);
335                 rcode = gdbm_store(indexdb, key_datum, data_datum, GDBM_REPLACE);
336                 if (rcode < 0) {
337                         printf("rlm_ippool_tool: Failed storing data to %s: %s\n",
338                                 indexdbname, gdbm_strerror(gdbm_errno));
339                         gdbm_close(indexdb);
340                         gdbm_close(sessiondb);
341                         return;
342                 }
343
344                 if (old)
345                         printf("rlm_ippool_tool: Allocated ip %s to client on nas %s,port %u\n",
346                                 ipaddress, old_key.nas,port);
347                 else
348                         printf("rlm_ippool_tool: Allocated ip %s to key  '%s'\n",ipaddress,hex_str);
349
350         }
351     gdbm_close(indexdb);
352     gdbm_close(sessiondb);
353 }
354 void tonewformat(char *sessiondbname,char *newsessiondbname){
355     GDBM_FILE sessiondb;
356     GDBM_FILE newsessiondb;
357     datum key_datum,keynext_datum,data_datum,newkey_datum;
358     old_ippool_key old_key;
359     ippool_key key;
360     uint8_t key_str[17];
361     char hex_str[35];
362     int rcode;
363
364     sessiondb=gdbm_open(sessiondbname,512,GDBM_READER,0,NULL);
365     newsessiondb=gdbm_open(newsessiondbname,512,GDBM_NEWDB,0,NULL);
366
367     if (sessiondb==NULL || newsessiondb==NULL) return;
368
369     memset(key_str,0,17);
370
371     key_datum=gdbm_firstkey(sessiondb);
372     while (key_datum.dptr) {
373         keynext_datum=gdbm_nextkey(sessiondb,key_datum);
374         if (key_datum.dsize==sizeof(struct old_ippool_key)) {
375                 char md5_input_str[MAX_STRING_LEN];
376                 FR_MD5_CTX md5_context;
377
378                 memcpy(&old_key,key_datum.dptr,sizeof(struct old_ippool_key));
379                 snprintf(md5_input_str,MAX_STRING_LEN, "%s %d",old_key.nas,old_key.port);
380                 fr_MD5Init(&md5_context);
381                 fr_MD5Update(&md5_context, md5_input_str, strlen(md5_input_str));
382                 fr_MD5Final(key_str, &md5_context);
383                 memcpy(key.key,key_str,16);
384                 fr_bin2hex(key_str,hex_str,16);
385                 hex_str[32] = '\0';
386                 printf("rlm_ippool_tool: Transforming pair nas/port (%s/%d) to md5 '%s'\n",
387                         old_key.nas,old_key.port,hex_str);
388                 newkey_datum.dptr = (char *) &key;
389                 newkey_datum.dsize = sizeof(ippool_key);
390                 data_datum=gdbm_fetch(sessiondb,key_datum);
391                 if (data_datum.dptr!=NULL){
392                     rcode=gdbm_store(newsessiondb,newkey_datum,data_datum,GDBM_REPLACE);
393                     if (rcode < 0) {
394                                 printf("Failed to update new file %s: %s\n",newsessiondbname,gdbm_strerror(gdbm_errno));
395                                 gdbm_close(newsessiondb);
396                                 gdbm_close(sessiondb);
397                                 return;
398                         }
399                 }
400         }
401         key_datum=keynext_datum;
402     }
403     gdbm_close(newsessiondb);
404     gdbm_close(sessiondb);
405 }
406
407 void viewdb(char *sessiondbname,char *indexdbname,char *ipaddress, int old) {
408     GDBM_FILE sessiondb;
409     GDBM_FILE indexdb;
410     datum key_datum,keynext_datum,data_datum,save_datum;
411     old_ippool_key old_key;
412     ippool_key key;
413     ippool_info info;
414     struct in_addr ipaddr;
415     int num;
416     uint8_t key_str[17];
417     char hex_str[35];
418     char *ip;
419     int mode=GDBM_READER;
420     int rcode;
421
422     if (rflag) mode=GDBM_WRITER;
423     sessiondb=gdbm_open(sessiondbname,512,mode,0,NULL);
424     indexdb=gdbm_open(indexdbname,512,mode,0,NULL);
425
426     if (sessiondb==NULL || indexdb==NULL) return;
427
428     memset(key_str,0,17);
429
430     key_datum=gdbm_firstkey(sessiondb);
431     while (key_datum.dptr) {
432         keynext_datum=gdbm_nextkey(sessiondb,key_datum);
433         if (key_datum.dsize==sizeof(struct ippool_key) || key_datum.dsize==sizeof(struct old_ippool_key)) {
434             if (old)
435                  memcpy(&old_key,key_datum.dptr,sizeof(struct old_ippool_key));
436             else
437                  memcpy(&key,key_datum.dptr,sizeof(struct ippool_key));
438
439             data_datum=gdbm_fetch(sessiondb,key_datum);
440             if (data_datum.dptr!=NULL) {
441
442                 memcpy(&info,data_datum.dptr,sizeof(struct ippool_info));
443                 memcpy(&ipaddr,&info.ipaddr,4);
444                 ip=inet_ntoa(ipaddr);
445
446                 if (info.active) active++;
447                 if (vflag && MATCH_IP(ipaddress,ip) && MATCH_ACTIVE(info)){
448                     if (old)
449                         printf("NAS:%s port:0x%x - ",old_key.nas,old_key.port);
450                     else{
451                         memcpy(key_str,key.key,16);
452                         fr_bin2hex(key_str,hex_str,16);
453                         hex_str[32] = '\0';
454                         printf("KEY: '%s' - ",hex_str);
455                     }
456                 }
457                 if (!vflag && aflag && info.active && MATCH_IP(ipaddress,ip))
458                     printf("%s\n",ip);
459                 else if (vflag && MATCH_IP(ipaddress,ip) && MATCH_ACTIVE(info))
460                     printf("ipaddr:%s active:%d cli:%s",
461                         inet_ntoa(ipaddr),info.active,info.cli);
462
463                 /*
464                  * algorythm copied from rlm_ippool.c:
465                  * - set active to zero
466                  * - set number of sessions to zero
467                  */
468                 if (rflag && MATCH_IP(ipaddress,ip)) {
469                     info.active=0;
470                         save_datum.dptr = key_datum.dptr;
471                         save_datum.dsize = key_datum.dsize;
472                     data_datum.dptr = (char *) &info;
473                     data_datum.dsize = sizeof(ippool_info);
474                     rcode=gdbm_store(sessiondb,key_datum,data_datum,GDBM_REPLACE);
475                     if (rcode < 0) {
476                                 printf("Failed to update %s: %s\n",ip,gdbm_strerror(gdbm_errno));
477                                 gdbm_close(indexdb);
478                                 gdbm_close(sessiondb);
479                                 return;
480                         }
481                     key_datum.dptr=(char *)&info.ipaddr;
482                     key_datum.dsize = sizeof(uint32_t);
483                     data_datum=gdbm_fetch(indexdb,key_datum);
484                     if (data_datum.dptr!=NULL) {
485                                 memcpy(&num, data_datum.dptr, sizeof(int));
486                                 if (num>0) {
487                                         num--;
488                                         data_datum.dptr = (char *) &num;
489                                         data_datum.dsize = sizeof(int);
490                                         rcode = gdbm_store(indexdb, key_datum, data_datum, GDBM_REPLACE);
491                                         if (rcode < 0) {
492                                                 printf("Failed to update %s: %s\n",ip,gdbm_strerror(gdbm_errno));
493                                                 gdbm_close(indexdb);
494                                                 gdbm_close(sessiondb);
495                                                 return;
496                                         }
497                                         if (num > 0 && info.extra == 1) {
498                                                 gdbm_delete(sessiondb, save_datum);
499                                         }
500                                 }
501                     }
502                 }
503
504                 key_datum.dptr=(char *)&info.ipaddr;
505                 key_datum.dsize = sizeof(uint32_t);
506                 data_datum=gdbm_fetch(indexdb,key_datum);
507                 if (data_datum.dptr!=NULL) {
508                     memcpy(&num, data_datum.dptr, sizeof(int));
509                     if (vflag && MATCH_IP(ipaddress,ip) && MATCH_ACTIVE(info))
510                         printf(" num:%d",num);
511                 }
512                 if (vflag && MATCH_IP(ipaddress,ip) && MATCH_ACTIVE(info))
513                     printf("\n");
514             } else
515                 if (vflag && ipaddress==NULL){
516                     if (old)
517                         printf("NAS:%s port:0x%x\n",old_key.nas,old_key.port);
518                     else{
519                         memcpy(key_str,key.key,16);
520                         fr_bin2hex(key_str,hex_str,16);
521                         hex_str[32] = '\0';
522                         printf("KEY: '%s' - ",hex_str);
523                     }
524                 }
525         }
526         key_datum=keynext_datum;
527     }
528     gdbm_close(indexdb);
529     gdbm_close(sessiondb);
530 }
531
532 void NEVER_RETURNS usage(char *argv0) {
533     printf("Usage: %s [-a] [-c] [-o] [-v] <session-db> <index-db> [ipaddress]\n",argv0);
534     printf("-a: print all active entries\n");
535     printf("-c: report number of active entries\n");
536     printf("-r: remove active entries\n");
537     printf("-v: verbose report of all entries\n");
538     printf("-o: Assume old database format (nas/port pair, not md5 output)\n");
539     printf("If an ipaddress is specified then that address is used to\n");
540     printf("limit the actions or output.\n");
541     printf("Usage: %s -n  <session-db> <index-db> <ipaddress> <nasIP> <nasPort>\n",argv0);
542     printf("-n: Mark the entry nasIP/nasPort as having ipaddress\n");
543     printf("Usage: %s -u <session-db> <new-session-db>\n",argv0);
544     printf("-u: Update old format database to new.\n");
545     exit(0);
546 }
547
548 int main(int argc,char **argv) {
549     int ch;
550     char *argv0=argv[0];
551
552     while ((ch=getopt(argc,argv,"acrvnou"))!=-1)
553         switch (ch) {
554         case 'a': aflag++;break;
555         case 'c': cflag++;break;
556         case 'r': rflag++;break;
557         case 'v': vflag=1;break;
558         case 'n': nflag=1;break;
559         case 'o': oflag=1;break;
560         case 'u': uflag=1;break;
561         default: usage(argv0);
562         }
563     argc -= optind;
564     argv += optind;
565
566     if ((argc==2 || argc==3) && !nflag && !uflag) {
567                 viewdb(argv[0],argv[1],argv[2],oflag);
568                 if (cflag) printf("%d\n",active);
569         } else
570                 if (argc==5 && nflag)
571                         addip(argv[0],argv[1],argv[2],argv[3],argv[4],oflag);
572                 else if (argc==2 && uflag)
573                         tonewformat(argv[0],argv[1]);
574                 else
575                         usage(argv0);
576     return 0;
577 }