Example #1
0
/* FIXME: In Blackjack this function should become generally available. */
void format_current_error_for_user(kstr *dest) {
    struct kerror *error_instance = kerror_get_current();
    int i;
    
    kstr_reset(dest);

    if (error_instance->stack.size == 0) {
        kstr_assign_cstr(dest, "unknown error");
    }
    
    else {
	for (i = error_instance->stack.size - 1; i >= 0; i--) {
	    struct kerror_node *node = (struct kerror_node *) karray_get(&error_instance->stack, i);
            /* Level 1 error are meant to be readable. */	    
            if (node->level >= 1) {
                if (i != error_instance->stack.size - 1) {
                    kstr_append_cstr(dest, ": ");
                }
            
                    kstr_append_kstr(dest, &node->text);
            }
	}
    }

    if (dest->slen == 0) 
        kstr_assign_cstr(dest, "unknown error");
}
Example #2
0
kstr *kdclient_format_error(const char *file, int line, const char *msg, va_list va) {
    char *p;
    kstr *err_msg, *err;
    kstr err_fmt;
    
    /* Search for @ */  
    p = strstr(msg, "@");
    if (p) {
        kstr_init_buf(&err_fmt, msg, p - msg);
        err_msg = kerror_str_n(0);        
        kstr_append_kstr(&err_fmt, err_msg);
        kstr_destroy(err_msg);
        kstr_append_cstr(&err_fmt, p + 1);
    } 
    else kstr_init_cstr(&err_fmt, msg);
    
    err = kmalloc(sizeof(kstr)); 
    kstr_init_sfv(err, err_fmt.data, va);  
    
    /* Add [file:line] before error message. */
    kstr_sf(&err_fmt, "[%s:%d] %s", file, line, err->data);
    kstr_assign_kstr(err, &err_fmt);
    
    kstr_clean(&err_fmt);

    return err;
}
Example #3
0
static void test_kstr() {
    kstr str1, str2, str3;
    kstr_init(&str1);
    kstr_init_cstr(&str2, "bar");
    kstr_init_kstr(&str3, &str2);

    assert(kstr_equal_cstr(&str2, "bar"));
    assert(kstr_equal_kstr(&str2, &str3));

    kstr_assign_cstr(&str3, "foobar");
    kstr_assign_kstr(&str1, &str3);
    kstr_sf(&str2, "%sbar", "foo");
    
    assert(kstr_equal_kstr(&str3, &str2));
    assert(kstr_equal_kstr(&str1, &str2));

    kstr_sf(&str2, "%s buffer to grow", "I want my");
    assert(kstr_equal_cstr(&str2, "I want my buffer to grow"));

    kstr_clear(&str2);
    assert(kstr_equal_cstr(&str2, ""));
    
    kstr_append_char(&str2, 'f');
    kstr_append_char(&str2, 'o');
    kstr_assign_cstr(&str1, "ob");
    kstr_append_kstr(&str2, &str1);
    kstr_append_cstr(&str2, "ar");
    assert(kstr_equal_cstr(&str2, "foobar"));

    kstr_free(&str1);
    kstr_free(&str2);
    kstr_free(&str3);
}
Example #4
0
static void test_knp_msg() {
    kbuffer msg1, msg2;
    kstr str;
    uint32_t i32;
    uint64_t i64;
    
    kbuffer_init(&msg1, 0);
    kbuffer_init(&msg2, 0);
    kstr_init(&str);
    
    knp_msg_write_uint32(&msg1, 3);
    knp_msg_write_uint64(&msg1, 4);
    kstr_append_cstr(&str, "hello");
    knp_msg_write_kstr(&msg1, &str);
    
    kbuffer_write(&msg2, msg1.data, msg1.len);
    assert(! knp_msg_read_uint32(&msg2, &i32) && i32 == 3);
    assert(! knp_msg_read_uint64(&msg2, &i64) && i64 == 4);
    assert(! knp_msg_read_kstr(&msg2, &str) && strcmp(str.data, "hello") == 0);
    assert(knp_msg_read_uint32(&msg2, &i32));
    
    kbuffer_clean(&msg1);
    kbuffer_clean(&msg2);
    kstr_free(&str);
}
Example #5
0
/** Converts a DNS name to a domain DN.
 * 
 * Example: AD.LOCAL => DC=AD,DC=LOCAL.
 *
 * This is very much AD specific.  It won't work for Lotus Domino DNs.
 */
char *kdldap_DNS_to_dn(apr_pool_t *pool, const char *dns_dom) {
    kstr r;
    const char *s = dns_dom;
    char *dn;
    
    kstr_init_cstr(&r, "DC=");
    
    while (*s) {
        if (*s == '.') kstr_append_cstr(&r, ",DC=");
        else kstr_append_char(&r, *s);
        s++;
    }
    
    dn = apr_pstrdup(pool, r.data);
    kstr_clean(&r);
    
    return dn;
}
Example #6
0
File: kstr.c Project: miraeye/f265
/* Replace all occurences of the string 'from' with the string 'to' in the
 * string specified.
 */
void kstr_replace(kstr *self, char *from, char *to) {
    kstr tmp;
    int i = 0;
    int l = strlen(from);
    
    assert(l);
    kstr_init(&tmp);
    
    while (i < self->slen) {
        if (! strncmp(self->data + i, from, l)) {
            kstr_append_cstr(&tmp, to);
            i += l;
        }
        
        else {
            kstr_append_char(&tmp, self->data[i]);
            i++;
        }
    }
    
    kstr_assign_kstr(self, &tmp);
    kstr_clean(&tmp);
}
Example #7
0
/* This function negociates a SSL session with the server.
 * This function sets the KMO error string. It returns 0, -1, -2, or -3.
 */ 
static int knp_negociate_ssl_session(struct knp_query *query, char *cert, k3p_proto *k3p) {
    int error = 0;
    SSL_METHOD *ssl_method;
    BIO *ssl_bio;
    
    kmod_log_msg(3, "knp_negociate_ssl_session() called.\n");
    
    /* Create the SSL driver. */
    struct knp_ssl_driver *driver = (struct knp_ssl_driver *) kmo_calloc(sizeof(struct knp_ssl_driver));
    assert(query->ssl_driver == NULL);
    query->ssl_driver = driver;
    
    ssl_method = SSLv3_client_method();
    if (ssl_method == NULL) {
    	kmo_seterror("cannot initialize SSL method");
	return -1;
    }
    
    driver->ssl_ctx = SSL_CTX_new(ssl_method);
    if (driver->ssl_ctx == NULL) {
    	kmo_seterror("cannot initialize SSL context");
	return -1;
    }

    driver->ssl = SSL_new(driver->ssl_ctx);
    if (driver->ssl == NULL) {
    	kmo_seterror("cannot initialize SSL session");
	return -1;
    }

    ssl_bio = BIO_new_socket(query->transfer.fd, BIO_NOCLOSE);
    if (ssl_bio == NULL) {
    	kmo_seterror("cannot initialize SSL BIO");
	return -1;
    }
    
    /* Set SSL BIO. 'ssl_bio' is owned by 'ssl', do not free. */
    SSL_set_bio(driver->ssl, ssl_bio, ssl_bio);
    
    /* If we have a certificate, set it in SSL. */
    if (cert) {
    	int i;
	BIO *cert_bio = NULL;
	X509 *cert_obj = NULL;
	X509_STORE *cert_store = NULL;
	X509_OBJECT x509_obj;
	kstr cert_buf;
	kstr_init(&cert_buf);

	/* Try. */
	do {
	    /* Recreate the certificate. */
	    kstr_append_cstr(&cert_buf, "-----BEGIN CERTIFICATE-----\n");
	    kstr_append_cstr(&cert_buf, cert);
	    kstr_append_cstr(&cert_buf, "-----END CERTIFICATE-----\n");

	    for (i = 0; i < cert_buf.slen; i++) {
		if (cert_buf.data[i] == '|') {
		    cert_buf.data[i] = '\n';
		}
	    }

	    /* Put the certificate text in a buffer. */
	    cert_bio = BIO_new_mem_buf(cert_buf.data, cert_buf.slen);

	    if (cert_bio == NULL) {
		kmo_seterror("cannot create SSL BIO for reading SSL certificate");
		error = -1;
		break;   
	    }

	    /* Create the certificate object with the buffer data. */
	    cert_obj = PEM_read_bio_X509(cert_bio, NULL, 0, NULL);

	    if (cert_obj == NULL) {
		kmo_seterror("cannot create SSL certificate");
		error = -1;
		break;
	    }

	    /* Add the certificate in the certificate store if it is not
	     * already present.
	     */

	    /* Get the certificate store. */
	    cert_store = SSL_CTX_get_cert_store(driver->ssl_ctx);

	    if (cert_store == NULL) {
		kmo_seterror("cannot get SSL certificate store");
		error = -1;
		break;
	    }

	    /* Understanding SSL's API is a daunting task. I've peeked at
	     * the source code and that code should work. For now. Sigh.
	     * Wouldn't it be nice if programmers bothered to make
	     * *library* APIs that are somewhat sane...
	     *
	     * Check if the certificate is already in the store.
	     */
	    x509_obj.type = X509_LU_X509;
	    x509_obj.data.x509 = cert_obj;

	    /* It seems the certificate is already in the store. */
	    if (X509_OBJECT_retrieve_match(cert_store->objs, &x509_obj)) {
		/* Void. */
	    }

	    /* Add the certificate in the store. We still own cert_obj after
	     * this call.
	     */
	    else if (X509_STORE_add_cert(cert_store, cert_obj) != 1) {
		kmo_seterror("cannot store SSL certificate");
		error = -1;
		break;
	    }

    	} while (0);

	if (cert_obj) X509_free(cert_obj);
	if (cert_bio) BIO_free(cert_bio);
	kstr_free(&cert_buf);
	
	if (error) return error;
    }

    /* If we need a certificate, require the server to send us its certificate. */
    SSL_set_verify(driver->ssl, cert ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);

    /* Loop until we connect or fail. */
    while (1) {
	error = SSL_connect(driver->ssl);

	/* We're connected. */
	if (error > 0) {
	    error = 0;
	    break;
	}

	else {
	    int ssl_error = SSL_get_error(driver->ssl, error);
	    error = 0;

	    /* SSL wants us to wait for reading data. */
	    if (ssl_error == SSL_ERROR_WANT_READ) {
	    	error = knp_query_wait_for_data(query, 1, "SSL negociation read failed", k3p);
		if (error) return error;
	    }

	    /* SSL wants us to wait for writing data. */
	    else if (ssl_error == SSL_ERROR_WANT_WRITE) {
		error = knp_query_wait_for_data(query, 0, "SSL negociation write failed", k3p);
		if (error) return error;
	    }

	    /* Life is tough. */
	    else {
		kmo_seterror("SSL negociation failed: %s", get_ssl_error_string(ssl_error));
        	return -1;
	    }
	}
    }

    /* Validate the server's certificate as needed. */
    if (cert) {

	/* Check if the server sent us a certificate. */
	X509 *peer_cert = SSL_get_peer_certificate(driver->ssl);

	if (peer_cert == NULL) {
	    kmo_seterror("the server did not send its SSL certificate");
	    return -1;
	}

	X509_free(peer_cert);

	/* Verify the certificate. */
	if (SSL_get_verify_result(driver->ssl) != X509_V_OK) {
	    kmo_seterror("the SSL certificate of the server is invalid");
	    return -1;
	}
    }
    
    return 0;
}
Example #8
0
/* This function asks the proxy to connect us to the end server.
 * This function sets the KMO error string. It returns 0, -1, -2 or -3.
 */
static int knp_handle_proxy(struct knp_query *query, k3p_proto *k3p, kstr *proxy_login, kstr *proxy_pwd) {
    int error = 0;
    int first_line = 1;
    struct kmo_data_transfer *transfer = &query->transfer;
    kstr msg;
    kstr str;
    
    kmod_log_msg(3, "knp_handle_proxy() called.\n");
    
    kstr_init(&msg);
    kstr_init(&str);
	
    /* Try. */
    do {
	/* Connect to the specified server and port. */
	kstr_sf(&msg, "CONNECT %s:%d HTTP/1.0\r\n", query->server_addr.data, query->server_port);
    	
	/* Using the following "user:pwd" credentials encoded in base 64. */
	if (proxy_login->slen > 0 || proxy_pwd->slen > 0) {
	    kbuffer in, out;
	    kbuffer_init(&in, 100);
	    kbuffer_init(&out, 100);
	    
	    kbuffer_write(&in, proxy_login->data, proxy_login->slen);
	    kbuffer_write(&in, ":", 1);
	    kbuffer_write(&in, proxy_pwd->data, proxy_pwd->slen);
	    bin2b64(&in, &out);
	    
	    kstr_append_cstr(&msg, "Proxy-Authorization: basic ");
	    kstr_append_buf(&msg, out.data, out.len);
	    kstr_append_cstr(&msg, "\r\n");
	    
	    kbuffer_clean(&in);
	    kbuffer_clean(&out);
	}
	
	/* An empty line marks the end of the request. */
	kstr_append_cstr(&msg, "\r\n");
	
	/* Send the message to the proxy. */
	transfer->read_flag = 0;
	transfer->buf = msg.data;
	transfer->min_len = transfer->max_len = msg.slen;
	error = knp_exec_transfer(transfer, k3p);
	if (error) break;
	
	if (transfer->status != KMO_COMM_TRANS_COMPLETED) {
	    assert(transfer->status == KMO_COMM_TRANS_ERROR);
	    kmo_seterror("proxy error: %s", kmo_data_transfer_err(transfer));
	    knp_query_handle_conn_error(query, transfer->err_msg ? KMO_SERROR_MISC : KMO_SERROR_TIMEOUT);
	    error = -1;
	    break;
	}
    
    	/* Receive the reply from the server, char by char to avoid reading past 
	 * the HTTP reply data.
	 */
	kstr_clear(&msg);
	
	while (1) {
	    char c;
	    transfer->read_flag = 1;
	    transfer->buf = &c;
	    transfer->min_len = transfer->max_len = 1;
	    error = knp_exec_transfer(transfer, k3p);
	    if (error) break;

	    if (transfer->status != KMO_COMM_TRANS_COMPLETED) {
		assert(transfer->status == KMO_COMM_TRANS_ERROR);
		kmo_seterror("proxy error: %s", kmo_data_transfer_err(transfer));
		knp_query_handle_conn_error(query, transfer->err_msg ? KMO_SERROR_MISC : KMO_SERROR_TIMEOUT);
		error = -1;
		break;
	    }
	    
	    kstr_append_char(&msg, c);
	    
	    /* We reached the end of a line. */
	    if (msg.slen >= 2 && msg.data[msg.slen - 2] == '\r' && msg.data[msg.slen - 1] == '\n') {
	    	
		/* This is the response line. Parse it. */
		if (first_line) {
		    int reply_code;
		    
		    /* Expecting "HTTP/x.x ddd <string>\r\n" */
		    if (msg.slen < 16 || msg.data[0] != 'H' || msg.data[1] != 'T' || msg.data[2] != 'T' ||
		        msg.data[3] != 'P' || ! is_digit(msg.data[9]) || ! is_digit(msg.data[10]) ||
			! is_digit(msg.data[11])) {
			
		    	kmo_seterror("invalid proxy HTTP reply");
		    	error = -1;
			break;
		    }
		    
		    /* Get the numeric code. */
		    reply_code = atoi(msg.data + 9);
		    
		    /* Not 200, it didn't work. */
		    if (reply_code != 200) {
		    	
		    	/* Get the reason. */
		    	kstr_assign_buf(&str, msg.data + 13, msg.slen - 2 - 13);
			kmo_seterror("the proxy refuses to connect: %s (code %d)", str.data, reply_code);
			error = -1;
			break;
		    }
		    
		    first_line = 0;
		}
		
		/* The server is sending us some unwanted line. Ignore it. */
		else if (msg.slen != 2) {
		    /* Void. */
		}
		
		/* We reached the end of the reply. The next bytes received will be SSL bytes. */
		else {
		    break;
		}
		
		/* Clear the line buffer. */
	    	kstr_clear(&msg);
	    }
	    
	    /* It's too long. */
	    else if (msg.slen > 1000) {
	    	kmo_seterror("HTTP reply too long");
    	    	error = -1;
		break;
	    }
	}
	
	if (error) break;
    
    } while (0);
    
    kstr_free(&msg);
    kstr_free(&str);
    
    return error;
}
Example #9
0
/* This function dumps the content of a KNP message buffer in the string
 * specified. This function sets the KMO error string when it encounters an
 * error in the buffer. It returns -1 on failure.
 */
int knp_msg_dump(char *buf, int buf_len, kstr *dump_str) {
    
    int error = 0;
    int pos = 0;
    uint32_t u32;
    uint64_t u64;
    kstr work_str;
    
    kstr_init(&work_str);
    kstr_clear(dump_str);

    while (pos < buf_len) {
    	
	uint8_t type = buf[pos];
    	pos++;
	
	if (type == KNP_UINT32) {
	    if (pos + 4 > buf_len) {
	    	kmo_seterror("uint32 specified but not included");
		error = -1;
		break;
	    }
	    
	    memcpy(&u32, buf + pos, 4);
	    kstr_sf(&work_str, "uint32> %u\n", ntohl(u32));
	    kstr_append_kstr(dump_str, &work_str);
	    pos += 4;
	}
	
	else if (type == KNP_UINT64) {
	    if (pos + 8 > buf_len) {
	    	kmo_seterror("uint64 specified but not included");
		error = -1;
		break;
	    }
	    
	    memcpy(&u64, buf + pos, 8);
	    kstr_sf(&work_str, "uint64> %llu\n", ntohll(u64));
	    kstr_append_kstr(dump_str, &work_str);
	    pos += 8;
	}
	
	else if (type == KNP_STR) {
	    if (pos + 4 > buf_len) {
	    	kmo_seterror("string specified but not included");
		error = -1;
		break;
	    }
	
	    memcpy(&u32, buf + pos, 4);
	    pos += 4;
	    u32 = ntohl(u32);
	    
	    if (pos + u32 > (uint32_t) buf_len) {
	    	kmo_seterror("string specified but not included");
		error = -1;
		break;
	    }
	    
	    kstr_sf(&work_str, "string %u> ", u32);
	    kstr_append_kstr(dump_str, &work_str);
	    kstr_append_buf(dump_str, buf + pos, u32);
	    kstr_append_cstr(dump_str, "\n");
	    pos += u32;
	}
	
	else {
	    kmo_seterror("invalid KNP identifier (%u)", type);
	    error = -1;
	    break;
	}
    }
    
    kstr_free(&work_str);
    return error;
}
Example #10
0
/* This function creates a mail_eval_res entry.
 * This function sets the KMO error string. It returns -1 on failure.
 */
static int create_mail_eval_res(sqlite3 *db, maildb_mail_info *mail_info, int64_t *entry_id) {
    sqlite3_stmt *stmt = NULL;
    kstr insert_str;
    int i;

    assert(*entry_id >= 0);
    
    /* Create the mail_eval_res entry. */
    kstr_init_cstr(&insert_str, "INSERT INTO mail_eval_res3 (");

    /* If entry_id is not 0, then we must specify the entry_id in the INSERT. */
    if (*entry_id != 0) {
    	kstr_append_cstr(&insert_str, "entry_id, ");
    }

    kstr_append_cstr(&insert_str,
		     "hash, ksn, status, display_pref, sig_msg, mid, original_packaging, mua, field_status, "
		     "att_plugin_nbr, attachment_nbr, attachment_status, sym_key, encryption_status, "
		     "decryption_error_msg, pod_status, pod_msg, otut_status, otut_string, "
		     "otut_msg, kpg_addr, kpg_port) "
		     "VALUES (");

    if (*entry_id != 0) {
    	kstr_append_cstr(&insert_str, "?, ");
    }

    kstr_append_cstr(&insert_str, "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);");
    if (sqlite3_prepare(db, insert_str.data, -1, &stmt, NULL)) goto ERR;
    
    i = 1;
    
    if (*entry_id != 0) {
    	if (sqlite3_bind_int64(stmt, i++, *entry_id)) goto ERR;
    }
    
    if (write_blob(stmt, i++, &mail_info->hash)) goto ERR;
    if (write_blob(stmt, i++, &mail_info->ksn)) goto ERR;
    if (sqlite3_bind_int(stmt, i++, mail_info->status)) goto ERR;
    
    if (sqlite3_bind_int(stmt, i++, mail_info->display_pref)) goto ERR;
    if (write_string(stmt, i++, &mail_info->sig_msg)) goto ERR;
    if (sqlite3_bind_int64(stmt, i++, mail_info->mid)) goto ERR;
    if (sqlite3_bind_int(stmt, i++, mail_info->original_packaging)) goto ERR;
    if (sqlite3_bind_int(stmt, i++, mail_info->mua)) goto ERR;

    if (sqlite3_bind_int(stmt, i++, mail_info->field_status)) goto ERR;
    if (sqlite3_bind_int(stmt, i++, mail_info->att_plugin_nbr)) goto ERR;
    if (sqlite3_bind_int(stmt, i++, mail_info->attachment_nbr)) goto ERR;
    if (write_blob(stmt, i++, &mail_info->attachment_status)) goto ERR;

    if (write_blob(stmt, i++, &mail_info->sym_key)) goto ERR;

    if (sqlite3_bind_int(stmt, i++, mail_info->encryption_status)) goto ERR;
    if (write_string(stmt, i++, &mail_info->decryption_error_msg)) goto ERR;
    if (sqlite3_bind_int(stmt, i++, mail_info->pod_status)) goto ERR;
    if (write_string(stmt, i++, &mail_info->pod_msg)) goto ERR;

    if (sqlite3_bind_int(stmt, i++, mail_info->otut_status)) goto ERR;
    if (write_blob(stmt, i++, &mail_info->otut_string)) goto ERR;
    if (write_string(stmt, i++, &mail_info->otut_msg)) goto ERR;
    if (write_string(stmt, i++, &mail_info->kpg_addr)) goto ERR;
    if (sqlite3_bind_int(stmt, i++, mail_info->kpg_port)) goto ERR;
    
    if (sqlite3_step(stmt) != SQLITE_DONE) goto ERR;
    finalize_stmt(db, &stmt);
    
    /* Obtain/validate the entry ID. */
    if (*entry_id == 0) {
    	*entry_id = sqlite3_last_insert_rowid(db);
    }
    
    else {
    	assert(*entry_id == sqlite3_last_insert_rowid(db));
    }
    
    kstr_free(&insert_str);
    return 0;
    
ERR:
    kmo_seterror(sqlite3_errmsg(db));
    finalize_stmt(db, &stmt);
    kstr_free(&insert_str);
    return -1;
}
Example #11
0
File: anp.c Project: fdgonthier/kas
/* This function dumps the content of a ANP message buffer in the string
 * specified. This function sets the KMOD error string when it encounters an
 * error in the buffer. It returns -1 on failure.
 */
int anp_dump(kbuffer *buf, kstr *dump_str) {
    int error = 0;
    kstr work_str;
    kstr data_str;
    kbuffer bin_buf;
    
    kstr_init(&work_str);
    kstr_init(&data_str);
    kbuffer_init(&bin_buf);
    kstr_reset(dump_str);

    while (! kbuffer_eof(buf)) {
	uint8_t type = buf->data[buf->pos];
	
	if (type == ANP_UINT32) {
	    uint32_t val;
	    error = anp_read_uint32(buf, &val);
	    if (error) break;
	    
	    kstr_sf(&work_str, "uint32> %u\n", val);
	    kstr_append_kstr(dump_str, &work_str);
	}
	
	else if (type == ANP_UINT64) {
	    uint64_t val;
	    error = anp_read_uint64(buf, &val);
	    if (error) break;
	    
	    kstr_sf(&work_str, "uint64> "PRINTF_64"u\n", val);
	    kstr_append_kstr(dump_str, &work_str);
	}
	
	else if (type == ANP_STR) {
	    error = anp_read_kstr(buf, &data_str);
	    if (error) break;
	
	    kstr_sf(&work_str, "string %u> ", data_str.slen);
	    kstr_append_kstr(dump_str, &work_str);
	    kstr_append_kstr(dump_str, &data_str);
	    kstr_append_cstr(dump_str, "\n");
	}
	
	else if (type == ANP_BIN) {
	    error = anp_read_bin(buf, &bin_buf);
	    if (error) break;
	
	    kstr_sf(&work_str, "binary %u> ", bin_buf.len);
	    kstr_append_kstr(dump_str, &work_str);
	    kstr_append_cstr(dump_str, "\n");
	}
	
	else {
	    kmod_set_error("invalid ANP identifier (%u)\n", type);
	    error = -1;
	    break;
	}
    }
    
    kstr_clean(&work_str);
    kstr_clean(&data_str);
    kbuffer_clean(&bin_buf);
    
    /* Reset the buffer position to 0. */
    buf->pos = 0;
    
    return error;
}