TS-2732 Run the code through indent, to follow our coding standards
Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/4f2dc70f Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/4f2dc70f Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/4f2dc70f Branch: refs/heads/master Commit: 4f2dc70f0e5b3a2969cb70bac77523d259a95610 Parents: 634ba75 Author: Leif Hedstrom <[email protected]> Authored: Sun Apr 20 13:19:30 2014 -0600 Committer: Leif Hedstrom <[email protected]> Committed: Sun Apr 20 13:19:30 2014 -0600 ---------------------------------------------------------------------- plugins/experimental/url_sig/url_sig.c | 836 ++++++++++++++-------------- plugins/experimental/url_sig/url_sig.h | 16 +- 2 files changed, 436 insertions(+), 416 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/trafficserver/blob/4f2dc70f/plugins/experimental/url_sig/url_sig.c ---------------------------------------------------------------------- diff --git a/plugins/experimental/url_sig/url_sig.c b/plugins/experimental/url_sig/url_sig.c index 0cde9d3..be85524 100644 --- a/plugins/experimental/url_sig/url_sig.c +++ b/plugins/experimental/url_sig/url_sig.c @@ -34,423 +34,443 @@ #include <ts/ts.h> #include <ts/remap.h> -static const char* PLUGIN_NAME = "url_sig"; - -struct config { - char *map_from; - char *map_to; - TSHttpStatus err_status; - char *err_url; - char keys[MAX_KEY_NUM][MAX_KEY_LEN]; +static const char *PLUGIN_NAME = "url_sig"; + +struct config +{ + char *map_from; + char *map_to; + TSHttpStatus err_status; + char *err_url; + char keys[MAX_KEY_NUM][MAX_KEY_LEN]; }; -TSReturnCode TSRemapInit(TSRemapInterface* api_info, char *errbuf, int errbuf_size) { - if (!api_info) { - strncpy(errbuf, "[tsremap_init] - Invalid TSRemapInterface argument", (size_t) (errbuf_size - 1)); - return TS_ERROR; - } - - if (api_info->tsremap_version < TSREMAP_VERSION) { - snprintf(errbuf, errbuf_size - 1, "[TSRemapInit] - Incorrect API version %ld.%ld", api_info->tsremap_version >> 16, - (api_info->tsremap_version & 0xffff)); - return TS_ERROR; - } - - TSDebug(PLUGIN_NAME, "plugin is succesfully initialized"); - return TS_SUCCESS; +TSReturnCode +TSRemapInit(TSRemapInterface * api_info, char *errbuf, int errbuf_size) +{ + if (!api_info) { + strncpy(errbuf, "[tsremap_init] - Invalid TSRemapInterface argument", (size_t) (errbuf_size - 1)); + return TS_ERROR; + } + + if (api_info->tsremap_version < TSREMAP_VERSION) { + snprintf(errbuf, errbuf_size - 1, "[TSRemapInit] - Incorrect API version %ld.%ld", api_info->tsremap_version >> 16, + (api_info->tsremap_version & 0xffff)); + return TS_ERROR; + } + + TSDebug(PLUGIN_NAME, "plugin is succesfully initialized"); + return TS_SUCCESS; } // To force a config file reload touch remap.config and do a "traffic_line -x" -TSReturnCode TSRemapNewInstance(int argc, char* argv[], void** ih, char* errbuf, int errbuf_size) { - char config_file[PATH_MAX]; - struct config *cfg; - - cfg = TSmalloc(sizeof(struct config)); - *ih = (void *) cfg; - - int i = 0; - for (i = 0; i < MAX_KEY_NUM; i++) { - cfg->keys[i][0] = '\0'; - } - - if (argc != 3) { - snprintf(errbuf, errbuf_size - 1, "[TSRemapNewKeyInstance] - Argument count wrong (%d)... Need exactly two pparam= (config file name).", - argc); - return TS_ERROR; - } - TSDebug(PLUGIN_NAME, "Initializing remap function of %s -> %s with config from %s", argv[0], argv[1], argv[2]); - cfg->map_from = TSstrndup( argv[0], strlen(argv[0])); - cfg->map_to = TSstrndup( argv[0], strlen(argv[1])); - - const char* install_dir = TSInstallDirGet(); - snprintf(config_file, sizeof(config_file), "%s/%s/%s", install_dir, "etc/trafficserver", argv[2]); - TSDebug(PLUGIN_NAME, "config file name: %s", config_file); - FILE *file = fopen(config_file, "r"); - if (file == NULL ) { - snprintf(errbuf, errbuf_size - 1, "[TSRemapNewInstance] - Error opening file %s.", config_file); - return TS_ERROR; - } - - char line[260]; - int line_no = 0; - int keynum; - while (fgets(line, sizeof(line), file) != NULL ) { - TSDebug(PLUGIN_NAME, "LINE: %s (%d)", line, (int) strlen(line)); - line_no++; - if (line[0] == '#' || strlen(line) <= 1) - continue; - char *pos = strchr(line, '='); - if (pos == NULL ) { - TSError("Error parsing line %d of file %s (%s).", line_no, config_file, line); - } - *pos = '\0'; - char *value = pos + 1; - while (isspace(*value)) // remove whitespace - value++; - pos = strchr(value, '\n'); // remove the new line, terminate the string - if (pos != NULL ) { - *pos = '\0'; - } else { - snprintf(errbuf, errbuf_size - 1, "[TSRemapNewInstance] - Maximum line (%d) exceeded on line %d.", MAX_KEY_LEN, line_no); - return TS_ERROR; - } - if (strncmp(line, "key", 3) == 0) { - if (value != NULL ) { - if (strncmp((char *) (line + 3), "0", 1) == 0) { - keynum = 0; - } else { - TSDebug(PLUGIN_NAME, ">>> %s <<<", line +3); - keynum = atoi((char *) (line + 3)); - if (keynum == 0) { - keynum = -1; // Not a Number - } - } - TSDebug(PLUGIN_NAME, "key number %d == %s", keynum, value); - if (keynum > MAX_KEY_NUM || keynum == -1) { - snprintf(errbuf, errbuf_size - 1, "[TSRemapNewInstance] - Key number (%d) > MAX_KEY_NUM (%d) or NaN.", keynum, MAX_KEY_NUM); - return TS_ERROR; - } - strcpy(&cfg->keys[keynum][0], value); - } - } else if (strncmp(line, "error_url", 9) == 0) { - if (atoi(value)) { - cfg->err_status = atoi(value); - } - value += 3; - while (isspace(*value)) - value++; -// if (strncmp(value, "http://", strlen("http://")) != 0) { -// snprintf(errbuf, errbuf_size - 1, -// "[TSRemapNewInstance] - Invalid config, err_status == 302, but err_url does not start with \"http://\""); -// return TS_ERROR; -// } - if (cfg->err_status == TS_HTTP_STATUS_MOVED_TEMPORARILY) - cfg->err_url = TSstrndup(value, strlen(value)); - else cfg->err_url = NULL; - } else { - TSError("Error parsing line %d of file %s (%s).", line_no, config_file, line); - } - } - - switch (cfg->err_status) { - case TS_HTTP_STATUS_MOVED_TEMPORARILY: - if (cfg->err_url == NULL ) { - snprintf(errbuf, errbuf_size - 1, "[TSRemapNewInstance] - Invalid config, err_status == 302, but err_url == NULL"); - return TS_ERROR; - } - printf("[url_sig] mapping {%s -> %s} with status %d and err url %s\n", argv[0], argv[1], cfg->err_status, cfg->err_url); - break; - case TS_HTTP_STATUS_FORBIDDEN: - if (cfg->err_url != NULL ) { - snprintf(errbuf, errbuf_size - 1, "[TSRemapNewInstance] - Invalid config, err_status == 403, but err_url != NULL"); - return TS_ERROR; - } - printf("[url_sig] mapping {%s -> %s} with status %d\n", argv[0], argv[1], cfg->err_status); - break; - default: - snprintf(errbuf, errbuf_size - 1, "[TSRemapNewInstance] - Return code %d not supported.", cfg->err_status); - return TS_ERROR; - - } - - i = 0; - for (i = 0; i < MAX_KEY_NUM; i++) { - if (cfg->keys[i] != NULL && strlen(cfg->keys[i]) > 0) - printf("[url_sig] shared secret key[%d] = %s\n", i, cfg->keys[i]); - } - fclose(file); - printf("%s version %s initialized.\n", PLUGIN_NAME, VERSION); - return TS_SUCCESS; +TSReturnCode +TSRemapNewInstance(int argc, char *argv[], void **ih, char *errbuf, int errbuf_size) +{ + char config_file[PATH_MAX]; + struct config *cfg; + + cfg = TSmalloc(sizeof(struct config)); + *ih = (void *) cfg; + + int i = 0; + for (i = 0; i < MAX_KEY_NUM; i++) { + cfg->keys[i][0] = '\0'; + } + + if (argc != 3) { + snprintf(errbuf, errbuf_size - 1, + "[TSRemapNewKeyInstance] - Argument count wrong (%d)... Need exactly two pparam= (config file name).", + argc); + return TS_ERROR; + } + TSDebug(PLUGIN_NAME, "Initializing remap function of %s -> %s with config from %s", argv[0], argv[1], argv[2]); + cfg->map_from = TSstrndup(argv[0], strlen(argv[0])); + cfg->map_to = TSstrndup(argv[0], strlen(argv[1])); + + const char *install_dir = TSInstallDirGet(); + snprintf(config_file, sizeof(config_file), "%s/%s/%s", install_dir, "etc/trafficserver", argv[2]); + TSDebug(PLUGIN_NAME, "config file name: %s", config_file); + FILE *file = fopen(config_file, "r"); + if (file == NULL) { + snprintf(errbuf, errbuf_size - 1, "[TSRemapNewInstance] - Error opening file %s.", config_file); + return TS_ERROR; + } + + char line[260]; + int line_no = 0; + int keynum; + while (fgets(line, sizeof(line), file) != NULL) { + TSDebug(PLUGIN_NAME, "LINE: %s (%d)", line, (int) strlen(line)); + line_no++; + if (line[0] == '#' || strlen(line) <= 1) + continue; + char *pos = strchr(line, '='); + if (pos == NULL) { + TSError("Error parsing line %d of file %s (%s).", line_no, config_file, line); + } + *pos = '\0'; + char *value = pos + 1; + while (isspace(*value)) // remove whitespace + value++; + pos = strchr(value, '\n'); // remove the new line, terminate the string + if (pos != NULL) { + *pos = '\0'; + } else { + snprintf(errbuf, errbuf_size - 1, "[TSRemapNewInstance] - Maximum line (%d) exceeded on line %d.", MAX_KEY_LEN, + line_no); + return TS_ERROR; + } + if (strncmp(line, "key", 3) == 0) { + if (value != NULL) { + if (strncmp((char *) (line + 3), "0", 1) == 0) { + keynum = 0; + } else { + TSDebug(PLUGIN_NAME, ">>> %s <<<", line + 3); + keynum = atoi((char *) (line + 3)); + if (keynum == 0) { + keynum = -1; // Not a Number + } + } + TSDebug(PLUGIN_NAME, "key number %d == %s", keynum, value); + if (keynum > MAX_KEY_NUM || keynum == -1) { + snprintf(errbuf, errbuf_size - 1, "[TSRemapNewInstance] - Key number (%d) > MAX_KEY_NUM (%d) or NaN.", keynum, + MAX_KEY_NUM); + return TS_ERROR; + } + strcpy(&cfg->keys[keynum][0], value); + } + } else if (strncmp(line, "error_url", 9) == 0) { + if (atoi(value)) { + cfg->err_status = atoi(value); + } + value += 3; + while (isspace(*value)) + value++; +// if (strncmp(value, "http://", strlen("http://")) != 0) { +// snprintf(errbuf, errbuf_size - 1, +// "[TSRemapNewInstance] - Invalid config, err_status == 302, but err_url does not start with \"http://\""); +// return TS_ERROR; +// } + if (cfg->err_status == TS_HTTP_STATUS_MOVED_TEMPORARILY) + cfg->err_url = TSstrndup(value, strlen(value)); + else + cfg->err_url = NULL; + } else { + TSError("Error parsing line %d of file %s (%s).", line_no, config_file, line); + } + } + + switch (cfg->err_status) { + case TS_HTTP_STATUS_MOVED_TEMPORARILY: + if (cfg->err_url == NULL) { + snprintf(errbuf, errbuf_size - 1, + "[TSRemapNewInstance] - Invalid config, err_status == 302, but err_url == NULL"); + return TS_ERROR; + } + printf("[url_sig] mapping {%s -> %s} with status %d and err url %s\n", argv[0], argv[1], cfg->err_status, + cfg->err_url); + break; + case TS_HTTP_STATUS_FORBIDDEN: + if (cfg->err_url != NULL) { + snprintf(errbuf, errbuf_size - 1, + "[TSRemapNewInstance] - Invalid config, err_status == 403, but err_url != NULL"); + return TS_ERROR; + } + printf("[url_sig] mapping {%s -> %s} with status %d\n", argv[0], argv[1], cfg->err_status); + break; + default: + snprintf(errbuf, errbuf_size - 1, "[TSRemapNewInstance] - Return code %d not supported.", cfg->err_status); + return TS_ERROR; + + } + + i = 0; + for (i = 0; i < MAX_KEY_NUM; i++) { + if (cfg->keys[i] != NULL && strlen(cfg->keys[i]) > 0) + printf("[url_sig] shared secret key[%d] = %s\n", i, cfg->keys[i]); + } + fclose(file); + printf("%s version %s initialized.\n", PLUGIN_NAME, VERSION); + return TS_SUCCESS; } -void TSRemapDeleteInstance(void* ih) { - struct config *cfg; - cfg = (struct config *) ih; - - TSError("Cleaning up..."); - TSfree(cfg->map_from); - TSfree(cfg->map_to); - TSfree(cfg->err_url); - TSfree(cfg); +void +TSRemapDeleteInstance(void *ih) +{ + struct config *cfg; + cfg = (struct config *) ih; + + TSError("Cleaning up..."); + TSfree(cfg->map_from); + TSfree(cfg->map_to); + TSfree(cfg->err_url); + TSfree(cfg); } -void err_log(char *url, char *msg) { - if (msg && url) { - TSDebug(PLUGIN_NAME, "[URL=%s]: %s", url, msg); - TSError("[URL=%s]: %s", url, msg); // This goes to error.log - } else { - TSError("Invalid err_log request"); - } +void +err_log(char *url, char *msg) +{ + if (msg && url) { + TSDebug(PLUGIN_NAME, "[URL=%s]: %s", url, msg); + TSError("[URL=%s]: %s", url, msg); // This goes to error.log + } else { + TSError("Invalid err_log request"); + } } -TSRemapStatus TSRemapDoRemap(void* ih, TSHttpTxn txnp, TSRemapRequestInfo *rri) { - struct config *cfg; - cfg = (struct config *) ih; - - int url_len = 0; - time_t expiration = 0; - int algorithm = -1; - int keyindex = -1; - int cmp_res; - int rval; - int i = 0; - int j = 0; - unsigned int sig_len = 0; - - /* all strings are locally allocated except url... about 25k per instance*/ - char *url; - char signed_part[8192] = { '\0' }; // this initializes the whole array and is needed - char urltokstr[8192] = { '\0' }; - char client_ip[CIP_STRLEN] = { '\0' }; - char ipstr[CIP_STRLEN] = { '\0' }; - unsigned char sig[MAX_SIG_SIZE + 1]; - char sig_string[2 * MAX_SIG_SIZE + 1]; - - /* these are just pointers into other allocations */ - char *signature = NULL; - char *parts = NULL; - char *part = NULL; - char *p = NULL, *pp = NULL; - char *query = NULL; - - int retval, sockfd; - socklen_t peer_len; - struct sockaddr_in peer; - - url = TSUrlStringGet(rri->requestBufp, rri->requestUrl, &url_len); - - if (url_len >= MAX_REQ_LEN - 1) { - err_log(url, "URL string too long."); - goto deny; - } - - TSDebug(PLUGIN_NAME, "%s", url); - - query = strstr(url, "?"); - if (query == NULL ) { - err_log(url, "Has no query string."); - goto deny; - } - - if (strncmp(url, "http://", strlen("http://")) != 0) { - err_log(url, "Invalid URL scheme - only http supported."); - goto deny; - } - - /* first, parse the query string */ - query++; /* get rid of the ? */ - TSDebug(PLUGIN_NAME, "Query string is:%s", query); - - // Client IP - this one is optional - p = strstr(query, CIP_QSTRING"="); - if (p != NULL ) { - - p += strlen(CIP_QSTRING + 1); - pp = strstr(p, "&"); - if ((pp - p) > CIP_STRLEN - 1 || (pp - p) < 4) { - err_log(url, "IP address string too long or short."); - goto deny; - } - strncpy(client_ip, p + strlen(CIP_QSTRING) + 1, (pp - p - (strlen(CIP_QSTRING) + 1))); - client_ip[pp - p - (strlen(CIP_QSTRING) + 1)] = '\0'; - TSDebug(PLUGIN_NAME, "CIP: -%s-", client_ip); - retval = TSHttpTxnClientFdGet(txnp, &sockfd); - if (retval != TS_SUCCESS) { - err_log(url, "Error getting sockfd."); - goto deny; - } - peer_len = sizeof(peer); - if (getpeername(sockfd, (struct sockaddr*) &peer, &peer_len) != 0) { - perror("Can't get peer address:"); - } - struct sockaddr_in *s = (struct sockaddr_in *) &peer; - inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr); - TSDebug(PLUGIN_NAME, "Peer address: -%s-", ipstr); - if (strcmp(ipstr, client_ip) != 0) { - err_log(url, "Client IP doesn't match signature."); - goto deny; - } - } - // Expiration - p = strstr(query, EXP_QSTRING"="); - if (p != NULL ) { - p += strlen(EXP_QSTRING) + 1; - expiration = atoi(p); - if (expiration == 0 || expiration < time(NULL )) { - err_log(url, "Invalid expiration, or expired."); - goto deny; - } - TSDebug(PLUGIN_NAME, "Exp: %d", (int) expiration); - } else { - err_log(url, "Expiration query string not found."); - goto deny; - } - // Algorithm - p = strstr(query, ALG_QSTRING"="); - if (p != NULL ) { - p += strlen(ALG_QSTRING) + 1; - algorithm = atoi(p); - // The check for a valid algorithm is later. - TSDebug(PLUGIN_NAME, "Algorithm: %d", algorithm); - } else { - err_log(url, "Algorithm query string not found."); - goto deny; - } - // Key index - p = strstr(query, KIN_QSTRING"="); - if (p != NULL ) { - p += strlen(KIN_QSTRING) + 1; - keyindex = atoi(p); - if (keyindex == -1) { - err_log(url, "Invalid key index."); - goto deny; - } - TSDebug(PLUGIN_NAME, "Key Index: %d", keyindex); - } else { - err_log(url, "KeyIndex query string not found."); - goto deny; - } - // Parts - p = strstr(query, PAR_QSTRING"="); - if (p != NULL ) { - p += strlen(PAR_QSTRING) + 1; - parts = p; // NOTE parts is not NULL terminated it is terminated by "&" of next param - p = strstr(parts, "&"); - TSDebug(PLUGIN_NAME, "Parts: %.*s", (int) (p - parts), parts); - } else { - err_log(url, "PartsSigned query string not found."); - goto deny; - } - // And finally, the sig (has to be last) - p = strstr(query, SIG_QSTRING"="); - if (p != NULL ) { - p += strlen(SIG_QSTRING) + 1; - signature = p; // NOTE sig is not NULL terminated, it has to be 20 chars - if ((algorithm == USIG_HMAC_SHA1 && strlen(signature) < SHA1_SIG_SIZE) || (algorithm == USIG_HMAC_MD5 && strlen(signature) < MD5_SIG_SIZE)) { - err_log(url, "Signature query string too short (< 20)."); - goto deny; - } - } else { - err_log(url, "Signature query string not found."); - goto deny; - } - - /* have the query string, and parameters passed initial checks */ - TSDebug(PLUGIN_NAME, "Found all needed parameters: C=%s E=%d A=%d K=%d P=%s S=%s", client_ip, (int) expiration, algorithm, keyindex, parts, - signature); - - /* find the string that was signed - cycle through the parts letters, adding the part of the fqdn/path if it is 1 */ - p = strstr(url, "?"); - memcpy(urltokstr, &url[strlen("http://")], p - url - strlen("http://")); - part = strtok_r(urltokstr, "/", &p); - while (part != NULL ) { - if (parts[j] == '1') { - strcpy(signed_part + strlen(signed_part), part); - strcpy(signed_part + strlen(signed_part), "/"); - } - if (parts[j + 1] == '0' || parts[j + 1] == '1') // This remembers the last part, meaning, if there are no more valid letters in parts - j++; // will keep repeating the value of the last one - part = strtok_r(NULL, "/", &p); - } - - signed_part[strlen(signed_part) - 1] = '?'; // chop off the last /, replace with '?' - p = strstr(query, SIG_QSTRING"="); - strncat(signed_part, query, (p - query) + strlen(SIG_QSTRING) + 1); - - TSDebug(PLUGIN_NAME, "Signed string=\"%s\"", signed_part); - - /* calculate the expected the signature with the right algorithm */ - switch (algorithm) { - case USIG_HMAC_SHA1: - HMAC(EVP_sha1(), (const unsigned char *) cfg->keys[keyindex], strlen(cfg->keys[keyindex]), (const unsigned char *) signed_part, - strlen(signed_part), sig, &sig_len); - if (sig_len != SHA1_SIG_SIZE) { - TSDebug(PLUGIN_NAME, "sig_len: %d", sig_len); - err_log(url, "Calculated sig len != SHA1_SIG_SIZE !"); - goto deny; - } - - break; - case USIG_HMAC_MD5: - HMAC(EVP_md5(), (const unsigned char *) cfg->keys[keyindex], strlen(cfg->keys[keyindex]), (const unsigned char *) signed_part, - strlen(signed_part), sig, &sig_len); - if (sig_len != MD5_SIG_SIZE) { - TSDebug(PLUGIN_NAME, "sig_len: %d", sig_len); - err_log(url, "Calculated sig len != MD5_SIG_SIZE !"); - goto deny; - } - break; - default: - err_log(url, "Algorithm not supported."); - goto deny; - } - - for (i = 0; i < sig_len; i++) { - sprintf(&(sig_string[i * 2]), "%02x", sig[i]); - } - - TSDebug(PLUGIN_NAME, "Expected signature: %s", sig_string); - - /* and compare to signature that was sent */ - cmp_res = strncmp(sig_string, signature, sig_len * 2); - if (cmp_res != 0) { - err_log(url, "Signature check failed."); - goto deny; - } else { - TSDebug(PLUGIN_NAME, "Signature check passed."); - goto allow; - } - - /* ********* Deny ********* */ - deny: if (url) - TSfree(url); - switch (cfg->err_status) { - case TS_HTTP_STATUS_MOVED_TEMPORARILY: - TSDebug(PLUGIN_NAME, "Redirecting to %s", cfg->err_url); - char *start, *end; - start = cfg->err_url; - end = start + strlen(cfg->err_url); - if (TSUrlParse(rri->requestBufp, rri->requestUrl, (const char **) &start, end) != TS_PARSE_DONE) { - err_log("url", "Error inn TSUrlParse!"); - } - rri->redirect = 1; - break; - case TS_HTTP_STATUS_FORBIDDEN: - default: - /* set status and body to be 403 */ - TSHttpTxnSetHttpRetStatus(txnp, TS_HTTP_STATUS_FORBIDDEN); - TSHttpTxnErrorBodySet(txnp, TSstrdup("Authorization Denied"), strlen("Authorization Denied") - 1, TSstrdup("text/plain")); - break; - } - return TSREMAP_DID_REMAP; - - /* ********* Allow ********* */ - allow: if (url) - TSfree(url); - /* drop the query string so we can cache-hit */ - rval = TSUrlHttpQuerySet(rri->requestBufp, rri->requestUrl, NULL, 0); - if (rval != TS_SUCCESS) { - TSError("Error stripping query string: %d.", rval); - } - return TSREMAP_NO_REMAP; +TSRemapStatus +TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo * rri) +{ + struct config *cfg; + cfg = (struct config *) ih; + + int url_len = 0; + time_t expiration = 0; + int algorithm = -1; + int keyindex = -1; + int cmp_res; + int rval; + int i = 0; + int j = 0; + unsigned int sig_len = 0; + + /* all strings are locally allocated except url... about 25k per instance */ + char *url; + char signed_part[8192] = { '\0' }; // this initializes the whole array and is needed + char urltokstr[8192] = { '\0' }; + char client_ip[CIP_STRLEN] = { '\0' }; + char ipstr[CIP_STRLEN] = { '\0' }; + unsigned char sig[MAX_SIG_SIZE + 1]; + char sig_string[2 * MAX_SIG_SIZE + 1]; + + /* these are just pointers into other allocations */ + char *signature = NULL; + char *parts = NULL; + char *part = NULL; + char *p = NULL, *pp = NULL; + char *query = NULL; + + int retval, sockfd; + socklen_t peer_len; + struct sockaddr_in peer; + + url = TSUrlStringGet(rri->requestBufp, rri->requestUrl, &url_len); + + if (url_len >= MAX_REQ_LEN - 1) { + err_log(url, "URL string too long."); + goto deny; + } + + TSDebug(PLUGIN_NAME, "%s", url); + + query = strstr(url, "?"); + if (query == NULL) { + err_log(url, "Has no query string."); + goto deny; + } + + if (strncmp(url, "http://", strlen("http://")) != 0) { + err_log(url, "Invalid URL scheme - only http supported."); + goto deny; + } + + /* first, parse the query string */ + query++; /* get rid of the ? */ + TSDebug(PLUGIN_NAME, "Query string is:%s", query); + + // Client IP - this one is optional + p = strstr(query, CIP_QSTRING "="); + if (p != NULL) { + + p += strlen(CIP_QSTRING + 1); + pp = strstr(p, "&"); + if ((pp - p) > CIP_STRLEN - 1 || (pp - p) < 4) { + err_log(url, "IP address string too long or short."); + goto deny; + } + strncpy(client_ip, p + strlen(CIP_QSTRING) + 1, (pp - p - (strlen(CIP_QSTRING) + 1))); + client_ip[pp - p - (strlen(CIP_QSTRING) + 1)] = '\0'; + TSDebug(PLUGIN_NAME, "CIP: -%s-", client_ip); + retval = TSHttpTxnClientFdGet(txnp, &sockfd); + if (retval != TS_SUCCESS) { + err_log(url, "Error getting sockfd."); + goto deny; + } + peer_len = sizeof(peer); + if (getpeername(sockfd, (struct sockaddr *) &peer, &peer_len) != 0) { + perror("Can't get peer address:"); + } + struct sockaddr_in *s = (struct sockaddr_in *) &peer; + inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr); + TSDebug(PLUGIN_NAME, "Peer address: -%s-", ipstr); + if (strcmp(ipstr, client_ip) != 0) { + err_log(url, "Client IP doesn't match signature."); + goto deny; + } + } + // Expiration + p = strstr(query, EXP_QSTRING "="); + if (p != NULL) { + p += strlen(EXP_QSTRING) + 1; + expiration = atoi(p); + if (expiration == 0 || expiration < time(NULL)) { + err_log(url, "Invalid expiration, or expired."); + goto deny; + } + TSDebug(PLUGIN_NAME, "Exp: %d", (int) expiration); + } else { + err_log(url, "Expiration query string not found."); + goto deny; + } + // Algorithm + p = strstr(query, ALG_QSTRING "="); + if (p != NULL) { + p += strlen(ALG_QSTRING) + 1; + algorithm = atoi(p); + // The check for a valid algorithm is later. + TSDebug(PLUGIN_NAME, "Algorithm: %d", algorithm); + } else { + err_log(url, "Algorithm query string not found."); + goto deny; + } + // Key index + p = strstr(query, KIN_QSTRING "="); + if (p != NULL) { + p += strlen(KIN_QSTRING) + 1; + keyindex = atoi(p); + if (keyindex == -1) { + err_log(url, "Invalid key index."); + goto deny; + } + TSDebug(PLUGIN_NAME, "Key Index: %d", keyindex); + } else { + err_log(url, "KeyIndex query string not found."); + goto deny; + } + // Parts + p = strstr(query, PAR_QSTRING "="); + if (p != NULL) { + p += strlen(PAR_QSTRING) + 1; + parts = p; // NOTE parts is not NULL terminated it is terminated by "&" of next param + p = strstr(parts, "&"); + TSDebug(PLUGIN_NAME, "Parts: %.*s", (int) (p - parts), parts); + } else { + err_log(url, "PartsSigned query string not found."); + goto deny; + } + // And finally, the sig (has to be last) + p = strstr(query, SIG_QSTRING "="); + if (p != NULL) { + p += strlen(SIG_QSTRING) + 1; + signature = p; // NOTE sig is not NULL terminated, it has to be 20 chars + if ((algorithm == USIG_HMAC_SHA1 && strlen(signature) < SHA1_SIG_SIZE) || + (algorithm == USIG_HMAC_MD5 && strlen(signature) < MD5_SIG_SIZE)) { + err_log(url, "Signature query string too short (< 20)."); + goto deny; + } + } else { + err_log(url, "Signature query string not found."); + goto deny; + } + + /* have the query string, and parameters passed initial checks */ + TSDebug(PLUGIN_NAME, "Found all needed parameters: C=%s E=%d A=%d K=%d P=%s S=%s", client_ip, (int) expiration, + algorithm, keyindex, parts, signature); + + /* find the string that was signed - cycle through the parts letters, adding the part of the fqdn/path if it is 1 */ + p = strstr(url, "?"); + memcpy(urltokstr, &url[strlen("http://")], p - url - strlen("http://")); + part = strtok_r(urltokstr, "/", &p); + while (part != NULL) { + if (parts[j] == '1') { + strcpy(signed_part + strlen(signed_part), part); + strcpy(signed_part + strlen(signed_part), "/"); + } + if (parts[j + 1] == '0' || parts[j + 1] == '1') // This remembers the last part, meaning, if there are no more valid letters in parts + j++; // will keep repeating the value of the last one + part = strtok_r(NULL, "/", &p); + } + + signed_part[strlen(signed_part) - 1] = '?'; // chop off the last /, replace with '?' + p = strstr(query, SIG_QSTRING "="); + strncat(signed_part, query, (p - query) + strlen(SIG_QSTRING) + 1); + + TSDebug(PLUGIN_NAME, "Signed string=\"%s\"", signed_part); + + /* calculate the expected the signature with the right algorithm */ + switch (algorithm) { + case USIG_HMAC_SHA1: + HMAC(EVP_sha1(), (const unsigned char *) cfg->keys[keyindex], strlen(cfg->keys[keyindex]), + (const unsigned char *) signed_part, strlen(signed_part), sig, &sig_len); + if (sig_len != SHA1_SIG_SIZE) { + TSDebug(PLUGIN_NAME, "sig_len: %d", sig_len); + err_log(url, "Calculated sig len != SHA1_SIG_SIZE !"); + goto deny; + } + + break; + case USIG_HMAC_MD5: + HMAC(EVP_md5(), (const unsigned char *) cfg->keys[keyindex], strlen(cfg->keys[keyindex]), + (const unsigned char *) signed_part, strlen(signed_part), sig, &sig_len); + if (sig_len != MD5_SIG_SIZE) { + TSDebug(PLUGIN_NAME, "sig_len: %d", sig_len); + err_log(url, "Calculated sig len != MD5_SIG_SIZE !"); + goto deny; + } + break; + default: + err_log(url, "Algorithm not supported."); + goto deny; + } + + for (i = 0; i < sig_len; i++) { + sprintf(&(sig_string[i * 2]), "%02x", sig[i]); + } + + TSDebug(PLUGIN_NAME, "Expected signature: %s", sig_string); + + /* and compare to signature that was sent */ + cmp_res = strncmp(sig_string, signature, sig_len * 2); + if (cmp_res != 0) { + err_log(url, "Signature check failed."); + goto deny; + } else { + TSDebug(PLUGIN_NAME, "Signature check passed."); + goto allow; + } + + /* ********* Deny ********* */ +deny:if (url) + TSfree(url); + switch (cfg->err_status) { + case TS_HTTP_STATUS_MOVED_TEMPORARILY: + TSDebug(PLUGIN_NAME, "Redirecting to %s", cfg->err_url); + char *start, *end; + start = cfg->err_url; + end = start + strlen(cfg->err_url); + if (TSUrlParse(rri->requestBufp, rri->requestUrl, (const char **) &start, end) != TS_PARSE_DONE) { + err_log("url", "Error inn TSUrlParse!"); + } + rri->redirect = 1; + break; + case TS_HTTP_STATUS_FORBIDDEN: + default: + /* set status and body to be 403 */ + TSHttpTxnSetHttpRetStatus(txnp, TS_HTTP_STATUS_FORBIDDEN); + TSHttpTxnErrorBodySet(txnp, TSstrdup("Authorization Denied"), strlen("Authorization Denied") - 1, + TSstrdup("text/plain")); + break; + } + return TSREMAP_DID_REMAP; + + /* ********* Allow ********* */ +allow:if (url) + TSfree(url); + /* drop the query string so we can cache-hit */ + rval = TSUrlHttpQuerySet(rri->requestBufp, rri->requestUrl, NULL, 0); + if (rval != TS_SUCCESS) { + TSError("Error stripping query string: %d.", rval); + } + return TSREMAP_NO_REMAP; } http://git-wip-us.apache.org/repos/asf/trafficserver/blob/4f2dc70f/plugins/experimental/url_sig/url_sig.h ---------------------------------------------------------------------- diff --git a/plugins/experimental/url_sig/url_sig.h b/plugins/experimental/url_sig/url_sig.h index c495b4b..dd24cc7 100644 --- a/plugins/experimental/url_sig/url_sig.h +++ b/plugins/experimental/url_sig/url_sig.h @@ -21,21 +21,21 @@ #define VERSION "1.0" /* in the query string that we add to sign the url: */ -#define CIP_QSTRING "C" /* C=24.0.33.12 designates the client IP address */ -#define EXP_QSTRING "E" /* E=1356128799 means expires at (seconds since Unix epoch) */ -#define ALG_QSTRING "A" /* A=1 means hashing algorithm 1 */ -#define KIN_QSTRING "K" /* K=3 means use key number 3 */ -#define PAR_QSTRING "P" /* P=1110 means use parts 0, 1 and 2 (and no more) for the hashing of the url after removing the 'http://' */ +#define CIP_QSTRING "C" /* C=24.0.33.12 designates the client IP address */ +#define EXP_QSTRING "E" /* E=1356128799 means expires at (seconds since Unix epoch) */ +#define ALG_QSTRING "A" /* A=1 means hashing algorithm 1 */ +#define KIN_QSTRING "K" /* K=3 means use key number 3 */ +#define PAR_QSTRING "P" /* P=1110 means use parts 0, 1 and 2 (and no more) for the hashing of the url after removing the 'http://' */ /* and making the parts by doing a split("/") */ -#define SIG_QSTRING "S" /* S=9e2828d570a4bee3c964f698b0985ee58b9f6b64 means 9e2828d570a4bee3c964f698b0985ee58b9f6b64 is the sig - This one has to be the last one of the string */ +#define SIG_QSTRING "S" /* S=9e2828d570a4bee3c964f698b0985ee58b9f6b64 means 9e2828d570a4bee3c964f698b0985ee58b9f6b64 is the sig + This one has to be the last one of the string */ #define CIP_STRLEN 20 #define EXP_STRLEN 16 #define PAR_STRLEN 16 #define MAX_PARTS 32 -#define MAX_HTTP_REQUEST_SIZE 8192 // +#define MAX_HTTP_REQUEST_SIZE 8192 // #define MAX_SIG_SIZE 20 #define SHA1_SIG_SIZE 20
