f444ba9b9da232c5cdd87a6ef6444a2f3b333088
[citadel.git] / citadel / modules / jabber / xmpp_sasl_service.c
1 /*
2  * $Id$ 
3  *
4  * Barebones SASL authentication service for XMPP (Jabber) clients.
5  *
6  * Note: RFC3920 says we "must" support DIGEST-MD5 but we only support PLAIN.
7  *
8  * Copyright (c) 2007 by Art Cancro
9  * This code is released under the terms of the GNU General Public License.
10  *
11  */
12
13 #include "sysdep.h"
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <stdio.h>
17 #include <fcntl.h>
18 #include <signal.h>
19 #include <pwd.h>
20 #include <errno.h>
21 #include <sys/types.h>
22
23 #if TIME_WITH_SYS_TIME
24 # include <sys/time.h>
25 # include <time.h>
26 #else
27 # if HAVE_SYS_TIME_H
28 #  include <sys/time.h>
29 # else
30 #  include <time.h>
31 # endif
32 #endif
33
34 #include <sys/wait.h>
35 #include <string.h>
36 #include <limits.h>
37 #include <ctype.h>
38 #include <libcitadel.h>
39 #include "citadel.h"
40 #include "server.h"
41 #include "citserver.h"
42 #include "support.h"
43 #include "config.h"
44 #include "user_ops.h"
45 #include "internet_addressing.h"
46 #include "md5.h"
47 #include "ctdl_module.h"
48
49 #ifdef HAVE_EXPAT
50 #include <expat.h>
51 #include "serv_xmpp.h"
52
53
54 /*
55  * PLAIN authentication.  Returns zero on success, nonzero on failure.
56  */
57 int xmpp_auth_plain(char *authstring)
58 {
59         char decoded_authstring[1024];
60         char ident[256];
61         char user[256];
62         char pass[256];
63         int result;
64         char *ptr = NULL;
65
66
67         /* Take apart the authentication string */
68
69         CtdlDecodeBase64(decoded_authstring, authstring, strlen(authstring));
70         safestrncpy(ident, decoded_authstring, sizeof ident);
71         safestrncpy(user, &decoded_authstring[strlen(ident) + 1], sizeof user);
72         safestrncpy(pass, &decoded_authstring[strlen(ident) + strlen(user) + 2], sizeof pass);
73
74
75         /* If there are underscores in either string, change them to spaces.  Some clients
76          * do not allow spaces so we can tell the user to substitute underscores if their
77          * login name contains spaces.
78          */
79         while (ptr=strstr(ident, "_")) {
80                 *ptr = ' ';
81         }
82
83         while (ptr=strstr(user, "_")) {
84                 *ptr = ' ';
85         }
86
87         /* Now attempt authentication */
88
89         if (!IsEmptyStr(ident)) {
90                 result = CtdlLoginExistingUser(user, ident);
91         }
92         else {
93                 result = CtdlLoginExistingUser(NULL, user);
94         }
95
96         if (result == login_ok) {
97                 if (CtdlTryPassword(pass) == pass_ok) {
98                         return(0);                              /* success */
99                 }
100         }
101
102         return(1);                                              /* failure */
103 }
104
105
106 /*
107  * Output the list of SASL mechanisms offered by this stream.
108  */
109 void xmpp_output_auth_mechs(void) {
110         cprintf("<mechanisms xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
111         cprintf("<mechanism>PLAIN</mechanism>");
112         cprintf("</mechanisms>");
113 }
114
115 /*
116  * Here we go ... client is trying to authenticate.
117  */
118 void xmpp_sasl_auth(char *sasl_auth_mech, char *authstring) {
119
120         if (strcasecmp(sasl_auth_mech, "PLAIN")) {
121                 cprintf("<failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
122                 cprintf("<invalid-mechanism/>");
123                 cprintf("</failure>");
124                 return;
125         }
126
127         if (CC->logged_in) logout(CC);  /* Client may try to log in twice.  Handle this. */
128
129         if (xmpp_auth_plain(authstring) == 0) {
130                 cprintf("<success xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\"/>");
131         }
132
133         else {
134                 cprintf("<failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
135                 cprintf("<not-authorized/>");
136                 cprintf("</failure>");
137         }
138 }
139
140
141
142 /*
143  * Non-SASL authentication
144  */
145 void jabber_non_sasl_authenticate(char *iq_id, char *username, char *password, char *resource) {
146         int result;
147
148         if (CC->logged_in) logout(CC);  /* Client may try to log in twice.  Handle this. */
149
150         result = CtdlLoginExistingUser(NULL, username);
151         if (result == login_ok) {
152                 result = CtdlTryPassword(password);
153                 if (result == pass_ok) {
154                         cprintf("<iq type=\"result\" id=\"%s\"></iq>", iq_id);  /* success */
155                         return;
156                 }
157         }
158
159         /* failure */
160         cprintf("<iq type=\"error\" id=\"%s\">", iq_id);
161         cprintf("<error code=\"401\" type=\"auth\">"
162                 "<not-authorized xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/>"
163                 "</error>"
164                 "</iq>"
165         );
166 }
167
168
169
170 #endif  /* HAVE_EXPAT */