Beispiel #1
0
static int parse_ops(char* act_s, struct dbops_action** action, int has_name) {
	int res = 0, i;
	char *c, *s, *part;
	static int query_no = 0;

	s = act_s;
	*action = pkg_malloc(sizeof(**action));
	if (!*action) return E_OUT_OF_MEM;
	memset(*action, 0, sizeof(**action));
	(*action)->query_no = query_no++;

	eat_spaces(s);
	c = s;
	eat_alphanum(c);
	if (has_name) {
		char *c2;
		c2 = c;
		eat_spaces(c2);
		if (c != s && *c2 == '=') {
			*c = '\0';
			if (find_action_by_name(s, -1) != NULL) {
				ERR(MODULE_NAME": parse_ops: duplicate query name: %s\n", s);
				return E_CFG;
			}		
			(*action)->query_name = s;
			s = c2+1;
			eat_spaces(s);
			c = s;
			eat_alphanum(c);
		}
		else {
			ERR(MODULE_NAME": parse_ops: query_no: %d, valid query name not found in '%s'\n%s\n%s\n", (*action)->query_no, s, c, c2);
			return E_CFG;
		}
	}

	if (c[0] == ':' && c[1] == '/' && c[2] == '/') { /* database part is optional */
		for (c=s; *c!=':'; c++) {
			*c = tolower(*c);                       /* _type_://user:host/database_name/ */
		}
		(*action)->db_url = s;
		s = c+1;
		while (*s == '/') s++;
		res = get_next_part(&s, &part, PART_DELIM, 1);  /* type://_user:host_/database_name/ */
		if (res < 0) return res;


		res = get_next_part(&s, &part, PART_DELIM, 0);  /* type://user:host/_database_name_/ */
		if (res < 0) return res;
	}
	res = get_next_part(&s, &part, PART_DELIM, 0);
	if (res < 0) return res;

	for (c = part; *c && *c != PART_DELIM; c++) {
		if (*c == ' ') {
			(*action)->is_raw_query = 1;
			*c = '\0';
			break;
		}
	}
	if (strcasecmp(part, "select") == 0)
		(*action)->operation = OPEN_QUERY_OPS;
	else if (strcasecmp(part, "insert") == 0)
		(*action)->operation = INSERT_OPS;
	else if (strcasecmp(part, "update") == 0)
		(*action)->operation = UPDATE_OPS;
	else if (strcasecmp(part, "replace") == 0)
		(*action)->operation = REPLACE_OPS;
	else if (strcasecmp(part, "delete") == 0)
		(*action)->operation = DELETE_OPS;
	else {
		if ((*action)->is_raw_query) *c = ' ';
		ERR(MODULE_NAME": parse_ops: query: %s(%d), unknown type of query '%s'\n", (*action)->query_name, (*action)->query_no, part);
		return E_CFG;
	}
	if ((*action)->is_raw_query) {
		*c = ' ';
		(*action)->raw.s = part;
		(*action)->table.s = part;
	}

	res = get_next_part(&s, &part, PART_DELIM, 0);
	if (res < 0) return res;
	if (!(*action)->is_raw_query) {

		if (!*part) {
			ERR(MODULE_NAME": parse_ops: query: %s(%d), table not specified near '%s' in '%s'\n", (*action)->query_name, (*action)->query_no, s, act_s);
			return E_CFG;
		}
		trim_apostr(&part);
		(*action)->table.s = part;

		res = get_next_part(&s, &part, PART_DELIM, 0);
		if (res < 0) return res;
		switch ((*action)->operation) {
			case OPEN_QUERY_OPS:
			case UPDATE_OPS:
			case REPLACE_OPS:
			case INSERT_OPS:
				res = split_fields(part, &(*action)->field_count, &(*action)->fields);
				if (res < 0) return res;
				if ((*action)->field_count == 0) {
					ERR(MODULE_NAME": parse_ops: query: %s(%d), no field specified near '%s' ?n '%s'\n", (*action)->query_name, (*action)->query_no, part, act_s);
					return E_CFG;
				}
				break;
			case DELETE_OPS:
				res = split_fields(part, &(*action)->where_count, &(*action)->wheres);
				if (res < 0) return res;
				res = get_next_part(&s, &part, PART_DELIM, 0);
				if (res < 0) return res;
				res = split_fields(part, &(*action)->op_count, &(*action)->ops);
				if (res < 0) return res;
				break;
			default:;
		}

		res = get_next_part(&s, &part, PART_DELIM, 0);
		if (res < 0) return res;
		switch ((*action)->operation) {
			case OPEN_QUERY_OPS:
			case UPDATE_OPS:
				res = split_fields(part, &(*action)->where_count, &(*action)->wheres);
				if (res < 0) return res;
				res = get_next_part(&s, &part, PART_DELIM, 0);
				if (res < 0) return res;
				res = split_fields(part, &(*action)->op_count, &(*action)->ops);
				if (res < 0) return res;
				res = get_next_part(&s, &part, PART_DELIM, 0);
				if (res < 0) return res;
				switch ((*action)->operation) {
					case OPEN_QUERY_OPS:
						if (*part) {
							(*action)->order.s = part;
						}
						res = get_next_part(&s, &part, PART_DELIM, 0);
						if (res < 0) return res;
						break;
					default:;
				}
				break;
			default:
				;
		}
	}

	/* values */
	res = split_fields(part, &(*action)->value_count, &(*action)->values);
	if (res < 0) return res;

	if ((*action)->value_count) {
		(*action)->value_types = (int*)pkg_malloc(sizeof(int) * (*action)->value_count);
		if ((*action)->value_types == NULL) {
			ERR(MODULE_NAME": No memory left\n");
			return -1;
		}

		for (i=0; i<(*action)->value_count; i++) {
			(*action)->value_types[i] = DB_CSTR; // DB_NONE; /* let decide db driver itself, FIXME: until jjanak changes then default type is string */
			res = get_type(&(*action)->values[i].s, &(*action)->value_types[i]);
			if (res < 0) return res;
		}
	}

	/* extra options */
	res = get_next_part(&s, &part, PART_DELIM, 0);
	if (res < 0) return res;

	(*action)->extra_ops_count = 0;
	c = part;
	while (*c) {
		char *fld;
		res = get_next_part(&c, &fld, FLD_DELIM, 1);
		if (res < 0) return res;
		(*action)->extra_ops_count++;
	}
	if ((*action)->extra_ops_count > 0) {
		(*action)->extra_ops = pkg_malloc( (*action)->extra_ops_count*sizeof(*(*action)->extra_ops));
		if (!(*action)->extra_ops) {
			ERR(MODULE_NAME": parse_ops: not enough pkg memory\n");
			return E_OUT_OF_MEM;
		}
		memset((*action)->extra_ops, 0, (*action)->extra_ops_count*sizeof(*(*action)->extra_ops));

		i = 0;
		c = part;
		while (*c) {
			char *fld;
			res = get_next_part(&c, &fld, FLD_DELIM, 0);
			if (res < 0) return res;
			/* name=[i|s]:value */
			(*action)->extra_ops[i].name = fld;
			eat_alphanum(fld);
			if (*fld != '=') {
				ERR(MODULE_NAME": parse_ops: query: %s(%d), bad extra parameter format in '%s'\n", (*action)->query_name, (*action)->query_no, (*action)->extra_ops[i].name);
				return E_CFG;
			}
			*fld = '\0';
			fld++;
			while (*fld==' ' || *fld=='\t') fld++;
			(*action)->extra_ops[i].type = DB_NONE;
			res = get_type(&fld, &(*action)->extra_ops[i].type);
			if (res < 0) return res;
			trim_apostr(&fld);
			(*action)->extra_ops[i].value = fld;
			DEBUG(MODULE_NAME": extra_ops #%d, name='%s', type=%d, val='%s'\n", i, (*action)->extra_ops[i].name, (*action)->extra_ops[i].type, (*action)->extra_ops[i].value);
			i++;
		}
	}

	if (*s) {
		ERR(MODULE_NAME": parse_ops: query: %s(%d), too many parameters/parts, remaining '%s' in '%s'\n", (*action)->query_name, (*action)->query_no, s, act_s);
		return E_CFG;
	}
	if ((*action)->is_raw_query) {
		DEBUG(MODULE_NAME": query: %s(%d) oper:%d database:'%s' query:'%s' value#:%d extra_ops#:%d\n", (*action)->query_name, (*action)->query_no, (*action)->operation, (*action)->db_url, (*action)->raw.s, (*action)->value_count, (*action)->extra_ops_count);
	}
	else {
		/* check num of fields */
		if ((((*action)->operation==OPEN_QUERY_OPS)?0:(*action)->field_count)+(*action)->where_count != (*action)->value_count) {
			ERR(MODULE_NAME": parse_ops: query: %s(%d), number of values does not correspond to number of fields (%d+%d!=%d) in '%s'\n", (*action)->query_name, (*action)->query_no, ((*action)->operation==OPEN_QUERY_OPS)?0:(*action)->field_count,  (*action)->where_count, (*action)->value_count, act_s);
			return E_CFG;
		}
		DEBUG(MODULE_NAME": query_no:%d oper:%d database:'%s' table:'%s' 'field#:'%d' where#:'%d' order:'%s' value#:%d extra_ops#:%d\n", (*action)->query_no, (*action)->operation, (*action)->db_url, (*action)->table.s, (*action)->field_count,  (*action)->where_count, (*action)->order.s, (*action)->value_count, (*action)->extra_ops_count);
	}
	return 0;
}
Beispiel #2
0
int main(int argc, char** argv)
{
    const char* secret;
    secret = getenv("TRACKING_SECRET");
    if (!secret) {
        fprintf(stderr, "TRACKING_SECRET not set\n");
        return 1;
    }
    
    char input_line[MAX_LINE];
    char plaintext[MAX_LINE];
    const EVP_CIPHER* cipher = EVP_aes_128_cbc();

    while (fgets(input_line, MAX_LINE, stdin) != NULL) {
        /* split the line into unique_id and query */
        char *unique_id, *query;
        split_fields(input_line, &unique_id, &query, NO_MORE_FIELDS);

        /* parse the query string to get the value we need */
        char *blob = NULL;

        char *key, *value;
        while (parse_query_param(&query, &key, &value) >= 0) {
            if (strcmp(key, "v") == 0) {
                blob = value;
                break;
            }
        }

        if (blob == NULL)
            continue;

        /* undo url encoding on the query string */
        int b64_size = url_decode(blob);
        if (b64_size < 0) 
            continue;

        /* split off the initialization vector from the actual ciphertext */
        char *initialization_vector, *ciphertext;

        initialization_vector = blob;
        initialization_vector[KEY_SIZE] = '\0';
        ciphertext = blob + 32;
        b64_size -= 32;

        /* base 64 decode and decrypt the ciphertext */
        BIO* bio = BIO_new_mem_buf(ciphertext, b64_size);

        BIO* b64 = BIO_new(BIO_f_base64());
        BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
        bio = BIO_push(b64, bio);

        BIO* aes = BIO_new(BIO_f_cipher());
        BIO_set_cipher(
            aes,
            cipher,
            (unsigned char*)secret,
            (unsigned char*)initialization_vector,
            0 /* decryption */
        );
        bio = BIO_push(aes, bio);

        /* stream the output through the filters */
        int plaintext_length = BIO_read(bio, plaintext, b64_size);
        plaintext[plaintext_length] = '\0';

        if (!BIO_get_cipher_status(bio)) {
            BIO_free_all(bio);
            continue;
        }

        /* clean up */
        BIO_free_all(bio);

        /* check that the plaintext isn't garbage; if there are
         * non-ascii characters in it, it's likely bad */
        bool non_ascii_junk = false;
        for (unsigned char* c = (unsigned char*)plaintext; *c != '\0'; c++) {
            if (*c > 0x7F) {
                non_ascii_junk = true;
                break;
            }
        }

        if (non_ascii_junk) {
            continue;
        }

        /* write out the unique id since we don't need it for ourselves */
        fputs(unique_id, stdout);

        /* split the fields out of the plaintext */
        char* current_string = plaintext;
        int field_index = 0;

        for (int i = 0; i < plaintext_length; i++) {
            char *c = plaintext + i;
            if (*c != '|')
                continue;
            
            *c = '\0';

            switch (field_index) {
            case FIELD_USER:
                /* we don't use the username; skip it */
                break;
            case FIELD_SRPATH:
                fputc('\t', stdout);
                fputs(current_string, stdout);

                fputc('\t', stdout);
                for (char* c2=current_string; *c2 != '\0'; c2++) {
                    if (*c2 == '-') {
                        *c2 = '\0';
                        break;
                    }
                }
                fputs(current_string, stdout);
                break;
            case FIELD_LANG:
                fputc('\t', stdout);
                for (char* c2=current_string; *c2 != '\0'; c2++) {
                    *c2 = tolower(*c2);
                }
                fputs(current_string, stdout);
                break;
            case FIELD_CNAME:
                assert(0!=1);
            }

            current_string = c + 1;
            field_index += 1;
        }

        if (field_index < FIELD_COUNT) {
            fputc('\t', stdout);
            fputs(current_string, stdout);
            field_index += 1;
        }

        for (; field_index < FIELD_COUNT; field_index++) 
            fputc('\t', stdout);

        /* all done! */
        fputc('\n', stdout);
    }

    return 0;
}
Beispiel #3
0
int main(int argc, char** argv)
{
    const char* secret;
    secret = getenv("TRACKING_SECRET");
    if (!secret) {
        fprintf(stderr, "TRACKING_SECRET not set\n");
        return 1;
    }

    char input_line[MAX_LINE];
    unsigned int hash_length = SHA_DIGEST_LENGTH;
    unsigned char input_hash[hash_length];
    unsigned char expected_hash[hash_length];
    int secret_length = strlen(secret);

    while (fgets(input_line, MAX_LINE, stdin) != NULL) {
        /* get the fields */
        char *ip, *path, *query, *unique_id;

        split_fields(
            input_line, 
            &ip, 
            &path, 
            &query, 
            &unique_id, 
            NO_MORE_FIELDS
        );

        /* in the query string, grab the fields we want to verify */
        char *id = NULL;
        char *hash = NULL;
        char *url = NULL;

        char *key, *value;
        while (parse_query_param(&query, &key, &value) >= 0) {
            if (strcmp(key, "id") == 0) {
                id = value;
            } else if (strcmp(key, "hash") == 0) {
                hash = value;
            } else if (strcmp(key, "url") == 0) {
                url = value;
            }
        }

        if (id == NULL || hash == NULL)
            continue;

        /* decode the params */
        int id_length = url_decode(id);
        if (id_length < 0)
            continue;

        if (url_decode(hash) != 40)
            continue;

        int url_length = 0;
        if (url != NULL) {
            url_length = url_decode(url);
            if (url_length < 0)
                continue;
        }

        /* turn the expected hash into bytes */
        bool bad_hash = false;
        for (int i = 0; i < hash_length; i++) {
            int count = sscanf(&hash[i*2], "%2hhx", &input_hash[i]);
            if (count != 1) {
                bad_hash = true;
                break;
            }
        }

        if (bad_hash)
            continue;

        /* generate the expected hash */
        HMAC_CTX ctx;

        // NOTE: EMR has openssl <1.0, so these HMAC methods don't return
        // error codes -- see https://www.openssl.org/docs/crypto/hmac.html
        HMAC_Init(&ctx, secret, secret_length, EVP_sha1());

        if (strcmp("/click", path) == 0 && url != NULL) {
            /* the url is only for click hashes */
            HMAC_Update(&ctx, url, url_length);
        }

        HMAC_Update(&ctx, id, id_length);
        HMAC_Final(&ctx, expected_hash, &hash_length);

        /* generate the old ip hash */
        SHA_CTX ctx_old;
        int result_old = 0;
        unsigned char expected_hash_old[SHA_DIGEST_LENGTH];

        result_old = SHA1_Init(&ctx_old);
        if (result_old == 0)
            continue;

        if (strcmp("/pixel/of_defenestration.png", path) != 0) {
            /* the IP is not included on adframe tracker hashes */
            result_old = SHA1_Update(&ctx_old, ip, strlen(ip));
            if (result_old == 0)
                continue;
        }

        result_old = SHA1_Update(&ctx_old, id, id_length);
        if (result_old == 0)
            continue;

        result_old = SHA1_Update(&ctx_old, secret, secret_length);
        if (result_old == 0)
            continue;

        result_old = SHA1_Final(expected_hash_old, &ctx_old);
        if (result_old == 0)
            continue;

        /* check that the hashes match */
        if (memcmp(input_hash, expected_hash, SHA_DIGEST_LENGTH) != 0 &&
            memcmp(input_hash, expected_hash_old, SHA_DIGEST_LENGTH) != 0)
            continue;

        /* split out the fullname and subreddit if necessary */
        char *fullname = id;
        char *subreddit = NULL;

        for (char *c = id; *c != '\0'; c++) {
            if (*c == '-') {
                subreddit = c + 1;
                *c = '\0';
                break;
            }
        }

        /* output stuff! */
        fputs(unique_id, stdout);
        fputc('\t', stdout);

        fputs(path, stdout);
        fputc('\t', stdout);

        fputs(fullname, stdout);
        fputc('\t', stdout);

        if (subreddit != NULL) {
            fputs(subreddit, stdout);
        }

        fputc('\n', stdout);
    }
}