~ubuntu-branches/ubuntu/wily/dovecot/wily

« back to all changes in this revision

Viewing changes to dovecot-managesieve/src/managesieve/main.c

  • Committer: Bazaar Package Importer
  • Author(s): CHuck Short, Chuck Short
  • Date: 2009-11-06 00:47:29 UTC
  • mfrom: (4.1.9 squeeze)
  • Revision ID: james.westby@ubuntu.com-20091106004729-i39n7v9e7d4h51f6
Tags: 1:1.2.6-1ubuntu1
* Merge from debian testing, remaining changes:
  Add new binary pkg dovecot-postfix that integrates postfix and dovecot
  automatically: (LP: #164837)
  + debian/control:
    - add new binary with short description
    - set Architecture all for dovecot-postfix (LP: #329878)
  + debian/dovecot-postfix.postinst:
    - create initial certificate symlinks to snakeoil.
    - set up postfix with postconf to:
      - use Maildir/ as the default mailbox.
      - use dovecot as the sasl authentication server.
      - use dovecot LDA (deliver).
      - use tls for smtp{d} services.
    - fix certificates paths in postfix' main.cf
    - add reject_unauth_destination to postfix' recipient restrictions
    - add reject_unknown_sender_domain to postfix' sender restrictions
    - rename configuration name on remove, delete on purge
    - restart dovecot after linking certificates
    - handle use case when postfix is unconfigurated
   + debian/dovecot-postfix.dirs: create backup directory for postfix's configuration
   + restart postfix and dovecot.
   + debian/dovecot-postfix.postrm:
     - remove all dovecot related configuration from postfix.
     - restart postfix and dovecot.
   + debian/dovecot-common.init:
     - check if /etc/dovecot/dovecot-postfix.conf exists and use it
       as the configuration file if so.
   + debian/patches/warning-ubuntu-postfix.dpatch
     - add warning about dovecot-postfix.conf in dovecot default 
       configuration file
   + debian/patches/dovecot-postfix.conf.diff:
     - Ubuntu server custom changes to the default dovecot configuration for
       better interfation with postfix
     - enable sieve plugin
   + debian/patches/dovecot-postfix.conf.diff:
     + Ubuntu server custom changes to the default dovecot configuration for
       better integration with postfix:
       - enable imap, pop3, imaps, pop3s and managesieve by default.
       - enable dovecot LDA (deliver).
       - enable SASL auth socket in postfix private directory.
   + debian/rules:
     - copy, patch and install dovecot-postfix.conf in /etc/dovecot/.
     - build architecure independent packages too
   + Use Snakeoil SSL certificates by default.
     - debian/control: Depend on ssl-cert.
     - debian/patches/ssl-cert-snakeoil.dpatch: Change default SSL cert
       paths to snakeoil.
     - debian/dovecot-common.postinst: Relax grep for SSL_* a bit.
   + Add autopkgtest to debian/tests/*.
   + Fast TearDown: Update the lsb init header to not stop in level 6.
   + Add ufw integration:
     - Created debian/dovecot-common.ufw.profile.
     - debian/rules:
       + install profile
     - debian/control:
       + Suggest ufw
   + debian/{control,rules}: enable PIE hardening.
   + dovecot-imapd, dovecot-pop3: Replaces dovecot-common (<< 1:1.1). LP: #254721
   + debian/control:
     - Update Vcs-* headers.
   + debian/rules:
     - Create emtpy stamp.h.in files in dovecot-sieve/ and dovecot-managesieve/
       if they're not there since empty files are not included in the diff.gz 
       file.
   + Add SMTP-AUTH support for Outlook (login auth mechanism)
   + Dropped:
     - debian/patches/security-CVE-2009-3235: Applied upstream.
     - debian/patches/fix-pop3-assertion.dpatch: Applied upstream.
     - dovecot-sieve and dovecot-managesieve: Use the debian patches instead.

  [Chuck Short]
  - Updated dovecot-sieve to 0.1.13.
  - Updated dovecot-managesieve to 0.11.9.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (c) 2002-2009 Dovecot Sieve authors, see the included COPYING file
2
 
 */
3
 
 
4
 
#include "common.h"
5
 
#include "ioloop.h"
6
 
#include "network.h"
7
 
#include "ostream.h"
8
 
#include "str.h"
9
 
#include "lib-signals.h"
10
 
#include "restrict-access.h"
11
 
#include "fd-close-on-exec.h"
12
 
#include "process-title.h"
13
 
#include "randgen.h"
14
 
#include "module-dir.h"
15
 
#include "dict-client.h"
16
 
 
17
 
#include "sieve-storage.h"
18
 
#include "sieve.h"
19
 
 
20
 
#include "commands.h"
21
 
 
22
 
#include <stdio.h>
23
 
#include <stdlib.h>
24
 
#include <unistd.h>
25
 
#include <syslog.h>
26
 
 
27
 
#define IS_STANDALONE() \
28
 
        (getenv("LOGGED_IN") == NULL)
29
 
 
30
 
#define CRITICAL_MSG \
31
 
  "Internal error occured. Refer to server log for more information."
32
 
#define CRITICAL_MSG_STAMP CRITICAL_MSG " [%Y-%m-%d %H:%M:%S]"
33
 
 
34
 
struct client_workaround_list {
35
 
        const char *name;
36
 
        enum client_workarounds num;
37
 
};
38
 
 
39
 
struct client_workaround_list client_workaround_list[] = {
40
 
        { NULL, 0 }
41
 
};
42
 
 
43
 
struct ioloop *ioloop;
44
 
unsigned int managesieve_max_line_length;
45
 
const char *managesieve_implementation_string;
46
 
enum client_workarounds client_workarounds = 0;
47
 
const char *logout_format;
48
 
 
49
 
static struct io *log_io = NULL;
50
 
static struct module *modules = NULL;
51
 
static char log_prefix[128]; /* syslog() needs this to be permanent */
52
 
 
53
 
void (*hook_client_created)(struct client **client) = NULL;
54
 
 
55
 
static void sig_die(int signo, void *context ATTR_UNUSED)
56
 
{
57
 
        /* warn about being killed because of some signal, except SIGINT (^C)
58
 
           which is too common at least while testing :) */
59
 
        if (signo != SIGINT)
60
 
                i_warning("Killed with signal %d", signo);
61
 
        io_loop_stop(ioloop);
62
 
}
63
 
 
64
 
static void log_error_callback(void *context ATTR_UNUSED)
65
 
{
66
 
        io_loop_stop(ioloop);
67
 
}
68
 
 
69
 
static void parse_workarounds(void)
70
 
{
71
 
        struct client_workaround_list *list;
72
 
        const char *env, *const *str;
73
 
 
74
 
        env = getenv("MANAGESIEVE_CLIENT_WORKAROUNDS");
75
 
        if (env == NULL)
76
 
                return;
77
 
 
78
 
        for (str = t_strsplit_spaces(env, " ,"); *str != NULL; str++) {
79
 
                list = client_workaround_list;
80
 
                for (; list->name != NULL; list++) {
81
 
                        if (strcasecmp(*str, list->name) == 0) {
82
 
                                client_workarounds |= list->num;
83
 
                                break;
84
 
                        }
85
 
                }
86
 
                if (list->name == NULL)
87
 
                        i_fatal("Unknown client workaround: %s", *str);
88
 
        }
89
 
}
90
 
 
91
 
static void open_logfile(void)
92
 
{
93
 
        const char *user;
94
 
 
95
 
        if (getenv("LOG_TO_MASTER") != NULL) {
96
 
                i_set_failure_internal();
97
 
                return;
98
 
        }
99
 
 
100
 
        if (getenv("LOG_PREFIX") != NULL)
101
 
                strncpy(log_prefix, getenv("LOG_PREFIX"), sizeof(log_prefix));
102
 
        else {
103
 
                user = getenv("USER");
104
 
                if (user == NULL) {
105
 
                        if (IS_STANDALONE())
106
 
                                user = getlogin();
107
 
                        if (user == NULL)
108
 
                                user = "??";
109
 
                }
110
 
                if (strlen(user) >= sizeof(log_prefix)-6) {     
111
 
                        /* quite a long user name, cut it */
112
 
                        user = t_strndup(user, sizeof(log_prefix)-6-2);
113
 
                        user = t_strconcat(user, "..", NULL);
114
 
                }
115
 
                i_snprintf(log_prefix, sizeof(log_prefix), "imap(%s): ", user);
116
 
        }
117
 
 
118
 
        if (getenv("USE_SYSLOG") != NULL) {
119
 
                const char *env = getenv("SYSLOG_FACILITY");
120
 
                i_set_failure_syslog(log_prefix, LOG_NDELAY,
121
 
                                     env == NULL ? LOG_MAIL : atoi(env));
122
 
        } else {
123
 
                /* log to file or stderr */
124
 
                i_set_failure_file(getenv("LOGFILE"), log_prefix);
125
 
        }
126
 
 
127
 
        if (getenv("INFOLOGFILE") != NULL)
128
 
                i_set_info_file(getenv("INFOLOGFILE"));
129
 
 
130
 
        i_set_failure_timestamp_format(getenv("LOGSTAMP"));
131
 
}
132
 
 
133
 
static void drop_privileges(void)
134
 
{
135
 
        const char *version;
136
 
 
137
 
        version = getenv("DOVECOT_VERSION");
138
 
        if (version != NULL && strcmp(version, PACKAGE_VERSION) != 0) {
139
 
                i_fatal("Dovecot version mismatch: "
140
 
                        "Master is v%s, managesieve is v"PACKAGE_VERSION" "
141
 
                        "(if you don't care, set version_ignore=yes)", version);
142
 
        }
143
 
 
144
 
        /* Log file or syslog opening probably requires roots */
145
 
        open_logfile();
146
 
 
147
 
        /* Most likely needed. Have to open /dev/urandom before possible
148
 
           chrooting. */
149
 
        random_init();
150
 
        
151
 
        /* Load the plugins before chrooting. Their init() is called later. */
152
 
        /* FIXME: MAIL_PLUGINS is a rather odd config value for a MANAGESIEVE
153
 
         * server 
154
 
         */
155
 
        if (getenv("MAIL_PLUGINS") != NULL) {
156
 
                const char *plugin_dir = getenv("MAIL_PLUGIN_DIR");
157
 
 
158
 
                if (plugin_dir == NULL)
159
 
                        plugin_dir = MODULEDIR"/managesieve";
160
 
                modules = module_dir_load(plugin_dir, getenv("MAIL_PLUGINS"),
161
 
                        TRUE, version);
162
 
        }       
163
 
 
164
 
        restrict_access_by_env(!IS_STANDALONE());
165
 
}
166
 
 
167
 
static void internal_error()
168
 
{
169
 
  struct tm *tm;
170
 
  char str[256];
171
 
 
172
 
  tm = localtime(&ioloop_time);
173
 
 
174
 
  printf("BYE \"%s\"\n",
175
 
    strftime(str, sizeof(str), CRITICAL_MSG_STAMP, tm) > 0 ?
176
 
    i_strdup(str) : i_strdup(CRITICAL_MSG));
177
 
}
178
 
 
179
 
static void main_init(void)
180
 
{
181
 
        struct sieve_storage *storage;
182
 
        struct client *client;
183
 
        const char *user, *str, *sieve_storage, *mail;
184
 
 
185
 
        lib_signals_init();
186
 
        lib_signals_set_handler(SIGINT, TRUE, sig_die, NULL);
187
 
        lib_signals_set_handler(SIGTERM, TRUE, sig_die, NULL);
188
 
        lib_signals_ignore(SIGPIPE, TRUE);
189
 
        lib_signals_ignore(SIGALRM, FALSE);
190
 
 
191
 
        user = getenv("USER");
192
 
        if (user == NULL) {
193
 
                if (IS_STANDALONE())
194
 
                        user = getlogin();
195
 
                if (user == NULL) {
196
 
                        internal_error();
197
 
                        i_fatal("USER environment missing");
198
 
                }
199
 
        }
200
 
 
201
 
        if (getenv("DEBUG") != NULL) {
202
 
                const char *home;
203
 
 
204
 
        home = getenv("HOME");
205
 
        i_info("Effective uid=%s, gid=%s, home=%s",
206
 
               dec2str(geteuid()), dec2str(getegid()),
207
 
               home != NULL ? home : "(none)");
208
 
        }
209
 
        
210
 
        if (getenv("STDERR_CLOSE_SHUTDOWN") != NULL) {
211
 
                /* If master dies, the log fd gets closed and we'll quit */
212
 
                log_io = io_add(STDERR_FILENO, IO_ERROR,
213
 
                                log_error_callback, NULL);
214
 
        }
215
 
 
216
 
        sieve_init("");
217
 
        dict_driver_register(&dict_driver_client);
218
 
        clients_init();
219
 
        commands_init();
220
 
 
221
 
        module_dir_init(modules);       
222
 
 
223
 
        /* Settings */
224
 
        str = getenv("MANAGESIEVE_MAX_LINE_LENGTH");
225
 
        managesieve_max_line_length = str != NULL ?
226
 
                (unsigned int)strtoul(str, NULL, 10) :
227
 
                DEFAULT_MANAGESIEVE_MAX_LINE_LENGTH;
228
 
 
229
 
        logout_format = getenv("MANAGESIEVE_LOGOUT_FORMAT");
230
 
        if (logout_format == NULL)
231
 
                logout_format = "bytes=%i/%o";
232
 
 
233
 
        str = getenv("MANAGESIEVE_IMPLEMENTATION_STRING");
234
 
        managesieve_implementation_string = str != NULL ?
235
 
    str : DEFAULT_MANAGESIEVE_IMPLEMENTATION_STRING;
236
 
 
237
 
        parse_workarounds();            
238
 
 
239
 
        mail = getenv("MAIL"); 
240
 
        sieve_storage = getenv("SIEVE_STORAGE");
241
 
        if ( (sieve_storage == NULL || *sieve_storage == '\0') && 
242
 
                !(mail == NULL || *mail == '\0') ) { 
243
 
                storage = sieve_storage_create_from_mail(mail, user);
244
 
        } else 
245
 
                storage = sieve_storage_create(sieve_storage, user);
246
 
 
247
 
        if (storage == NULL) { 
248
 
        internal_error();
249
 
 
250
 
                /* failed */
251
 
                if (sieve_storage != NULL && *sieve_storage != '\0')   
252
 
                        i_fatal("Failed to create sieve storage with data: %s", sieve_storage);
253
 
                else if (mail != NULL && *mail != '\0')   
254
 
                        i_fatal("Failed to create sieve storage with mail-data: %s", mail);
255
 
                else {
256
 
                        const char *home;
257
 
            
258
 
                        home = getenv("HOME");
259
 
                        if (home == NULL) home = "not set";
260
 
            
261
 
                        i_fatal("SIEVE_STORAGE and MAIL environment missing and "
262
 
                                "autodetection failed (home %s)", home);
263
 
                }
264
 
        }
265
 
        
266
 
        client = client_create(0, 1, storage);
267
 
        
268
 
        client_send_ok(client, "Logged in.");
269
 
}
270
 
 
271
 
static void main_deinit(void)
272
 
{
273
 
        if (log_io != NULL)
274
 
                io_remove(&log_io);
275
 
        clients_deinit();
276
 
 
277
 
        module_dir_unload(&modules);
278
 
        commands_deinit();
279
 
        dict_driver_unregister(&dict_driver_client);
280
 
        sieve_deinit();
281
 
        random_deinit();
282
 
 
283
 
        lib_signals_deinit();
284
 
        closelog();
285
 
}
286
 
 
287
 
int main(int argc ATTR_UNUSED, char *argv[], char *envp[])
288
 
{
289
 
#ifdef DEBUG
290
 
        if (getenv("LOGGED_IN") != NULL && getenv("GDB") == NULL)
291
 
                fd_debug_verify_leaks(3, 1024);
292
 
#endif
293
 
        if (IS_STANDALONE() && getuid() == 0 &&
294
 
            net_getpeername(1, NULL, NULL) == 0) {
295
 
                printf("NO \"managesieve binary must not be started from "
296
 
                       "inetd, use managesieve-login instead.\"\n");
297
 
                return 1;
298
 
        }
299
 
 
300
 
        /* NOTE: we start rooted, so keep the code minimal until
301
 
           restrict_access_by_env() is called */
302
 
        lib_init();
303
 
        drop_privileges();
304
 
 
305
 
        process_title_init(argv, envp);
306
 
        ioloop = io_loop_create();
307
 
 
308
 
        main_init();
309
 
        io_loop_run(ioloop);
310
 
        main_deinit();
311
 
 
312
 
        io_loop_destroy(&ioloop);
313
 
        lib_deinit();
314
 
 
315
 
        return 0;
316
 
}