Ejemplo n.º 1
0
/* This function normalizes a path. It simplifies the directory portion and
 * makes the path absolute if requested.
 */
void kpath_normalize(kstr *path, int absolute_flag, int format) {
    struct kpath_dir dir;
    kstr dir_path, filename, ext;
    
    kstr_init(&dir_path);
    kstr_init(&filename);
    kstr_init(&ext);
    kpath_dir_init(&dir);
    
    /* If requested, make the path absolute. */
    if (absolute_flag) kpath_make_absolute(path, format);
    
    /* Split the path. */
    kpath_split(path, &dir_path, &filename, &ext, format);
    
    /* Decompose, simplify and recompose the directory portion. */
    kpath_decompose_dir(&dir_path, &dir, format);
    kpath_simplify_dir(&dir);
    kpath_recompose_dir(&dir_path, &dir, format);
    
    /* Recompose the path. */
    kstr_assign_kstr(path, &dir_path);
    kstr_append_kstr(path, &filename);
    
    if (ext.slen) {
        kstr_append_char(path, '.');
        kstr_append_kstr(path, &ext);
    }
    
    kpath_dir_clean(&dir);
    kstr_clean(&dir_path);
    kstr_clean(&filename);
    kstr_clean(&ext);
}
Ejemplo n.º 2
0
Archivo: main.c Proyecto: tmbx/kas
/* This function should be called to log a message in the KMOD log.
 * Arguments:
 * Message logging level (1, 2, 3, 4) (higher number is lower priority).
 * Format is the usual printf() format, and the following args are the args that
 *   printf() takes.
 */
void kmod_log_msg(int level, const char *format, ...) {
    va_list arg;
    char date[256];
    kstr str, fmt;
    time_t now;

    if ((level & global_opts.log_level) != level) return;

    va_start(arg, format);

    kstr_init(&fmt);
    kstr_init(&str);

    time(&now);
    strftime(date, 256, "%Y/%m/%d %H:%M:%S", localtime(&now));

    kstr_sf(&fmt, "%s : %s", date, format);
    kstr_sfv(&str, fmt.data, arg);

    fprintf(global_opts.log_file, "%s", str.data);

    va_end(arg);
    kstr_clean(&str);
    kstr_clean(&fmt);
}
Ejemplo n.º 3
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);
}
Ejemplo n.º 4
0
struct kcd_client* kcd_client_new() {
    struct kcd_client *self = (struct kcd_client *) kcalloc(sizeof(struct kcd_client));
    self->sock = -1;
    kstr_init(&self->addr);
    ktls_init(&self->conn);
    return self;
}
Ejemplo n.º 5
0
Archivo: vnc.c Proyecto: fdgonthier/kas
static void kcd_vnc_mode_state_init(struct kcd_vnc_mode_state *self, struct kcd_ticket_mode_state *tms) {
    memset(self, 0, sizeof(struct kcd_vnc_mode_state));
    self->proxy_sock = -1;
    kstr_init(&self->end_error_msg);
    kcd_process_init(&self->process);
    self->tms = tms;
}
Ejemplo n.º 6
0
/* This function verifies the integrity of the database. */
int maildb_integrity_check(maildb *mdb) {
    int error = 0;
    sqlite3 *db = (sqlite3 *) mdb->db;
    sqlite3_stmt *stmt = NULL;
    kstr val;
    
    kstr_init(&val);
    
    do {
	if (sqlite3_prepare(db, "PRAGMA integrity_check;", -1, &stmt, NULL) ||
	    sqlite3_step(stmt) != SQLITE_ROW) {
	    
	    kmo_seterror(sqlite3_errmsg(db));
	    error = -1;
	    break;
	}
	
	read_string(stmt, &val, 0);
	
	if (strcmp(val.data, "ok")) {
	    kmo_seterror("sqlite database is corrupted");
	    error = -1;
	    break;
	}
	
    } while (0);
    
    kstr_free(&val);
    finalize_stmt(db, &stmt);
    return error;
}
Ejemplo n.º 7
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);
}
Ejemplo n.º 8
0
static void test_khash() {
    khash h;
    kstr str;
    char *one = "one";
    int a = 1;
    int nb1 = 3;
    int nb2 = 4;
    int nb3 = 3;
    
    khash_init(&h);
    kstr_init(&str);
    
    khash_set_func(&h, khash_cstr_key, khash_cstr_cmp);
    khash_add(&h, one, &a);
    assert(khash_get(&h, one) == &a);
    kstr_sf(&str, "%c%c%c", 'o', 'n', 'e');
    assert(khash_get(&h, str.data) == &a);

    khash_clear(&h);
    khash_set_func(&h, khash_int_key, khash_int_cmp);
    khash_add(&h, &nb1, &nb1);
    khash_add(&h, &nb2, &nb2);
    assert(khash_get(&h, &nb3) == &nb1);
    
    khash_free(&h);
    kstr_free(&str);
}
Ejemplo n.º 9
0
/* This function logs the content of a message that is sent / received from the
 * network.
 */
static void knp_log_msg(char *side, uint32_t major, uint32_t minor, uint32_t msg_type, kbuffer *payload,
    	    	    	kstr *addr, uint32_t port) {
    assert(knp_log);
    int error = 0;
    kstr dump;

    kstr_init(&dump);
    error = knp_msg_dump(payload->data, payload->len, &dump);

    if (error) {
	fprintf(knp_log, "%s: badly formatted payload: %s.\n", side, kmo_strerror());
	fwrite(payload->data, 1, payload->len, knp_log);
    }

    else {
    	int cat = (msg_type & 0xff00) >> 8;
	int id = msg_type & 0xff;
    
	fprintf(knp_log, "%s version=%u,%u type=%u,%u len=%u address=%s port=%u>\n",
	    	side, major, minor, cat, id, payload->len, addr->data, port);
	fwrite(dump.data, 1, dump.slen, knp_log);
    }

    fprintf(knp_log, "\n");
    kstr_free(&dump);
}
Ejemplo n.º 10
0
Archivo: anp.c Proyecto: fdgonthier/kas
/* Same as anp_dump(), but the header of the message is also dumped. */
int anp_msg_dump(struct anp_msg *self, kstr *dump_str) {
    int error = 0;
    kstr work_str;
    
    kstr_init(&work_str);
    kstr_reset(dump_str);

    kstr_sf(&work_str, "major> %u\n", self->major);
    kstr_append_kstr(dump_str, &work_str);

    kstr_sf(&work_str, "minor> %u\n", self->minor);
    kstr_append_kstr(dump_str, &work_str);

    kstr_sf(&work_str, "type> %u\n", self->minor);
    kstr_append_kstr(dump_str, &work_str);

    kstr_sf(&work_str, "id> "PRINTF_64"u\n", self->minor);
    kstr_append_kstr(dump_str, &work_str);

    if (anp_dump(&self->payload, &work_str)) {
        error = -1;
    } else {
        kstr_append_kstr(dump_str, &work_str);
    }

    kstr_clean(&work_str);
    return error;
}
Ejemplo n.º 11
0
Archivo: kstr.c Proyecto: miraeye/f265
/* This function ensures that the string specified does not get too large. If
 * the internal memory associated to the string is bigger than the threshold
 * specified, the memory associated to the string is released and a new, small
 * buffer is allocated for the string. In all cases, the string is cleared.
 */
void kstr_shrink(kstr *self, int max_size) {
    if (self->slen > max_size) {
    	kstr_clean(self);
	kstr_init(self);
    }
    
    kstr_reset(self);
}
Ejemplo n.º 12
0
/* This function ensures that the string specified does not get too large. If
 * the internal memory associated to the string is bigger than the threshold
 * specified, the memory associated to the string is released and a new, small
 * buffer is allocated for the string. In all cases, the string is cleared
 * ('slen' is set to 0).
 */
void kstr_shrink(kstr *self, int max_size) {
    if (self->slen > max_size) {
    	kstr_free(self);
	kstr_init(self);
    }

    self->slen = 0;
}
Ejemplo n.º 13
0
static void test_util_bin_to_hex() {
    unsigned char in[4] = { 0xaf, 0x00, 0xfa, 0x0d };
    kstr out;
    kstr_init(&out);
    util_bin_to_hex(in, 4, &out);
    assert(kstr_equal_cstr(&out, "af00fa0d"));
    kstr_free(&out);
}
Ejemplo n.º 14
0
Archivo: main.c Proyecto: tmbx/kas
static void kdaemon_init() {
    global_opts.quit_flag = 0;
    global_opts.log_level = KCD_LOG_CRIT;
    global_opts.log_file = stderr;
    global_opts.remote_host = NULL;
    global_opts.local_host = NULL;
    global_opts.second_host = NULL;
    global_opts.remote_port = 0;
    global_opts.second_port = 0;
    global_opts.local_port = 0;
    global_opts.local_first = 0;
    kstr_init(&global_opts.ssl_cert_path);
}
Ejemplo n.º 15
0
/* This function creates and initializes a KNP query.
 * The login OTUT must be set manually if it's needed.
 */
struct knp_query * knp_query_new(int contact, int login_type, int cmd_type, kbuffer *cmd_payload,
                                 kstr *all_req_str) {
    struct knp_query *query = (struct knp_query *) kmo_calloc(sizeof(struct knp_query));
    query->contact = contact;
    kstr_init(&query->server_addr);
    query->login_type = login_type;
    query->cmd_type = cmd_type;
    query->cmd_payload = cmd_payload;
    kmo_data_transfer_init(&query->transfer);
    query->transfer.driver = kmo_sock_driver;
    kstr_assign_kstr(&query->all_req_str, all_req_str);

    return query;
}
Ejemplo n.º 16
0
/* This function converts a path to an absolute path, if needed. */
void kpath_make_absolute(kstr *path, int format) {
    kstr tmp;

    /* Return if the path is already absolute. */
    if (kpath_is_absolute(path, format)) return;
    
    kstr_init(&tmp);
    
    /* Get the current working directory and append the relative path to the
     * current working directory.
     */
    kpath_getcwd(&tmp);
    kstr_append_kstr(&tmp, path);
    kstr_assign_kstr(path, &tmp);
    
    kstr_clean(&tmp);
}
Ejemplo n.º 17
0
static void test_mail_parse_addr_field() {
    kstr addr_field;
    karray addr_array;
    char *john = "*****@*****.**";
    int i;
    
    kstr_init(&addr_field);
    karray_init(&addr_array);

    kstr_sf(&addr_field, ";%s;;John Doe <%s>;<%s>", john, john, john);
    assert(! mail_parse_addr_field(&addr_field, &addr_array));
    assert(addr_array.size == 3);
    
    for (i = 0; i < addr_array.size; i++) {
    	 assert(! strcmp(((kstr *) addr_array.data[i])->data, john));
    }
    
    kmo_clear_kstr_array(&addr_array);
    
    kstr_sf(&addr_field, "<>");
    assert(mail_parse_addr_field(&addr_field, &addr_array));
    
    kstr_sf(&addr_field, "<");
    assert(mail_parse_addr_field(&addr_field, &addr_array));
    
    kstr_sf(&addr_field, ">");
    assert(mail_parse_addr_field(&addr_field, &addr_array));
    
    kstr_sf(&addr_field, "foobar");
    assert(mail_parse_addr_field(&addr_field, &addr_array));
    
    kstr_sf(&addr_field, "foobar@@example.com");
    assert(mail_parse_addr_field(&addr_field, &addr_array));
    
    kstr_sf(&addr_field, ">text<");
    assert(mail_parse_addr_field(&addr_field, &addr_array));
    
    kstr_sf(&addr_field, "foo;[email protected]");
    assert(mail_parse_addr_field(&addr_field, &addr_array));
    
    kstr_free(&addr_field);
    karray_free(&addr_array);
}
Ejemplo n.º 18
0
/* This function returns the mail info having the hash and KSN specified.
 * This function sets the KMO error string. It returns -1 on general failure,
 * -2 if not found.
 */
static int maildb_sqlite_get_mail_info_from_hash(maildb *mdb, maildb_mail_info *mail_info, kstr *hash, kstr *ksn) {
    int error = 0;
    sqlite3 *db = (sqlite3 *) mdb->db;
    int64_t entry_id;
    
    error = get_entry_id_from_hash(db, hash, ksn, &entry_id);
    if (error) return -1;
    
    /* If we failed to find the mail, and a hash and a KSN were provided, we redo
     * the search with only the KSN, to find sent encrypted mails.
     */
    if (entry_id == 0 && hash->slen > 0 && ksn->slen > 0) {
    	kstr empty_hash;
	kstr_init(&empty_hash);
    	error = get_entry_id_from_hash(db, &empty_hash, ksn, &entry_id);
	kstr_free(&empty_hash);
    	if (error) return -1;
    }
    
    return maildb_sqlite_get_mail_info_from_entry_id(mdb, mail_info, entry_id);
}
Ejemplo n.º 19
0
Archivo: kstr.c Proyecto: 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);
}
Ejemplo n.º 20
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;
}
Ejemplo n.º 21
0
void kmo_error_start() {
    kstr_init(&kmo_error_str);
    kstr_init(&kmo_scratch_str);
}
Ejemplo n.º 22
0
kstr * kstr_new() {
    kstr *str = (kstr *) kmo_malloc(sizeof(kstr));
    kstr_init(str);
    return str;
}
Ejemplo n.º 23
0
Archivo: kstr.c Proyecto: miraeye/f265
void kstr_init_sfv(kstr *self, const char *format, va_list args) {
    kstr_init(self);
    kstr_sfv(self, format, args);
}
Ejemplo n.º 24
0
Archivo: kstr.c Proyecto: miraeye/f265
kstr* kstr_new() {
    kstr *self = (kstr *) kmalloc(sizeof(kstr));
    kstr_init(self);
    return self;
}
Ejemplo n.º 25
0
static struct kthread_specific * kthread_specific_new() {
    struct kthread_specific *self = (struct kthread_specific *) kcalloc(sizeof(struct kthread_specific));
    kerror_init(&self->error_stack);
    kstr_init(&self->err_str);
    return self;
}
Ejemplo n.º 26
0
/* This function handles a connection in VNC proxy mode. */
static int kcd_frontend_handle_vnc(struct kcd_client *client) {
    int error = 0;
    int proxy_sock = -1;
    char begin_string[KCD_VNC_BEGIN_STRING_LENGTH + 1];
    kstr cred_path;
    
    kdaemon_set_task("VNC proxy | %s", client->addr.data);
    kmod_log_msg(KCD_LOG_BRIEF, "kcd_frontend_handle_vnc() called.\n");
    
    assert(strlen(KCD_VNC_TEST_KCD_VNC_BEGIN_STRING) == KCD_VNC_BEGIN_STRING_LENGTH);
    
    begin_string[KCD_VNC_BEGIN_STRING_LENGTH] = 0;
    kstr_init(&cred_path);
    
    do {
        int port;
        
        if (!global_opts.vnc_mode) {
            kmod_set_error("VNC proxy mode disabled");
            error = -1;
            break;
        }
        
        /* Receive the file name. */
        error = kcd_frontend_tls_xfer(&client->conn, begin_string, KCD_VNC_BEGIN_STRING_LENGTH, 1);
        if (error) break;

        /* This is a test. */
        if (! strncmp(begin_string, KCD_VNC_TEST_KCD_VNC_BEGIN_STRING, KCD_VNC_BEGIN_STRING_LENGTH)) {
            kmod_log_msg(KCD_LOG_MISC, "kcd_proxy_handle_vnc(): test connection.\n");
            error = kcd_frontend_tls_xfer(&client->conn, KCD_VNC_TEST_RESPONSE, KCD_VNC_TEST_RESPONSE_LENGTH, 0);
            if (error) break;
        }
        
        /* This is a genuine VNC connection. */
        else {
            
            /* 'begin_string' is a credential file. */
            char *file_name = begin_string;

            /* Check if that file exists. */
            kstr_sf(&cred_path, "%s/%s", global_opts.vnc_cred_path.data, file_name);
        
            if (! kfs_regular(cred_path.data)) {
                kmod_set_error("credential file %s does not exist", file_name);
                error = -1;
                break;
            }
        
            /* Get the port. */
            port = atoi(file_name + KCD_VNC_PORT_OFFSET);
        
            /* Note: don't delete the credential file, IE sucks and connects
             * twice.
             */
        
            /* Connect to the VNC proxy. */
            error = kproxy_connect_tcp(&proxy_sock, global_opts.kcd_host.data, port);
            if (error) break;
        
            /* Loop within the proxy. */
            error = kcd_frontend_proxy_loop(&client->conn, proxy_sock, "VNC proxy");
            if (error) break;
        }
        
    } while (0);
    
    ksock_close(&proxy_sock);
    kstr_clean(&cred_path); 
    
    return error;
}
Ejemplo n.º 27
0
Archivo: vnc.c Proyecto: fdgonthier/kas
/* This function starts the VNC session. */
int kcd_vnc_start_session(struct kcd_ticket_mode_state *tms) {
    int error = 0;
    struct kcd_vnc_mode_state vms;
    kstr subject;
    kbuffer *kbb = &tms->kws_bound_buf, *in_buf = &tms->aq.input_buf, *out_buf = &tms->aq.output_buf;
    
    kcd_vnc_mode_state_init(&vms, tms);
    kstr_init(&subject);
    
    do {
        /* Check the right to start/join a VNC session. */
        error = kcd_vnc_check_right(tms);
        if (error) break;
        
        /* Get the extra information from the command. */
        if (anp_read_kstr(&tms->in_msg->payload, &subject)) {
            error = -2;
            break;
        }
        
	/* Start the proxy server. */
	error = kcd_vnc_start_proxy(&vms);
	if (error) break;
        
        /* Start the session in Postgres. This has to be done after the proxy
         * has been started so that the session does not get collected early.
         */
        anp_write_kstr(kbb, &subject);
        anp_write_uint32(kbb, vms.proxy_port);
        error = kcd_ticket_mode_kws_bound_query(tms, "start_vnc", ktime_now_sec(), NULL);
        if (error) break;
        
        error = anp_read_uint64(out_buf, &vms.session_id);
        if (error) break;
	
	/* Send the "OK" to the client. */
        kcd_ticket_mode_new_out_msg(tms, KANP_RES_OK);
        
        if (tms->client->effective_minor > 2) {
            tms->out_msg->type = KANP_RES_VNC_START_SESSION;
            anp_write_uint64(&tms->out_msg->payload, vms.session_id);
        }
	    
        error = kcd_ticket_mode_send_msg(tms);
	if (error) break;
	
	/* Loop communicating with the proxy. */
	error = kcd_vnc_proxy_comm_loop(&vms);
	if (error) break;
        
        /* Terminate the session. */
        anp_write_uint64(in_buf, tms->kws_id);
        anp_write_uint32(in_buf, tms->user_id);
        anp_write_uint64(in_buf, vms.session_id);
        anp_write_uint32(in_buf, tms->client->effective_minor >= 5 ? 5 : 2);
        anp_write_uint32(in_buf, vms.end_error_code);
        anp_write_kstr(in_buf, &vms.end_error_msg);
        error = kcd_exec_safe_pg_anp_query(&tms->db_conn, &tms->aq, "end_vnc");
        if (error) break;
    
    } while (0);
    
    /* Kill and collect the proxy server. */
    if (error != -1) {
        if (kcd_process_kill_and_collect(&vms.process)) {
            error = -1;
        }
    }
    
    /* Log the proxy output. */
    kcd_process_log_output(&vms.process, 1, 1);
    
    kcd_vnc_mode_state_clean(&vms);
    kstr_clean(&subject);
    
    return error;
}
Ejemplo n.º 28
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;
}
Ejemplo n.º 29
0
/* This function connects to the specified server (possibly through a proxy) and
 * negociates a SSL session. REMARK: a backport was applied to this function. It
 * was ugly in the first place, the backport didn't help any. All of it is
 * rewritten in the next version. REMARK 2: whooops, modified it again. It's
 * getting prettier by the minute.
 * This function sets the KMO error string. It returns 0, -1, -2, or -3.
 */
static int knp_query_connect(struct knp_query *self, struct knp_proto *knp) {
    assert(self->transfer.fd == -1);
    assert(self->ssl_driver == NULL);
    
    kmod_log_msg(3, "knp_query_connect() called.\n");
    
    int error = 0;
    kstr str;
    int use_srv = 0;
    int use_proxy = 0;
    kstr proxy_addr;
    uint32_t proxy_port = 0;
    kstr proxy_login;
    kstr proxy_pwd;
    char *cert = NULL;
    struct kmo_data_transfer *transfer = &self->transfer;
    
    kstr_init(&str);
    kstr_init(&proxy_addr);
    kstr_init(&proxy_login);
    kstr_init(&proxy_pwd);
    
    /* Try. */
    do {
	/* We're contacting the KPS. */
	if (self->contact == KNP_CONTACT_KPS && k3p_is_using_kps(knp->server_info)) {
	    kstr_assign_kstr(&self->server_addr, &knp->server_info->kps_net_addr);
	    self->server_port = knp->server_info->kps_port_num;
	    
	    if (knp->server_info->kps_use_proxy) {
	    	use_proxy = 1;
	    	kstr_assign_kstr(&proxy_addr, &knp->server_info->kps_proxy_net_addr);
		proxy_port = knp->server_info->kps_proxy_port_num;
		kstr_assign_kstr(&proxy_login, &knp->server_info->kps_proxy_login);
		kstr_assign_kstr(&proxy_pwd, &knp->server_info->kps_proxy_pwd);
	    }
	}
	
	/* We're contacting the KOS. */
	else {
	    #ifdef __DEBUG_KOS_ADDRESS__
	    kstr_assign_cstr(&self->server_addr, __DEBUG_KOS_ADDRESS__);
	    if (ops_address || ous_address || ots_address || iks_address || eks_address) {}
	    #else

            /* This is the option to use a one-stop server for all
               online service requests. */
            if (self->all_req_str.slen > 0) {
                kstr_assign_kstr(&self->server_addr, &self->all_req_str);
            }
	    
	    else if (knp->server_info->kos_use_proxy || knp->use_kpg) {
		switch (self->contact) {
		    case KNP_CONTACT_KPS: kstr_assign_cstr(&self->server_addr, ops_address); break;
		    case KNP_CONTACT_OPS: kstr_assign_cstr(&self->server_addr, ops_address); break;
		    case KNP_CONTACT_OUS: kstr_assign_cstr(&self->server_addr, ous_address); break;
		    case KNP_CONTACT_OTS: kstr_assign_cstr(&self->server_addr, ots_address); break;
		    case KNP_CONTACT_IKS: kstr_assign_cstr(&self->server_addr, iks_address); break;
		    case KNP_CONTACT_EKS: kstr_assign_cstr(&self->server_addr, eks_address); break;
		    default: assert(0);
		};
		
		if (knp->use_kpg) {
		    switch (self->contact) {
			case KNP_CONTACT_OPS: kstr_assign_cstr(&self->server_addr, knp->kpg_addr.data); break;
			case KNP_CONTACT_OUS: kstr_assign_cstr(&self->server_addr, knp->kpg_addr.data); break;
			case KNP_CONTACT_OTS: kstr_assign_cstr(&self->server_addr, knp->kpg_addr.data); break;
		    };
		}
	    }
	    
	    else {
		use_srv = 1;
		
		switch (self->contact) {
		    case KNP_CONTACT_KPS: kstr_assign_cstr(&self->server_addr, srv_ops_address); break;
		    case KNP_CONTACT_OPS: kstr_assign_cstr(&self->server_addr, srv_ops_address); break;
		    case KNP_CONTACT_OUS: kstr_assign_cstr(&self->server_addr, srv_ous_address); break;
		    case KNP_CONTACT_OTS: kstr_assign_cstr(&self->server_addr, srv_ots_address); break;
		    case KNP_CONTACT_IKS: kstr_assign_cstr(&self->server_addr, srv_iks_address); break;
		    case KNP_CONTACT_EKS: kstr_assign_cstr(&self->server_addr, srv_eks_address); break;
		    default: assert(0);
		};
	    }
	    #endif
	    
	    #ifdef __DEBUG_KOS_PORT__
	    self->server_port = __DEBUG_KOS_PORT__;
	    if (kos_port) {}
	    #else
	    self->server_port = kos_port;
	    
	    if (knp->use_kpg) {
		switch (self->contact) {
		    case KNP_CONTACT_OPS: self->server_port = knp->kpg_port; break;
		    case KNP_CONTACT_OUS: self->server_port = knp->kpg_port; break;
		    case KNP_CONTACT_OTS: self->server_port = knp->kpg_port; break;
		};
	    }
	    #endif
	    
	    if (knp->server_info->kos_use_proxy) {
	    	use_proxy = 1;
	    	kstr_assign_kstr(&proxy_addr, &knp->server_info->kos_proxy_net_addr);
		proxy_port = knp->server_info->kos_proxy_port_num;
		kstr_assign_kstr(&proxy_login, &knp->server_info->kos_proxy_login);
		kstr_assign_kstr(&proxy_pwd, &knp->server_info->kos_proxy_pwd);
	    }
	    
	    #ifdef NDEBUG
	    cert = kos_cert;
	    #else
	    if (kos_cert) {}
	    #endif
	}
	
	/* Validate our contact information. */
	if (self->server_addr.slen == 0 || self->server_port == 0) {
	    kmo_seterror("invalid server information");
    	    knp_query_handle_conn_error(self, KMO_SERROR_MISC);
	    error = -1;
    	    break;
	}
	
	if (use_proxy && (proxy_addr.slen == 0 || proxy_port == 0)) {
	    kmo_seterror("invalid proxy information");
    	    knp_query_handle_conn_error(self, KMO_SERROR_MISC);
	    error = -1;
	    break;
	}
    	
	/* Connect to the proxy or the end server directly. */
	if (! use_srv) {
	    error = kmo_sock_create(&transfer->fd);
	    if (error) break;
	
	    error = kmo_sock_set_unblocking(transfer->fd);
	    if (error) break;
	
	    error = kmo_sock_connect(transfer->fd, 
				     use_proxy ? proxy_addr.data : self->server_addr.data,
				     use_proxy ? proxy_port : self->server_port);
	    if (error) {
		knp_query_handle_conn_error(self, KMO_SERROR_UNREACHABLE);
		break;
	    }
	    
	    kstr_sf(&str, "cannot connect to %s", use_proxy ? proxy_addr.data : self->server_addr.data);
	    error = knp_query_wait_for_data(self, 0, str.data, knp->k3p);
	    
	    if (error) {
		if (error == -1) self->serv_error_id = KMO_SERROR_UNREACHABLE;
		break;
	    }
	    
	    error = kmo_sock_connect_check(transfer->fd, use_proxy ? proxy_addr.data : self->server_addr.data);
	    
	    if (error) {
		knp_query_handle_conn_error(self, KMO_SERROR_UNREACHABLE);
		break;
	    }
	    
	    /* If there is a proxy, asks it to connect us to the end server. */
	    if (use_proxy) {
		error = knp_handle_proxy(self, knp->k3p, &proxy_login, &proxy_pwd);
		if (error) break;
	    }
	}
	
	/* Connect using the SRV entries. */
	else {
	    error = knp_query_srv_connect(self, knp, self->server_addr.data);
	    if (error) break;
	}
	
	/* Negociate the SSL session. */
	error = knp_negociate_ssl_session(self, cert, knp->k3p);
	if (error) break;
	
    } while (0);
    
    if (error) knp_query_disconnect(self);
    
    kstr_free(&str);
    kstr_free(&proxy_addr);
    kstr_free(&proxy_login);
    kstr_free(&proxy_pwd);
    
    return error;
}
Ejemplo n.º 30
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;
}