/* 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); }
/* 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); }
static void kdclient_log_very_internal(int is_err, const char *file, int line, const char *log_channel, const char *msg, va_list va) { struct kerror *error_instance = kerror_get_current(); int i, level = (is_err ? LOG_ERR : LOG_WARNING); kstr err; kstr_init_sfv(&err, msg, va); log_write_line(level, log_channel, file, line, "%s", err.data); if (error_instance->stack.size <= 0) { kstr_clean(&err); return; } if (is_err) log_write(level, log_channel, "*** Error stack ***"); else log_write(level, log_channel, "*** Warning stack ***"); for (i = 0; i < error_instance->stack.size; i++) { struct kerror_node *en = (struct kerror_node *)karray_get(&error_instance->stack, i); log_write(level, log_channel, "[%s:%d] %s", en->file, en->line, en->text.data); } log_write(level, log_channel, "*** End ***"); kstr_clean(&err); }
static void kthread_specific_destroy(struct kthread_specific *self) { if (self) { kerror_clean(&self->error_stack); kstr_clean(&self->err_str); kfree(self); } }
/* 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; }
/** Tries to instanciate the key. * * This call tagcrypt to instanciate a key. This is useful to check * if the key was correctly loaded. * * The object will be destroyed at pool destruction time. */ int kdkey_load_key(apr_pool_t *pool, struct kdkey_info *ki) { kbuffer key_data; kstr key_data_str; int r = -1; kstr_init_buf(&key_data_str, ki->data, ki->data_s); if (kbuffer_init_b64(&key_data, &key_data_str) < 0) { KERROR_SET(_keys_, 1, "failed to read key"); return -1; } switch (ki->type) { case SKEY_ENCRYPTION: case SKEY_SIGNATURE: r = kdkey_load_skey(pool, &key_data, ki); break; case PKEY_ENCRYPTION: case PKEY_SIGNATURE: r = kdkey_load_pkey(pool, ki->type, &key_data, ki); break; default: KERROR_SET(_keys_, 1, "unknown key type"); return -1; } kstr_clean(&key_data_str); kbuffer_clean(&key_data); return r; }
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; }
void kcd_client_destroy(struct kcd_client *self) { if (self) { ksock_close(&self->sock); kstr_clean(&self->addr); ktls_clean(&self->conn); kfree(self); } }
/* 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); }
/** Create a new unsigned public key. * * This is used to support older version of the key. This does not * allocate anything on the pool but register a cleanup function to * remove the key. */ int kdkey_new_unsigned_pkey(apr_pool_t *pool, const char *pkey, size_t pkey_s, enum key_type ktype, struct kdkey_info *ki) { tagcrypt_pkey *pk; kbuffer pkey_buf; int err = 0; kstr str; kstr_init_buf(&str, pkey, pkey_s); err = kbuffer_init_b64(&pkey_buf, &str); if (err != 0) { KERROR_SET(_keys_, 0, "cannot create public key"); kstr_clean(&str); return -1; } do { pk = tagcrypt_pkey_new(&pkey_buf, ktype); if (pk == NULL) { KERROR_SET(_keys_, 0, "cannot create public key"); err = -1; break; } ki->owner = KEY_OWNER; ki->owner_s = KEY_OWNER_S; ki->data = NULL; ki->data_s = 0; ki->key = pk; /* Register the key cleanup function. */ apr_pool_cleanup_register(pool, pk, kdkey_destroy_pkey, kdkey_destroy_pkey); } while (0); kstr_clean(&str); kbuffer_clean(&pkey_buf); return err; }
/* Sign ki_in into ki_out, using signing_key. The buffered format of ki_in and ki_out does not match. */ int kdkey_sign_key(struct kdkey_info *ki_in, kbuffer *out, int for_enc_hack) { int err = -1; enum key_type type; kbuffer buf; tagcrypt_pkey *pkey_in = NULL; tagcrypt_skey *signing_key = NULL; type = kdkey_to_tagcrypt(ki_in->type); kstr str; /* TRY */ do { /* put the key in a buffer */ kstr_init_cstr(&str, ki_in->data); err = kbuffer_init_b64(&buf, &str); kstr_clean(&str); if (err) { err = -2; break; } err = -1; /* instanciate the key */ pkey_in = tagcrypt_pkey_new(&buf, type); if (pkey_in == NULL) break; /* FIXME: ugly hack */ if (for_enc_hack) signing_key = NULL; else { /* get the timestamp key */ signing_key = tm_skey_info.key; if (signing_key == NULL) break; } /* sign the key */ if (tagcrypt_sign_pkey(out, signing_key, pkey_in)) { KERROR_SET(_keys_, 0, "failed to sign key"); break; } kbuffer_write8(out, '\0'); err = 0; } while (0); if (err != -2) kbuffer_clean(&buf); tagcrypt_pkey_destroy (pkey_in); return err; }
/* 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); }
/** 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; }
/* 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); }
static void kdaemon_clean() { kstr_clean(&global_opts.ssl_cert_path); }
void kpath_dir_clean(struct kpath_dir *self) { kpath_dir_reset(self); kstr_clean(&self->abs_part); karray_clean(&self->components); }
/** Return an ordinary key object. Returns -1 on error, 0 on missing key, and 1 on success. */ int kdkey_get_key(apr_pool_t *pool, uint64_t key_id, enum kdkey_type ktype, struct kdkey_info **ki) { kbuffer buf; enum key_type type; kstr str; int err = 0; assert((ktype > SKEY_START && ktype < SKEY_END) || (ktype > PKEY_START && ktype < PKEY_END)); switch (ktype) { /* Those go through the database object. */ case SKEY_ENCRYPTION: case SKEY_SIGNATURE: case PKEY_ENCRYPTION: case PKEY_SIGNATURE: err = kddb_fetch_key(pool, key_id, ktype, ki); /* Key fetch error. */ if (err < 0) { KERROR_PUSH(_keys_, 0, "failed to fetch key "PRINTF_64"u", key_id); err = -1; break; } /* Key not found. */ if (err == 0) return 0; type = kdkey_to_tagcrypt(ktype); kstr_init_buf(&str, (*ki)->data, (*ki)->data_s); err = kbuffer_init_b64(&buf, &str); kstr_clean(&str); if (err) break; if (ktype == SKEY_ENCRYPTION || ktype == SKEY_SIGNATURE) { (*ki)->key = tagcrypt_skey_new(&buf); if ((*ki)->key == NULL) { KERROR_SET(_keys_, 0, "ill-formed secret key in database"); err = -1; break; } /* Check for inconsistent key ID. */ if (((tagcrypt_skey *)(*ki)->key)->keyid != (*ki)->key_id) { KERROR_SET(_keys_, 0, "ill-formed key, internal key ID: "PRINTF_64"u, external key ID: "PRINTF_64"u", ((tagcrypt_skey *)(*ki)->key)->keyid, (*ki)->key_id); err = -1; break; } /* Register memory cleanup function. */ if ((*ki)->key != NULL) apr_pool_cleanup_register(pool, (*ki)->key, kdkey_destroy_skey, kdkey_destroy_skey); } else if (ktype == PKEY_ENCRYPTION || ktype == PKEY_SIGNATURE) { (*ki)->key = tagcrypt_pkey_new(&buf, type); if ((*ki)->key == NULL) { KERROR_SET(_keys_, 0, "ill-formed public key in database"); err = -1; break; } /* Check for inconsistent key ID. */ if (((tagcrypt_pkey *)(*ki)->key)->keyid != (*ki)->key_id) { KERROR_SET(_keys_, 0, "ill-formed key, internal key ID: "PRINTF_64"u, external key ID: "PRINTF_64"u", ((tagcrypt_pkey *)(*ki)->key)->keyid, (*ki)->key_id); err = -1; break; } /* Register memory cleanup function. */ if ((*ki)->key != NULL) apr_pool_cleanup_register(pool, (*ki)->key, kdkey_destroy_pkey, kdkey_destroy_pkey); } if ((*ki)->key == NULL) { err = -1; KERROR_SET(_keys_, 0, "failed to create key "PRINTF_64"u", key_id); } kbuffer_clean(&buf); err = 1; break; case PKEY_TIMESTAMP: *ki = &tm_pkey_info; break; case PKEY_LICENSE: *ki = &license_pkey_info; break; #ifdef REQUEST_GETSIG case SKEY_TIMESTAMP: *ki = &tm_skey_info; break; #endif // REQUEST_GETSIG default: abort(); } return err; }
/* 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; }
int otut_gen_ticket(apr_pool_t *parent_pool, struct kd_user *self, uint32_t nb_valid, const char *otut_addr, kbuffer *sign_buf) { int error = -1; char *real_addr; kbuffer skey_buffer; kbuffer *otut_addr_buf = NULL; tagcrypt_skey *skey = NULL; int is_allowed; apr_pool_t *pool; int err; kstr str; /* Check if there is a key. */ assert(self->sig_skey->key_id != 0); apr_pool_create(&pool, parent_pool); do { /* Make sure the OTUT address is an SMTP address. */ if (otut_addr[0] != '/') real_addr = (char *)otut_addr; /* it's not? well, convert it. */ else if (kddb_convert_address(pool, otut_addr, self->primary_email_addr, &real_addr) < 0) { KERROR_PUSH(_db_, 0, "failed to convert %s to SMTP address.", otut_addr); break; } /* Check if the user owns the address he is asking the user to answer to. This disallows potential freebies. */ if (kddb_is_email_allowed(pool, self, real_addr, &is_allowed, NULL) < 0) { KERROR_PUSH(_db_, 0, "failed to check if the email address is allowable"); break; } if (!is_allowed) { KERROR_SET(_db_, 0, "user is not allowed to request a ticket for the address %s", real_addr); break; } /* Put the key in a buffer. */ kstr_init_cstr(&str, self->sig_skey->data); err = kbuffer_init_b64(&skey_buffer, &str); kstr_clean(&str); if (err != 0) { KERROR_PUSH(_db_, 0, "failed to convert the key to binary format from base64"); kbuffer_clean(&skey_buffer); break; } /* Instanciate the private signature key. */ if ((skey = tagcrypt_skey_new(&skey_buffer)) == NULL) { KERROR_SET(_db_, 0, "failed to instanciate key"); kbuffer_clean(&skey_buffer); break; } kbuffer_clean(&skey_buffer); /* Make a buffer for the address to keep tagcrypt happy. */ otut_addr_buf = kbuffer_new(); kbuffer_write(otut_addr_buf, (uint8_t *)real_addr, strlen(real_addr)); /* Generate the ticket. */ if (tagcrypt_gen_ticket(skey, nb_valid, otut_addr_buf, sign_buf) < 0) { KERROR_SET(_db_, 0, "failed to produce ticket"); break; } error = 0; } while (0); /* Cleanup. */ if (otut_addr_buf != NULL) kbuffer_destroy(otut_addr_buf); if (skey != NULL) tagcrypt_skey_destroy(skey); return error; }
void kstr_destroy(kstr *str) { kstr_clean(str); kfree(str); }
/* This function decomposes the directory path specified into an array of * subcomponents. If the path is absolute, the absolute part will be something * like 'C:\' on Windows and '/' on UNIX, otherwise it will be empty. The * remaining components will not contain delimiters. * * The path 'C:/toto/bar' will yield ('C:\', 'toto', 'bar') on Windows with alt * support. * The path '/toto/bar/' will yield ('/', 'toto', 'bar') on UNIX. * The path './../foo/' will yield ('.', '..', 'foo'). * The path '' will yield (). */ void kpath_decompose_dir(kstr *path, struct kpath_dir *dir, int format) { int scan_pos = 0; kstr cur_component; /* Get the platform format. */ int platform_format = kpath_get_platform_format(format); /* Determine if the path is absolute. */ int is_absolute = kpath_is_absolute(path, format); kstr_init(&cur_component); kpath_dir_reset(dir); /* If the path is absolute, obtain the absolute part. */ if (is_absolute) { if (platform_format == KPATH_FORMAT_UNIX) { kstr_append_char(&dir->abs_part, '/'); scan_pos = 1; } else { kstr_append_buf(&dir->abs_part, path->data, 2); kstr_append_char(&dir->abs_part, kpath_delim(format)); scan_pos = 3; } } /* Scan the rest of the path. */ while (scan_pos < path->slen) { /* We encountered a delimiter. */ if (kpath_is_delim(path->data[scan_pos], format)) { /* If the current component is empty, ignore it. Otherwise, add the * component in the component array. */ if (cur_component.slen) { kstr *s = kstr_new(); kstr_assign_kstr(s, &cur_component); karray_push(&dir->components, s); } /* Reset the current component. */ kstr_reset(&cur_component); } /* Append the current character. */ else kstr_append_char(&cur_component, path->data[scan_pos]); scan_pos++; } /* Add the last component, if any, in the component array. */ if (cur_component.slen) { kstr *s = kstr_new(); kstr_assign_kstr(s, &cur_component); karray_push(&dir->components, s); } kstr_clean(&cur_component); }
/* 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; }
static void kcd_vnc_mode_state_clean(struct kcd_vnc_mode_state *self) { ksock_close(&self->proxy_sock); kstr_clean(&self->end_error_msg); kcd_process_clean(&self->process); }
/* MAIN entry point */ int main(int argc, char *argv[]) { int i, n, ret = 0; int config_loop; int verbosity; int detach; kstr *err_msg; struct kdsignal_info sigs[] = { {SIGALRM, kd_SIGALRM_handler }, {SIGINT, kd_SIGINT_handler }, {SIGTERM, kd_SIGTERM_handler }, {SIGCHLD, kd_SIGCHLD_handler }, {SIGUSR1, kd_SIGUSR1_handler }, {SIGHUP, kd_SIGHUP_handler } }; int ignored_sigs[] = {SIGPIPE, 0}; apr_pool_t *server_pool; printf("Teambox Sign-On Server daemon\n"); printf("Copyright (C) 2006-2012 Opersys inc.\n\n"); ktools_initialize(); kmem_set_handler(NULL, NULL, NULL, NULL, kd_abort_handler, NULL); /* Configuration and option setup. 1 - Load the internal defaults. They have the least priority. 2 - Load the configuration file. 3 - Load the command line options, overriding 2 and 1. */ /* Initializes APR. */ apr_initialize(); apr_pool_create(&main_pool, NULL); /* Configuration. */ do { log_open(main_pool); log_set_all_level("syslog", 0); if (options_load(main_pool, opts_tbl, opts_tbl_cnt, CONFIG_PATH "/tbxsosd.conf", kd_options_error_handler, 0) < 0) { kstr str; kstr_init(&str); format_current_error_for_user(&str); fprintf(stderr, "config read error: %s.\n", str.data); kstr_clean(&str); break; } kd_init_logging(); /* Command line stuff. */ if (kd_options_parse(argc, argv) < 0) { ret = -1; break; } /* Load options for local use. No need to check the return value since the values should have been set earlier when parsing the command line. */ detach = options_get_bool("server.detach"); verbosity = options_get_uint32("server.log_verbosity"); log_set_verbosity(verbosity); /* Proceed to static initialization of modules. */ if (kdssl_static_init(main_pool) < 0) { kd_dump_error(); err_msg = kerror_str_n(0); CRITICAL(_log_server_, "SSL initialization failed: %s.", err_msg->data); kstr_destroy(err_msg); ret = -1; break; } if (kdclient_static_init(main_pool) < 0) { kd_dump_error(); err_msg = kerror_str_n(0); ERROR(_log_server_, "Basic initialization failed: %s", err_msg->data); kstr_destroy(err_msg); ret = -1; break; } if (kdkey_static_init() < 0) { kd_dump_error(); err_msg = kerror_str_n(0); ERROR(_log_server_, "Basic initialization failed: %s", err_msg->data); kstr_destroy(err_msg); ret = -1; break; } /* Spawn the master process. */ if (detach && kd_spawn(main_pool) == 0) break; kdsignal_handled(sizeof(sigs) / sizeof(struct kdsignal_info), sigs); kdsignal_ignored(ignored_sigs); apr_pool_create(&server_pool, main_pool); /* Block all signals we say we are handling since it's the job of the server object to handle them. */ kdsignal_block_all_handled(); /* Create the new server object. */ if ((server = kdserver_new(server_pool)) == NULL) { kd_dump_error(); err_msg = kerror_str_n(0); CRITICAL(_log_server_, "Error initializing the server: %s", err_msg->data); kstr_destroy(err_msg); ret = -1; break; } /* At this point, the expected behavior in signal handling can resume. */ kdsignal_unblock_all_handled(); for (i = 0; i < server->ssl_sock_count; i++) INFO(_log_server_, "Listening for SSL on %s:%ld.", inet_ntoa(server->ssl_sock_addr[i]->sin_addr), ntohs(server->ssl_sock_addr[i]->sin_port)); for (i = 0; i < server->n_sock_count; i++) INFO(_log_server_, "Listening on %s:%ld.", inet_ntoa(server->n_sock_addr[i]->sin_addr), ntohs(server->n_sock_addr[i]->sin_port)); /* Loop in the server. This will block until the server quits. */ config_loop = 1; while (config_loop && !ret) { n = kdserver_main(server, main_pool); if (n < 0) { err_msg = kerror_str_n(0); CRITICAL(_log_server_, "Server error: %s", err_msg->data); kstr_destroy(err_msg); ret = - 1; break; } /* Reloading configuration was demanded. */ else if (n == 0 && server->sig_flag & FLAG_REHASH) { INFO(_log_server_, "Reloading configuration."); /* Get rid of this block. */ kdsignal_block_all_handled(); apr_pool_destroy(server_pool); server = NULL; kdsignal_unblock_all_handled(); if (options_reload(main_pool, CONFIG_PATH "/tbxsosd.conf") < 0) { kd_dump_error(); CRITICAL(_log_server_, "config read error"); ret = -1; } if (kdclient_static_init(main_pool) < 0) { kd_dump_error(); err_msg = kerror_str_n(0); CRITICAL(_log_server_, "Basic initialization failed: %s", err_msg->data); kstr_destroy(err_msg); ret = -1; } apr_pool_create(&server_pool, main_pool); /* Block all signals we say we are handling since it's the job of the server object to handle them. */ kdsignal_block_all_handled(); /* Create the new server object. */ if ((server = kdserver_new(server_pool)) == NULL) { kd_dump_error(); err_msg = kerror_str_n(0); CRITICAL(_log_server_, "Error initializing the server: %s", err_msg->data); kstr_destroy(err_msg); ret = -1; break; } /* At this point, the expected behavior in signal handling can resume. */ kdsignal_unblock_all_handled(); } /* Clean quit. */ else if (n == 0) { INFO(_log_server_, "Server terminating."); config_loop = 0; } } } while (0); kdkey_static_clean(); apr_pool_destroy(main_pool); apr_terminate(); ktools_finalize(); return ret; }
/* 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; }
/** Initialize common data for the kdkey object. */ int kdkey_static_init() { kbuffer buf, mk_buf, lk_buf; kstr str; int err; master_pkey_info.data = master_pkey_str; master_pkey_info.data_s = strlen(master_pkey_str); license_pkey_info.data = license_pkey_str; license_pkey_info.data_s = strlen(license_pkey_str); do { /* Load the master public key. */ kstr_init_cstr(&str, master_pkey_str); kbuffer_init_b64(&mk_buf, &str); kstr_clean(&str); master_pkey_info.key = tagcrypt_pkey_new(&mk_buf, KEY_TYPE_MASTER); /* Load the license public key. */ kstr_init_cstr(&str, license_pkey_str); kbuffer_init_b64(&lk_buf, &str); kstr_clean(&str); license_pkey_info.key = tagcrypt_pkey_new(&lk_buf, KEY_TYPE_MASTER); kbuffer_clean(&lk_buf); kbuffer_clean(&mk_buf); #ifdef REQUEST_GETSIG tm_pkey_str = options_get_str("keysign.public"); tm_skey_str = options_get_str("keysign.private"); tm_pkey_info.data = tm_pkey_str; tm_pkey_info.data_s = strlen(tm_pkey_str); tm_skey_info.data = tm_skey_str; tm_skey_info.data_s = strlen(tm_skey_str); kstr_init_buf(&str, tm_skey_info.data, tm_skey_info.data_s); err = kbuffer_init_b64(&buf, &str); kstr_clean(&str); if (err) { KERROR_SET(_keys_, 0, "cannot convert the secret key from base64 to binary"); break; } else /* FIXME: I believe this is actually a bug in libktools. Errors are pushed by libktools even where there is no returned errors. */ kerror_reset(); tm_skey_info.key = tagcrypt_skey_new(&buf); kbuffer_clean(&buf); if (tm_skey_info.key == NULL) { KERROR_SET(_keys_, 0, "cannot create internal timestamp key object"); err = -1; break; } #endif // REQUEST_GETSIG /* Cleans libktools error. */ kerror_reset(); err = 0; } while (0); return err ? -1 : 0; }