Changeset e71cfbc


Ignore:
Timestamp:
2009-10-13T22:33:12Z (10 years ago)
Author:
Wilmer van der Gaast <wilmer@…>
Branches:
master
Children:
99c8f13
Parents:
7ea8697
Message:

Turns out I *did* implement HTTPS auth for Yahoo! myself already, but I
kept it as a patch somewhere in my homedir because I thought I didn't
need it. I like this code more so I'll use it instead.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • protocols/yahoo/libyahoo2.c

    r7ea8697 re71cfbc  
    9090#include "base64.h"
    9191#include "http_client.h"
    92 
    93 static void yahoo_process_auth_response(struct http_request *req);
    9492
    9593#ifdef USE_STRUCT_CALLBACKS
     
    23092307}
    23102308
     2309struct yahoo_https_auth_data
     2310{
     2311        struct yahoo_input_data *yid;
     2312        char *token;
     2313        char *chal;
     2314};
     2315
     2316static void yahoo_https_auth_token_init(struct yahoo_https_auth_data *had);
     2317static void yahoo_https_auth_token_finish(struct http_request *req);
     2318static void yahoo_https_auth_init(struct yahoo_https_auth_data *had);
     2319static void yahoo_https_auth_finish(struct http_request *req);
     2320
     2321/* Extract a value from a login.yahoo.com response. Assume CRLF-linebreaks
     2322   and FAIL miserably if they're not there... */
     2323static char *yahoo_ha_find_key(char *response, char *key)
     2324{
     2325        char *s, *end;
     2326        int len = strlen(key);
     2327       
     2328        s = response;
     2329        do {
     2330                if (strncmp(s, key, len) == 0 && s[len] == '=') {
     2331                        s += len + 1;
     2332                        if ((end = strchr(s, '\r')))
     2333                                return g_strndup(s, end - s);
     2334                        else
     2335                                return g_strdup(s);
     2336                }
     2337               
     2338                if ((s = strchr(s, '\n')))
     2339                        s ++;
     2340        } while (s && *s);
     2341       
     2342        return NULL;
     2343}
     2344
     2345static enum yahoo_status yahoo_https_status_parse(int code)
     2346{
     2347        switch (code)
     2348        {
     2349                case 1212: return YAHOO_LOGIN_PASSWD;
     2350                case 1213: return YAHOO_LOGIN_LOCK;
     2351                case 1235: return YAHOO_LOGIN_UNAME;
     2352                default: return (enum yahoo_status) code;
     2353        }
     2354}
     2355
    23112356static void yahoo_process_auth_0x10(struct yahoo_input_data *yid, const char *seed, const char *sn)
    23122357{
     2358        struct yahoo_https_auth_data *had = g_new0(struct yahoo_https_auth_data, 1);
     2359       
     2360        had->yid = yid;
     2361        had->chal = g_strdup(seed);
     2362       
     2363        yahoo_https_auth_token_init(had);
     2364}
     2365
     2366static void yahoo_https_auth_token_init(struct yahoo_https_auth_data *had)
     2367{
     2368        struct yahoo_input_data *yid = had->yid;
     2369        struct yahoo_data *yd = yid->yd;
     2370        struct http_request *req;
     2371        char *login, *passwd, *chal;
    23132372        char *url;
    2314 
    2315         yid->yd->login_cookie = strdup(seed);
    2316 
    2317         url = g_strdup_printf(
    2318                 "https://login.yahoo.com/config/pwtoken_get?"
    2319                 "src=ymsgr&ts=&login=%s&passwd=%s&chal=%s",
    2320                 yid->yd->user, yid->yd->password, seed);
    2321 
    2322         http_dorequest_url(url, yahoo_process_auth_response, yid);
     2373       
     2374        login = g_strndup(yd->user, 3 * strlen(yd->user));
     2375        http_encode(login);
     2376        passwd = g_strndup(yd->password, 3 * strlen(yd->password));
     2377        http_encode(passwd);
     2378        chal = g_strndup(had->chal, 3 * strlen(had->chal));
     2379        http_encode(chal);
     2380       
     2381        url = g_strdup_printf("https://login.yahoo.com/config/pwtoken_get?src=ymsgr&ts=%d&login=%s&passwd=%s&chal=%s",
     2382                               (int) time(NULL), login, passwd, chal);
     2383       
     2384        req = http_dorequest_url(url, yahoo_https_auth_token_finish, had);
    23232385       
    23242386        g_free(url);
     2387        g_free(chal);
     2388        g_free(passwd);
     2389        g_free(login);
     2390}
     2391
     2392static void yahoo_https_auth_token_finish(struct http_request *req)
     2393{
     2394        struct yahoo_https_auth_data *had = req->data;
     2395        struct yahoo_input_data *yid = had->yid;
     2396        struct yahoo_data *yd = yid->yd;
     2397        int st;
     2398       
     2399        if (req->status_code != 200) {
     2400                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, 2000 + req->status_code, NULL);
     2401                goto fail;
     2402        }
     2403       
     2404        if (sscanf(req->reply_body, "%d", &st) != 1 || st != 0) {
     2405                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, yahoo_https_status_parse(st), NULL);
     2406                goto fail;
     2407        }
     2408       
     2409        if ((had->token = yahoo_ha_find_key(req->reply_body, "ymsgr")) == NULL) {
     2410                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, 3001, NULL);
     2411                goto fail;
     2412        }
     2413       
     2414        return yahoo_https_auth_init(had);
     2415       
     2416fail:
     2417        g_free(had->token);
     2418        g_free(had->chal);
     2419        g_free(had);
     2420}
     2421
     2422static void yahoo_https_auth_init(struct yahoo_https_auth_data *had)
     2423{
     2424        struct http_request *req;
     2425        char *url;
     2426       
     2427        url = g_strdup_printf("https://login.yahoo.com/config/pwtoken_login?src=ymsgr&ts=%d&token=%s",
     2428                              (int) time(NULL), had->token);
     2429       
     2430        req = http_dorequest_url(url, yahoo_https_auth_finish, had);
     2431       
     2432        g_free(url);
     2433}
     2434
     2435static void yahoo_https_auth_finish(struct http_request *req)
     2436{
     2437        struct yahoo_https_auth_data *had = req->data;
     2438        struct yahoo_input_data *yid = had->yid;
     2439        struct yahoo_data *yd = yid->yd;
     2440        struct yahoo_packet *pack;
     2441        char *crumb;
     2442        int st;
     2443       
     2444        md5_byte_t result[16];
     2445        md5_state_t ctx;
     2446       
     2447        unsigned char yhash[32];
     2448
     2449        if (req->status_code != 200) {
     2450                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, 2000 + req->status_code, NULL);
     2451                goto fail;
     2452        }
     2453       
     2454        if (sscanf(req->reply_body, "%d", &st) != 1 || st != 0) {
     2455                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, yahoo_https_status_parse(st), NULL);
     2456                goto fail;
     2457        }
     2458       
     2459        if ((yd->cookie_y = yahoo_ha_find_key(req->reply_body, "Y")) == NULL ||
     2460            (yd->cookie_t = yahoo_ha_find_key(req->reply_body, "T")) == NULL ||
     2461            (crumb = yahoo_ha_find_key(req->reply_body, "crumb")) == NULL) {
     2462                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, 3002, NULL);
     2463                goto fail;
     2464        }
     2465       
     2466        md5_init(&ctx); 
     2467        md5_append(&ctx, (unsigned char*) crumb, 11);
     2468        md5_append(&ctx, (unsigned char*) had->chal, strlen(had->chal));
     2469        md5_finish(&ctx, result);
     2470        to_y64(yhash, result, 16);
     2471
     2472        pack = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP, yd->initial_status, yd->session_id);
     2473        yahoo_packet_hash(pack, 1, yd->user);
     2474        yahoo_packet_hash(pack, 0, yd->user);
     2475        yahoo_packet_hash(pack, 277, yd->cookie_y);
     2476        yahoo_packet_hash(pack, 278, yd->cookie_t);
     2477        yahoo_packet_hash(pack, 307, (char*) yhash);
     2478        yahoo_packet_hash(pack, 244, "524223");
     2479        yahoo_packet_hash(pack, 2, yd->user);
     2480        yahoo_packet_hash(pack, 2, "1");
     2481        yahoo_packet_hash(pack, 98, "us");
     2482        yahoo_packet_hash(pack, 135, "7.5.0.647");
     2483       
     2484        yahoo_send_packet(yid, pack, 0);
     2485               
     2486        yahoo_packet_free(pack);
     2487       
     2488        return;
     2489       
     2490fail:
     2491        g_free(had->token);
     2492        g_free(had->chal);
     2493        g_free(had);
    23252494}
    23262495
     
    23542523                        break;
    23552524                case 2:
    2356                         /* HTTPS */
    23572525                        yahoo_process_auth_0x10(yid, seed, sn);
    23582526                        break;
     
    36633831}
    36643832
    3665 /* #define LOG(x...) printf x */
    3666 
    3667 static void yahoo_process_auth_response(struct http_request *req)
    3668 {
    3669         char *line_end;
    3670         char *token;
    3671         char *cookie;
    3672 
    3673         int error_code = 0;
    3674         int is_ymsgr = 0;
    3675 
    3676         struct yahoo_input_data *yid = req->data;
    3677 
    3678         char crypt_hash[25];
    3679 
    3680         md5_byte_t result[16];
    3681         md5_state_t ctx;
    3682 
    3683         struct yahoo_packet *packet = NULL;
    3684        
    3685         if (y_list_find(inputs, yid) == NULL)
    3686                 return;
    3687        
    3688         if (req->status_code != 200) {
    3689                 error_code = 3000 + req->status_code;
    3690                 goto FAIL;
    3691         }
    3692 
    3693         token = req->reply_body;
    3694         line_end = strstr(token, "\r\n");
    3695 
    3696         if (line_end) {
    3697                 *line_end = '\0';
    3698 
    3699                 line_end += 2;
    3700         }
    3701        
    3702         if (sscanf(token, "%d", &error_code) != 1) {
    3703                 error_code = 3000;
    3704                 goto FAIL;
    3705         }
    3706 
    3707         switch(error_code) {
    3708                 case 0:
    3709                         /* successful */
    3710                         break;
    3711 
    3712                 case 1212:
    3713                         LOG(("Incorrect ID or password\n"));
    3714                         error_code = YAHOO_LOGIN_PASSWD;
    3715                         goto FAIL;
    3716 
    3717                 case 1213:
    3718                         LOG(("Security lock from too many failed login attempts\n"));
    3719                         error_code = YAHOO_LOGIN_LOCK;
    3720                         goto FAIL;
    3721 
    3722                 case 1214:
    3723                         LOG(("Security lock\n"));
    3724                         goto FAIL;
    3725 
    3726                 case 1235:
    3727                         LOG(("User ID not taken yet\n"));
    3728                         error_code = YAHOO_LOGIN_UNAME;
    3729                         goto FAIL;
    3730 
    3731                 case 1216:
    3732                         LOG(("Seems to be a lock, but shows the same generic User ID/Password failure\n"));
    3733                         goto FAIL;
    3734 
    3735                 default:
    3736                         /* Unknown error code */
    3737                         LOG(("Unknown Error\n"));
    3738                         goto FAIL;
    3739         }
    3740 
    3741         if ( !strncmp(line_end, "ymsgr=", 6) ) {
    3742                 is_ymsgr = 1;
    3743         }
    3744         else if ( strncmp(line_end, "crumb=", 6) ) {
    3745                 LOG(("Oops! There was no ymsgr=. Where do I get my token from now :("));
    3746                 LOG(("I got this:\n\n%s\n",line_end));
    3747                 error_code = 2201;
    3748                 goto FAIL;
    3749         }
    3750 
    3751         token = line_end+6;
    3752 
    3753         line_end = strstr(token, "\r\n");
    3754 
    3755         if(line_end) {
    3756                 *line_end = '\0';
    3757                 line_end += 2;
    3758         }
    3759 
    3760         /* Go for the crumb */
    3761         if(is_ymsgr) {
    3762                 char *url;
    3763 
    3764                 url = g_strdup_printf(
    3765                         "https://login.yahoo.com/config/pwtoken_login?"
    3766                         "src=ymsgr&ts=&token=%s", token);
    3767 
    3768                 http_dorequest_url(url, yahoo_process_auth_response, yid);
    3769 
    3770                 g_free(url);
    3771 
    3772                 return;
    3773         }
    3774 
    3775         /* token is actually crumb */
    3776 
    3777         if(!line_end) {
    3778                 /* We did not get our cookies. Cry. */
    3779         }
    3780 
    3781         if((cookie = strstr(req->reply_headers, "Set-Cookie: Y=")) &&
    3782            (line_end = strstr(cookie + 14, "\r\n"))) {
    3783                 *line_end = '\0';
    3784                 yid->yd->cookie_y = strdup(cookie + 14);
    3785                 *line_end = ';';
    3786         } else {
    3787                 /* Cry. */
    3788                 LOG(("NO Y Cookie!"));
    3789                 error_code = 2202;
    3790                 goto FAIL;
    3791         }
    3792 
    3793         if((cookie = strstr(req->reply_headers, "Set-Cookie: T=")) &&
    3794            (line_end = strstr(cookie + 14, "\r\n"))) {
    3795                 *line_end = '\0';
    3796                 yid->yd->cookie_t = strdup(cookie + 14);
    3797                 *line_end = ';';
    3798         } else {
    3799                 /* Cry. */
    3800                 LOG(("NO T Cookie!"));
    3801                 error_code = 2203;
    3802                 goto FAIL;
    3803         }
    3804 
    3805         md5_init(&ctx);
    3806         md5_append(&ctx, (md5_byte_t *)token, strlen(token));
    3807         md5_append(&ctx, (md5_byte_t *)yid->yd->login_cookie, strlen(yid->yd->login_cookie));
    3808         md5_finish(&ctx, result);
    3809 
    3810         to_y64((unsigned char*)crypt_hash, result, 16);
    3811 
    3812         packet = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP, yid->yd->initial_status, yid->yd->session_id);
    3813         yahoo_packet_hash(packet, 1, yid->yd->user);
    3814         yahoo_packet_hash(packet, 0, yid->yd->user);
    3815         yahoo_packet_hash(packet, 277, yid->yd->cookie_y);
    3816         yahoo_packet_hash(packet, 278, yid->yd->cookie_t);
    3817         yahoo_packet_hash(packet, 307, crypt_hash);
    3818         yahoo_packet_hash(packet, 244, "2097087");      /* Rekkanoryo says this is the build number */
    3819         yahoo_packet_hash(packet, 2, yid->yd->user);
    3820         yahoo_packet_hash(packet, 2, "1");
    3821         yahoo_packet_hash(packet, 98, "us");            /* TODO Put country code */
    3822         yahoo_packet_hash(packet, 135, "9.0.0.1389");
    3823                
    3824         yahoo_send_packet(yid, packet, 0);
    3825 
    3826         yahoo_packet_free(packet);
    3827 
    3828         /* We don't need this anymore */
    3829         free(yid->yd->login_cookie);
    3830         yid->yd->login_cookie = NULL;
    3831        
    3832         return;
    3833 
    3834 FAIL:
    3835         YAHOO_CALLBACK(ext_yahoo_login_response)(yid->yd->client_id, error_code, NULL);
    3836 }
    3837 
    3838 
    38393833static void (*yahoo_process_connection[])(struct yahoo_input_data *, int over) = {
    38403834        yahoo_process_pager_connection,
Note: See TracChangeset for help on using the changeset viewer.