Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • storage_xml.c

    r64b4263 rd628339  
    3434
    3535typedef enum {
    36         XML_PASS_CHECK = 0,
    37         XML_LOAD
    38 } xml_action;
     36        XML_PASS_CHECK_ONLY = -1,
     37        XML_PASS_UNKNOWN = 0,
     38        XML_PASS_WRONG,
     39        XML_PASS_OK
     40} xml_pass_st;
    3941
    4042/* To make it easier later when extending the format: */
     
    6365{
    6466        struct xt_node *c;
    65         struct set *s;
    6667
    6768        for (c = node->children; (c = xt_find_node(c, "setting")); c = c->next) {
    6869                char *name = xt_find_attr(c, "name");
    69                 char *locked = xt_find_attr(c, "locked");
    7070
    7171                if (!name) {
     
    8080                }
    8181                set_setstr(head, name, c->text);
    82                 if (locked && !g_strcasecmp(locked, "true")) {
    83                         s = set_find(head, name);
    84                         if (s) {
    85                                 s->flags |= SET_LOCKED;
    86                         }
    87                 }
     82        }
     83}
     84
     85/* Use for unsupported/not-found protocols. Save settings as-is but don't allow changes. */
     86static void handle_settings_raw(struct xt_node *node, set_t **head)
     87{
     88        struct xt_node *c;
     89
     90        for (c = node->children; (c = xt_find_node(c, "setting")); c = c->next) {
     91                char *name = xt_find_attr(c, "name");
     92
     93                if (!name) {
     94                        continue;
     95                }
     96
     97                set_t *s = set_add(head, name, NULL, NULL, NULL);
     98                set_setstr(head, name, c->text);
     99                s->flags |= SET_HIDDEN |
     100                            ACC_SET_OFFLINE_ONLY | ACC_SET_ONLINE_ONLY;
    88101        }
    89102}
     
    92105{
    93106        struct xml_parsedata *xd = data;
    94         char *protocol, *handle, *server, *password = NULL, *autoconnect, *tag, *locked;
     107        char *protocol, *handle, *server, *password = NULL, *autoconnect, *tag;
    95108        char *pass_b64 = NULL;
    96109        unsigned char *pass_cr = NULL;
    97         int pass_len, local = 0;
     110        int pass_len;
    98111        struct prpl *prpl = NULL;
    99112        account_t *acc;
     
    105118        autoconnect = xt_find_attr(node, "autoconnect");
    106119        tag = xt_find_attr(node, "tag");
    107         locked = xt_find_attr(node, "locked");
    108120
    109121        protocol = xt_find_attr(node, "protocol");
     
    111123                prpl = find_protocol(protocol);
    112124                if (!prpl) {
    113                         irc_rootmsg(xd->irc, "Error loading user config: Protocol not found: `%s'", protocol);
    114                         return XT_ABORT;
    115                 }
    116                 local = protocol_account_islocal(protocol);
     125                        irc_rootmsg(xd->irc, "Warning: Protocol not found: `%s'", protocol);
     126                        prpl = (struct prpl*) &protocol_missing;
     127                }
    117128        }
    118129
    119130        if (!handle || !pass_b64 || !protocol || !prpl) {
    120131                return XT_ABORT;
    121         }
    122 
    123         pass_len = base64_decode(pass_b64, (unsigned char **) &pass_cr);
    124         if (xd->irc->auth_backend) {
    125                 password = g_strdup((char *)pass_cr);
     132        } else if ((pass_len = base64_decode(pass_b64, (unsigned char **) &pass_cr)) &&
     133                   arc_decode(pass_cr, pass_len, &password, xd->given_pass) >= 0) {
     134                acc = account_add(xd->irc->b, prpl, handle, password);
     135                if (server) {
     136                        set_setstr(&acc->set, "server", server);
     137                }
     138                if (autoconnect) {
     139                        set_setstr(&acc->set, "auto_connect", autoconnect);
     140                }
     141                if (tag) {
     142                        set_setstr(&acc->set, "tag", tag);
     143                }
     144                if (prpl == &protocol_missing) {
     145                        set_t *s = set_add(&acc->set, "_protocol_name", protocol, NULL, NULL);
     146                        s->flags |= SET_HIDDEN | SET_NOSAVE |
     147                                    ACC_SET_OFFLINE_ONLY | ACC_SET_ONLINE_ONLY;
     148                }
    126149        } else {
    127                 pass_len = arc_decode(pass_cr, pass_len, &password, xd->given_pass);
    128                 if (pass_len < 0) {
    129                         g_free(pass_cr);
    130                         g_free(password);
    131                         return XT_ABORT;
    132                 }
    133         }
    134 
    135         acc = account_add(xd->irc->b, prpl, handle, password);
    136         if (server) {
    137                 set_setstr(&acc->set, "server", server);
    138         }
    139         if (autoconnect) {
    140                 set_setstr(&acc->set, "auto_connect", autoconnect);
    141         }
    142         if (tag) {
    143                 set_setstr(&acc->set, "tag", tag);
    144         }
    145         if (local) {
    146                 acc->flags |= ACC_FLAG_LOCAL;
    147         }
    148         if (locked && !g_strcasecmp(locked, "true")) {
    149                 acc->flags |= ACC_FLAG_LOCKED;
     150                g_free(pass_cr);
     151                g_free(password);
     152                return XT_ABORT;
    150153        }
    151154
     
    153156        g_free(password);
    154157
    155         handle_settings(node, &acc->set);
     158        if (prpl == &protocol_missing) {
     159                handle_settings_raw(node, &acc->set);
     160        } else {
     161                handle_settings(node, &acc->set);
     162        }
    156163
    157164        for (c = node->children; (c = xt_find_node(c, "buddy")); c = c->next) {
     
    203210};
    204211
    205 static storage_status_t xml_load_real(irc_t *irc, const char *my_nick, const char *password, xml_action action)
     212static storage_status_t xml_load_real(irc_t *irc, const char *my_nick, const char *password, xml_pass_st action)
    206213{
    207214        struct xml_parsedata xd[1];
     
    245252        }
    246253
    247         if (action == XML_PASS_CHECK) {
     254        {
    248255                char *nick = xt_find_attr(node, "nick");
    249256                char *pass = xt_find_attr(node, "password");
    250                 char *backend = xt_find_attr(node, "auth_backend");
    251 
    252                 if (!nick || !(pass || backend)) {
     257
     258                if (!nick || !pass) {
    253259                        goto error;
    254                 }
    255 
    256                 if (backend) {
    257                         g_free(xd->irc->auth_backend);
    258                         xd->irc->auth_backend = g_strdup(backend);
    259                         ret = STORAGE_CHECK_BACKEND;
    260260                } else if ((st = md5_verify_password(xd->given_pass, pass)) != 0) {
    261261                        ret = STORAGE_INVALID_PASSWORD;
    262                 } else {
    263                         ret = STORAGE_OK;
    264                 }
    265                 goto error;
    266         }
    267 
     262                        goto error;
     263                }
     264        }
     265
     266        if (action == XML_PASS_CHECK_ONLY) {
     267                ret = STORAGE_OK;
     268                goto error;
     269        }
     270
     271        /* DO NOT call xt_handle() before verifying the password! */
    268272        if (xt_handle(xp, NULL, 1) == XT_HANDLED) {
    269273                ret = STORAGE_OK;
     
    280284static storage_status_t xml_load(irc_t *irc, const char *password)
    281285{
    282         return xml_load_real(irc, irc->user->nick, password, XML_LOAD);
    283 }
    284 
    285 static storage_status_t xml_check_pass(irc_t *irc, const char *my_nick, const char *password)
    286 {
    287         return xml_load_real(irc, my_nick, password, XML_PASS_CHECK);
     286        return xml_load_real(irc, irc->user->nick, password, XML_PASS_UNKNOWN);
     287}
     288
     289static storage_status_t xml_check_pass(const char *my_nick, const char *password)
     290{
     291        return xml_load_real(NULL, my_nick, password, XML_PASS_CHECK_ONLY);
    288292}
    289293
     
    300304        struct xt_node *root, *cur;
    301305
     306        /* Generate a salted md5sum of the password. Use 5 bytes for the salt
     307           (to prevent dictionary lookups of passwords) to end up with a 21-
     308           byte password hash, more convenient for base64 encoding. */
     309        random_bytes(pass_md5 + 16, 5);
     310        md5_init(&md5_state);
     311        md5_append(&md5_state, (md5_byte_t *) irc->password, strlen(irc->password));
     312        md5_append(&md5_state, pass_md5 + 16, 5);   /* Add the salt. */
     313        md5_finish(&md5_state, pass_md5);
     314        /* Save the hash in base64-encoded form. */
     315        pass_buf = base64_encode(pass_md5, 21);
     316
    302317        root = cur = xt_new_node("user", NULL, NULL);
    303         if (irc->auth_backend) {
    304                 xt_add_attr(cur, "auth_backend", irc->auth_backend);
    305         } else {
    306                 /* Generate a salted md5sum of the password. Use 5 bytes for the salt
    307                    (to prevent dictionary lookups of passwords) to end up with a 21-
    308                    byte password hash, more convenient for base64 encoding. */
    309                 random_bytes(pass_md5 + 16, 5);
    310                 md5_init(&md5_state);
    311                 md5_append(&md5_state, (md5_byte_t *) irc->password, strlen(irc->password));
    312                 md5_append(&md5_state, pass_md5 + 16, 5);   /* Add the salt. */
    313                 md5_finish(&md5_state, pass_md5);
    314                 /* Save the hash in base64-encoded form. */
    315                 pass_buf = base64_encode(pass_md5, 21);
    316                 xt_add_attr(cur, "password", pass_buf);
    317                 g_free(pass_buf);
    318         }
    319 
    320318        xt_add_attr(cur, "nick", irc->user->nick);
     319        xt_add_attr(cur, "password", pass_buf);
    321320        xt_add_attr(cur, "version", XML_FORMAT_VERSION);
     321
     322        g_free(pass_buf);
    322323
    323324        xml_generate_settings(cur, &irc->b->set);
     
    330331                int pass_len;
    331332
    332                 if(irc->auth_backend) {
    333                         /* If we don't "own" the password, it may change without us
    334                          * knowing, so we cannot encrypt the data, as we then may not be
    335                          * able to decrypt it */
    336                         pass_b64 = base64_encode((unsigned char *)acc->pass, strlen(acc->pass));
     333                pass_len = arc_encode(acc->pass, strlen(acc->pass), (unsigned char **) &pass_cr, irc->password, 12);
     334                pass_b64 = base64_encode(pass_cr, pass_len);
     335                g_free(pass_cr);
     336
     337                cur = xt_new_node("account", NULL, NULL);
     338                if (acc->prpl == &protocol_missing) {
     339                        xt_add_attr(cur, "protocol", set_getstr(&acc->set, "_protocol_name"));
    337340                } else {
    338                         pass_len = arc_encode(acc->pass, strlen(acc->pass), (unsigned char **) &pass_cr, irc->password, 12);
    339                         pass_b64 = base64_encode(pass_cr, pass_len);
    340                         g_free(pass_cr);
    341                 }
    342 
    343                 cur = xt_new_node("account", NULL, NULL);
    344                 xt_add_attr(cur, "protocol", acc->prpl->name);
     341                        xt_add_attr(cur, "protocol", acc->prpl->name);
     342                }
    345343                xt_add_attr(cur, "handle", acc->user);
    346344                xt_add_attr(cur, "password", pass_b64);
     
    350348                        xt_add_attr(cur, "server", acc->server);
    351349                }
    352                 if (acc->flags & ACC_FLAG_LOCKED) {
    353                         xt_add_attr(cur, "locked", "true");
    354                 }
    355350
    356351                g_free(pass_b64);
     
    397392                        xt_add_child(cur, xset = xt_new_node("setting", set->value, NULL));
    398393                        xt_add_attr(xset, "name", set->key);
    399                         if (set->flags & SET_LOCKED) {
    400                                 xt_add_attr(xset, "locked", "true");
    401                         }
    402394                }
    403395        }
     
    458450
    459451
    460 static storage_status_t xml_remove(const char *nick)
     452static storage_status_t xml_remove(const char *nick, const char *password)
    461453{
    462454        char s[512], *lc;
     455        storage_status_t status;
     456
     457        status = xml_check_pass(nick, password);
     458        if (status != STORAGE_OK) {
     459                return status;
     460        }
    463461
    464462        lc = g_strdup(nick);
Note: See TracChangeset for help on using the changeset viewer.