Avoid calling globfree twice on failure.
[strongswan.git] / src / libcharon / plugins / stroke / stroke_cred.c
index cfa33a7..f4616a2 100644 (file)
@@ -95,7 +95,8 @@ struct private_stroke_cred_t {
 typedef struct {
        private_stroke_cred_t *this;
        identification_t *id;
-       certificate_type_t type;
+       certificate_type_t cert;
+       key_type_t key;
 } id_data_t;
 
 /**
@@ -116,15 +117,18 @@ static bool private_filter(id_data_t *data,
        private_key_t *key;
 
        key = *in;
-       if (data->id == NULL)
+       if (data->key == KEY_ANY || data->key == key->get_type(key))
        {
-               *out = key;
-               return TRUE;
-       }
-       if (key->has_fingerprint(key, data->id->get_encoding(data->id)))
-       {
-               *out = key;
-               return TRUE;
+               if (data->id == NULL)
+               {
+                       *out = key;
+                       return TRUE;
+               }
+               if (key->has_fingerprint(key, data->id->get_encoding(data->id)))
+               {
+                       *out = key;
+                       return TRUE;
+               }
        }
        return FALSE;
 }
@@ -140,6 +144,7 @@ static enumerator_t* create_private_enumerator(private_stroke_cred_t *this,
        data = malloc_thing(id_data_t);
        data->this = this;
        data->id = id;
+       data->key = type;
 
        this->lock->read_lock(this->lock);
        return enumerator_create_filter(this->private->create_enumerator(this->private),
@@ -155,7 +160,7 @@ static bool certs_filter(id_data_t *data, certificate_t **in, certificate_t **ou
        public_key_t *public;
        certificate_t *cert = *in;
 
-       if (data->type != CERT_ANY && data->type != cert->get_type(cert))
+       if (data->cert != CERT_ANY && data->cert != cert->get_type(cert))
        {
                return FALSE;
        }
@@ -168,11 +173,14 @@ static bool certs_filter(id_data_t *data, certificate_t **in, certificate_t **ou
        public = cert->get_public_key(cert);
        if (public)
        {
-               if (public->has_fingerprint(public, data->id->get_encoding(data->id)))
+               if (data->key == KEY_ANY || data->key != public->get_type(public))
                {
-                       public->destroy(public);
-                       *out = *in;
-                       return TRUE;
+                       if (public->has_fingerprint(public, data->id->get_encoding(data->id)))
+                       {
+                               public->destroy(public);
+                               *out = *in;
+                               return TRUE;
+                       }
                }
                public->destroy(public);
        }
@@ -195,7 +203,8 @@ static enumerator_t* create_cert_enumerator(private_stroke_cred_t *this,
        data = malloc_thing(id_data_t);
        data->this = this;
        data->id = id;
-       data->type = cert;
+       data->cert = cert;
+       data->key = key;
 
        this->lock->read_lock(this->lock);
        return enumerator_create_filter(this->certs->create_enumerator(this->certs),
@@ -674,47 +683,63 @@ static err_t extract_secret(chunk_t *secret, chunk_t *line)
 }
 
 /**
- * Data to pass to passphrase_cb
+ * Data for passphrase callback
  */
 typedef struct {
        /** socket we use for prompting */
        FILE *prompt;
        /** private key file */
-       char *file;
-       /** buffer for passphrase */
-       char buf[256];
+       char *path;
+       /** number of tries */
+       int try;
 } passphrase_cb_data_t;
 
 /**
- * Passphrase callback to read from stroke fd
+ * Callback function to receive Passphrases
  */
-chunk_t passphrase_cb(passphrase_cb_data_t *data, int try)
+static shared_key_t* passphrase_cb(passphrase_cb_data_t *data,
+                                                               shared_key_type_t type,
+                                                               identification_t *me, identification_t *other,
+                                                               id_match_t *match_me, id_match_t *match_other)
 {
-       chunk_t secret = chunk_empty;;
+       chunk_t secret;
+       char buf[256];
 
-       if (try > 5)
+       if (type != SHARED_ANY && type != SHARED_PRIVATE_KEY_PASS)
        {
-               fprintf(data->prompt, "invalid passphrase, too many trials\n");
-               return chunk_empty;
-       }
-       if (try == 1)
-       {
-               fprintf(data->prompt, "Private key '%s' is encrypted\n", data->file);
+               return NULL;
        }
-       else
+
+       if (data->try > 1)
        {
-               fprintf(data->prompt, "invalid passphrase\n");
+               if (data->try > 5)
+               {
+                       fprintf(data->prompt, "PIN invalid, giving up.\n");
+                       return NULL;
+               }
+               fprintf(data->prompt, "PIN invalid!\n");
        }
+       data->try++;
+       fprintf(data->prompt, "Private key '%s' is encrypted.\n", data->path);
        fprintf(data->prompt, "Passphrase:\n");
-       if (fgets(data->buf, sizeof(data->buf), data->prompt))
+       if (fgets(buf, sizeof(buf), data->prompt))
        {
-               secret = chunk_create(data->buf, strlen(data->buf));
-               if (secret.len)
+               secret = chunk_create(buf, strlen(buf));
+               if (secret.len > 1)
                {       /* trim appended \n */
                        secret.len--;
+                       if (match_me)
+                       {
+                               *match_me = ID_MATCH_PERFECT;
+                       }
+                       if (match_other)
+                       {
+                               *match_other = ID_MATCH_NONE;
+                       }
+                       return shared_key_create(SHARED_PRIVATE_KEY_PASS, chunk_clone(secret));
                }
        }
-       return secret;
+       return NULL;
 }
 
 /**
@@ -734,13 +759,18 @@ typedef struct {
 /**
  * Callback function to receive PINs
  */
-static shared_key_t* pin_cb(pin_cb_data_t *data,
+static shared_key_t* pin_cb(pin_cb_data_t *data, shared_key_type_t type,
                                                        identification_t *me, identification_t *other,
                                                        id_match_t *match_me, id_match_t *match_other)
 {
        chunk_t secret;
        char buf[256];
 
+       if (type != SHARED_ANY && type != SHARED_PIN)
+       {
+               return NULL;
+       }
+
        if (!me || !chunk_equals(me->get_encoding(me), data->keyid))
        {
                return NULL;
@@ -748,7 +778,7 @@ static shared_key_t* pin_cb(pin_cb_data_t *data,
 
        if (data->try > 1)
        {
-               fprintf(data->prompt, "PIN invalid, giving up.\n", data->card);
+               fprintf(data->prompt, "PIN invalid, aborting.\n");
                return NULL;
        }
        data->try++;
@@ -859,6 +889,7 @@ static bool load_pin(private_stroke_cred_t *this, chunk_t line, int line_nr,
        chunk = chunk_from_hex(chunk_create(keyid, strlen(keyid)), NULL);
        if (secret.len == 7 && strneq(secret.ptr, "%prompt", 7))
        {
+               free(secret.ptr);
                if (!prompt)
                {       /* no IO channel to prompt, skip */
                        free(chunk.ptr);
@@ -934,7 +965,7 @@ static bool load_private(private_stroke_cred_t *this, chunk_t line, int line_nr,
        char path[PATH_MAX];
        chunk_t filename;
        chunk_t secret = chunk_empty;
-       private_key_t *key = NULL;
+       private_key_t *key;
 
        err_t ugh = extract_value(&filename, &line);
 
@@ -972,23 +1003,53 @@ static bool load_private(private_stroke_cred_t *this, chunk_t line, int line_nr,
        }
        if (secret.len == 7 && strneq(secret.ptr, "%prompt", 7))
        {
-               if (prompt)
+               callback_cred_t *cb = NULL;
+               passphrase_cb_data_t pp_data = {
+                       .prompt = prompt,
+                       .path = path,
+                       .try = 1,
+               };
+
+               free(secret.ptr);
+               if (!prompt)
                {
-                       passphrase_cb_data_t data = {
-                               .prompt = prompt,
-                               .file = path,
-                       };
-                       key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
-                                                                        key_type, BUILD_FROM_FILE, path,
-                                                                        BUILD_PASSPHRASE_CALLBACK,
-                                                                        passphrase_cb, &data, BUILD_END);
+                       return TRUE;
                }
+               /* use callback credential set to prompt for the passphrase */
+               pp_data.prompt = prompt;
+               pp_data.path = path;
+               pp_data.try = 1;
+               cb = callback_cred_create_shared((void*)passphrase_cb, &pp_data);
+               lib->credmgr->add_local_set(lib->credmgr, &cb->set);
+
+               /* unlock, as the builder might ask for a secret */
+               this->lock->unlock(this->lock);
+               key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, key_type,
+                                                                BUILD_FROM_FILE, path, BUILD_END);
+               this->lock->write_lock(this->lock);
+
+               lib->credmgr->remove_local_set(lib->credmgr, &cb->set);
+               cb->destroy(cb);
        }
        else
        {
+               mem_cred_t *mem = NULL;
+               shared_key_t *shared;
+
+               /* provide our pin in a temporary credential set */
+               shared = shared_key_create(SHARED_PRIVATE_KEY_PASS, secret);
+               mem = mem_cred_create();
+               mem->add_shared(mem, shared, NULL);
+               lib->credmgr->add_local_set(lib->credmgr, &mem->set);
+
+               /* unlock, as the builder might ask for a secret */
+               this->lock->unlock(this->lock);
                key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, key_type,
-                                                                BUILD_FROM_FILE, path,
-                                                                BUILD_PASSPHRASE, secret, BUILD_END);
+                                                                BUILD_FROM_FILE, path, BUILD_END);
+               this->lock->write_lock(this->lock);
+
+               lib->credmgr->remove_local_set(lib->credmgr, &mem->set);
+               mem->destroy(mem);
        }
        if (key)
        {
@@ -1000,7 +1061,6 @@ static bool load_private(private_stroke_cred_t *this, chunk_t line, int line_nr,
        {
                DBG1(DBG_CFG, "  loading private key from '%s' failed", path);
        }
-       chunk_clear(&secret);
        return TRUE;
 }
 
@@ -1090,7 +1150,7 @@ static void load_secrets(private_stroke_cred_t *this, char *file, int level,
                close(fd);
                return;
        }
-       addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+       addr = mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
        if (addr == MAP_FAILED)
        {
                DBG1(DBG_LIB, "mapping '%s' failed: %s", file, strerror(errno));
@@ -1174,7 +1234,6 @@ static void load_secrets(private_stroke_cred_t *this, char *file, int level,
                        if (glob(pattern, GLOB_ERR, NULL, &buf) != 0)
                        {
                                DBG1(DBG_CFG, "expanding file expression '%s' failed", pattern);
-                               globfree(&buf);
                        }
                        else
                        {