Exemple #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;
}
Exemple #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;
};
Exemple #3
0
PKI_MEM_STACK *URL_get_data_pkcs11_url ( URL *url, ssize_t size ) {

#ifdef HAVE_P11
	// PKCS11_CTX   *ctx   = NULL;
	PKCS11_SLOT  *slots = NULL;
	PKCS11_TOKEN *tk    = NULL;

	char *libfile = NULL;
	int num = 0;
	int i = 0;

	char * search_label = NULL;
	char * search_id = NULL;
	char * search_slot = NULL;
	char * search_slotid = NULL;

	PKI_MEM *tmp_mem = NULL;
	PKI_MEM_STACK *sk = NULL;

	if( !url ) return (NULL);

	/*
	if((libfile = pkcs11_parse_url_libpath ( url )) == NULL ) {
		return( NULL );
	}
	*/

	/*
	slot = pkcs11_parse_url_slot ( url );
	id = pkcs11_parse_url_id ( url );
	*/

	if( ctx == NULL ) {
		if((ctx = PKCS11_CTX_new ()) == NULL ) {
			return(NULL);
		}

		PKI_log_debug("Loading %s Library", url->addr );
		if(( i = PKCS11_CTX_load(ctx, url->addr)) != 0 ) {
			PKI_log_err("Can not load library %s [err::%d]", url->addr, i);
			// ERR_print_errors_fp( stderr );
		}
	}

	if( PKCS11_enumerate_slots( ctx, &slots, &num ) == -1 ) {
		PKI_log_err ("Can not enumerate slots");
		goto err;
        };

	if(( sk = PKI_STACK_MEM_new()) == NULL ) {
		goto err;
	}

	search_slot   = pkcs11_parse_url_getval( url, "slot" );
	search_slotid = pkcs11_parse_url_getval( url, "slotid" );
	search_label  = pkcs11_parse_url_getval( url, "label" );
	search_id     = pkcs11_parse_url_getval( url, "id" );
	
	if( search_slot )
		PKI_log_debug("DEBUG::PKCS11::SEARCH::SLOT =>  %s\n", search_slot);
	if( search_slotid )
		PKI_log_debug("DEBUG::PKCS11::SEARCH::SLOTID =>  %s\n", search_slotid);
	if( search_label )
		PKI_log_debug("DEBUG::PKCS11::SEARCH::LABEL => %s\n", search_label);
	if( search_id )
		PKI_log_debug("DEBUG::PKCS11::SEARCH::ID =>    %s\n", search_id);

	for(i = 0; i < num; i++ ) {

		BIO *mem = NULL;
		BUF_MEM *mem_buf = NULL;

		PKCS11_CERT *certs = NULL;
		PKCS11_SLOT *p = NULL;
		PKCS11_CERT *x = NULL;

		PKCS11_KEY  *keyList = NULL;
		PKCS11_KEY  *key     = NULL;
		EVP_PKEY    *evp_pkey = NULL;

		int n = 0;
		int t = 0;
		int n_objs = 0;
		int p_ret = 0;
		
                p = &slots[i];

                if((!p) || ((tk = p->token) == NULL) ) {
			continue;
		}

		if( (search_slot) && ( strncmp_nocase( search_slot, 
				tk->label, strlen(search_slot) == 0) )) {
			continue;
		}

		if( (search_slotid) && ( atoi(search_slotid) != i )) {
			PKI_log_debug("PKCS11::SLOTID is %s (%d), curr is %d\n",
					search_slotid, atoi(search_slotid), i);
			continue;
		}

		if( strncmp_nocase( url->attrs, "cert", 4 ) == 0) {
			PKI_log_debug("PKCS11::CERT DATATYPE SELECTED!\n");
			if((mem = BIO_new(BIO_s_mem())) == NULL ) {
				goto err;
			}

			/* Get the list of certificates in the slot */
			p_ret = PKCS11_enumerate_certs( tk, &certs, &n_objs);

			for( n = 0; n < n_objs; n++ ) {

				/* Pointer to the current certificate */
				x = &certs[n];

				PKI_log_debug("PKCS11::CERT label=%s\n",
					x->label);
				PKI_log_debug("PKCS11::CERT id=");
				for( t = 0; t < x->id_len; t ++ ) {
					printf("%c", x->id[t] );
				} printf("\n");

				if( (search_label) &&
					(strncmp_nocase( search_label, x->label,
						strlen( search_label)) != 0 )){
					PKI_log_debug("PKCS11::LABEL does not"
						"match, SKIPPING!!!!\n");
					continue;
				}
 
				if( search_id ) {
					int stop = 0;

					for( t = 0; t < x->id_len; t ++ ) {
						if( search_id[t] != x->id[t] ) {
							stop = 1;
							break;
						}
					}

					if( stop == 1 ) { 
					printf("DEBUG::PKCS11::ID does not"
						"match, SKIPPING!!!!\n");
						continue;
					}
				}
 
				/* Write the cert in PEM format to memory */
				p_ret = PEM_write_bio_X509( mem, x->x509 );

				/* Get the pointer to the memory buffer */
				BIO_get_mem_ptr( mem, &mem_buf );

				/* Push a PKI_MEM buffer on the stack */
				tmp_mem = PKI_MEM_new_null();
				PKI_MEM_add ( tmp_mem, mem_buf->data, 
							mem_buf->length);
				PKI_STACK_push( sk, tmp_mem );
			}

			/* Free the temp memory buffer */
			if( mem ) BIO_free( mem );

		} else if (strncmp_nocase( url->attrs, "key", 3) == 0 ) {
			char *pin = NULL;

			PKI_log_debug("PKCS11::KEY DATATYPE SELECTED!\n");

			pin = pkcs11_parse_url_getval( url, "pin" );

			if ( (tk->loginRequired == 1) && (pin != NULL ) ) {
				p_ret = PKCS11_login ( p, 0, pin );
				PKI_log_debug("PKCS11::LOGIN Result %d\n",
					p_ret );
        		}

			if((mem = BIO_new(BIO_s_mem())) == NULL ) {
				goto err;
			}

		        p_ret = PKCS11_enumerate_keys ( tk, &keyList, &n_objs );

			for( n = 0; n < n_objs; n++ ) {
				key = &keyList[n];

				printf("DEBUG::PKCS11::KEY label=%s\n",
					key->label);
				printf("DEBUG::PKCS11::KEY id=");
				for( t = 0; t < key->id_len; t ++ ) {
					printf("%c", key->id[t] );
				} printf("\n");

				if( (search_label) &&
					(strncmp_nocase( search_label, x->label,
						strlen( search_label)) != 0 )){
					printf("DEBUG::PKCS11::LABEL does not"
						"match, SKIPPING!!!!\n");
					continue;
				}
 
				if( search_id ) {
					int stop = 0;

					for( t = 0; t < x->id_len; t ++ ) {
						if( search_id[t] != x->id[t] ) {
							stop = 1;
							break;
						}
					}

					if( stop == 1 ) { 
					printf("DEBUG::PKCS11::ID does not"
						"match, SKIPPING!!!!\n");
						continue;
					}
				}
 
				/* Get Private Key in OpenSSL format */
				evp_pkey = PKCS11_get_private_key( key );

				/* Write the cert in PEM format to memory */
				p_ret = PEM_write_bio_PUBKEY( mem, evp_pkey );

				/* Get the pointer to the memory buffer */
				BIO_get_mem_ptr( mem, &mem_buf );

				/* Push a PKI_MEM buffer on the stack */
				tmp_mem = PKI_MEM_new_null();
				PKI_MEM_add ( tmp_mem, mem_buf->data, 
							mem_buf->length);
				PKI_STACK_push( sk, tmp_mem );
			}

			if( mem ) BIO_free ( mem );

		} else {
			printf("DEBUG::PKCS11::OTHER DATATYPE SELECTED!\n");
		}
	}

err:
	if( slots ) PKCS11_release_all_slots( ctx, slots, num );

	/*
	if( ctx ) { 
		PKCS11_CTX_unload(ctx);
		PKCS11_CTX_free(ctx);
	}
	*/

	if( libfile ) PKI_Free (libfile);

	if( search_slot ) PKI_Free ( search_slot );
	if( search_slotid ) PKI_Free ( search_slotid );
	if( search_label ) PKI_Free ( search_label );
	if( search_id ) PKI_Free ( search_id );

	return ( sk );

#else
	return ( NULL );
#endif
}
Exemple #4
0
PKI_MEM_STACK *URL_get_data_mysql_url ( const URL *url, ssize_t size ) {

#ifdef HAVE_MYSQL
	MYSQL_ROW row;
	MYSQL * sql = NULL;
	MYSQL_FIELD *fields = NULL;
	MYSQL_RES *res = NULL;

	unsigned long *lengths = NULL;
	long long n_rows = 0;
	int n_fields = 0;

	PKI_MEM *tmp_mem = NULL;
	PKI_MEM_STACK *sk = NULL;

	char * query = NULL;

	if( !url ) return (NULL);

	if((sql = db_connect ( url )) == NULL )
	{
		return NULL;
	}

	if ((query = parse_url_query(url)) == NULL)
	{
		PKI_log_err("Can not parse URL query");
		goto end;
	}
	else mysql_query(sql, query);

	/* Get the Data */
	if((res = mysql_store_result( sql )) == NULL)
	{
		PKI_log_err("Can not retrieve SQL data");
		goto end;
	}

	if( ((n_rows = (long long) mysql_num_rows( res )) < 1 ) || 
			((sk = PKI_STACK_MEM_new()) == NULL))
	{
		PKI_log_err("No returned rows found");
		goto end;
	}

	while((row = mysql_fetch_row(res)) != NULL )
	{
		/* Count the number of fields retrieved */
		n_fields = (int) mysql_num_fields( res );
		lengths = mysql_fetch_lengths( res );
		fields = mysql_fetch_fields( res );
		if (!fields)
		{
			PKI_ERROR(PKI_ERR_GENERAL, "can not fetch query fields");
			break;
		}

		if (n_fields > 0)
		{
			tmp_mem = PKI_MEM_new_null();
			if (size == 0 || (( size > 0 ) && ( lengths[0] < size)))
			{
				PKI_MEM_add(tmp_mem,row[0],lengths[0]);

				/* For now, let's only deal with one 
				   field at the time */
				PKI_STACK_push( sk, tmp_mem );
			}
		}
	}

end:

	if (query) PKI_Free (query);
	db_close ( sql );

	return ( sk );

#else
	return ( NULL );
#endif
}