Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • storage_xml.c

    rd628339 r64b4263  
    3434
    3535typedef enum {
    36         XML_PASS_CHECK_ONLY = -1,
    37         XML_PASS_UNKNOWN = 0,
    38         XML_PASS_WRONG,
    39         XML_PASS_OK
    40 } xml_pass_st;
     36        XML_PASS_CHECK = 0,
     37        XML_LOAD
     38} xml_action;
    4139
    4240/* To make it easier later when extending the format: */
     
    6563{
    6664        struct xt_node *c;
     65        struct set *s;
    6766
    6867        for (c = node->children; (c = xt_find_node(c, "setting")); c = c->next) {
    6968                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         }
    83 }
    84 
    85 /* Use for unsupported/not-found protocols. Save settings as-is but don't allow changes. */
    86 static 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;
     82                if (locked && !g_strcasecmp(locked, "true")) {
     83                        s = set_find(head, name);
     84                        if (s) {
     85                                s->flags |= SET_LOCKED;
     86                        }
     87                }
    10188        }
    10289}
     
    10592{
    10693        struct xml_parsedata *xd = data;
    107         char *protocol, *handle, *server, *password = NULL, *autoconnect, *tag;
     94        char *protocol, *handle, *server, *password = NULL, *autoconnect, *tag, *locked;
    10895        char *pass_b64 = NULL;
    10996        unsigned char *pass_cr = NULL;
    110         int pass_len;
     97        int pass_len, local = 0;
    11198        struct prpl *prpl = NULL;
    11299        account_t *acc;
     
    118105        autoconnect = xt_find_attr(node, "autoconnect");
    119106        tag = xt_find_attr(node, "tag");
     107        locked = xt_find_attr(node, "locked");
    120108
    121109        protocol = xt_find_attr(node, "protocol");
     
    123111                prpl = find_protocol(protocol);
    124112                if (!prpl) {
    125                         irc_rootmsg(xd->irc, "Warning: Protocol not found: `%s'", protocol);
    126                         prpl = (struct prpl*) &protocol_missing;
    127                 }
     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);
    128117        }
    129118
    130119        if (!handle || !pass_b64 || !protocol || !prpl) {
    131120                return XT_ABORT;
    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                 }
     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);
    149126        } else {
    150                 g_free(pass_cr);
    151                 g_free(password);
    152                 return XT_ABORT;
     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;
    153150        }
    154151
     
    156153        g_free(password);
    157154
    158         if (prpl == &protocol_missing) {
    159                 handle_settings_raw(node, &acc->set);
    160         } else {
    161                 handle_settings(node, &acc->set);
    162         }
     155        handle_settings(node, &acc->set);
    163156
    164157        for (c = node->children; (c = xt_find_node(c, "buddy")); c = c->next) {
     
    210203};
    211204
    212 static storage_status_t xml_load_real(irc_t *irc, const char *my_nick, const char *password, xml_pass_st action)
     205static storage_status_t xml_load_real(irc_t *irc, const char *my_nick, const char *password, xml_action action)
    213206{
    214207        struct xml_parsedata xd[1];
     
    252245        }
    253246
    254         {
     247        if (action == XML_PASS_CHECK) {
    255248                char *nick = xt_find_attr(node, "nick");
    256249                char *pass = xt_find_attr(node, "password");
    257 
    258                 if (!nick || !pass) {
     250                char *backend = xt_find_attr(node, "auth_backend");
     251
     252                if (!nick || !(pass || backend)) {
    259253                        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                         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! */
     262                } else {
     263                        ret = STORAGE_OK;
     264                }
     265                goto error;
     266        }
     267
    272268        if (xt_handle(xp, NULL, 1) == XT_HANDLED) {
    273269                ret = STORAGE_OK;
     
    284280static storage_status_t xml_load(irc_t *irc, const char *password)
    285281{
    286         return xml_load_real(irc, irc->user->nick, password, XML_PASS_UNKNOWN);
    287 }
    288 
    289 static 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);
     282        return xml_load_real(irc, irc->user->nick, password, XML_LOAD);
     283}
     284
     285static 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);
    292288}
    293289
     
    304300        struct xt_node *root, *cur;
    305301
    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 
    317302        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
    318320        xt_add_attr(cur, "nick", irc->user->nick);
    319         xt_add_attr(cur, "password", pass_buf);
    320321        xt_add_attr(cur, "version", XML_FORMAT_VERSION);
    321 
    322         g_free(pass_buf);
    323322
    324323        xml_generate_settings(cur, &irc->b->set);
     
    331330                int pass_len;
    332331
    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);
     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));
     337                } 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                }
    336342
    337343                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"));
    340                 } else {
    341                         xt_add_attr(cur, "protocol", acc->prpl->name);
    342                 }
     344                xt_add_attr(cur, "protocol", acc->prpl->name);
    343345                xt_add_attr(cur, "handle", acc->user);
    344346                xt_add_attr(cur, "password", pass_b64);
     
    348350                        xt_add_attr(cur, "server", acc->server);
    349351                }
     352                if (acc->flags & ACC_FLAG_LOCKED) {
     353                        xt_add_attr(cur, "locked", "true");
     354                }
    350355
    351356                g_free(pass_b64);
     
    392397                        xt_add_child(cur, xset = xt_new_node("setting", set->value, NULL));
    393398                        xt_add_attr(xset, "name", set->key);
     399                        if (set->flags & SET_LOCKED) {
     400                                xt_add_attr(xset, "locked", "true");
     401                        }
    394402                }
    395403        }
     
    450458
    451459
    452 static storage_status_t xml_remove(const char *nick, const char *password)
     460static storage_status_t xml_remove(const char *nick)
    453461{
    454462        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         }
    461463
    462464        lc = g_strdup(nick);
Note: See TracChangeset for help on using the changeset viewer.