Back to index

citadel  8.12
xmpp_sasl_service.c
Go to the documentation of this file.
00001 /*
00002  * Barebones SASL authentication service for XMPP (Jabber) clients.
00003  *
00004  * Note: RFC3920 says we "must" support DIGEST-MD5 but we only support PLAIN.
00005  *
00006  * Copyright (c) 2007-2009 by Art Cancro
00007  *
00008  *  This program is open source software; you can redistribute it and/or modify
00009  *  it under the terms of the GNU General Public License version 3.
00010  *  
00011  *  
00012  *
00013  *  This program is distributed in the hope that it will be useful,
00014  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  *  GNU General Public License for more details.
00017  *
00018  *  
00019  *  
00020  *  
00021  *
00022  */
00023 
00024 #include "sysdep.h"
00025 #include <stdlib.h>
00026 #include <unistd.h>
00027 #include <stdio.h>
00028 #include <fcntl.h>
00029 #include <signal.h>
00030 #include <pwd.h>
00031 #include <errno.h>
00032 #include <sys/types.h>
00033 
00034 #if TIME_WITH_SYS_TIME
00035 # include <sys/time.h>
00036 # include <time.h>
00037 #else
00038 # if HAVE_SYS_TIME_H
00039 #  include <sys/time.h>
00040 # else
00041 #  include <time.h>
00042 # endif
00043 #endif
00044 
00045 #include <sys/wait.h>
00046 #include <string.h>
00047 #include <limits.h>
00048 #include <ctype.h>
00049 #include <expat.h>
00050 #include <libcitadel.h>
00051 #include "citadel.h"
00052 #include "server.h"
00053 #include "citserver.h"
00054 #include "support.h"
00055 #include "config.h"
00056 #include "user_ops.h"
00057 #include "internet_addressing.h"
00058 #include "md5.h"
00059 #include "ctdl_module.h"
00060 #include "serv_xmpp.h"
00061 
00062 
00063 /*
00064  * PLAIN authentication.  Returns zero on success, nonzero on failure.
00065  */
00066 int xmpp_auth_plain(char *authstring)
00067 {
00068        char decoded_authstring[1024];
00069        char ident[256];
00070        char user[256];
00071        char pass[256];
00072        int result;
00073        long len;
00074 
00075 
00076        /* Take apart the authentication string */
00077        memset(pass, 0, sizeof(pass));
00078 
00079        CtdlDecodeBase64(decoded_authstring, authstring, strlen(authstring));
00080        safestrncpy(ident, decoded_authstring, sizeof ident);
00081        safestrncpy(user, &decoded_authstring[strlen(ident) + 1], sizeof user);
00082        len = safestrncpy(pass, &decoded_authstring[strlen(ident) + strlen(user) + 2], sizeof pass);
00083        if (len < 0)
00084               len = -len;
00085 
00086        /* If there are underscores in either string, change them to spaces.  Some clients
00087         * do not allow spaces so we can tell the user to substitute underscores if their
00088         * login name contains spaces.
00089         */
00090        convert_spaces_to_underscores(ident);
00091        convert_spaces_to_underscores(user);
00092 
00093        /* Now attempt authentication */
00094 
00095        if (!IsEmptyStr(ident)) {
00096               result = CtdlLoginExistingUser(user, ident);
00097        }
00098        else {
00099               result = CtdlLoginExistingUser(NULL, user);
00100        }
00101 
00102        if (result == login_ok) {
00103               if (CtdlTryPassword(pass, len) == pass_ok) {
00104                      return(0);                         /* success */
00105               }
00106        }
00107 
00108        return(1);                                       /* failure */
00109 }
00110 
00111 
00112 /*
00113  * Output the list of SASL mechanisms offered by this stream.
00114  */
00115 void xmpp_output_auth_mechs(void) {
00116        cprintf("<mechanisms xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
00117        cprintf("<mechanism>PLAIN</mechanism>");
00118        cprintf("</mechanisms>");
00119 }
00120 
00121 /*
00122  * Here we go ... client is trying to authenticate.
00123  */
00124 void xmpp_sasl_auth(char *sasl_auth_mech, char *authstring) {
00125 
00126        if (strcasecmp(sasl_auth_mech, "PLAIN")) {
00127               cprintf("<failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
00128               cprintf("<invalid-mechanism/>");
00129               cprintf("</failure>");
00130               return;
00131        }
00132 
00133         if (CC->logged_in) CtdlUserLogout();  /* Client may try to log in twice.  Handle this. */
00134 
00135        if (CC->nologin) {
00136               cprintf("<failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
00137               cprintf("<system-shutdown/>");
00138               cprintf("</failure>");
00139        }
00140 
00141        else if (xmpp_auth_plain(authstring) == 0) {
00142               cprintf("<success xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\"/>");
00143        }
00144 
00145        else {
00146               cprintf("<failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
00147               cprintf("<not-authorized/>");
00148               cprintf("</failure>");
00149        }
00150 }
00151 
00152 
00153 
00154 /*
00155  * Non-SASL authentication
00156  */
00157 void xmpp_non_sasl_authenticate(char *iq_id, char *username, char *password, char *resource) {
00158        int result;
00159        char xmlbuf[256];
00160 
00161         if (CC->logged_in) CtdlUserLogout();  /* Client may try to log in twice.  Handle this. */
00162 
00163        result = CtdlLoginExistingUser(NULL, username);
00164        if (result == login_ok) {
00165               result = CtdlTryPassword(password, strlen(password));
00166               if (result == pass_ok) {
00167                      cprintf("<iq type=\"result\" id=\"%s\"></iq>", xmlesc(xmlbuf, iq_id, sizeof xmlbuf));      /* success */
00168                      return;
00169               }
00170        }
00171 
00172        /* failure */
00173        cprintf("<iq type=\"error\" id=\"%s\">", xmlesc(xmlbuf, iq_id, sizeof xmlbuf));
00174        cprintf("<error code=\"401\" type=\"auth\">"
00175               "<not-authorized xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/>"
00176               "</error>"
00177               "</iq>"
00178        );
00179 }