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