merging
authorVolker Birk <vb@pep-project.org>
Tue, 03 May 2016 08:30:41 +0200
changeset 5646f958c76773d
parent 563 6f0c0366fc63
parent 562 fe56206d4630
child 565 e29bd4aeb5ea
merging
     1.1 --- a/db/en.csv	Tue May 03 08:30:22 2016 +0200
     1.2 +++ b/db/en.csv	Tue May 03 08:30:41 2016 +0200
     1.3 @@ -1891,7 +1891,7 @@
     1.4  en,1890,ANESTHETIC,0
     1.5  en,1891,ANESTHETIST,0
     1.6  en,1892,ANESTHETIZE,0
     1.7 -en,1893,ANESTHETIZER,0
     1.8 +en,1893,STAPLE,0
     1.9  en,1894,ANET,0
    1.10  en,1895,ANET,0
    1.11  en,1896,ANETT,0
    1.12 @@ -7845,7 +7845,7 @@
    1.13  en,7844,CASSANDRE,0
    1.14  en,7845,CASSANDRY,0
    1.15  en,7846,CASSATT,0
    1.16 -en,7847,CASSAUNDRA,0
    1.17 +en,7847,HORSE,0
    1.18  en,7848,CASSAVA,0
    1.19  en,7849,CASSEROLE,0
    1.20  en,7850,CASSETTE,0
    1.21 @@ -11681,7 +11681,7 @@
    1.22  en,11680,CUCKOO,0
    1.23  en,11681,CUCUMBER,0
    1.24  en,11682,CUDDLE,0
    1.25 -en,11683,CUDDLY,0
    1.26 +en,11683,BATTERY,0
    1.27  en,11684,CUDGEL,0
    1.28  en,11685,CUE,0
    1.29  en,11686,CUFF,0
    1.30 @@ -16555,7 +16555,7 @@
    1.31  en,16554,EVERYPLACE,0
    1.32  en,16555,EVERYTHING,0
    1.33  en,16556,EVERYWHERE,0
    1.34 -en,16557,EVICT,0
    1.35 +en,16557,CORRECT,0
    1.36  en,16558,EVICTION,0
    1.37  en,16559,EVIDENCE,0
    1.38  en,16560,EVIDENT,0
    1.39 @@ -22884,7 +22884,7 @@
    1.40  en,22883,HORRIFYING,0
    1.41  en,22884,HORROR,0
    1.42  en,22885,HORS,0
    1.43 -en,22886,HORSE,0
    1.44 +en,22886,CASSAUNDRA,0
    1.45  en,22887,HORSEBACK,0
    1.46  en,22888,HORSEDOM,0
    1.47  en,22889,HORSEFLESH,0
    1.48 @@ -31918,7 +31918,7 @@
    1.49  en,31917,NAMER,0
    1.50  en,31918,NAMESAKE,0
    1.51  en,31919,NAMIBIA,0
    1.52 -en,31920,NAMIBIAN,0
    1.53 +en,31920,XKCD,0
    1.54  en,31921,NAMING,0
    1.55  en,31922,NAN,0
    1.56  en,31923,NANA,0
    1.57 @@ -44371,7 +44371,7 @@
    1.58  en,44370,STANZA,0
    1.59  en,44371,STAPH,0
    1.60  en,44372,STAPHS,0
    1.61 -en,44373,STAPLE,0
    1.62 +en,44373,ANESTHETIZER,0
    1.63  en,44374,STAPLED,0
    1.64  en,44375,STAPLER,0
    1.65  en,44376,STAPLETON,0
    1.66 @@ -54021,7 +54021,7 @@
    1.67  en,54020,ANESTHETIC,0
    1.68  en,54021,ANESTHETIST,0
    1.69  en,54022,ANESTHETIZE,0
    1.70 -en,54023,ANESTHETIZER,0
    1.71 +en,54023,STAPLE,0
    1.72  en,54024,ANET,0
    1.73  en,54025,ANET,0
    1.74  en,54026,ANETT,0
    1.75 @@ -56428,7 +56428,7 @@
    1.76  en,56427,BATTED,0
    1.77  en,56428,BATTEN,0
    1.78  en,56429,BATTER,0
    1.79 -en,56430,BATTERY,0
    1.80 +en,56430,CUDDLY,0
    1.81  en,56431,BATTING,0
    1.82  en,56432,BATTLE,0
    1.83  en,56433,BATTLEDORE,0
    1.84 @@ -63034,7 +63034,7 @@
    1.85  en,63033,CORRAL,0
    1.86  en,63034,CORRALLED,0
    1.87  en,63035,CORRALLING,0
    1.88 -en,63036,CORRECT,0
    1.89 +en,63036,EVICT,0
    1.90  en,63037,CORRECTABLE,0
    1.91  en,63038,CORRECTED,0
    1.92  en,63039,CORRECTION,0
    1.93 @@ -63811,7 +63811,7 @@
    1.94  en,63810,CUCKOO,0
    1.95  en,63811,CUCUMBER,0
    1.96  en,63812,CUDDLE,0
    1.97 -en,63813,CUDDLY,0
    1.98 +en,63813,BATTERY,0
    1.99  en,63814,CUDGEL,0
   1.100  en,63815,CUE,0
   1.101  en,63816,CUFF,0
     2.1 --- a/src/keymanagement.c	Tue May 03 08:30:22 2016 +0200
     2.2 +++ b/src/keymanagement.c	Tue May 03 08:30:41 2016 +0200
     2.3 @@ -70,7 +70,31 @@
     2.4      if (!(session && identity && !EMPTYSTR(identity->address)))
     2.5          return PEP_ILLEGAL_VALUE;
     2.6  
     2.7 -    status = get_identity(session, identity->address, &stored_identity);
     2.8 +    int _no_user_id = EMPTYSTR(identity->user_id);
     2.9 +
    2.10 +    if (_no_user_id)
    2.11 +    {
    2.12 +        free(identity->user_id);
    2.13 +
    2.14 +        identity->user_id = calloc(1, identity->address_size + 6);
    2.15 +        if (!identity->user_id)
    2.16 +        {
    2.17 +            return PEP_OUT_OF_MEMORY;
    2.18 +        }
    2.19 +        snprintf(identity->user_id, identity->address_size + 5,
    2.20 +                 "TOFU_%s", identity->address);
    2.21 +
    2.22 +        if(identity->user_id)
    2.23 +        {
    2.24 +            identity->user_id_size = strlen(identity->user_id);
    2.25 +        }
    2.26 +    }
    2.27 +    
    2.28 +    status = get_identity(session,
    2.29 +                          identity->address,
    2.30 +                          identity->user_id,
    2.31 +                          &stored_identity);
    2.32 +    
    2.33      assert(status != PEP_OUT_OF_MEMORY);
    2.34      if (status == PEP_OUT_OF_MEMORY)
    2.35          return PEP_OUT_OF_MEMORY;
    2.36 @@ -82,15 +106,6 @@
    2.37          if (status == PEP_OUT_OF_MEMORY)
    2.38              return PEP_OUT_OF_MEMORY;
    2.39  
    2.40 -        if (EMPTYSTR(identity->user_id)) {
    2.41 -            free(identity->user_id);
    2.42 -            identity->user_id = strndup(stored_identity->user_id, stored_identity->user_id_size);
    2.43 -            assert(identity->user_id);
    2.44 -            if (identity->user_id == NULL)
    2.45 -                return PEP_OUT_OF_MEMORY;
    2.46 -            identity->user_id_size = stored_identity->user_id_size;
    2.47 -        }
    2.48 -
    2.49          if (EMPTYSTR(identity->username)) {
    2.50              free(identity->username);
    2.51              identity->username = strndup(stored_identity->username, stored_identity->username_size);
    2.52 @@ -218,10 +233,15 @@
    2.53              identity->username_size = 9;
    2.54          }
    2.55  
    2.56 -        status = set_identity(session, identity);
    2.57 -        assert(status == PEP_STATUS_OK);
    2.58 -        if (status != PEP_STATUS_OK) {
    2.59 -            return status;
    2.60 +        // Identity doesn't get stored if is was just about checking existing
    2.61 +        // user by address (i.e. no user id but already stored)
    2.62 +        if (!(_no_user_id && stored_identity))
    2.63 +        {
    2.64 +            status = set_identity(session, identity);
    2.65 +            assert(status == PEP_STATUS_OK);
    2.66 +            if (status != PEP_STATUS_OK) {
    2.67 +                return status;
    2.68 +            }
    2.69          }
    2.70      }
    2.71  
    2.72 @@ -235,6 +255,7 @@
    2.73  
    2.74  DYNAMIC_API PEP_STATUS myself(PEP_SESSION session, pEp_identity * identity)
    2.75  {
    2.76 +    pEp_identity *stored_identity;
    2.77      PEP_STATUS status;
    2.78      stringlist_t *keylist = NULL;
    2.79  
    2.80 @@ -253,12 +274,69 @@
    2.81  
    2.82      DEBUG_LOG("myself", "debug", identity->address);
    2.83  
    2.84 -    status = find_keys(session, identity->address, &keylist);
    2.85 +    
    2.86 +    status = get_identity(session,
    2.87 +                          identity->address,
    2.88 +                          identity->user_id,
    2.89 +                          &stored_identity);
    2.90 +    
    2.91      assert(status != PEP_OUT_OF_MEMORY);
    2.92      if (status == PEP_OUT_OF_MEMORY)
    2.93          return PEP_OUT_OF_MEMORY;
    2.94 -
    2.95 -    if (keylist == NULL || keylist->value == NULL) {
    2.96 +    
    2.97 +    if (stored_identity)
    2.98 +    {
    2.99 +        if (EMPTYSTR(identity->fpr)) {
   2.100 +            identity->fpr = strndup(stored_identity->fpr, stored_identity->fpr_size);
   2.101 +            assert(identity->fpr);
   2.102 +            if (identity->fpr == NULL)
   2.103 +            {
   2.104 +                return PEP_OUT_OF_MEMORY;
   2.105 +            }
   2.106 +            identity->fpr_size = stored_identity->fpr_size;
   2.107 +        }
   2.108 +    }
   2.109 +    else
   2.110 +    {
   2.111 +        free(identity->fpr);
   2.112 +        identity->fpr_size = 0;
   2.113 +        
   2.114 +        status = find_keys(session, identity->address, &keylist);
   2.115 +        assert(status != PEP_OUT_OF_MEMORY);
   2.116 +        if (status == PEP_OUT_OF_MEMORY)
   2.117 +            return PEP_OUT_OF_MEMORY;
   2.118 +        
   2.119 +        if (keylist != NULL && keylist->value != NULL)
   2.120 +        {
   2.121 +            // BUG : Vulnerable to auto-key-import poisoning.
   2.122 +            //       Attacker's key with forged userId could have been
   2.123 +            //       auto imported from already received email and be used here
   2.124 +            
   2.125 +            // TODO : iterate over list to elect best key
   2.126 +            // TODO : discard keys which aren't private
   2.127 +            // TODO : discard keys which aren't either
   2.128 +            //             - own generated key
   2.129 +            //             - own from synchronized device group
   2.130 +            //             - already fully trusted as a public key of known
   2.131 +            //               identity, for that same address
   2.132 +            //               (case of imported key for mailing lists)
   2.133 +            
   2.134 +            identity->fpr = strdup(keylist->value);
   2.135 +            assert(identity->fpr);
   2.136 +            if (identity->fpr == NULL)
   2.137 +            {
   2.138 +                return PEP_OUT_OF_MEMORY;
   2.139 +            }
   2.140 +            identity->fpr_size = strlen(identity->fpr);
   2.141 +        }
   2.142 +        
   2.143 +    }
   2.144 +    
   2.145 +    // TODO : Check key for revoked state
   2.146 +    
   2.147 +    if (EMPTYSTR(identity->fpr) /* or revoked */)
   2.148 +    {
   2.149 +        
   2.150          DEBUG_LOG("generating key pair", "debug", identity->address);
   2.151          status = generate_keypair(session, identity);
   2.152          assert(status != PEP_OUT_OF_MEMORY);
   2.153 @@ -268,20 +346,21 @@
   2.154              DEBUG_LOG("generating key pair failed", "debug", buf);
   2.155              return status;
   2.156          }
   2.157 -
   2.158 +        
   2.159          status = find_keys(session, identity->address, &keylist);
   2.160          assert(status != PEP_OUT_OF_MEMORY);
   2.161          if (status == PEP_OUT_OF_MEMORY)
   2.162              return PEP_OUT_OF_MEMORY;
   2.163 -
   2.164 +        
   2.165          assert(keylist && keylist->value);
   2.166          if (keylist == NULL || keylist->value == NULL) {
   2.167              return PEP_UNKNOWN_ERROR;
   2.168          }
   2.169      }
   2.170 -    else {
   2.171 +    else
   2.172 +    {
   2.173          bool expired;
   2.174 -        status = key_expired(session, keylist->value, &expired);
   2.175 +        status = key_expired(session, identity->fpr, &expired);
   2.176          assert(status == PEP_STATUS_OK);
   2.177          if (status != PEP_STATUS_OK) {
   2.178              goto free_keylist;
   2.179 @@ -289,21 +368,11 @@
   2.180  
   2.181          if (status == PEP_STATUS_OK && expired) {
   2.182              timestamp *ts = new_timestamp(time(NULL) + KEY_EXPIRE_DELTA);
   2.183 -            renew_key(session, keylist->value, ts);
   2.184 +            renew_key(session, identity->fpr, ts);
   2.185              free_timestamp(ts);
   2.186          }
   2.187      }
   2.188  
   2.189 -    if (identity->fpr)
   2.190 -        free(identity->fpr);
   2.191 -    identity->fpr = strdup(keylist->value);
   2.192 -    assert(identity->fpr);
   2.193 -    if (identity->fpr == NULL){
   2.194 -        status = PEP_OUT_OF_MEMORY;
   2.195 -        goto free_keylist;
   2.196 -    }
   2.197 -    identity->fpr_size = strlen(identity->fpr);
   2.198 -
   2.199      status = set_identity(session, identity);
   2.200      assert(status == PEP_STATUS_OK);
   2.201      if (status != PEP_STATUS_OK) {
     3.1 --- a/src/message_api.c	Tue May 03 08:30:22 2016 +0200
     3.2 +++ b/src/message_api.c	Tue May 03 08:30:41 2016 +0200
     3.3 @@ -877,6 +877,9 @@
     3.4      assert(session);
     3.5      assert(msg);
     3.6  
     3.7 +    if (msg->dir == PEP_dir_incoming)
     3.8 +        return;
     3.9 +
    3.10      assert(msg->from && msg->from->fpr);
    3.11      if (msg->from == NULL || msg->from->fpr == NULL)
    3.12          return;
    3.13 @@ -929,8 +932,9 @@
    3.14      assert(session);
    3.15      assert(src);
    3.16      assert(dst);
    3.17 +    assert(enc_format != PEP_enc_none);
    3.18  
    3.19 -    if (!(session && src && dst))
    3.20 +    if (!(session && src && dst && enc_format != PEP_enc_none))
    3.21          return PEP_ILLEGAL_VALUE;
    3.22  
    3.23      if (src->dir == PEP_dir_incoming)
    3.24 @@ -945,13 +949,7 @@
    3.25      status = myself(session, src->from);
    3.26      if (status != PEP_STATUS_OK)
    3.27          goto pep_error;
    3.28 -    
    3.29 -    if (enc_format == PEP_enc_none)
    3.30 -    {
    3.31 -        attach_own_key(session, src);
    3.32 -        return PEP_UNENCRYPTED;
    3.33 -    }
    3.34 -    
    3.35 +
    3.36      keys = new_stringlist(src->from->fpr);
    3.37      if (keys == NULL)
    3.38          goto enomem;
     4.1 --- a/src/pEpEngine.c	Tue May 03 08:30:22 2016 +0200
     4.2 +++ b/src/pEpEngine.c	Tue May 03 08:30:41 2016 +0200
     4.3 @@ -140,14 +140,15 @@
     4.4                  "   comment text\n"
     4.5                  ");\n"
     4.6                  "create table if not exists identity (\n"
     4.7 -                "   address text primary key,\n"
     4.8 +                "   address text,\n"
     4.9                  "   user_id text\n"
    4.10                  "       references person (id)\n"
    4.11                  "       on delete cascade,\n"
    4.12                  "   main_key_id text\n"
    4.13                  "       references pgp_keypair (fpr)\n"
    4.14                  "       on delete set null,\n"
    4.15 -                "   comment text\n"
    4.16 +                "   comment text,\n"
    4.17 +                "   primary key (address, user_id)\n"
    4.18                  ");\n"
    4.19                  "create table if not exists trust (\n"
    4.20                  "   user_id text not null\n"
    4.21 @@ -186,13 +187,13 @@
    4.22          sql_log = "insert into log (title, entity, description, comment)"
    4.23                    "values (?1, ?2, ?3, ?4);";
    4.24  
    4.25 -        sql_get_identity =    "select fpr, identity.user_id, username, comm_type, lang"
    4.26 +        sql_get_identity =    "select fpr, username, comm_type, lang"
    4.27                              "   from identity"
    4.28                              "   join person on id = identity.user_id"
    4.29                              "   join pgp_keypair on fpr = identity.main_key_id"
    4.30                              "   join trust on id = trust.user_id"
    4.31                              "       and pgp_keypair_fpr = identity.main_key_id"
    4.32 -                            "   where address = ?1 ;";
    4.33 +                            "   where address = ?1 and identity.user_id = ?2;";
    4.34  
    4.35          sql_trustword = "select id, word from wordlist where lang = lower(?1) "
    4.36                         "and id = ?2 ;";
    4.37 @@ -201,21 +202,21 @@
    4.38                           "values (?1, ?2, ?3) ;";
    4.39  
    4.40          sql_set_pgp_keypair = "insert or replace into pgp_keypair (fpr) "
    4.41 -                              "values (?1) ;";
    4.42 +                              "values (upper(replace(?1,' ',''))) ;";
    4.43  
    4.44          sql_set_identity = "insert or replace into identity (address, main_key_id, "
    4.45 -                           "user_id) values (?1, ?2, ?3) ;";
    4.46 +                           "user_id) values (?1, upper(replace(?2,' ','')), ?3) ;";
    4.47  
    4.48          sql_set_trust = "insert or replace into trust (user_id, pgp_keypair_fpr, comm_type) "
    4.49 -                        "values (?1, ?2, ?3) ;";
    4.50 +                        "values (?1, upper(replace(?2,' ','')), ?3) ;";
    4.51  
    4.52 -        sql_get_trust = "select user_id, comm_type from trust where user_id = ?1 "
    4.53 -                        "and pgp_keypair_fpr = ?2 ;";
    4.54 +        sql_get_trust = "select comm_type from trust where user_id = ?1 "
    4.55 +                        "and pgp_keypair_fpr = upper(replace(?2,' ','')) ;";
    4.56  
    4.57 -        sql_least_trust = "select min(comm_type) from trust where pgp_keypair_fpr = ?1 ;";
    4.58 +        sql_least_trust = "select min(comm_type) from trust where pgp_keypair_fpr = upper(replace(?1,' ','')) ;";
    4.59  
    4.60          sql_mark_as_compromized = "update trust not indexed set comm_type = 15"
    4.61 -                                  " where pgp_keypair_fpr = ?1 ;";
    4.62 +                                  " where pgp_keypair_fpr = upper(replace(?1,' ','')) ;";
    4.63  
    4.64          sql_crashdump = "select timestamp, title, entity, description, comment"
    4.65                          " from log order by timestamp desc limit ?1 ;";
    4.66 @@ -226,13 +227,13 @@
    4.67  
    4.68          // blacklist
    4.69  
    4.70 -        sql_blacklist_add = "insert or replace into blacklist_keys (fpr) values (?1) ;"
    4.71 -                            "delete from identity where main_key_id = ?1 ;"
    4.72 -                            "delete from pgp_keypair where fpr = ?1 ;";
    4.73 +        sql_blacklist_add = "insert or replace into blacklist_keys (fpr) values (upper(replace(?1,' ',''))) ;"
    4.74 +                            "delete from identity where main_key_id = upper(replace(?1,' ','')) ;"
    4.75 +                            "delete from pgp_keypair where fpr = upper(replace(?1,' ','')) ;";
    4.76  
    4.77 -        sql_blacklist_delete = "delete from blacklist_keys where fpr = ?1 ;";
    4.78 +        sql_blacklist_delete = "delete from blacklist_keys where fpr = upper(replace(?1,' ','')) ;";
    4.79  
    4.80 -        sql_blacklist_is_listed = "select count(*) from blacklist_keys where fpr = ?1 ;";
    4.81 +        sql_blacklist_is_listed = "select count(*) from blacklist_keys where fpr = upper(replace(?1,' ','')) ;";
    4.82  
    4.83          sql_blacklist_retrieve = "select * from blacklist_keys ;";
    4.84      }
    4.85 @@ -671,7 +672,9 @@
    4.86  }
    4.87  
    4.88  DYNAMIC_API PEP_STATUS get_identity(
    4.89 -        PEP_SESSION session, const char *address,
    4.90 +        PEP_SESSION session,
    4.91 +        const char *address,
    4.92 +        const char *user_id,
    4.93          pEp_identity **identity
    4.94      )
    4.95  {
    4.96 @@ -689,6 +692,7 @@
    4.97  
    4.98      sqlite3_reset(session->get_identity);
    4.99      sqlite3_bind_text(session->get_identity, 1, address, -1, SQLITE_STATIC);
   4.100 +    sqlite3_bind_text(session->get_identity, 2, user_id, -1, SQLITE_STATIC);
   4.101  
   4.102      result = sqlite3_step(session->get_identity);
   4.103      switch (result) {
   4.104 @@ -696,15 +700,15 @@
   4.105          _identity = new_identity(
   4.106                  address,
   4.107                  (const char *) sqlite3_column_text(session->get_identity, 0),
   4.108 -                (const char *) sqlite3_column_text(session->get_identity, 1),
   4.109 -                (const char *) sqlite3_column_text(session->get_identity, 2)
   4.110 +                user_id,
   4.111 +                (const char *) sqlite3_column_text(session->get_identity, 1)
   4.112                  );
   4.113          assert(_identity);
   4.114          if (_identity == NULL)
   4.115              return PEP_OUT_OF_MEMORY;
   4.116  
   4.117 -        _identity->comm_type = (PEP_comm_type) sqlite3_column_int(session->get_identity, 3);
   4.118 -        _lang = (const char *) sqlite3_column_text(session->get_identity, 4);
   4.119 +        _identity->comm_type = (PEP_comm_type) sqlite3_column_int(session->get_identity, 2);
   4.120 +        _lang = (const char *) sqlite3_column_text(session->get_identity, 3);
   4.121          if (_lang && _lang[0]) {
   4.122              assert(_lang[0] >= 'a' && _lang[0] <= 'z');
   4.123              assert(_lang[1] >= 'a' && _lang[1] <= 'z');
   4.124 @@ -868,16 +872,7 @@
   4.125      result = sqlite3_step(session->get_trust);
   4.126      switch (result) {
   4.127      case SQLITE_ROW: {
   4.128 -        const char * user_id = (const char *) sqlite3_column_text(session->get_trust, 0);
   4.129 -        int comm_type = (PEP_comm_type) sqlite3_column_int(session->get_trust, 1);
   4.130 -
   4.131 -        if (strcmp(user_id, identity->user_id) != 0) {
   4.132 -            free(identity->user_id);
   4.133 -            identity->user_id = strdup(user_id);
   4.134 -            assert(identity->user_id);
   4.135 -            if (identity->user_id == NULL)
   4.136 -                return PEP_OUT_OF_MEMORY;
   4.137 -        }
   4.138 +        int comm_type = (PEP_comm_type) sqlite3_column_int(session->get_trust, 0);
   4.139          identity->comm_type = comm_type;
   4.140          break;
   4.141      }
     5.1 --- a/src/pEpEngine.h	Tue May 03 08:30:22 2016 +0200
     5.2 +++ b/src/pEpEngine.h	Tue May 03 08:30:41 2016 +0200
     5.3 @@ -432,6 +432,8 @@
     5.4  //    parameters:
     5.5  //        session (in)        session handle
     5.6  //        address (in)        C string with communication address, UTF-8 encoded
     5.7 +//        user_id (in)        unique C string to identify person that identity
     5.8 +//                            is refering to
     5.9  //        identity (out)      pointer to pEp_identity structure with results or
    5.10  //                            NULL if failure
    5.11  //
    5.12 @@ -443,11 +445,12 @@
    5.13  //        more
    5.14  
    5.15  DYNAMIC_API PEP_STATUS get_identity(
    5.16 -        PEP_SESSION session, const char *address,
    5.17 +        PEP_SESSION session,
    5.18 +        const char *address,
    5.19 +        const char *user_id,
    5.20          pEp_identity **identity
    5.21      );
    5.22  
    5.23 -
    5.24  // set_identity() - set identity information
    5.25  //
    5.26  //    parameters: