/* * rlm_ippool_tool.c * * Version: $Id$ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * Copyright 2003, 2006 FreeRADIUS Project, http://www.freeradius.org/ * Copyright 2003 Edwin Groothuis, edwin@mavetju.org * Permission from Edwin Groothuis for release under GPL is archived here: * http://lists.cistron.nl/archives/freeradius-devel/2003/09/frm00247.html * */ /* The original license follows. This license applies to the tarball at http://www.mavetju.org/unix/general.php Copyright 2003 by Edwin Groothuis, edwin@mavetju.org All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ RCSID("$Id$") #include #include #include #include "../../include/md5.h" static int active = 0; static int aflag = 0; static int cflag = 0; static int rflag = 0; static int vflag = 0; static int nflag = 0; static int oflag = 0; static int uflag = 0; typedef struct ippool_info { uint32_t ipaddr; char active; char cli[32]; char extra; } ippool_info; #define MAX_NAS_NAME_SIZE 64 typedef struct old_ippool_key { char nas[MAX_NAS_NAME_SIZE]; uint16_t port; } old_ippool_key; typedef struct ippool_key { char key[16]; } ippool_key; #define MATCH_IP(ip1, ip2) ((ip1) == NULL || strcmp((ip1), (ip2)) == 0) #define MATCH_ACTIVE(info) ((info).active == 1 || !aflag) void addip(char *sessiondbname, char *indexdbname, char *ipaddress, char *NASname, char *NASport, int old); void viewdb(char *sessiondbname, char *indexdbname, char *ipaddress, int old); void tonewformat(char *sessiondbname, char *newsessiondbname); void usage(char *argv0); void addip(char *sessiondbname, char *indexdbname, char *ipaddress, char *NASname, char *NASport, int old) { GDBM_FILE sessiondb; GDBM_FILE indexdb; datum key_datum, data_datum, save_datum; datum nextkey; ippool_key key; old_ippool_key old_key; ippool_info entry; struct in_addr ipaddr; uint8_t key_str[17]; char hex_str[35]; int num = 0; int mppp = 0; int mode = GDBM_WRITER; int rcode; int delete = 0; uint16_t port; bool found = false; memset(&key, 0, sizeof(key)); /* -Winitialize */ sessiondb = gdbm_open(sessiondbname, 512, mode, 0,NULL); indexdb = gdbm_open(indexdbname, 512, mode, 0,NULL); if (inet_aton(ipaddress, &ipaddr) == 0) { printf("rlm_ippool_tool: Unable to convert IP address '%s'\n", ipaddress); return; } if (!sessiondb) { printf("rlm_ippool_tool: Unable to open DB '%s'\n", sessiondbname); return; } if (!indexdb) { printf("rlm_ippool_tool: Unable to open DB '%s'\n", indexdbname); return; } port = strtoul(NASport, NULL, 0); /* Basically from rlm_ippool.c */ if (old){ strlcpy(old_key.nas, NASname, sizeof(old_key.nas)); old_key.port = port; key_datum.dptr = (char *) &old_key; key_datum.dsize = sizeof(old_ippool_key); } else { char md5_input_str[MAX_STRING_LEN]; FR_MD5_CTX md5_context; snprintf(md5_input_str, MAX_STRING_LEN, "%s %s", NASname, NASport); fr_md5_init(&md5_context); fr_md5_update(&md5_context, (uint8_t *) md5_input_str, strlen(md5_input_str)); fr_md5_final(key_str, &md5_context); memcpy(key.key, key_str, 16); fr_bin2hex(hex_str, key_str, 16); hex_str[32] = '\0'; key_datum.dptr = (char *) &key; key_datum.dsize = sizeof(ippool_key); } data_datum = gdbm_fetch(sessiondb, key_datum); if (data_datum.dptr != NULL){ found = true; memcpy(&entry, data_datum.dptr, sizeof(ippool_info)); if (entry.active){ if (old) { printf("rlm_ippool_tool: Deleting stale entry for ip/port %s/%u", ipaddress, port); } else { printf("rlm_ippool_tool: Deleting stale entry for key: '%s'", hex_str); } entry.active = 0; save_datum.dptr = key_datum.dptr; save_datum.dsize = key_datum.dsize; data_datum.dptr = (char*) &entry; data_datum.dsize = sizeof(ippool_info); rcode = gdbm_store(sessiondb, key_datum, data_datum, GDBM_REPLACE); if (rcode < 0) { printf("rlm_ippool_tool: Failed storing data to %s: %s\n", sessiondbname, gdbm_strerror(gdbm_errno)); goto close; } key_datum.dptr = (char *) &entry.ipaddr; key_datum.dsize = sizeof(uint32_t); data_datum = gdbm_fetch(indexdb, key_datum); if (data_datum.dptr != NULL) { memcpy(&num, data_datum.dptr, sizeof(int)); if (num > 0) { num--; data_datum.dptr = (char *) # data_datum.dsize = sizeof(int); rcode = gdbm_store(indexdb, key_datum, data_datum, GDBM_REPLACE); if (rcode < 0) { printf("rlm_ippool_tool: Failed storing data to %s: %s\n", indexdbname, gdbm_strerror(gdbm_errno)); goto close; } if (num > 0 && entry.extra == 1) { gdbm_delete(sessiondb, save_datum); } } } } } key_datum.dptr = NULL; if (!key_datum.dptr) { key_datum = gdbm_firstkey(sessiondb); while (key_datum.dptr) { data_datum = gdbm_fetch(sessiondb, key_datum); if (data_datum.dptr != NULL) { memcpy(&entry, data_datum.dptr, sizeof(ippool_info)); free(data_datum.dptr); if (entry.active == 0 && entry.ipaddr == ipaddr.s_addr) { datum tmp; tmp.dptr = (char *) &entry.ipaddr; tmp.dsize = sizeof(uint32_t); data_datum = gdbm_fetch(indexdb, tmp); if (data_datum.dptr){ memcpy(&num, data_datum.dptr, sizeof(int)); free(data_datum.dptr); if (num == 0){ delete = 1; break; } } else { delete = 1; break; } } } nextkey = gdbm_nextkey(sessiondb, key_datum); free(key_datum.dptr); key_datum = nextkey; } } if (key_datum.dptr){ if (found && ! mppp){ datum key_datum_tmp, data_datum_tmp; old_ippool_key old_key_tmp; ippool_key key_tmp; if (old){ strlcpy(old_key_tmp.nas, NASname, sizeof(old_key_tmp.nas)); old_key_tmp.port = port; key_datum_tmp.dptr = (char *) &old_key_tmp; key_datum_tmp.dsize = sizeof(old_ippool_key); } else { memcpy(key_tmp.key, key_str, 16); key_datum_tmp.dptr = (char *) &key_tmp; key_datum_tmp.dsize = sizeof(ippool_key); } data_datum_tmp = gdbm_fetch(sessiondb, key_datum_tmp); if (data_datum_tmp.dptr != NULL) { rcode = gdbm_store(sessiondb, key_datum, data_datum_tmp, GDBM_REPLACE); if (rcode < 0) { printf("rlm_ippool_tool: Failed storing data to %s: %s\n", sessiondbname, gdbm_strerror(gdbm_errno)); goto close; } free(data_datum_tmp.dptr); } } else { if (delete) { gdbm_delete(sessiondb, key_datum); } } free(key_datum.dptr); entry.active = 1; data_datum.dptr = (char *) &entry; data_datum.dsize = sizeof(ippool_info); if (old){ strlcpy(old_key.nas, NASname, sizeof(old_key.nas)); old_key.port = port; key_datum.dptr = (char *) &old_key; key_datum.dsize = sizeof(old_ippool_key); printf("rlm_ippool_tool: Allocating ip to nas/port: %s/%u\n", old_key.nas, old_key.port); } else { memcpy(key.key, key_str, 16); key_datum.dptr = (char *) &key; key_datum.dsize = sizeof(ippool_key); printf("rlm_ippool_tool: Allocating ip to key: '%s'\n", hex_str); } rcode = gdbm_store(sessiondb, key_datum, data_datum, GDBM_REPLACE); if (rcode < 0) { printf("rlm_ippool_tool: Failed storing data to %s: %s\n", sessiondbname, gdbm_strerror(gdbm_errno)); goto close; } /* Increase the ip index count */ key_datum.dptr = (char *) &entry.ipaddr; key_datum.dsize = sizeof(uint32_t); data_datum = gdbm_fetch(indexdb, key_datum); if (data_datum.dptr) { memcpy(&num, data_datum.dptr, sizeof(int)); } else { num = 0; } num++; printf("rlm_ippool_tool: num: %d\n", num); data_datum.dptr = (char *) # data_datum.dsize = sizeof(int); rcode = gdbm_store(indexdb, key_datum, data_datum, GDBM_REPLACE); if (rcode < 0) { printf("rlm_ippool_tool: Failed storing data to %s: %s\n", indexdbname, gdbm_strerror(gdbm_errno)); goto close; } if (old) { printf("rlm_ippool_tool: Allocated ip %s to client on nas %s, port %u\n", ipaddress, old_key.nas, port); } else { printf("rlm_ippool_tool: Allocated ip %s to key '%s'\n", ipaddress, hex_str); } } close: gdbm_close(indexdb); gdbm_close(sessiondb); } void tonewformat(char *sessiondbname, char *newsessiondbname) { GDBM_FILE sessiondb; GDBM_FILE newsessiondb; datum key_datum, keynext_datum, data_datum, newkey_datum; old_ippool_key old_key; ippool_key key; uint8_t key_str[17]; char hex_str[35]; int rcode; sessiondb = gdbm_open(sessiondbname, 512, GDBM_READER, 0,NULL); newsessiondb = gdbm_open(newsessiondbname, 512, GDBM_NEWDB, 0,NULL); if (!sessiondb || !newsessiondb) return; memset(key_str, 0, 17); key_datum = gdbm_firstkey(sessiondb); while (key_datum.dptr) { keynext_datum = gdbm_nextkey(sessiondb, key_datum); if (key_datum.dsize != sizeof(struct old_ippool_key)) { goto next; } char md5_input_str[MAX_STRING_LEN]; FR_MD5_CTX md5_context; memcpy(&old_key, key_datum.dptr, sizeof(struct old_ippool_key)); snprintf(md5_input_str, MAX_STRING_LEN, "%s %d", old_key.nas, old_key.port); fr_md5_init(&md5_context); fr_md5_update(&md5_context, (uint8_t *) md5_input_str, strlen(md5_input_str)); fr_md5_final(key_str, &md5_context); memcpy(key.key, key_str, 16); fr_bin2hex(hex_str, key_str, 16); hex_str[32] = '\0'; printf("rlm_ippool_tool: Transforming pair nas/port (%s/%d) to md5 '%s'\n", old_key.nas, old_key.port, hex_str); newkey_datum.dptr = (char *) &key; newkey_datum.dsize = sizeof(ippool_key); data_datum = gdbm_fetch(sessiondb, key_datum); if (!data_datum.dptr) { goto next; } rcode = gdbm_store(newsessiondb, newkey_datum, data_datum, GDBM_REPLACE); if (rcode < 0) { printf("Failed to update new file %s: %s\n", newsessiondbname, gdbm_strerror(gdbm_errno)); gdbm_close(newsessiondb); gdbm_close(sessiondb); return; } next: key_datum = keynext_datum; } gdbm_close(newsessiondb); gdbm_close(sessiondb); } void viewdb(char *sessiondbname, char *indexdbname, char *ipaddress, int old) { GDBM_FILE sessiondb; GDBM_FILE indexdb; datum key_datum, keynext_datum, data_datum, save_datum; old_ippool_key old_key; ippool_key key; ippool_info info; struct in_addr ipaddr; int num; uint8_t key_str[17]; char hex_str[35]; char *ip; int mode = GDBM_READER; int rcode; if (rflag) mode = GDBM_WRITER; sessiondb = gdbm_open(sessiondbname, 512, mode, 0,NULL); indexdb = gdbm_open(indexdbname, 512, mode, 0,NULL); if ((!sessiondb) || (!indexdb)) { return; } memset(&key, 0, sizeof(key)); /* -Winitialize */ memset(key_str, 0,17); key_datum = gdbm_firstkey(sessiondb); while (key_datum.dptr) { keynext_datum = gdbm_nextkey(sessiondb, key_datum); if ((key_datum.dsize != sizeof(struct ippool_key)) && (key_datum.dsize != sizeof(struct old_ippool_key))) { goto next; } if (old) { memcpy(&old_key, key_datum.dptr, sizeof(struct old_ippool_key)); } else { memcpy(&key, key_datum.dptr, sizeof(struct ippool_key)); } data_datum = gdbm_fetch(sessiondb, key_datum); if (!data_datum.dptr) { goto next; } memcpy(&info, data_datum.dptr, sizeof(struct ippool_info)); memcpy(&ipaddr, &info.ipaddr, 4); ip = inet_ntoa(ipaddr); if (info.active) active++; if (vflag && MATCH_IP(ipaddress, ip) && MATCH_ACTIVE(info)) { if (old) { printf("NAS:%s port:0x%x - ", old_key.nas, old_key.port); } else { memcpy(key_str, key.key, 16); fr_bin2hex(hex_str, key_str, 16); hex_str[32] = '\0'; printf("KEY: '%s' - ", hex_str); } } if (!vflag && aflag && info.active && MATCH_IP(ipaddress, ip)) { printf("%s\n", ip); } else if (vflag && MATCH_IP(ipaddress, ip) && MATCH_ACTIVE(info)) { printf("ipaddr:%s active:%d cli:%s", inet_ntoa(ipaddr), info.active, info.cli); } /* * algorythm copied from rlm_ippool.c: * - set active to zero * - set number of sessions to zero */ if (rflag && MATCH_IP(ipaddress, ip)) { info.active = 0; save_datum.dptr = key_datum.dptr; save_datum.dsize = key_datum.dsize; data_datum.dptr = (char *) &info; data_datum.dsize = sizeof(ippool_info); rcode = gdbm_store(sessiondb, key_datum, data_datum, GDBM_REPLACE); if (rcode < 0) { printf("Failed to update %s: %s\n", ip, gdbm_strerror(gdbm_errno)); gdbm_close(indexdb); gdbm_close(sessiondb); return; } key_datum.dptr = (char *)&info.ipaddr; key_datum.dsize = sizeof(uint32_t); data_datum = gdbm_fetch(indexdb, key_datum); if (data_datum.dptr != NULL) { memcpy(&num, data_datum.dptr, sizeof(int)); if (num > 0) { num--; data_datum.dptr = (char *) # data_datum.dsize = sizeof(int); rcode = gdbm_store(indexdb, key_datum, data_datum, GDBM_REPLACE); if (rcode < 0) { printf("Failed to update %s: %s\n", ip, gdbm_strerror(gdbm_errno)); gdbm_close(indexdb); gdbm_close(sessiondb); return; } if (num > 0 && info.extra == 1) { gdbm_delete(sessiondb, save_datum); } } } } key_datum.dptr = (char *)&info.ipaddr; key_datum.dsize = sizeof(uint32_t); data_datum = gdbm_fetch(indexdb, key_datum); if (data_datum.dptr!= NULL) { memcpy(&num, data_datum.dptr, sizeof(int)); if (vflag && MATCH_IP(ipaddress, ip) && MATCH_ACTIVE(info)) { printf(" num:%d", num); } } if (vflag && MATCH_IP(ipaddress, ip) && MATCH_ACTIVE(info)) { printf("\n"); } else if (vflag && !ipaddress){ if (old) { printf("NAS:%s port:0x%x\n", old_key.nas, old_key.port); } else { memcpy(key_str, key.key, 16); fr_bin2hex(hex_str, key_str, 16); hex_str[32] = '\0'; printf("KEY: '%s' - ", hex_str); } } next: key_datum = keynext_datum; } gdbm_close(indexdb); gdbm_close(sessiondb); } void NEVER_RETURNS usage(char *argv0) { printf("Usage: %s [-a] [-c] [-o] [-v] [ipaddress]\n", argv0); printf(" -a: print all active entries\n"); printf(" -c: report number of active entries\n"); printf(" -r: remove active entries\n"); printf(" -v: verbose report of all entries\n"); printf(" -o: Assume old database format (nas/port pair, not md5 output)\n"); printf(" If an ipaddress is specified then that address is used to\n"); printf(" limit the actions or output.\n"); printf(" Usage: %s -n \n", argv0); printf(" -n: Mark the entry nasIP/nasPort as having ipaddress\n"); printf(" Usage: %s -u \n", argv0); printf(" -u: Update old format database to new.\n"); exit(0); } int main(int argc, char **argv) { int ch; char *argv0 = argv[0]; while ((ch = getopt(argc, argv, "acrvnou"))!= -1) switch (ch) { case 'a': aflag++; break; case 'c': cflag++; break; case 'r': rflag++; break; case 'v': vflag = 1; break; case 'n': nflag = 1; break; case 'o': oflag = 1; break; case 'u': uflag = 1; break; default: usage(argv0); } argc -= optind; argv += optind; if ((argc == 2 || argc == 3) && !nflag && !uflag) { viewdb(argv[0], argv[1], argv[2], oflag); if (cflag) printf("%d\n", active); } else { if (argc == 5 && nflag) { addip(argv[0], argv[1], argv[2], argv[3], argv[4], oflag); } else if (argc == 2 && uflag) { tonewformat(argv[0], argv[1]); } else { usage(argv0); } } return 0; }