1 | /***************************************************************************\ |
---|
2 | * * |
---|
3 | * BitlBee - An IRC to IM gateway * |
---|
4 | * Jabber module - SASL authentication * |
---|
5 | * * |
---|
6 | * Copyright 2006 Wilmer van der Gaast <wilmer@gaast.net> * |
---|
7 | * * |
---|
8 | * This program is free software; you can redistribute it and/or modify * |
---|
9 | * it under the terms of the GNU General Public License as published by * |
---|
10 | * the Free Software Foundation; either version 2 of the License, or * |
---|
11 | * (at your option) any later version. * |
---|
12 | * * |
---|
13 | * This program is distributed in the hope that it will be useful, * |
---|
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * |
---|
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
---|
16 | * GNU General Public License for more details. * |
---|
17 | * * |
---|
18 | * You should have received a copy of the GNU General Public License along * |
---|
19 | * with this program; if not, write to the Free Software Foundation, Inc., * |
---|
20 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * |
---|
21 | * * |
---|
22 | \***************************************************************************/ |
---|
23 | |
---|
24 | #include "jabber.h" |
---|
25 | #include "base64.h" |
---|
26 | |
---|
27 | #define SASL_NS "urn:ietf:params:xml:ns:xmpp-sasl" |
---|
28 | |
---|
29 | xt_status sasl_pkt_mechanisms( struct xt_node *node, gpointer data ) |
---|
30 | { |
---|
31 | struct gaim_connection *gc = data; |
---|
32 | struct jabber_data *jd = gc->proto_data; |
---|
33 | struct xt_node *c, *reply; |
---|
34 | char *s; |
---|
35 | int sup_plain = 0, sup_digest = 0; |
---|
36 | |
---|
37 | if( !sasl_supported( gc ) ) |
---|
38 | { |
---|
39 | /* Should abort this now, since we should already be doing |
---|
40 | IQ authentication. Strange things happen when you try |
---|
41 | to do both... */ |
---|
42 | serv_got_crap( gc, "XMPP 1.0 non-compliant server seems to support SASL, please report this as a BitlBee bug!" ); |
---|
43 | return XT_HANDLED; |
---|
44 | } |
---|
45 | |
---|
46 | s = xt_find_attr( node, "xmlns" ); |
---|
47 | if( !s || strcmp( s, SASL_NS ) != 0 ) |
---|
48 | { |
---|
49 | signoff( gc ); |
---|
50 | return XT_ABORT; |
---|
51 | } |
---|
52 | |
---|
53 | c = node->children; |
---|
54 | while( ( c = xt_find_node( c, "mechanism" ) ) ) |
---|
55 | { |
---|
56 | if( c->text && g_strcasecmp( c->text, "PLAIN" ) == 0 ) |
---|
57 | sup_plain = 1; |
---|
58 | if( c->text && g_strcasecmp( c->text, "DIGEST-MD5" ) == 0 ) |
---|
59 | sup_digest = 1; |
---|
60 | |
---|
61 | c = c->next; |
---|
62 | } |
---|
63 | |
---|
64 | if( !sup_plain && !sup_digest ) |
---|
65 | { |
---|
66 | signoff( gc ); |
---|
67 | return XT_ABORT; |
---|
68 | } |
---|
69 | |
---|
70 | reply = xt_new_node( "auth", NULL, NULL ); |
---|
71 | xt_add_attr( reply, "xmlns", SASL_NS ); |
---|
72 | |
---|
73 | if( sup_plain ) |
---|
74 | { |
---|
75 | int len; |
---|
76 | |
---|
77 | xt_add_attr( reply, "mechanism", "PLAIN" ); |
---|
78 | |
---|
79 | /* With SASL PLAIN in XMPP, the text should be b64(\0user\0pass) */ |
---|
80 | len = strlen( jd->username ) + strlen( gc->acc->pass ) + 2; |
---|
81 | s = g_malloc( len + 1 ); |
---|
82 | s[0] = 0; |
---|
83 | strcpy( s + 1, jd->username ); |
---|
84 | strcpy( s + 2 + strlen( jd->username ), gc->acc->pass ); |
---|
85 | reply->text = base64_encode( s, len ); |
---|
86 | reply->text_len = strlen( reply->text ); |
---|
87 | g_free( s ); |
---|
88 | } |
---|
89 | |
---|
90 | if( !jabber_write_packet( gc, reply ) ) |
---|
91 | { |
---|
92 | xt_free_node( reply ); |
---|
93 | return XT_ABORT; |
---|
94 | } |
---|
95 | xt_free_node( reply ); |
---|
96 | |
---|
97 | /* To prevent classic authentication from happening. */ |
---|
98 | jd->flags |= JFLAG_STREAM_STARTED; |
---|
99 | |
---|
100 | return XT_HANDLED; |
---|
101 | } |
---|
102 | |
---|
103 | xt_status sasl_pkt_challenge( struct xt_node *node, gpointer data ) |
---|
104 | { |
---|
105 | return XT_HANDLED; |
---|
106 | } |
---|
107 | |
---|
108 | xt_status sasl_pkt_result( struct xt_node *node, gpointer data ) |
---|
109 | { |
---|
110 | struct gaim_connection *gc = data; |
---|
111 | struct jabber_data *jd = gc->proto_data; |
---|
112 | char *s; |
---|
113 | |
---|
114 | s = xt_find_attr( node, "xmlns" ); |
---|
115 | if( !s || strcmp( s, SASL_NS ) != 0 ) |
---|
116 | { |
---|
117 | signoff( gc ); |
---|
118 | return XT_ABORT; |
---|
119 | } |
---|
120 | |
---|
121 | if( strcmp( node->name, "success" ) == 0 ) |
---|
122 | { |
---|
123 | set_login_progress( gc, 1, "Authentication finished" ); |
---|
124 | jd->flags |= JFLAG_AUTHENTICATED | JFLAG_STREAM_RESTART; |
---|
125 | } |
---|
126 | else if( strcmp( node->name, "failure" ) == 0 ) |
---|
127 | { |
---|
128 | hide_login_progress( gc, "Authentication failure" ); |
---|
129 | signoff( gc ); |
---|
130 | return XT_ABORT; |
---|
131 | } |
---|
132 | |
---|
133 | return XT_HANDLED; |
---|
134 | } |
---|
135 | |
---|
136 | /* This one is needed to judge if we'll do authentication using IQ or SASL. |
---|
137 | It's done by checking if the <stream:stream> from the server has a |
---|
138 | version attribute. I don't know if this is the right way though... */ |
---|
139 | gboolean sasl_supported( struct gaim_connection *gc ) |
---|
140 | { |
---|
141 | struct jabber_data *jd = gc->proto_data; |
---|
142 | |
---|
143 | return ( jd->xt && jd->xt->root && xt_find_attr( jd->xt->root, "version" ) ) != NULL; |
---|
144 | } |
---|