parent
536311bdef
commit
fc5c7975aa
@ -0,0 +1,373 @@
|
||||
Patch by Robert Scheck <robert@fedoraproject.org> for geoipupdate <= 2.5.0 which backports
|
||||
the support for hashed license keys. It is based on the following upstream commits:
|
||||
|
||||
1. https://github.com/maxmind/geoipupdate/commit/b7862460b6769f5c40b72de835b868882c3f3883
|
||||
2. https://github.com/maxmind/geoipupdate/commit/4b41ea887e836ddb1a36c0c3a071ac49e8d71a25
|
||||
3. https://github.com/maxmind/geoipupdate/commit/01fcfc1170dcedc35c758e111b8905cf6513d8b9
|
||||
4. https://github.com/maxmind/geoipupdate/commit/6794f2eed0063a50749bf400e135f4f47ca2f465
|
||||
5. https://github.com/maxmind/geoipupdate/commit/0670ee3e1237a72bae785877b354dbfe135de6be
|
||||
6. https://github.com/maxmind/geoipupdate/commit/cddabc6f645ea3abbb8117ef0d03069df560fc36
|
||||
7. https://github.com/maxmind/geoipupdate/commit/35a640087a4eca4e37306b717fa8513e26487b47
|
||||
8. https://github.com/maxmind/geoipupdate/commit/642978928019f87181dd7c108b0363841c0135a9
|
||||
9. https://github.com/maxmind/geoipupdate/commit/824ef039bbc8a2ed5a90d1da5a51d4a1639fdb09
|
||||
|
||||
--- geoipupdate-2.5.0/bin/geoipupdate.c 2017-10-30 15:38:24.000000000 +0100
|
||||
+++ geoipupdate-2.5.0/bin/geoipupdate.c.licensekey 2023-04-13 21:23:51.340750299 +0200
|
||||
@@ -22,6 +22,7 @@
|
||||
enum gu_status {
|
||||
GU_OK = 0,
|
||||
GU_ERROR = 1,
|
||||
+ GU_NO_UPDATE = 2,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@@ -41,17 +42,14 @@
|
||||
static int md5hex(const char *, char *);
|
||||
static void common_req(CURL *, geoipupdate_s *);
|
||||
static size_t get_expected_file_md5(char *, size_t, size_t, void *);
|
||||
-static void
|
||||
+static int
|
||||
download_to_file(geoipupdate_s *, const char *, const char *, char *);
|
||||
static long get_server_time(geoipupdate_s *);
|
||||
static size_t mem_cb(void *, size_t, size_t, void *);
|
||||
static in_mem_s *in_mem_s_new(void);
|
||||
static void in_mem_s_delete(in_mem_s *);
|
||||
-static in_mem_s *get(geoipupdate_s *, const char *);
|
||||
-static void md5hex_license_ipaddr(geoipupdate_s *, const char *, char *);
|
||||
static int update_database_general_all(geoipupdate_s *);
|
||||
static int update_database_general(geoipupdate_s *, const char *);
|
||||
-static int update_country_database(geoipupdate_s *);
|
||||
static int gunzip_and_replace(geoipupdate_s const *const,
|
||||
char const *const,
|
||||
char const *const,
|
||||
@@ -196,14 +194,12 @@
|
||||
return GU_ERROR;
|
||||
}
|
||||
|
||||
- err = (gu->license.account_id == NO_ACCOUNT_ID)
|
||||
- ? update_country_database(gu)
|
||||
- : update_database_general_all(gu);
|
||||
+ err = update_database_general_all(gu);
|
||||
}
|
||||
geoipupdate_s_delete(gu);
|
||||
}
|
||||
curl_global_cleanup();
|
||||
- return err ? GU_ERROR : GU_OK;
|
||||
+ return err & GU_ERROR ? GU_ERROR : GU_OK;
|
||||
}
|
||||
|
||||
static ssize_t my_getline(char **linep, size_t *linecapp, FILE *stream) {
|
||||
@@ -242,8 +238,9 @@
|
||||
say_if(up->verbose, "AccountID %d\n", up->license.account_id);
|
||||
continue;
|
||||
}
|
||||
- if (sscanf(strt, "LicenseKey %12s", &up->license.license_key[0]) == 1) {
|
||||
- say_if(up->verbose, "LicenseKey %s\n", up->license.license_key);
|
||||
+ if (sscanf(strt, "LicenseKey %99s", &up->license.license_key[0]) == 1) {
|
||||
+ say_if(
|
||||
+ up->verbose, "LicenseKey %.4s...\n", up->license.license_key);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -534,15 +531,11 @@
|
||||
// Make an HTTP request and download the response body to a file.
|
||||
//
|
||||
// If the HTTP status is not 2xx, we have a error message in the body rather
|
||||
-// than a file. Write it to stderr and exit.
|
||||
-//
|
||||
-// TODO(wstorey@maxmind.com): Return boolean/int whether we succeeded rather
|
||||
-// than exiting. Beyond being cleaner and easier to test, it will allow us to
|
||||
-// clean up after ourselves better.
|
||||
-static void download_to_file(geoipupdate_s *gu,
|
||||
- const char *url,
|
||||
- const char *fname,
|
||||
- char *expected_file_md5) {
|
||||
+// than a file. Write it to stderr and return an error.
|
||||
+static int download_to_file(geoipupdate_s *gu,
|
||||
+ const char *url,
|
||||
+ const char *fname,
|
||||
+ char *expected_file_md5) {
|
||||
FILE *f = fopen(fname, "wb");
|
||||
if (f == NULL) {
|
||||
fprintf(stderr, "Can't open %s: %s\n", fname, strerror(errno));
|
||||
@@ -553,6 +546,20 @@
|
||||
CURL *curl = gu->curl;
|
||||
|
||||
expected_file_md5[0] = '\0';
|
||||
+
|
||||
+ char account_id[10] = {0};
|
||||
+ int n = snprintf(account_id, 10, "%d", gu->license.account_id);
|
||||
+ exit_if(n < 0,
|
||||
+ "Error creating account ID string for %d: %s\n",
|
||||
+ gu->license.account_id,
|
||||
+ strerror(errno));
|
||||
+ exit_if(n < 0 || n >= 10,
|
||||
+ "An unexpectedly large account ID was encountered: %d\n",
|
||||
+ gu->license.account_id);
|
||||
+
|
||||
+ curl_easy_setopt(curl, CURLOPT_USERNAME, account_id);
|
||||
+ curl_easy_setopt(curl, CURLOPT_PASSWORD, gu->license.license_key);
|
||||
+
|
||||
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, get_expected_file_md5);
|
||||
curl_easy_setopt(curl, CURLOPT_HEADERDATA, expected_file_md5);
|
||||
|
||||
@@ -577,7 +584,19 @@
|
||||
exit(1);
|
||||
}
|
||||
|
||||
- if (status < 200 || status >= 300) {
|
||||
+ if (status == 304) {
|
||||
+ say_if(gu->verbose, "No new updates available\n");
|
||||
+ unlink(fname);
|
||||
+ return GU_NO_UPDATE;
|
||||
+ }
|
||||
+
|
||||
+ if (status == 401) {
|
||||
+ fprintf(stderr, "Your account ID or license key is invalid\n");
|
||||
+ unlink(fname);
|
||||
+ return GU_ERROR;
|
||||
+ }
|
||||
+
|
||||
+ if (status != 200) {
|
||||
fprintf(stderr,
|
||||
"Received an unexpected HTTP status code of %ld from %s:\n",
|
||||
status,
|
||||
@@ -589,7 +608,7 @@
|
||||
free(message);
|
||||
}
|
||||
unlink(fname);
|
||||
- exit(1);
|
||||
+ return GU_ERROR;
|
||||
}
|
||||
|
||||
// We have HTTP 2xx.
|
||||
@@ -600,8 +619,9 @@
|
||||
fprintf(stderr,
|
||||
"Did not receive a valid expected database MD5 from server\n");
|
||||
unlink(fname);
|
||||
- exit(1);
|
||||
+ return GU_ERROR;
|
||||
}
|
||||
+ return GU_OK;
|
||||
}
|
||||
|
||||
// Retrieve the server file time for the previous HTTP request.
|
||||
@@ -645,7 +665,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
-static in_mem_s *get(geoipupdate_s *gu, const char *url) {
|
||||
+static int update_database_general(geoipupdate_s *gu, const char *edition_id) {
|
||||
+ char *url = NULL, *geoip_filename = NULL, *geoip_gz_filename = NULL;
|
||||
+ char hex_digest[33] = {0};
|
||||
+
|
||||
+ // Get the filename.
|
||||
+ xasprintf(&url,
|
||||
+ "%s://%s/app/update_getfilename?product_id=%s",
|
||||
+ gu->proto,
|
||||
+ gu->host,
|
||||
+ edition_id);
|
||||
+
|
||||
in_mem_s *mem = in_mem_s_new();
|
||||
|
||||
say_if(gu->verbose, "url: %s\n", url);
|
||||
@@ -663,47 +693,16 @@
|
||||
long status = 0;
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
|
||||
|
||||
- exit_if(status < 200 || status >= 300,
|
||||
- "Received an unexpected HTTP status code of %ld from %s",
|
||||
- status,
|
||||
- url);
|
||||
-
|
||||
- return mem;
|
||||
-}
|
||||
-
|
||||
-// Generate an MD5 hash of the concatenation of license key with IP address.
|
||||
-//
|
||||
-// This hash is suitable for the challenge parameter for downloading from the
|
||||
-// /update_secure endpoint.
|
||||
-static void md5hex_license_ipaddr(geoipupdate_s *gu,
|
||||
- const char *client_ipaddr,
|
||||
- char *new_digest_str) {
|
||||
- unsigned char digest[16];
|
||||
- MD5_CONTEXT context;
|
||||
- md5_init(&context);
|
||||
- md5_write(&context,
|
||||
- (unsigned char *)gu->license.license_key,
|
||||
- strlen(gu->license.license_key));
|
||||
- md5_write(&context, (unsigned char *)client_ipaddr, strlen(client_ipaddr));
|
||||
- md5_final(&context);
|
||||
- memcpy(digest, context.buf, 16);
|
||||
- for (int i = 0; i < 16; i++) {
|
||||
- snprintf(&new_digest_str[2 * i], 3, "%02x", digest[i]);
|
||||
+ if (status != 200) {
|
||||
+ fprintf(stderr,
|
||||
+ "Received an unexpected HTTP status code of %ld from %s\n",
|
||||
+ status,
|
||||
+ url);
|
||||
+ free(url);
|
||||
+ in_mem_s_delete(mem);
|
||||
+ return GU_ERROR;
|
||||
}
|
||||
-}
|
||||
-
|
||||
-static int update_database_general(geoipupdate_s *gu, const char *edition_id) {
|
||||
- char *url = NULL, *geoip_filename = NULL, *geoip_gz_filename = NULL,
|
||||
- *client_ipaddr = NULL;
|
||||
- char hex_digest[33] = {0}, hex_digest2[33] = {0};
|
||||
|
||||
- // Get the filename.
|
||||
- xasprintf(&url,
|
||||
- "%s://%s/app/update_getfilename?product_id=%s",
|
||||
- gu->proto,
|
||||
- gu->host,
|
||||
- edition_id);
|
||||
- in_mem_s *mem = get(gu, url);
|
||||
free(url);
|
||||
if (mem->size == 0) {
|
||||
fprintf(stderr, "edition_id %s not found\n", edition_id);
|
||||
@@ -718,63 +717,27 @@
|
||||
md5hex(geoip_filename, hex_digest);
|
||||
say_if(gu->verbose, "md5hex_digest: %s\n", hex_digest);
|
||||
|
||||
- // Look up our IP.
|
||||
- xasprintf(&url, "%s://%s/app/update_getipaddr", gu->proto, gu->host);
|
||||
- mem = get(gu, url);
|
||||
- free(url);
|
||||
-
|
||||
- client_ipaddr = strdup(mem->ptr);
|
||||
- if (NULL == client_ipaddr) {
|
||||
- fprintf(stderr, "Unable to allocate memory for client IP address.\n");
|
||||
- free(geoip_filename);
|
||||
- in_mem_s_delete(mem);
|
||||
- return GU_ERROR;
|
||||
- }
|
||||
-
|
||||
- in_mem_s_delete(mem);
|
||||
-
|
||||
- say_if(gu->verbose, "Client IP address: %s\n", client_ipaddr);
|
||||
-
|
||||
- // Make the challenge MD5 hash.
|
||||
- md5hex_license_ipaddr(gu, client_ipaddr, hex_digest2);
|
||||
-
|
||||
- free(client_ipaddr);
|
||||
- say_if(gu->verbose, "md5hex_digest2 (challenge): %s\n", hex_digest2);
|
||||
-
|
||||
// Download.
|
||||
xasprintf(&url,
|
||||
- "%s://%s/app/"
|
||||
- "update_secure?db_md5=%s&challenge_md5=%s&user_id=%d&edition_id=%"
|
||||
- "s",
|
||||
+ "%s://%s/geoip/databases/%s/update?db_md5=%s",
|
||||
gu->proto,
|
||||
gu->host,
|
||||
- hex_digest,
|
||||
- hex_digest2,
|
||||
- gu->license.account_id,
|
||||
- edition_id);
|
||||
+ edition_id,
|
||||
+ hex_digest);
|
||||
xasprintf(&geoip_gz_filename, "%s.gz", geoip_filename);
|
||||
|
||||
char expected_file_md5[33] = {0};
|
||||
- download_to_file(gu, url, geoip_gz_filename, expected_file_md5);
|
||||
+ int rc = download_to_file(gu, url, geoip_gz_filename, expected_file_md5);
|
||||
free(url);
|
||||
|
||||
- // Was there actually an update? We can tell because if not we will have
|
||||
- // the same MD5 reported back. Note in the past we would check the response
|
||||
- // body which does still say whether we have an update.
|
||||
- if (strcmp(hex_digest, expected_file_md5) == 0) {
|
||||
- say_if(gu->verbose, "No new updates available\n");
|
||||
- unlink(geoip_gz_filename);
|
||||
- free(geoip_filename);
|
||||
- free(geoip_gz_filename);
|
||||
- return GU_OK;
|
||||
- }
|
||||
-
|
||||
- long filetime = -1;
|
||||
- if (gu->preserve_file_times) {
|
||||
- filetime = get_server_time(gu);
|
||||
+ if (rc == GU_OK) {
|
||||
+ long filetime = -1;
|
||||
+ if (gu->preserve_file_times) {
|
||||
+ filetime = get_server_time(gu);
|
||||
+ }
|
||||
+ rc = gunzip_and_replace(
|
||||
+ gu, geoip_gz_filename, geoip_filename, expected_file_md5, filetime);
|
||||
}
|
||||
- int rc = gunzip_and_replace(
|
||||
- gu, geoip_gz_filename, geoip_filename, expected_file_md5, filetime);
|
||||
|
||||
free(geoip_gz_filename);
|
||||
free(geoip_filename);
|
||||
@@ -790,53 +753,6 @@
|
||||
return err;
|
||||
}
|
||||
|
||||
-static int update_country_database(geoipupdate_s *gu) {
|
||||
- char *geoip_filename = NULL, *geoip_gz_filename = NULL, *url = NULL;
|
||||
- char hex_digest[33] = {0};
|
||||
-
|
||||
- xasprintf(&geoip_filename, "%s/GeoIP.dat", gu->database_dir);
|
||||
- xasprintf(&geoip_gz_filename, "%s/GeoIP.dat.gz", gu->database_dir);
|
||||
-
|
||||
- // Calculate the MD5 hash of the database we currently have, if any. We get
|
||||
- // back a zero MD5 hash if we don't have it yet.
|
||||
- md5hex(geoip_filename, hex_digest);
|
||||
- say_if(gu->verbose, "md5hex_digest: %s\n", hex_digest);
|
||||
-
|
||||
- xasprintf(&url,
|
||||
- "%s://%s/app/update?license_key=%s&md5=%s",
|
||||
- gu->proto,
|
||||
- gu->host,
|
||||
- &gu->license.license_key[0],
|
||||
- hex_digest);
|
||||
-
|
||||
- char expected_file_md5[33] = {0};
|
||||
- download_to_file(gu, url, geoip_gz_filename, expected_file_md5);
|
||||
- free(url);
|
||||
-
|
||||
- // Was there actually an update? We can tell because if not we will have
|
||||
- // the same MD5 reported back. Note in the past we would check the response
|
||||
- // body which does still say whether we have an update.
|
||||
- if (strcmp(hex_digest, expected_file_md5) == 0) {
|
||||
- say_if(gu->verbose, "No new updates available\n");
|
||||
- unlink(geoip_gz_filename);
|
||||
- free(geoip_filename);
|
||||
- free(geoip_gz_filename);
|
||||
- return GU_OK;
|
||||
- }
|
||||
-
|
||||
- long filetime = -1;
|
||||
- if (gu->preserve_file_times) {
|
||||
- filetime = get_server_time(gu);
|
||||
- }
|
||||
- int rc = gunzip_and_replace(
|
||||
- gu, geoip_gz_filename, geoip_filename, expected_file_md5, filetime);
|
||||
-
|
||||
- free(geoip_gz_filename);
|
||||
- free(geoip_filename);
|
||||
-
|
||||
- return rc;
|
||||
-}
|
||||
-
|
||||
// Decompress the compressed database and move it into place in the database
|
||||
// directory.
|
||||
//
|
||||
--- geoipupdate-2.5.0/bin/geoipupdate.h 2017-10-30 15:38:24.000000000 +0100
|
||||
+++ geoipupdate-2.5.0/bin/geoipupdate.h.licensekey 2023-04-13 20:59:03.483969697 +0200
|
||||
@@ -12,7 +12,11 @@
|
||||
|
||||
typedef struct {
|
||||
int account_id;
|
||||
- char license_key[13];
|
||||
+ // For a long time, license keys were restricted to 12 characters. However,
|
||||
+ // we want to change this for newer license keys. The array size is
|
||||
+ // arbitrarily 100 as that seems big enough to hold any future license
|
||||
+ // key.
|
||||
+ char license_key[100];
|
||||
edition_s *first;
|
||||
} license_s;
|
||||
|
Loading…
Reference in new issue