* split cutuserkey() out of makeuserkey(); its name doesn't show that theres a modifi...
[citadel.git] / citadel / modules / xmpp / 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-2009 by Art Cancro
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License as published by
12  *  the Free Software Foundation; either version 3 of the License, or
13  *  (at your option) any later version.
14  *
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program; if not, write to the Free Software
22  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  *
24  */
25
26 #include "sysdep.h"
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <stdio.h>
30 #include <fcntl.h>
31 #include <signal.h>
32 #include <pwd.h>
33 #include <errno.h>
34 #include <sys/types.h>
35
36 #if TIME_WITH_SYS_TIME
37 # include <sys/time.h>
38 # include <time.h>
39 #else
40 # if HAVE_SYS_TIME_H
41 #  include <sys/time.h>
42 # else
43 #  include <time.h>
44 # endif
45 #endif
46
47 #include <sys/wait.h>
48 #include <string.h>
49 #include <limits.h>
50 #include <ctype.h>
51 #include <expat.h>
52 #include <libcitadel.h>
53 #include "citadel.h"
54 #include "server.h"
55 #include "citserver.h"
56 #include "support.h"
57 #include "config.h"
58 #include "user_ops.h"
59 #include "internet_addressing.h"
60 #include "md5.h"
61 #include "ctdl_module.h"
62 #include "serv_xmpp.h"
63
64
65 /*
66  * PLAIN authentication.  Returns zero on success, nonzero on failure.
67  */
68 int xmpp_auth_plain(char *authstring)
69 {
70         char decoded_authstring[1024];
71         char ident[256];
72         char user[256];
73         char pass[256];
74         int result;
75         long len;
76
77
78         /* Take apart the authentication string */
79         memset(pass, 0, sizeof(pass));
80
81         CtdlDecodeBase64(decoded_authstring, authstring, strlen(authstring));
82         safestrncpy(ident, decoded_authstring, sizeof ident);
83         safestrncpy(user, &decoded_authstring[strlen(ident) + 1], sizeof user);
84         len = safestrncpy(pass, &decoded_authstring[strlen(ident) + strlen(user) + 2], sizeof pass);
85         if (len < 0)
86                 len = -len;
87
88         /* If there are underscores in either string, change them to spaces.  Some clients
89          * do not allow spaces so we can tell the user to substitute underscores if their
90          * login name contains spaces.
91          */
92         convert_spaces_to_underscores(ident);
93         convert_spaces_to_underscores(user);
94
95         /* Now attempt authentication */
96
97         if (!IsEmptyStr(ident)) {
98                 result = CtdlLoginExistingUser(user, ident);
99         }
100         else {
101                 result = CtdlLoginExistingUser(NULL, user);
102         }
103
104         if (result == login_ok) {
105                 if (CtdlTryPassword(pass, len) == pass_ok) {
106                         return(0);                              /* success */
107                 }
108         }
109
110         return(1);                                              /* failure */
111 }
112
113
114 /*
115  * Output the list of SASL mechanisms offered by this stream.
116  */
117 void xmpp_output_auth_mechs(void) {
118         cprintf("<mechanisms xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
119         cprintf("<mechanism>PLAIN</mechanism>");
120         cprintf("</mechanisms>");
121 }
122
123 /*
124  * Here we go ... client is trying to authenticate.
125  */
126 void xmpp_sasl_auth(char *sasl_auth_mech, char *authstring) {
127
128         if (strcasecmp(sasl_auth_mech, "PLAIN")) {
129                 cprintf("<failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
130                 cprintf("<invalid-mechanism/>");
131                 cprintf("</failure>");
132                 return;
133         }
134
135         if (CC->logged_in) CtdlUserLogout();  /* Client may try to log in twice.  Handle this. */
136
137         if (CC->nologin) {
138                 cprintf("<failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
139                 cprintf("<system-shutdown/>");
140                 cprintf("</failure>");
141         }
142
143         else if (xmpp_auth_plain(authstring) == 0) {
144                 cprintf("<success xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\"/>");
145         }
146
147         else {
148                 cprintf("<failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
149                 cprintf("<not-authorized/>");
150                 cprintf("</failure>");
151         }
152 }
153
154
155
156 /*
157  * Non-SASL authentication
158  */
159 void xmpp_non_sasl_authenticate(char *iq_id, char *username, char *password, char *resource) {
160         int result;
161         char xmlbuf[256];
162
163         if (CC->logged_in) CtdlUserLogout();  /* Client may try to log in twice.  Handle this. */
164
165         result = CtdlLoginExistingUser(NULL, username);
166         if (result == login_ok) {
167                 result = CtdlTryPassword(password, strlen(password));
168                 if (result == pass_ok) {
169                         cprintf("<iq type=\"result\" id=\"%s\"></iq>", xmlesc(xmlbuf, iq_id, sizeof xmlbuf));   /* success */
170                         return;
171                 }
172         }
173
174         /* failure */
175         cprintf("<iq type=\"error\" id=\"%s\">", xmlesc(xmlbuf, iq_id, sizeof xmlbuf));
176         cprintf("<error code=\"401\" type=\"auth\">"
177                 "<not-authorized xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/>"
178                 "</error>"
179                 "</iq>"
180         );
181 }