Пример #1
0
int PKI_HTTP_get_socket (const PKI_SOCKET * sock,
	                 const char       * data,
			 size_t             data_size,
		         const char       * content_type,
			 int                method,
			 int                timeout,
	                 size_t             max_size,
			 PKI_MEM_STACK   ** sk ) {

	size_t len = 0;

	const char *my_cont_type = "application/unknown";

	PKI_HTTP *http_rv	 = NULL;

	int rv   = -1;
	int ret  = PKI_OK;

	size_t max_len = 0;
	size_t auth_len = 0;

	char *tmp  = NULL;
	char *auth_tmp = NULL;
    
	char *head_get =
			"GET %s HTTP/1.1\r\n"
			"Host: %s\r\n"
			"User-Agent: LibPKI\r\n"
			"Connection: close\r\n"
			"%s";

	char *head_post = 
			"POST %s HTTP/1.1\r\n"
			"Host: %s\r\n"
			"User-Agent: LibPKI\r\n"
			"Connection: close\r\n"
			"Content-type: %s\r\n"
			"Content-Length: %d\r\n"
			"%s";

	char *head = NULL;

	if ( timeout < 0 ) timeout = 0;

	if ( !sock || !sock->url ) return PKI_ERR;

	// Process the authentication information if provided by the caller
	if (sock->url && sock->url->usr && sock->url->pwd)
	{
		// Rough estimate for the auth string
		max_len = strlen(sock->url->usr) + strlen(sock->url->pwd) + 100;

		// Special case for when a usr/pwd was specified in the URL
		auth_tmp = PKI_Malloc(len);
		auth_len = (size_t)snprintf(auth_tmp, len, "Authentication: user %s:%s\r\n\r\n", sock->url->usr, sock->url->pwd);
	}
	else
	{
		// If we do not have the auth info, we just add the end of header
		auth_len = 2;
		auth_tmp = "\r\n";
	}

	if (method == PKI_HTTP_METHOD_GET)
	{
		// Gets the right header
		head = head_get;

		// Estimate the header's final size
		max_len =
				strlen(head) +
				strlen(sock->url->path) +
				strlen(sock->url->addr) +
				101;

		// Allocates enough space for the header
		tmp = PKI_Malloc ( max_len + auth_len );

		// Prints the header into the tmp container
		len = (size_t) snprintf(tmp, max_len, head, sock->url->path, sock->url->addr, auth_tmp);
	}
	else if (method == PKI_HTTP_METHOD_POST)
	{
		// Gets the right head
		head = head_post;

		// Determines the right content type
		if ( content_type ) my_cont_type = content_type;
		else my_cont_type = "text/html";

		// Checks the max len for the allocated header
		max_len =
				strlen(head) +
				strlen(sock->url->path) +
				strlen(sock->url->addr) +
				strlen(my_cont_type) +
				101;

		// Allocates the memory for the header
		tmp = PKI_Malloc ( max_len + auth_len );

		// Prints the header into the tmp container
		len = (size_t) snprintf(tmp, max_len, head, sock->url->path, sock->url->addr, 
					my_cont_type, data_size, auth_tmp );
	}
	else
	{
		PKI_log_err ( "Method (%d) not supported!", method );
		return PKI_ERR;
	}

	// PKI_MEM *r = PKI_MEM_new_data(len, tmp);
	// URL_put_data("file://http_req.txt", r, NULL, NULL, 0, 0, NULL);
	// PKI_MEM_free(r);

	if ((rv = (int) PKI_SOCKET_write(sock, tmp, len)) < 0)
	{
		PKI_log_err("Can not write HTTP header to socket");
		PKI_Free(tmp);
		goto err;
	}

	// Free the tmp pointer that held the request header
	if (tmp) PKI_Free (tmp);

	// If we were using a POST method, we need to actually send the data
	if(data != NULL)
	{
		PKI_log_err("{DEBUG} Writing Data -> data_size = %d, data = %p", data_size, data);

		if ((PKI_SOCKET_write(sock, data, data_size)) < 0)
		{
			PKI_log_err ("Can not write POST to socket.");
			goto err;
		}
	}
	
	// Let's now wait for the response from the server
	if ((http_rv = PKI_HTTP_get_message(sock, timeout, max_size)) == NULL)
	{
		PKI_log_err ("HTTP retrieval error\n");
		goto err;
	}

	// We shall now check for the return code
	if (http_rv->code >= 400 )
	{
		goto err;
	}
	else if (http_rv->code >= 300)
	{
		/* Redirection - let's try that */
		if (http_rv->location == NULL)
		{
			PKI_log_debug ( "HTTP Redirection but no location provided!");
			goto err;
		}

    PKI_log_debug("HTTP Redirection Detected [URL: %s]", http_rv->location );

		if (strstr(http_rv->location, "://") != NULL)
		{
			URL *url_tmp = NULL;

			if( strncmp_nocase( http_rv->location, sock->url->url_s, 
					(int) strlen(http_rv->location)) == 0)
			{
				PKI_log_debug( "HTTP cyclic redirection!");
				goto err;
			}

			if ((url_tmp = URL_new ( http_rv->location )) == NULL)
			{
				PKI_log_debug("HTTP location is not a valid URI (%s)", http_rv->location );
				goto err;
			}

			if ( sock->url->ssl == 0 )
			{
				ret = PKI_HTTP_get_url ( url_tmp, data, 
					data_size, content_type, method, timeout, 
							max_size, sk, NULL );
			}
			else
			{
				PKI_SSL *ssl2 = PKI_SSL_dup ( sock->ssl );

				ret = PKI_HTTP_get_url ( url_tmp, data, 
					data_size, content_type, method, timeout, 
							max_size, sk, ssl2 );
			}

			if ( url_tmp ) URL_free ( url_tmp );
	
			goto end;

		}
		else
		{
			const char *prot_s = NULL;
			char new_url[2048];
			URL *my_new_url = NULL;
			PKI_SSL *ssl2 = PKI_SSL_dup ( sock->ssl );

			prot_s = URL_proto_to_string ( sock->url->proto );
			if( !prot_s ) goto err;

			snprintf(new_url, sizeof(new_url),"%s://%s%s", prot_s, sock->url->addr, http_rv->location );

			if( strncmp_nocase( new_url, sock->url->url_s, (int) strlen ( new_url )) == 0 )
			{
				PKI_log_debug( "HTTP cyclic redirection!");
				goto err;
			}

			my_new_url = URL_new ( new_url );

			ret = PKI_HTTP_get_url ( my_new_url, data, data_size, content_type, method,
						timeout, max_size, sk, ssl2 );

			if (ssl2) PKI_SSL_free ( ssl2 );
		}
	}
	else if (http_rv->code != 200)
	{
		PKI_log_debug( "Unknown HTTP Return code [Code: %d]", http_rv->code );
		goto err;
	}

	/*
	PKI_log_err("{DEBUG} method = %d, header->size = %d, body = %p, body_size = %d",
			  http_rv->method, http_rv->head->size, http_rv->body, http_rv->body->size);
	URL_put_data("file://http-resp-header.txt", http_rv->head, NULL, NULL, 0, 0, NULL);
	URL_put_data("file://http-resp-data.txt", http_rv->body, NULL, NULL, 0, 0, NULL);
	*/

	// If a Pointer was provided, we want the data back
	if (sk) {

		// Checks if the caller provided an already allocated data
		// structure. If not, we allocate it.
		if (*sk) PKI_STACK_MEM_free_all(*sk);

    // Allocates a new structure
		if ((*sk = PKI_STACK_MEM_new()) == NULL) {

      // If a memory error occurs report it and exit
			PKI_ERROR(PKI_ERR_MEMORY_ALLOC, NULL);

      // Nothing more to do
			goto err;
		}

		// Add the returned value to the stack
		if (PKI_STACK_MEM_push(*sk, http_rv->body) != PKI_OK) {
			PKI_log_err("Can not push the HTTP result body in the result stack");
			goto err;
		}

		// Remove ownership of the body PKI_MEM from the original
		// HTTP msg container
		http_rv->body = NULL;
	}

end:
	// Finally free the HTTP message memory
	if (http_rv) PKI_HTTP_free(http_rv);

	// Returns the result
	return ret;

err:
	// Error condition
	if (http_rv) PKI_HTTP_free ( http_rv );

	// Free the locally allocated memory
	if (*sk) PKI_STACK_MEM_free_all(*sk);
	*sk = NULL;

	return PKI_ERR;
}
Пример #2
0
/*! \brief Returns a MEM STACK with the requested DNS records */
PKI_MEM_STACK *URL_get_data_dns_url(URL *url, ssize_t size) {

	PKI_MEM_STACK *ret = NULL;

#ifdef HAVE_LIBRESOLV

	int type = T_A;
	PKI_MEM *obj = NULL;

	if( (!url) || (!url->addr)) {
		return NULL;
	}

	unsigned char response[NS_PACKETSZ];

	ns_msg dnsMessage;
	ns_rr dnsRecord;

	int dnsRecordSection = ns_s_an;
	int dns_msgCount = 0;
	int len = 0;

	// Check the Type of record
	if ((type = URL_get_dns_type(url->attrs)) == -1) return NULL;

	PKI_log_debug("DNS URI: Searching for %s (%s/%d)",
		url->addr, url->attrs, type);

	if ((len = res_search(url->addr, C_IN, type, response, sizeof(response))) < 0)
	{
		// An Error Occurred
		PKI_log_err("DNS URI: search failed\n");
		return NULL;
	}

	if (ns_initparse(response, len, &dnsMessage) < 0)
	{
		// This should not happen if the record is correct
		PKI_log_err("DNS URI: can not init DNS parsing of the dnsMessage\n");
		return NULL;
	}

	len = ns_msg_count(dnsMessage, dnsRecordSection);
	PKI_log_debug("DNS_URI: msg count ==> %d\n", len);

	if (len <= 0) return NULL;

	if((ret = PKI_STACK_MEM_new()) == NULL ) {
		PKI_log_debug ("DNS URI: Memory Failure");
		return NULL;
	}

	for (dns_msgCount = 0; dns_msgCount < len; dns_msgCount++)
	{
		PKI_log_debug("DNS URI: Retrieving DNS record #%d",dns_msgCount);

		if (ns_parserr(&dnsMessage, dnsRecordSection, dns_msgCount, &dnsRecord))
		{
			// ERROR: ns_parserr failed, let's continue to the next record
			PKI_log_err("DNS URI: Can not parse record %d of %d", dns_msgCount, len);
			continue;
		}

		PKI_log_debug("DNS URI: type = %d (req: %d)\n", ns_rr_type(dnsRecord), type);

		if (type == pki_ns_t_address)
		{
			switch (ns_rr_type(dnsRecord))
			{
				case T_A:
				case T_AAAA:
				case T_CNAME:
					break;
				default:
					continue;
			}
		}
		else if (type != ns_rr_type(dnsRecord))
		{
			PKI_log_debug("DNS URI: recived type %d is different from requested (%d)", 
				type, ns_rr_type(dnsRecord));
			// continue;
		}

		// int i = 0;
		int rv = 0;
		// int len = 0;
		int offset = 0;

		char dnsRecordName[MAXDNAME];

		memset(dnsRecordName, '\x0', MAXDNAME);
		// Parse the different types of DNS records
		if ((ns_rr_type(dnsRecord) == T_A) || (ns_rr_type(dnsRecord) == T_AAAA))
		{
			// These require Translation using IPv4/IPv6 functions
			int family = AF_INET;

			if (ns_rr_type(dnsRecord) == T_A) family = AF_INET;
			else family = AF_INET6;

			if(inet_ntop(family, ns_rr_rdata(dnsRecord), dnsRecordName, 
				sizeof(dnsRecordName)) == NULL)
			{
				// Can not convert
				continue;
			}
		}
		else if ((ns_rr_type(dnsRecord) == T_CNAME) || (ns_rr_type(dnsRecord) == T_MX) ||
			(ns_rr_type(dnsRecord) == T_NS))
		{
			if (ns_rr_type(dnsRecord) == T_MX) offset = NS_INT16SZ;

			rv = ns_name_uncompress(ns_msg_base(dnsMessage), ns_msg_end(dnsMessage),
				ns_rr_rdata(dnsRecord) + offset, dnsRecordName, MAXDNAME);

			// ERROR, can not uncompress the names
			if (rv < 0) continue;
		}
		else if (ns_rr_type(dnsRecord) == T_SRV)
		{
			// This requires special handling, the format is [SHORT][SHORT][SHORT][DATA]
			// unsigned short *pri = (unsigned short *) ns_rr_rdata(dnsRecord);
			// unsigned short *weight = (unsigned short *) &(ns_rr_rdata(dnsRecord)[2]);
			// unsigned short *port = (unsigned short *) &(ns_rr_rdata(dnsRecord)[4]);

			// Shall we return the additional data too ?
			// printf("PRI : %d\n", *pri);
			// printf("WEIGHT : %d\n", ntohs(*weight));
			// printf("PORT : %d\n", ntohs(*port));

			offset = 6;
			rv = ns_name_uncompress(ns_msg_base(dnsMessage), ns_msg_end(dnsMessage),
				ns_rr_rdata(dnsRecord) + offset, dnsRecordName, MAXDNAME);

			if (rv < 0) continue;
		}
		else if (ns_rr_type(dnsRecord) == T_TXT)
		{
			// Special handling required. Format is [BYTE][DATA]
			unsigned char *p = (unsigned char *)ns_rr_rdata(dnsRecord);

			snprintf(dnsRecordName, (size_t) *p+1, "%s", &ns_rr_rdata(dnsRecord)[1]);
		}
		else
		{
			PKI_log_debug("DNS URI: record type not supported [%d]", ns_rr_type(dnsRecord));
			continue;
		}

		if((obj = PKI_MEM_new_null()) == NULL ) {
			// Memory Allocation Error, we abort
			break;
		}

		if (strlen(dnsRecordName) > 0) {
			// If it is a printable value, we add the parsed version of the
			// record
			if(PKI_MEM_add(obj, (char *) dnsRecordName, strlen(dnsRecordName)) == PKI_ERR) {
				/* ERROR in memory growth */;
				PKI_log_err("DNS URI: Memory Allocation Error");
				break;
			}
		} else {
			// The value is not parsed/parsable, we return the raw data
			// the application should know what to do with the data!
			if(PKI_MEM_add(obj, (char *) ns_rr_rdata(dnsRecord), 
					ns_rr_rdlen(dnsRecord)) == PKI_ERR) {
				/* ERROR in memory growth */;
				PKI_log_err("DNS URI: Memory Allocation Error");
				break;
			}
		}

/*
		printf("MSG Data [%d]:\n", ns_rr_rdlen(dnsRecord));
		for (i=0; i < ns_rr_rdlen(dnsRecord); i++)
		{
			unsigned char *kk;

			kk = (unsigned char *) &ns_rr_rdata(dnsRecord)[i];
			printf("%x:", *kk);
		};
		printf("\n");

		fprintf(stderr, "DEBUG: RV => %d (err: %d, %s)\n", rv, h_errno, hstrerror(h_errno));
		fprintf(stderr, "DEBUG: name => %s (%s)\n", ns_rr_name(dnsRecord), url->addr);
		fprintf(stderr, "DEBUG: value => %s\n", dnsRecordName);
		fprintf(stderr, "DEBUG: type => %d\n", ns_rr_type(dnsRecord));
		fprintf(stderr, "DEBUG: class => %d\n", ns_rr_class(dnsRecord));
*/

		PKI_STACK_MEM_push(ret, obj);

		// PKI_log_debug("DNS URI: Added object #%d to stack", PKI_STACK_MEM_elements(ret));
	}

#endif

	return ret;
};