Added stroke user-creds command, to set username/password for a connection.
authorTobias Brunner <tobias@strongswan.org>
Tue, 17 Apr 2012 09:18:37 +0000 (11:18 +0200)
committerTobias Brunner <tobias@strongswan.org>
Tue, 17 Apr 2012 12:20:58 +0000 (14:20 +0200)
src/libcharon/plugins/stroke/stroke_config.c
src/libcharon/plugins/stroke/stroke_config.h
src/libcharon/plugins/stroke/stroke_socket.c
src/stroke/stroke.c
src/stroke/stroke_keywords.h
src/stroke/stroke_keywords.txt
src/stroke/stroke_msg.h

index f09c741..3a4574a 100644 (file)
@@ -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(),
index 05e4665..450d517 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2012 Tobias Brunner
  * Copyright (C) 2008 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
@@ -53,6 +54,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.
         */
        void (*destroy)(stroke_config_t *this);
index 72757ec..d51cdaf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 Tobias Brunner
+ * Copyright (C) 2011-2012 Tobias Brunner
  * Copyright (C) 2008 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
@@ -472,6 +472,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
  */
 static void stroke_loglevel(private_stroke_socket_t *this,
@@ -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;
index 2e08114..bb29956 100644 (file)
@@ -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);
        }
index 3bd68bd..554d071 100644 (file)
@@ -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
index 4a4cc57..1d7ab8a 100644 (file)
@@ -64,3 +64,4 @@ purgeike,        STROKE_PURGE_IKE
 exportx509,      STROKE_EXPORT_X509
 leases,          STROKE_LEASES
 memusage,        STROKE_MEMUSAGE
+user-creds,      STROKE_USER_CREDS
index f3c525b..7a469d3 100644 (file)
@@ -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];
 };