diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c index f09c74155..3a4574a91 100644 --- a/src/libcharon/plugins/stroke/stroke_config.c +++ b/src/libcharon/plugins/stroke/stroke_config.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2008 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -956,6 +957,141 @@ METHOD(stroke_config_t, del, void, } } +METHOD(stroke_config_t, set_user_credentials, void, + private_stroke_config_t *this, stroke_msg_t *msg, FILE *prompt) +{ + enumerator_t *enumerator, *children; + peer_cfg_t *peer, *found = NULL; + auth_class_t auth_class; + auth_cfg_t *auth_cfg; + child_cfg_t *child; + identification_t *id; + shared_key_type_t type = SHARED_ANY; + chunk_t password = chunk_empty; + + this->mutex->lock(this->mutex); + enumerator = this->list->create_enumerator(this->list); + while (enumerator->enumerate(enumerator, (void**)&peer)) + { /* find the peer (or child) config with the given name */ + if (streq(peer->get_name(peer), msg->user_creds.name)) + { + found = peer; + } + else + { + children = peer->create_child_cfg_enumerator(peer); + while (children->enumerate(children, &child)) + { + if (streq(child->get_name(child), msg->user_creds.name)) + { + found = peer; + break; + } + } + children->destroy(children); + } + + if (found) + { + break; + } + } + enumerator->destroy(enumerator); + + if (!found) + { + DBG1(DBG_CFG, " no config named '%s'", msg->user_creds.name); + fprintf(prompt, "no config named '%s'\n", msg->user_creds.name); + this->mutex->unlock(this->mutex); + return; + } + + id = identification_create_from_string(msg->user_creds.username); + if (strlen(msg->user_creds.username) == 0 || + !id || id->get_type(id) == ID_ANY) + { + DBG1(DBG_CFG, " invalid username '%s'", msg->user_creds.username); + fprintf(prompt, "invalid username '%s'\n", msg->user_creds.username); + this->mutex->unlock(this->mutex); + DESTROY_IF(id); + return; + } + + /* replace/set the username in the first suitable auth_cfg */ + enumerator = found->create_auth_cfg_enumerator(found, TRUE); + while (enumerator->enumerate(enumerator, (void**)&auth_cfg)) + { + auth_class = (uintptr_t)auth_cfg->get(auth_cfg, AUTH_RULE_AUTH_CLASS); + if (auth_class == AUTH_CLASS_EAP) + { + DBG1(DBG_CFG, " configured EAP-Identity %Y", id); + if (!auth_cfg->replace_value(auth_cfg, AUTH_RULE_EAP_IDENTITY, id)) + { + auth_cfg->add(auth_cfg, AUTH_RULE_EAP_IDENTITY, id); + } + type = SHARED_EAP; + break; + } + } + enumerator->destroy(enumerator); + + if (type == SHARED_ANY) + { + DBG1(DBG_CFG, " config '%s' unsuitable for user credentials", + msg->user_creds.name); + fprintf(prompt, "config '%s' unsuitable for user credentials\n", + msg->user_creds.name); + this->mutex->unlock(this->mutex); + id->destroy(id); + return; + } + this->mutex->unlock(this->mutex); + + if (msg->user_creds.password) + { + char *pass; + + pass = msg->user_creds.password; + password = chunk_clone(chunk_create(pass, strlen(pass))); + memwipe(pass, strlen(pass)); + } + else + { /* prompt the user for the password */ + char buf[256]; + + fprintf(prompt, "Password:\n"); + if (fgets(buf, sizeof(buf), prompt)) + { + password = chunk_clone(chunk_create(buf, strlen(buf))); + if (password.len > 0) + { /* trim trailing \n */ + password.len--; + } + memwipe(buf, sizeof(buf)); + } + } + + if (password.len) + { + shared_key_t *shared; + linked_list_t *owners; + + shared = shared_key_create(type, password); + + owners = linked_list_create(); + owners->insert_last(owners, id->clone(id)); + this->cred->add_shared(this->cred, shared, owners); + + DBG1(DBG_CFG, " added %N secret for %Y", shared_key_type_names, + type, id); + DBG4(DBG_CFG, " secret: %#B", &password); + } + else + { /* in case a user answers the password prompt by just pressing enter */ + chunk_clear(&password); + } +} + METHOD(stroke_config_t, destroy, void, private_stroke_config_t *this) { @@ -980,6 +1116,7 @@ stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred) }, .add = _add, .del = _del, + .set_user_credentials = _set_user_credentials, .destroy = _destroy, }, .list = linked_list_create(), diff --git a/src/libcharon/plugins/stroke/stroke_config.h b/src/libcharon/plugins/stroke/stroke_config.h index 05e4665ca..450d517f3 100644 --- a/src/libcharon/plugins/stroke/stroke_config.h +++ b/src/libcharon/plugins/stroke/stroke_config.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2008 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -52,6 +53,15 @@ struct stroke_config_t { */ void (*del)(stroke_config_t *this, stroke_msg_t *msg); + /** + * Set the username and password for a connection in this backend. + * + * @param msg received stroke message + * @param prompt I/O channel to prompt for the password + */ + void (*set_user_credentials)(stroke_config_t *this, stroke_msg_t *msg, + FILE *prompt); + /** * Destroy a stroke_config instance. */ diff --git a/src/libcharon/plugins/stroke/stroke_socket.c b/src/libcharon/plugins/stroke/stroke_socket.c index 72757ec16..d51cdafde 100644 --- a/src/libcharon/plugins/stroke/stroke_socket.c +++ b/src/libcharon/plugins/stroke/stroke_socket.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Tobias Brunner + * Copyright (C) 2011-2012 Tobias Brunner * Copyright (C) 2008 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -471,6 +471,21 @@ static void stroke_memusage(private_stroke_socket_t *this, } } +/** + * Set username and password for a connection + */ +static void stroke_user_creds(private_stroke_socket_t *this, + stroke_msg_t *msg, FILE *out) +{ + pop_string(msg, &msg->user_creds.name); + pop_string(msg, &msg->user_creds.username); + pop_string(msg, &msg->user_creds.password); + + DBG1(DBG_CFG, "received stroke: user-creds '%s'", msg->user_creds.name); + + this->config->set_user_credentials(this->config, msg, out); +} + /** * set the verbosity debug output */ @@ -644,6 +659,9 @@ static job_requeue_t process(stroke_job_context_t *ctx) case STR_MEMUSAGE: stroke_memusage(this, msg, out); break; + case STR_USER_CREDS: + stroke_user_creds(this, msg, out); + break; default: DBG1(DBG_CFG, "received unknown stroke"); break; diff --git a/src/stroke/stroke.c b/src/stroke/stroke.c index 2e081147c..bb299567b 100644 --- a/src/stroke/stroke.c +++ b/src/stroke/stroke.c @@ -1,5 +1,5 @@ /* Stroke for charon is the counterpart to whack from pluto - * Copyright (C) 2007 Tobias Brunner + * Copyright (C) 2007-2012 Tobias Brunner * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -352,6 +352,19 @@ static int memusage() return send_stroke_msg(&msg); } +static int user_credentials(char *name, char *user, char *pass) +{ + stroke_msg_t msg; + + msg.type = STR_USER_CREDS; + msg.length = offsetof(stroke_msg_t, buffer); + msg.user_creds.name = push_string(&msg, name); + msg.user_creds.username = push_string(&msg, user); + msg.user_creds.password = push_string(&msg, pass); + return send_stroke_msg(&msg); +} + + static int set_loglevel(char *type, u_int level) { stroke_msg_t msg; @@ -427,6 +440,11 @@ static void exit_usage(char *error) printf(" stroke memusage\n"); printf(" Show leases of a pool:\n"); printf(" stroke leases [POOL [ADDRESS]]\n"); + printf(" Set username and password for a connection:\n"); + printf(" stroke user-creds NAME USERNAME [PASSWORD]\n"); + printf(" where: NAME is a connection name added with \"stroke add\"\n"); + printf(" USERNAME is the username\n"); + printf(" PASSWORD is the optional password, you'll be asked to enter it if not given\n"); exit_error(error); } @@ -567,6 +585,14 @@ int main(int argc, char *argv[]) case STROKE_MEMUSAGE: res = memusage(); break; + case STROKE_USER_CREDS: + if (argc < 4) + { + exit_usage("\"user-creds\" needs a connection name, " + "username and optionally a password"); + } + res = user_credentials(argv[2], argv[3], argc > 4 ? argv[4] : NULL); + break; default: exit_usage(NULL); } diff --git a/src/stroke/stroke_keywords.h b/src/stroke/stroke_keywords.h index 3bd68bdc3..554d071f3 100644 --- a/src/stroke/stroke_keywords.h +++ b/src/stroke/stroke_keywords.h @@ -57,6 +57,7 @@ typedef enum { STROKE_EXPORT_X509, STROKE_LEASES, STROKE_MEMUSAGE, + STROKE_USER_CREDS, } stroke_keyword_t; #define STROKE_LIST_FIRST STROKE_LIST_PUBKEYS diff --git a/src/stroke/stroke_keywords.txt b/src/stroke/stroke_keywords.txt index 4a4cc57a9..1d7ab8a45 100644 --- a/src/stroke/stroke_keywords.txt +++ b/src/stroke/stroke_keywords.txt @@ -64,3 +64,4 @@ purgeike, STROKE_PURGE_IKE exportx509, STROKE_EXPORT_X509 leases, STROKE_LEASES memusage, STROKE_MEMUSAGE +user-creds, STROKE_USER_CREDS diff --git a/src/stroke/stroke_msg.h b/src/stroke/stroke_msg.h index f3c525ba7..7a469d3ac 100644 --- a/src/stroke/stroke_msg.h +++ b/src/stroke/stroke_msg.h @@ -218,6 +218,8 @@ struct stroke_msg_t { STR_EXPORT, /* print memory usage details */ STR_MEMUSAGE, + /* set username and password for a connection */ + STR_USER_CREDS, /* more to come */ } type; @@ -340,6 +342,13 @@ struct stroke_msg_t { char *pool; char *address; } leases; + + /* data for STR_USER_CREDS */ + struct { + char *name; + char *username; + char *password; + } user_creds; }; char buffer[STROKE_BUF_LEN]; };