1/* geoipupdate.c
2 *
3 * Copyright (C) 2006 MaxMind LLC
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19
20#include "GeoIP.h"
21#include "GeoIPUpdate.h"
22
23#include <unistd.h>
24#include <stdio.h>
25#include <stdlib.h>
26#ifdef HAVE_GETOPT_H
27#include <getopt.h>
28#endif
29#include <ctype.h>
30
31#define PRODUCT_ID_TOKEN "ProductIds"
32#define USER_ID_TOKEN "UserId"
33#define LICENSE_KEY_TOKEN "LicenseKey"
34#define LICENSE_KEY_LENGTH 12
35
36const char *GeoIPConfFile = "GeoIP.conf";
37
38static void * realloc_or_die( void * ptr, size_t size ){
39    void * new = realloc( ptr, size );
40    if ( !new ) {
41        free(ptr);
42        fprintf(stderr, "Out of memory\n");
43        exit(1);
44    }
45    return new;
46}
47
48void usage() {
49  fprintf(stderr,"Usage: geoipupdate [-hv] [-f license_file] [-d custom directory]\n");
50}
51
52void my_printf(char * str) {
53	printf("%s", str);
54}
55
56void print_status (int err, char * license_file) {
57	if (err == GEOIP_NO_NEW_UPDATES) {
58		fprintf(stdout,"GeoIP Database up to date\n");
59	} else if (err == GEOIP_LICENSE_KEY_INVALID_ERR) {
60		fprintf(stderr,"Invalid License Key in %s - Please visit http://www.maxmind.com/app/products for a subscription\n",license_file);
61	} else if (err == GEOIP_USER_ID_INVALID_ERR){
62		fprintf(stderr,"Invalid UserID\n");
63	} else if (err == GEOIP_PRODUCT_ID_INVALID_ERR){
64		fprintf(stderr,"Invalid product ID or subscription expired\n");
65	} else if (err < 0) {
66		fprintf(stderr,"Received Error %d (%s) when attempting to update GeoIP Database\n",err, GeoIP_get_error_message(err));
67	} else {
68		fprintf(stdout,"Updated database\n");
69	}
70}
71
72int main (int argc, char *argv[]) {
73  int verbose = 0;
74  char * license_file = NULL;
75	FILE * license_fh;
76	int n = 40;
77	int line_index = 0;
78	unsigned char *lineptr = malloc(sizeof(char) * n);
79	char *a_license_key_str, *a_ptr;
80	char *the_license_key_str = "";
81  char * the_reference_empty_license_key_str = the_license_key_str;
82	char *a_user_id_str = NULL;
83	/* the string that holds the user id */
84	char *the_user_id_str = NULL;
85	/* the integer that holds the length of the string the_user_id_str */
86	int the_user_id_strl = 0;
87	/* the integer that holds the alloc length of the string the_user_id_str */
88	int the_user_id_stral = 0;
89	char *a_product_id_str = NULL;
90	char **the_product_id_str = NULL;
91	int *the_product_id_strl = NULL;
92	int *the_product_id_stral = NULL;
93	int num_product_ids = 0;
94	char * client_ipaddr = NULL;
95	char * custom_directory = NULL;
96	int c;
97	int err = 0;
98	int i;
99
100	opterr = 0;
101
102	while ((c = getopt (argc, argv, "hvf:d:")) != -1)
103    switch (c) {
104		case 'h':
105			usage();
106			exit(0);
107		case 'v':
108			verbose = 1;
109                        break;
110		case 'f':
111			license_file = optarg;
112			break;
113		case 'd':
114			custom_directory = optarg;
115			break;
116		case '?':
117			if (isprint (optopt))
118				fprintf (stderr, "Unknown option `-%c'.\n", optopt);
119			else
120				fprintf (stderr,
121								 "Unknown option character `\\x%x'.\n",
122								 optopt);
123			usage();
124			exit(1);
125		default:
126			abort();
127		}
128
129	if (custom_directory != NULL) {
130		GeoIP_setup_custom_directory(custom_directory);
131	}
132	if (license_file == NULL) {
133		license_file = malloc(sizeof(char) * (strlen(SYSCONFDIR)+strlen(GeoIPConfFile)+2));
134		license_file[0] = '\0';
135		strcat(license_file, SYSCONFDIR);
136		strcat(license_file, "/");
137		strcat(license_file, GeoIPConfFile);
138	}
139
140  license_fh = fopen(license_file,"r");
141	if (license_fh == NULL) {
142		fprintf(stderr,"Error opening GeoIP Configuration file %s\n",license_file);
143		exit(1);
144	}
145
146	if (verbose == 1)
147		printf("Opened License file %s\n", license_file);
148
149	do {
150		c = fgetc(license_fh);
151		if (line_index >= n) {
152			n += 20;
153			lineptr = realloc_or_die(lineptr, n);
154		}
155		if ( c == 13 ) {
156		  continue;
157		}
158		if (c == 10 || c == EOF) {
159			lineptr[line_index++] = '\0';
160			line_index = 0;
161			if (lineptr[0] == '#')
162				continue;
163			/* get the product ids from the config file */
164			a_product_id_str = strstr((char *)lineptr, PRODUCT_ID_TOKEN);//search for a product id token in the line
165			if (a_product_id_str != NULL) {
166				a_ptr = a_product_id_str;
167				/* set pos at the end of product id token */
168				a_ptr += strlen(PRODUCT_ID_TOKEN) + 1;
169				while (a_ptr[0] == ' ') {
170					/* skip spaces */
171					a_ptr++;
172				}
173				/* alloc the array of product ids */
174				the_product_id_str = (char **) malloc((num_product_ids+1) * sizeof(char*)); /* array of strings */
175				the_product_id_strl = (int *) malloc((num_product_ids+1) * sizeof(char*));  /* array of string lengths */
176				the_product_id_stral = (int *) malloc((num_product_ids+1) * sizeof(char*)); /* array of string alloc lengths */
177				while (a_ptr[0] != '\0') {
178					/* add new product id to the array of product ids */
179					the_product_id_str[num_product_ids] = (char *) malloc(20); /* the string */
180					the_product_id_strl[num_product_ids] = 0;                  /* the length of the string */
181					the_product_id_stral[num_product_ids] = 20;                /* the alloc length of the string */
182					while ((a_ptr[0] != ' ') & (a_ptr[0] != '\0')) {
183						if (the_product_id_strl[num_product_ids] >= the_product_id_stral[num_product_ids]) {
184							/* if the length of the string is equal or more than
185							 * alloc length of the string then realloc the string and
186							 * increase the alloc length by 20 */
187							the_product_id_stral[num_product_ids] = the_product_id_stral[num_product_ids] + 20;
188							the_product_id_str[num_product_ids] = (char *) realloc_or_die(the_product_id_str[num_product_ids],the_product_id_stral[num_product_ids]+4);
189						}
190						/* read the product id from the line in the config file */
191						the_product_id_str[num_product_ids][the_product_id_strl[num_product_ids]] = a_ptr[0];
192						the_product_id_strl[num_product_ids]++;
193						a_ptr++;
194					}
195				        the_product_id_str[num_product_ids][the_product_id_strl[num_product_ids]] = 0;
196					while ((a_ptr[0] == ' ') & (a_ptr[0] != '\0')) {
197						a_ptr++;//skip spaces
198					}
199					/* new product id add, realloc the arrays */
200					num_product_ids = num_product_ids + 1;
201					/* array of string */
202					the_product_id_str = (char **) realloc_or_die(the_product_id_str,(num_product_ids+1) * sizeof(char*));
203					/* array of string lengths */
204					the_product_id_strl = (int *) realloc_or_die(the_product_id_strl,(num_product_ids+1) * sizeof(char*));
205					/* array of string alloc lengths */
206					the_product_id_stral = (int *) realloc_or_die(the_product_id_stral,(num_product_ids+1) * sizeof(char*));
207				}
208			}
209
210			/* get the user id from the config file */
211			a_user_id_str = strstr((char *)lineptr, USER_ID_TOKEN); /* search for a user id token in the line */
212			if (a_user_id_str != NULL) {
213				a_ptr = a_user_id_str;
214				/* set the position at the end of user id token */
215				a_ptr += strlen(USER_ID_TOKEN) + 1;
216				while (a_ptr[0] == ' ') {
217					/* skip spaces */
218					a_ptr++;
219				}
220				/* get the string that has the user id */
221				the_user_id_stral = 20;
222				the_user_id_str = (char *)malloc(the_user_id_stral);
223				/* loop while the chars are numbers */
224				while ((a_ptr[0] >= '0') & (a_ptr[0] <= '9')) {
225					the_user_id_str[the_user_id_strl++] = a_ptr[0];
226					a_ptr++;
227					if (the_user_id_strl >= the_user_id_stral) {
228						/* if the length of user id string is greater or equal to
229						 * the alloc length of user id string then
230						 * add 20 to the alloc length and realloc the user id string */
231						the_user_id_stral += 20;
232						the_user_id_str = realloc_or_die(the_user_id_str,the_user_id_stral);
233					}
234				}
235				the_user_id_str[the_user_id_strl] = 0; /* add NUL char */
236			}
237			a_license_key_str = strstr((char *)lineptr, LICENSE_KEY_TOKEN);
238			if (a_license_key_str != NULL) {
239				a_ptr = a_license_key_str;
240				a_ptr += strlen(LICENSE_KEY_TOKEN) + 1;
241				while (a_ptr[0] == ' ') {
242					a_ptr++;
243				}
244				the_license_key_str = malloc(sizeof(char) * (LICENSE_KEY_LENGTH + 1));
245				strncpy(the_license_key_str, a_ptr, LICENSE_KEY_LENGTH);
246				the_license_key_str[LICENSE_KEY_LENGTH] = '\0';
247			}
248		} else {
249			lineptr[line_index++] = c;
250		}
251	} while (c != EOF);
252
253	free(lineptr);
254
255	fclose(license_fh);
256
257	if (verbose == 1) {
258		printf("Read in license key %s\n", the_license_key_str);
259		printf("number of product ids %d \n",num_product_ids);
260	}
261
262	if (the_user_id_str != NULL) {
263		/* update the databases using the user id string, the license key string and the product id for each database */
264		client_ipaddr = NULL;
265		for (i = 0; i < num_product_ids; i++) {
266			err = GeoIP_update_database_general(the_user_id_str, the_license_key_str, the_product_id_str[i], verbose,&client_ipaddr, &my_printf);
267			print_status(err, license_file);
268		}
269	} else {
270		/* Old format with just license key for MaxMind GeoIP Country database updates
271		 * here for backwards compatibility */
272		err = GeoIP_update_database(the_license_key_str, verbose, &my_printf);
273		print_status(err, license_file);
274	}
275
276	if (the_product_id_str != NULL) {
277		/* free the product ids */
278		for (i = 0; i < num_product_ids; i++ ) {
279			free(the_product_id_str[i]);
280		}
281		free(the_product_id_str);
282		free(the_product_id_strl);
283		free(the_product_id_stral);
284	}
285
286  if ( the_reference_empty_license_key_str != the_license_key_str )
287    free(the_license_key_str);
288
289	if (the_user_id_str)
290		free(the_user_id_str);
291
292	if (client_ipaddr) {
293		free(client_ipaddr);
294	}
295	exit(err);
296}
297