Changes in protocols/jabber/sasl.c [911d97a:af97b23]
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
protocols/jabber/sasl.c
r911d97a raf97b23 26 26 #include "jabber.h" 27 27 #include "base64.h" 28 #include "oauth2.h"29 #include "oauth.h"30 28 31 29 xt_status sasl_pkt_mechanisms( struct xt_node *node, gpointer data ) … … 35 33 struct xt_node *c, *reply; 36 34 char *s; 37 int sup_plain = 0, sup_digest = 0 , sup_oauth2 = 0, sup_fb = 0;35 int sup_plain = 0, sup_digest = 0; 38 36 39 37 if( !sasl_supported( ic ) ) … … 61 59 if( c->text && g_strcasecmp( c->text, "DIGEST-MD5" ) == 0 ) 62 60 sup_digest = 1; 63 if( c->text && g_strcasecmp( c->text, "X-OAUTH2" ) == 0 )64 sup_oauth2 = 1;65 if( c->text && g_strcasecmp( c->text, "X-FACEBOOK-PLATFORM" ) == 0 )66 sup_fb = 1;67 61 68 62 c = c->next; … … 79 73 xt_add_attr( reply, "xmlns", XMLNS_SASL ); 80 74 81 if( set_getbool( &ic->acc->set, "oauth" ) ) 82 { 83 int len; 84 85 if( !sup_oauth2 ) 86 { 87 imcb_error( ic, "OAuth requested, but not supported by server" ); 88 imc_logout( ic, FALSE ); 89 xt_free_node( reply ); 90 return XT_ABORT; 91 } 92 93 /* X-OAUTH2 is, not *the* standard OAuth2 SASL/XMPP implementation. 94 It's currently used by GTalk and vaguely documented on 95 http://code.google.com/apis/cloudprint/docs/rawxmpp.html . */ 96 xt_add_attr( reply, "mechanism", "X-OAUTH2" ); 97 98 len = strlen( jd->username ) + strlen( jd->oauth2_access_token ) + 2; 99 s = g_malloc( len + 1 ); 100 s[0] = 0; 101 strcpy( s + 1, jd->username ); 102 strcpy( s + 2 + strlen( jd->username ), jd->oauth2_access_token ); 103 reply->text = base64_encode( (unsigned char *)s, len ); 104 reply->text_len = strlen( reply->text ); 105 g_free( s ); 106 } 107 else if( sup_fb && strstr( ic->acc->pass, "session_key=" ) ) 108 { 109 xt_add_attr( reply, "mechanism", "X-FACEBOOK-PLATFORM" ); 110 jd->flags |= JFLAG_SASL_FB; 111 } 112 else if( sup_digest ) 75 if( sup_digest ) 113 76 { 114 77 xt_add_attr( reply, "mechanism", "DIGEST-MD5" ); … … 133 96 } 134 97 135 if( reply &&!jabber_write_packet( ic, reply ) )98 if( !jabber_write_packet( ic, reply ) ) 136 99 { 137 100 xt_free_node( reply ); … … 234 197 struct im_connection *ic = data; 235 198 struct jabber_data *jd = ic->proto_data; 236 struct xt_node *reply _pkt= NULL;199 struct xt_node *reply = NULL; 237 200 char *nonce = NULL, *realm = NULL, *cnonce = NULL; 238 201 unsigned char cnonce_bin[30]; 239 202 char *digest_uri = NULL; 240 203 char *dec = NULL; 241 char *s = NULL , *reply = NULL;204 char *s = NULL; 242 205 xt_status ret = XT_ABORT; 243 206 … … 247 210 dec = frombase64( node->text ); 248 211 249 if( jd->flags & JFLAG_SASL_FB ) 250 { 251 /* Facebook proprietary authentication. Not as useful as it seemed, but 252 the code's written now, may as well keep it.. 253 254 Mechanism is described on http://developers.facebook.com/docs/chat/ 255 and in their Python module. It's all mostly useless because the tokens 256 expire after 24h. */ 257 GSList *p_in = NULL, *p_out = NULL, *p; 258 md5_state_t md5; 259 char time[33], *token; 260 const char *secret; 261 262 oauth_params_parse( &p_in, dec ); 263 oauth_params_add( &p_out, "nonce", oauth_params_get( &p_in, "nonce" ) ); 264 oauth_params_add( &p_out, "method", oauth_params_get( &p_in, "method" ) ); 265 oauth_params_free( &p_in ); 266 267 token = g_strdup( ic->acc->pass ); 268 oauth_params_parse( &p_in, token ); 269 g_free( token ); 270 oauth_params_add( &p_out, "session_key", oauth_params_get( &p_in, "session_key" ) ); 271 272 g_snprintf( time, sizeof( time ), "%lld", (long long) ( gettime() * 1000 ) ); 273 oauth_params_add( &p_out, "call_id", time ); 274 oauth_params_add( &p_out, "api_key", oauth2_service_facebook.consumer_key ); 275 oauth_params_add( &p_out, "v", "1.0" ); 276 oauth_params_add( &p_out, "format", "XML" ); 277 278 md5_init( &md5 ); 279 for( p = p_out; p; p = p->next ) 280 md5_append( &md5, p->data, strlen( p->data ) ); 281 282 secret = oauth_params_get( &p_in, "secret" ); 283 if( secret ) 284 md5_append( &md5, (unsigned char*) secret, strlen( secret ) ); 285 md5_finish_ascii( &md5, time ); 286 oauth_params_add( &p_out, "sig", time ); 287 288 reply = oauth_params_string( p_out ); 289 oauth_params_free( &p_out ); 290 oauth_params_free( &p_in ); 291 } 292 else if( !( s = sasl_get_part( dec, "rspauth" ) ) ) 212 if( !( s = sasl_get_part( dec, "rspauth" ) ) ) 293 213 { 294 214 /* See RFC 2831 for for information. */ … … 351 271 352 272 /* Now build the SASL response string: */ 353 reply = g_strdup_printf( "username=\"%s\",realm=\"%s\",nonce=\"%s\",cnonce=\"%s\"," 354 "nc=%08x,qop=auth,digest-uri=\"%s\",response=%s,charset=%s", 355 jd->username, realm, nonce, cnonce, 1, digest_uri, Hh, "utf-8" ); 273 g_free( dec ); 274 dec = g_strdup_printf( "username=\"%s\",realm=\"%s\",nonce=\"%s\",cnonce=\"%s\"," 275 "nc=%08x,qop=auth,digest-uri=\"%s\",response=%s,charset=%s", 276 jd->username, realm, nonce, cnonce, 1, digest_uri, Hh, "utf-8" ); 277 s = tobase64( dec ); 356 278 } 357 279 else 358 280 { 359 281 /* We found rspauth, but don't really care... */ 360 } 361 362 s = reply ? tobase64( reply ) : NULL; 363 reply_pkt = xt_new_node( "response", s, NULL ); 364 xt_add_attr( reply_pkt, "xmlns", XMLNS_SASL ); 365 366 if( !jabber_write_packet( ic, reply_pkt ) ) 282 g_free( s ); 283 s = NULL; 284 } 285 286 reply = xt_new_node( "response", s, NULL ); 287 xt_add_attr( reply, "xmlns", XMLNS_SASL ); 288 289 if( !jabber_write_packet( ic, reply ) ) 367 290 goto silent_error; 368 291 … … 378 301 g_free( cnonce ); 379 302 g_free( nonce ); 380 g_free( reply );381 303 g_free( realm ); 382 304 g_free( dec ); 383 305 g_free( s ); 384 xt_free_node( reply _pkt);306 xt_free_node( reply ); 385 307 386 308 return ret; … … 425 347 return ( jd->xt && jd->xt->root && xt_find_attr( jd->xt->root, "version" ) ) != 0; 426 348 } 427 428 void sasl_oauth2_init( struct im_connection *ic )429 {430 char *msg, *url;431 432 imcb_log( ic, "Starting OAuth authentication" );433 434 /* Temporary contact, just used to receive the OAuth response. */435 imcb_add_buddy( ic, "jabber_oauth", NULL );436 url = oauth2_url( &oauth2_service_google,437 "https://www.googleapis.com/auth/googletalk" );438 msg = g_strdup_printf( "Open this URL in your browser to authenticate: %s", url );439 imcb_buddy_msg( ic, "jabber_oauth", msg, 0, 0 );440 imcb_buddy_msg( ic, "jabber_oauth", "Respond to this message with the returned "441 "authorization token.", 0, 0 );442 443 g_free( msg );444 g_free( url );445 }446 447 static gboolean sasl_oauth2_remove_contact( gpointer data, gint fd, b_input_condition cond )448 {449 struct im_connection *ic = data;450 if( g_slist_find( jabber_connections, ic ) )451 imcb_remove_buddy( ic, "jabber_oauth", NULL );452 return FALSE;453 }454 455 static void sasl_oauth2_got_token( gpointer data, const char *access_token, const char *refresh_token );456 457 int sasl_oauth2_get_refresh_token( struct im_connection *ic, const char *msg )458 {459 char *code;460 int ret;461 462 imcb_log( ic, "Requesting OAuth access token" );463 464 /* Don't do it here because the caller may get confused if the contact465 we're currently sending a message to is deleted. */466 b_timeout_add( 1, sasl_oauth2_remove_contact, ic );467 468 code = g_strdup( msg );469 g_strstrip( code );470 ret = oauth2_access_token( &oauth2_service_google, OAUTH2_AUTH_CODE,471 code, sasl_oauth2_got_token, ic );472 473 g_free( code );474 return ret;475 }476 477 int sasl_oauth2_refresh( struct im_connection *ic, const char *refresh_token )478 {479 return oauth2_access_token( &oauth2_service_google, OAUTH2_AUTH_REFRESH,480 refresh_token, sasl_oauth2_got_token, ic );481 }482 483 static void sasl_oauth2_got_token( gpointer data, const char *access_token, const char *refresh_token )484 {485 struct im_connection *ic = data;486 struct jabber_data *jd;487 488 if( g_slist_find( jabber_connections, ic ) == NULL )489 return;490 491 jd = ic->proto_data;492 493 if( access_token == NULL )494 {495 imcb_error( ic, "OAuth failure (missing access token)" );496 imc_logout( ic, TRUE );497 return;498 }499 if( refresh_token != NULL )500 {501 g_free( ic->acc->pass );502 ic->acc->pass = g_strdup_printf( "refresh_token=%s", refresh_token );503 }504 505 g_free( jd->oauth2_access_token );506 jd->oauth2_access_token = g_strdup( access_token );507 508 jabber_connect( ic );509 }
Note: See TracChangeset
for help on using the changeset viewer.