X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fmodules%2Fmanagesieve%2Fserv_managesieve.c;h=e085d5991a1691a7988e8df2f4c3f2c8afbef794;hb=425c3723bd35cf6e2048027e36c721a78784b8c7;hp=c43d8aa192ceac085610b4da2eba4f147f98ac22;hpb=84aa84fdd0a02f703c5e836f258e33f950c66355;p=citadel.git diff --git a/citadel/modules/managesieve/serv_managesieve.c b/citadel/modules/managesieve/serv_managesieve.c index c43d8aa19..e085d5991 100644 --- a/citadel/modules/managesieve/serv_managesieve.c +++ b/citadel/modules/managesieve/serv_managesieve.c @@ -1,12 +1,20 @@ -/** - * $Id$ - * +/* * This module is an managesieve implementation for the Citadel system. * It is compliant with all of the following: * * http://tools.ietf.org/html/draft-martin-managesieve-06 * as this draft expires with this writing, you might need to search for * the new one. + * + * Copyright (c) 2007-2018 by the citadel.org team + * + * This program is open source software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3. + * + * This program 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. */ #include "sysdep.h" @@ -38,45 +46,27 @@ #include #include #include +#include #include "citadel.h" #include "server.h" #include "citserver.h" #include "support.h" #include "config.h" #include "control.h" -#include "room_ops.h" #include "user_ops.h" -#include "policy.h" #include "database.h" #include "msgbase.h" -#include "tools.h" #include "internet_addressing.h" -#include "imap_tools.h" #include "genstamp.h" #include "domain.h" #include "clientsocket.h" #include "locate_host.h" #include "citadel_dirs.h" - -#ifdef HAVE_OPENSSL -#include "serv_crypto.h" -#endif - -#ifndef HAVE_SNPRINTF -#include "snprintf.h" -#endif - - #include "ctdl_module.h" - - - -#ifdef HAVE_LIBSIEVE - #include "serv_sieve.h" -/** +/* * http://tools.ietf.org/html/draft-martin-managesieve-06 * * this is the draft this code tries to implement. @@ -99,12 +89,73 @@ enum { /** Command states for login authentication */ mgsve_plain }; -#define MGSVE CC->MGSVE +#define MGSVE ((struct citmgsve *)CC->session_specific_data) + +int old_imap_parameterize(char** args, char *in) +{ + char* out = in; + int num = 0; + + for (;;) + { + /* Skip whitespace. */ + + while (isspace(*in)) + in++; + if (*in == 0) + break; + + /* Found the start of a token. */ + + args[num++] = out; + + /* Read in the token. */ + + for (;;) + { + int c = *in++; + if (isspace(c)) + break; + + if (c == '\"') + { + /* Found a quoted section. */ + + for (;;) + { + c = *in++; + if (c == '\"') + break; + else if (c == '\\') + c = *in++; + + *out++ = c; + if (c == 0) + return num; + } + } + else if (c == '\\') + { + c = *in++; + *out++ = c; + } + else + *out++ = c; + + if (c == 0) + return num; + } + *out++ = '\0'; + } + + return num; +} /*****************************************************************************/ /* MANAGESIEVE Server */ /*****************************************************************************/ + void sieve_outbuf_append(char *str) { size_t newlen = strlen(str)+1; @@ -128,7 +179,7 @@ void sieve_outbuf_append(char *str) */ void cmd_mgsve_caps(void) { - cprintf("\"IMPLEMENTATION\" \"CITADEL Sieve v6.84\"\r\n" /* TODO: put citversion here. */ + cprintf("\"IMPLEMENTATION\" \"CITADEL Sieve " PACKAGE_VERSION "\"\r\n" "\"SASL\" \"PLAIN\"\r\n" /*DIGEST-MD5 GSSAPI SASL sucks.*/ #ifdef HAVE_OPENSSL /* if TLS is already there, should we say that again? */ @@ -146,9 +197,9 @@ void managesieve_greeting(void) { strcpy(CC->cs_clientname, "Managesieve session"); - CC->internal_pgm = 1; + CC->internal_pgm = 0; CC->cs_flags |= CS_STEALTH; - MGSVE = malloc(sizeof(struct citmgsve)); + CC->session_specific_data = malloc(sizeof(struct citmgsve)); memset(MGSVE, 0, sizeof(struct citmgsve)); cmd_mgsve_caps(); } @@ -159,12 +210,12 @@ long GetSizeToken(char * token) char *cursor = token; char *number; - while ((*cursor != '\0') && + while (!IsEmptyStr(cursor) && (*cursor != '{')) { cursor++; } - if (*cursor == '\0') + if (IsEmptyStr(cursor)) return -1; number = cursor + 1; while ((*cursor != '\0') && @@ -176,7 +227,7 @@ long GetSizeToken(char * token) if (cursor[-1] == '+') cursor--; - if (*cursor == '\0') + if (IsEmptyStr(cursor)) return -1; return atol(number); @@ -188,13 +239,13 @@ char *ReadString(long size, char *command) if (size < 1) { cprintf("NO %s: %ld BAD Message length must be at least 1.\r\n", command, size); - CC->kill_me = 1; + CC->kill_me = KILLME_READSTRING_FAILED; return NULL; } MGSVE->transmitted_message = malloc(size + 2); if (MGSVE->transmitted_message == NULL) { cprintf("NO %s Cannot allocate memory.\r\n", command); - CC->kill_me = 1; + CC->kill_me = KILLME_MALLOC_FAILED; return NULL; } MGSVE->transmitted_length = size; @@ -216,23 +267,32 @@ void cmd_mgsve_auth(int num_parms, char **parms, struct sdm_userdata *u) /* todo, check length*/ { char auth[SIZ]; - int retval; - char *message = ReadString(GetSizeToken(parms[2]), parms[0]); + char *message; + char *username; + + message = NULL; + memset (auth, 0, SIZ); + if (parms[2][0] == '{') + message = ReadString(GetSizeToken(parms[2]), parms[0]); if (message != NULL) {/**< do we have tokenized login? */ - retval = CtdlDecodeBase64(auth, MGSVE->transmitted_message, SIZ); + CtdlDecodeBase64(auth, MGSVE->transmitted_message, strlen(MGSVE->transmitted_message)); } else - retval = CtdlDecodeBase64(auth, parms[2], SIZ); - - if (login_ok == CtdlLoginExistingUser(NULL, auth)) + CtdlDecodeBase64(auth, parms[2], strlen(parms[2])); + username = auth; + if ((*username == '\0') && (*(username + 1) != '\0')) + username ++; + + if (login_ok == CtdlLoginExistingUser(username)) { char *pass; + pass = &(auth[strlen(auth)+1]); /* for some reason the php script sends us the username twice. y? */ pass = &(pass[strlen(pass)+1]); - if (pass_ok == CtdlTryPassword(pass)) + if (pass_ok == CtdlTryPassword(pass, strlen(pass))) { MGSVE->command_state = mgsve_password; cprintf("OK\r\n"); @@ -240,38 +300,35 @@ void cmd_mgsve_auth(int num_parms, char **parms, struct sdm_userdata *u) } } } - cprintf("NO \"Authentication Failure.\"\r\n");/* we just support auth plain. */ - CC->kill_me = 1; + CC->kill_me = KILLME_AUTHFAILED; } -#ifdef HAVE_OPENSSL /** * STARTTLS command chapter 2.2 */ void cmd_mgsve_starttls(void) { /** answer with OK, and fire off tls session. */ cprintf("OK\r\n"); - CtdlStartTLS(NULL, NULL, NULL); + CtdlModuleStartCryptoMsgs(NULL, NULL, NULL); cmd_mgsve_caps(); } -#endif -/** - *LOGOUT command, see chapter 2.3 +/* + * LOGOUT command, see chapter 2.3 */ void cmd_mgsve_logout(struct sdm_userdata *u) { cprintf("OK\r\n"); - lprintf(CTDL_NOTICE, "MgSve bye."); - CC->kill_me = 1; + syslog(LOG_NOTICE, "MgSve bye."); + CC->kill_me = KILLME_CLIENT_LOGGED_OUT; } -/** +/* * HAVESPACE command. see chapter 2.5 */ void cmd_mgsve_havespace(void) @@ -282,7 +339,7 @@ void cmd_mgsve_havespace(void) if (MGSVE->command_state != mgsve_password) { cprintf("NO\r\n"); - CC->kill_me = 1; + CC->kill_me = KILLME_QUOTA; } else { @@ -292,7 +349,7 @@ void cmd_mgsve_havespace(void) } } -/** +/* * PUTSCRIPT command, see chapter 2.6 */ void cmd_mgsve_putscript(int num_parms, char **parms, struct sdm_userdata *u) @@ -326,7 +383,7 @@ void cmd_mgsve_putscript(int num_parms, char **parms, struct sdm_userdata *u) } else { cprintf("%s NO Read failed.\r\n", parms[0]); - CC->kill_me = 1; + CC->kill_me = KILLME_READ_FAILED; return; } @@ -394,7 +451,7 @@ void cmd_mgsve_getscript(int num_parms, char **parms, struct sdm_userdata *u) slen = strlen(script_content); outbuf = malloc (slen + 64); snprintf(outbuf, slen + 64, "{%ld+}\r\n%s\r\nOK\r\n",slen, script_content); - cprintf(outbuf); + cprintf("%s", outbuf); } else cprintf("No \"there is no script by that name %s \"\r\n", parms[1]); @@ -450,7 +507,10 @@ void mgsve_auth(char *argbuf) { if (strlen(argbuf) >= 7) { } else { - CtdlEncodeBase64(username_prompt, "Username:", 9); + size_t len = CtdlEncodeBase64(username_prompt, "Username:", 9, 0); + if (username_prompt[len - 1] == '\n') { + username_prompt[len - 1] = '\0'; + } cprintf("334 %s\r\n", username_prompt); } return; @@ -477,7 +537,6 @@ void mgsve_auth(char *argbuf) { /* * implements the STARTTLS command (Citadel API version) */ -#ifdef HAVE_OPENSSL void _mgsve_starttls(void) { char ok_response[SIZ]; @@ -490,9 +549,8 @@ void _mgsve_starttls(void) "554 5.7.3 TLS not supported here\r\n"); sprintf(error_response, "554 5.7.3 Internal error\r\n"); - CtdlStartTLS(ok_response, nosup_response, error_response); + CtdlModuleStartCryptoMsgs(ok_response, nosup_response, error_response); } -#endif /* @@ -512,16 +570,16 @@ void managesieve_command_loop(void) { memset(cmdbuf, 0, sizeof cmdbuf); /* Clear it, just in case */ length = client_getln(cmdbuf, sizeof cmdbuf); if (length >= 1) { - num_parms = imap_parameterize(parms, cmdbuf); + num_parms = old_imap_parameterize(parms, cmdbuf); if (num_parms == 0) return; length = strlen(parms[0]); } if (length < 1) { - lprintf(CTDL_CRIT, "Client disconnected: ending session.\n"); - CC->kill_me = 1; + syslog(LOG_CRIT, "managesieve: client disconnected: ending session.\n"); + CC->kill_me = KILLME_CLIENT_DISCONNECTED; return; } - lprintf(CTDL_INFO, "MANAGESIEVE: %s\n", cmdbuf); + syslog(LOG_INFO, "MANAGESIEVE: %s\n", cmdbuf); if ((length>= 12) && (!strncasecmp(parms[0], "AUTHENTICATE", 12))){ cmd_mgsve_auth(num_parms, parms, &u); } @@ -538,7 +596,7 @@ void managesieve_command_loop(void) { cmd_mgsve_caps(); } /** these commands need to be authenticated. throw it out if it tries. */ - else if (!CtdlAccessCheck(ac_logged_in)) + else if (CC->logged_in != 0) { msiv_load(&u); if ((length>= 9) && (!strncasecmp(parms[0], "HAVESPACE", 9))){ @@ -565,36 +623,45 @@ void managesieve_command_loop(void) { msiv_store(&u, changes_made); } else { - cprintf("No\r\n"); - lprintf(CTDL_INFO, "illegal Managesieve command: %s", parms[0]); - CC->kill_me = 1; + cprintf("No Invalid access or command.\r\n"); + syslog(LOG_INFO, "illegal Managesieve command: %s", parms[0]); + CC->kill_me = KILLME_ILLEGAL_MANAGESIEVE_COMMAND; } } +/* + * This cleanup function blows away the temporary memory and files used by + * the server. + */ +void managesieve_cleanup_function(void) { -#endif /* HAVE_LIBSIEVE */ - -CTDL_MODULE_INIT(managesieve) -{ - -#ifdef HAVE_LIBSIEVE - - CtdlRegisterServiceHook(config.c_managesieve_port, /* MGSVE */ - NULL, - managesieve_greeting, - managesieve_command_loop, - NULL); + /* Don't do this stuff if this is not a managesieve session! */ + if (CC->h_command_function != managesieve_command_loop) return; -#else /* HAVE_LIBSIEVE */ + syslog(LOG_DEBUG, "Performing managesieve cleanup hook\n"); + free(MGSVE); +} - lprintf(CTDL_INFO, "This server is missing libsieve. Managesieve protocol is disabled..\n"); -#endif /* HAVE_LIBSIEVE */ - /* return our Subversion id for the Log */ - return "$Id$"; +const char* CitadelServiceManageSieve = "ManageSieve"; +CTDL_MODULE_INIT(managesieve) +{ + if (!threading) + { + CtdlRegisterServiceHook(CtdlGetConfigInt("c_managesieve_port"), + NULL, + managesieve_greeting, + managesieve_command_loop, + NULL, + CitadelServiceManageSieve); + CtdlRegisterSessionHook(managesieve_cleanup_function, EVT_STOP, PRIO_STOP + 30); + } + + /* return our module name for the log */ + return "managesieve"; }