stable now but there are GIANT PIECES MISSING
[citadel.git] / citadel / modules / xmpp / xmpp_sasl_service.c
1 /*
2  * Barebones SASL authentication service for XMPP (Jabber) clients.
3  *
4  * Note: RFC3920 says we "must" support DIGEST-MD5 but we only support PLAIN.
5  *
6  * Copyright (c) 2007-2019 by Art Cancro
7  *
8  * This program is open source software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 3.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  */
16
17 #include "sysdep.h"
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <stdio.h>
21 #include <fcntl.h>
22 #include <signal.h>
23 #include <pwd.h>
24 #include <errno.h>
25 #include <sys/types.h>
26 #include <time.h>
27 #include <sys/wait.h>
28 #include <string.h>
29 #include <limits.h>
30 #include <ctype.h>
31 #include <expat.h>
32 #include <libcitadel.h>
33 #include "citadel.h"
34 #include "server.h"
35 #include "citserver.h"
36 #include "support.h"
37 #include "config.h"
38 #include "user_ops.h"
39 #include "internet_addressing.h"
40 #include "ctdl_module.h"
41 #include "serv_xmpp.h"
42
43
44 /*
45  * PLAIN authentication.  Returns zero on success, nonzero on failure.
46  */
47 int xmpp_auth_plain(char *authstring)
48 {
49         char decoded_authstring[1024];
50         char ident[256];
51         char user[256];
52         char pass[256];
53         int result;
54         long len;
55
56         /* Take apart the authentication string */
57         memset(pass, 0, sizeof(pass));
58
59         CtdlDecodeBase64(decoded_authstring, authstring, strlen(authstring));
60         safestrncpy(ident, decoded_authstring, sizeof ident);
61         safestrncpy(user, &decoded_authstring[strlen(ident) + 1], sizeof user);
62         len = safestrncpy(pass, &decoded_authstring[strlen(ident) + strlen(user) + 2], sizeof pass);
63         if (len < 0) {
64                 len = -len;
65         }
66
67         if (!IsEmptyStr(ident)) {
68                 result = CtdlLoginExistingUser(ident);
69         }
70         else {
71                 result = CtdlLoginExistingUser(user);
72         }
73
74         if (result == login_ok) {
75                 if (CtdlTryPassword(pass, len) == pass_ok) {
76                         return(0);                              /* success */
77                 }
78         }
79
80         return(1);                                              /* failure */
81 }
82
83
84 /*
85  * Output the list of SASL mechanisms offered by this stream.
86  */
87 void xmpp_output_auth_mechs(void) {
88         cprintf("<mechanisms xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
89         cprintf("<mechanism>PLAIN</mechanism>");
90         cprintf("</mechanisms>");
91 }
92
93
94 /*
95  * Here we go ... client is trying to authenticate.
96  */
97 void xmpp_sasl_auth(char *sasl_auth_mech, char *authstring) {
98
99         if (strcasecmp(sasl_auth_mech, "PLAIN")) {
100                 cprintf("<failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
101                 cprintf("<invalid-mechanism/>");
102                 cprintf("</failure>");
103                 return;
104         }
105
106         if (CC->logged_in) {
107                 CtdlUserLogout();  /* Client may try to log in twice.  Handle this. */
108         }
109
110         if (CC->nologin) {
111                 cprintf("<failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
112                 cprintf("<system-shutdown/>");
113                 cprintf("</failure>");
114         }
115
116         else if (xmpp_auth_plain(authstring) == 0) {
117                 cprintf("<success xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\"/>");
118         }
119
120         else {
121                 cprintf("<failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
122                 cprintf("<not-authorized/>");
123                 cprintf("</failure>");
124         }
125 }
126
127
128 /*
129  * Non-SASL authentication
130  */
131 void xmpp_non_sasl_authenticate(char *iq_id, char *username, char *password) {
132         int result;
133         char xmlbuf[256];
134
135         if (CC->logged_in) {
136                 CtdlUserLogout();  /* Client may try to log in twice.  Handle this. */
137         }
138
139         result = CtdlLoginExistingUser(username);
140         if (result == login_ok) {
141                 result = CtdlTryPassword(password, strlen(password));
142                 if (result == pass_ok) {
143                         cprintf("<iq type=\"result\" id=\"%s\"></iq>", xmlesc(xmlbuf, iq_id, sizeof xmlbuf));   /* success */
144                         return;
145                 }
146         }
147
148         /* failure */
149         cprintf("<iq type=\"error\" id=\"%s\">", xmlesc(xmlbuf, iq_id, sizeof xmlbuf));
150         cprintf("<error code=\"401\" type=\"auth\">"
151                 "<not-authorized xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/>"
152                 "</error>"
153                 "</iq>"
154         );
155 }