예제 #1
0
파일: http_s.c 프로젝트: openca/libpki
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
PKI_X509_OCSP_REQ * ocspd_req_get_socket ( int connfd, OCSPD_CONFIG *ocspd_conf)
{
	PKI_X509_OCSP_REQ 	*req = NULL;
	PKI_X509_OCSP_REQ_VALUE *req_val = NULL;

	PKI_IO			*mem = NULL;
	PKI_MEM			*pathmem = NULL;
	PKI_MEM 		*b64mem = NULL;

	PKI_SOCKET		sock;

	size_t maxsize  = 0;
	maxsize = (size_t) ocspd_conf->max_req_size;

	PKI_HTTP *http_msg = NULL;

	if ( connfd <= 0 ) return NULL;

	// Initialize the sock structure
	sock.ssl = NULL;
	PKI_SOCKET_set_fd ( &sock, connfd );

	http_msg = PKI_HTTP_get_message(&sock, (int) ocspd_conf->max_timeout_secs, maxsize);
	if (http_msg == NULL)
	{
		PKI_log_err ("Network Error while reading Request!");
		return NULL;
	};

	/* If method is METHOD_GET we shall de-urlify the buffer and get the
	   right begin (keep in mind there might be a path set in the config */

	if( http_msg->method == PKI_HTTP_METHOD_GET )
	{
		char *req_pnt = NULL;

		if (http_msg->path == NULL)
		{
			PKI_log_err("Malformed GET request");
			goto err;
		}

		req_pnt = http_msg->path;
		while(strchr(req_pnt, '/') != NULL)
		{
			req_pnt = strchr(req_pnt, '/') + 1;
		}

		pathmem = PKI_MEM_new_data(strlen(req_pnt), (unsigned char *) req_pnt);
		if (pathmem == NULL)
		{
			PKI_log_err("Memory Allocation Error!");
			goto err;
		}

		if((b64mem = PKI_MEM_url_decode (pathmem, 0)) == NULL)
		{
			PKI_log_err("Memory Allocation Error!");
			PKI_MEM_free(pathmem);
			pathmem = NULL; // Safety
			goto err;
		}

		if (PKI_MEM_B64_decode(b64mem, 76) == PKI_ERR )
		{
			PKI_log_err ("Error decoding B64 Mem");
			PKI_MEM_free ( b64mem );
			b64mem = NULL;
			req_pnt = http_msg->path;
			while(req_pnt[0] == '/')
			{
				req_pnt=req_pnt + 1;
			}
			b64mem = PKI_MEM_new_data(strlen(req_pnt), (unsigned char *) req_pnt);
			if (b64mem == NULL)
			{
				PKI_log_err("Memory Allocation Error!");
				goto err;
			}
			if (PKI_MEM_B64_decode(b64mem, 76) == PKI_ERR )
			{
				PKI_log_err ("Error decoding B64 Mem");
				PKI_MEM_free ( b64mem );
				goto err;
			}
		}

		if((mem = BIO_new_mem_buf(b64mem->data, (int) b64mem->size )) == NULL)
		{
			PKI_log_err("Memory Allocation Error");
			PKI_MEM_free ( b64mem );
			goto err;
		}

		if((req_val = d2i_OCSP_REQ_bio(mem, NULL)) == NULL ) {
				PKI_log_err("Can not parse REQ");
		}

		PKI_MEM_free ( b64mem );
		BIO_free (mem);

	}
	else if ( http_msg->method == PKI_HTTP_METHOD_POST)
	{
		mem = BIO_new_mem_buf(http_msg->body->data, (int) http_msg->body->size);
		if (mem == NULL)
		{
			PKI_log_err( "Memory Allocation Error");
			goto err;
		}
		else
		{
			if ((req_val = d2i_OCSP_REQ_bio(mem, NULL)) == NULL)
			{
				PKI_log_err("Can not parse REQ");
			}
			BIO_free (mem);
		}
	}
	else
	{
		PKI_log_err ( "HTTP Method not supported");
		goto err;
	}

	if ( !req_val ) goto err;

	req = PKI_X509_new_value(PKI_DATATYPE_X509_OCSP_REQ, req_val, NULL);
	if (req == NULL)
	{
		PKI_log_err ("Can not generate a new X509_OCSP_REQ");
		goto err;
	}

	if ( http_msg ) PKI_HTTP_free ( http_msg );

	return (req);

err:
	if (http_msg) PKI_HTTP_free(http_msg);

	return NULL;
}