2021-05-05 17:16:26 +03:00

186 lines
5.0 KiB
C

/*
* ejabberd external authentication program
*
* (c) Alexander Vdolainen 2013, 2018, 2019, 2021 <alex@vapaa.xyz>
*
* this is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* this is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.";
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/select.h>
#include <errno.h>
#include <netdb.h>
#include <string.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <stdarg.h>
#include <getopt.h>
#include <ejabbermsg.h>
#include <tlsport.h>
#include <imapf.h>
#include <smtpf.h>
#include <eport.h>
unsigned long djb_hash(const char *s)
{
unsigned long hash = 5381;
int c;
while((c = *s++))
hash = ((hash << 5) + hash) + c;
return hash;
}
#define MAX_SUPPL_DATA 64
#define PRG_NAME "daemon for ejabberd to provide IMAPS/SMTPS auth"
static void print_help(const char *cname)
{
fprintf(stdout, "\n%s - %s\n\n", cname, PRG_NAME);
fprintf(stdout, "USAGE:\n");
fprintf(stdout, "\t%s -S | --smtp-host <SMTP hostname> -s | --smtp-port <port> "
"-I | --imap-host <IMAP hostname> -i | --imap-port <port>", cname);
fprintf(stdout, "\n\n\t%s -h | --help\n", cname);
fprintf(stdout, "\nNOTE: This program is designed to be used from ejabberd only.\n");
return;
}
int main(int argc, char **argv)
{
char *smtp_host, *smtp_port, *imap_host, *imap_port;
char msgbuf[MAX_USER_LEN + MAX_DOMAIN_LEN + MAX_PASSWORD_LEN + MAX_SUPPL_DATA];
struct tlsport connection;
struct ejabber_msg m;
int opt, msgbuflen = 0;
smtp_host = smtp_port = imap_port = imap_host = NULL;
while(1) {
int option_index = 0;
static struct option long_options[] = {
{"help", no_argument, NULL, 'h'},
{"smtp-host", required_argument, NULL, 'S'},
{"smtp-port", required_argument, NULL, 's'},
{"imap-host", required_argument, NULL, 'I'},
{"imap-port", required_argument, NULL, 'i'},
{NULL, 0, NULL, 0},
};
if((opt = getopt_long(argc, argv, "hS:s:I:i:", long_options, &option_index)) == -1)
break;
switch(opt) {
case 'h':
print_help(argv[0]);
return 0;
break;
case 'S': smtp_host = optarg; break;
case 's': smtp_port = optarg; break;
case 'I': imap_host = optarg; break;
case 'i': imap_port = optarg; break;
default: abort(); break;
}
}
/* arguments check up */
if(!smtp_host || !smtp_port) {
fprintf(stderr, "Error: SMTPs information is not complete.\n");
main_einval_moimoi:
print_help(argv[0]);
return EINVAL;
}
if(!imap_port || !imap_host) {
fprintf(stderr, "Error: IMAPs information is not complete.\n");
goto main_einval_moimoi;
}
/* take care about space borrowed from stack */
msgbuflen = MAX_USER_LEN + MAX_DOMAIN_LEN + MAX_PASSWORD_LEN + MAX_SUPPL_DATA;
memset(msgbuf, 0, msgbuflen);
/* libs init */
ssllib_init();
/* main loop */
while(eport_read(stdin, msgbuf, msgbuflen) > 0) {
opt = eport_ejabberd_msgread(msgbuf, msgbuflen, &m);
if(opt < 0) {
abort_parsing:
fprintf(stderr, "Error: message isn't valid.\nExiting.\n");
ssllib_free();
abort();
}
/* deal with message */
switch(ejabber_msg_event(&m)) {
case EJA_AUTH:
if(opt != 3) goto abort_parsing;
/* connect to IMAPs */
if(tls_connect(imap_host, imap_port, &connection)) {
fprintf(stderr, "Error: unable to connect to IMAPs.\n");
opt = 0;
} else {
opt = imap_auth(&connection, &m);
tls_close(&connection);
}
break;
case EJA_ISUSER:
if(opt != 2) goto abort_parsing;
/* connect to SMTPs */
if(tls_connect(smtp_host, smtp_port, &connection)) {
fprintf(stderr, "Error: unable to connect to SMTPs.\n");
opt = 0;
} else {
opt = smtp_checkuser(&connection, &m, smtp_host);
tls_close(&connection);
}
break;
case EJA_SETPASS:
case EJA_TRYREGISTER:
case EJA_REMOVEUSER:
case EJA_REMOVEUSER3:
/* still aren't supported by the program */
fprintf(stderr, "Error: This type of message are not supported.\n");
opt = 0;
break;
case EJA_UNKNOWN:
default: /* something goes wrong with message */
goto abort_parsing;
break;
}
/* finally, reply ... */
opt = ((int16_t)opt << 8) | (((int16_t)opt >> 8) & 0xff);
eport_write(stdout, (char *)(&opt), sizeof(int16_t));
/* clear the buffer */
memset(msgbuf, 0, msgbuflen);
}
ssllib_free();
return 0;
}