1 /* autocreate.c -- Mailbox list manipulation routines
2  *
3  * Copyright (c) 1994-2012 Carnegie Mellon University.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in
14  *    the documentation and/or other materials provided with the
15  *    distribution.
16  *
17  * 3. The name "Carnegie Mellon University" must not be used to
18  *    endorse or promote products derived from this software without
19  *    prior written permission. For permission or any legal
20  *    details, please contact
21  *      Carnegie Mellon University
22  *      Center for Technology Transfer and Enterprise Creation
23  *      4615 Forbes Avenue
24  *      Suite 302
25  *      Pittsburgh, PA  15213
26  *      (412) 268-7393, fax: (412) 268-7395
27  *      innovation@andrew.cmu.edu
28  *
29  * 4. Redistributions of any form whatsoever must retain the following
30  *    acknowledgment:
31  *    "This product includes software developed by Computing Services
32  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
33  *
34  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
35  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
36  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
37  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
38  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
39  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
40  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
41  */
42 
43 #include <config.h>
44 
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 
49 #ifdef HAVE_UNISTD_H
50 #include <unistd.h>
51 #endif
52 
53 #include <errno.h>
54 #include <sys/types.h>
55 #include <sys/stat.h>
56 #include <sys/uio.h>
57 #include <fcntl.h>
58 #include <time.h>
59 #include <syslog.h>
60 
61 #include "global.h"
62 #include "annotate.h"
63 #include "util.h"
64 #include "user.h"
65 #include "xmalloc.h"
66 #include "mailbox.h"
67 #include "mboxlist.h"
68 
69 /* generated headers are not necessarily in current directory */
70 #include "imap/imap_err.h"
71 
72 #ifdef USE_SIEVE
73 
74 #include "sieve/sieve_interface.h"
75 #include "sieve/script.h"
76 
77 #define TIMSIEVE_FAIL   -1
78 #define TIMSIEVE_OK     0
79 #define MAX_FILENAME    1024
80 
81 /*
82  * Find the name of the sieve script
83  * given the source script and compiled script names
84  */
get_script_name(const char * filename)85 static const char *get_script_name(const char *filename)
86 {
87     const char *p;
88 
89     p = strrchr(filename, '/');
90     if (p == NULL)
91         return filename;
92     else
93         return p + 1;
94 }
95 
autocreate_sieve(const char * userid,const char * source_script)96 static int autocreate_sieve(const char *userid, const char *source_script)
97 {
98     /* XXX - this is really ugly, but too much work to tidy up right now -- Bron */
99     sieve_script_t *s = NULL;
100     bytecode_info_t *bc = NULL;
101     char *err = NULL;
102     FILE *in_stream, *out_fp;
103     int out_fd, in_fd, r, k;
104     int do_compile = 0;
105     const char *compiled_source_script = NULL;
106     const char *sievename = get_script_name(source_script);
107     const char *sieve_script_dir = NULL;
108     char sieve_script_name[MAX_FILENAME];
109     char sieve_bcscript_name[MAX_FILENAME];
110     char sieve_default[MAX_FILENAME];
111     char sieve_tmpname[MAX_FILENAME];
112     char sieve_bctmpname[MAX_FILENAME];
113     char sieve_bclink_name[MAX_FILENAME];
114     char buf[4096];
115     mode_t oldmask;
116     struct stat statbuf;
117 
118     /* We don't support using the homedirectory, like timsieved */
119     if (config_getswitch(IMAPOPT_SIEVEUSEHOMEDIR)) {
120         syslog(LOG_WARNING,"autocreate_sieve: autocreate_sieve does not work with sieveusehomedir option in imapd.conf");
121         return 1;
122     }
123 
124     /* Check if sievedir is defined in imapd.conf */
125     if(!config_getstring(IMAPOPT_SIEVEDIR)) {
126         syslog(LOG_WARNING, "autocreate_sieve: sievedir option is not defined. Check imapd.conf");
127         return 1;
128     }
129 
130     /* Check if autocreate_sieve_compiledscript is defined in imapd.conf */
131     if(!(compiled_source_script = config_getstring(IMAPOPT_AUTOCREATE_SIEVE_SCRIPT_COMPILED))) {
132         syslog(LOG_WARNING, "autocreate_sieve: autocreate_sieve_compiledscript option is not defined. Compiling it");
133         do_compile = 1;
134     }
135 
136     if (!(sieve_script_dir = user_sieve_path(userid))) {
137         syslog(LOG_WARNING, "autocreate_sieve: unable to determine sieve directory for user %s", userid);
138         return 1;
139     }
140 
141     if(snprintf(sieve_tmpname, MAX_FILENAME, "%s/%s.script.NEW",sieve_script_dir, sievename) >= MAX_FILENAME) {
142         syslog(LOG_WARNING, "autocreate_sieve: Invalid sieve path %s, %s, %s", sieve_script_dir, sievename, userid);
143         return 1;
144     }
145     if(snprintf(sieve_bctmpname, MAX_FILENAME, "%s/%s.bc.NEW",sieve_script_dir, sievename) >= MAX_FILENAME) {
146         syslog(LOG_WARNING, "autocreate_sieve: Invalid sieve path %s, %s, %s", sieve_script_dir, sievename, userid);
147         return 1;
148     }
149     if(snprintf(sieve_script_name, MAX_FILENAME, "%s/%s.script",sieve_script_dir, sievename) >= MAX_FILENAME) {
150         syslog(LOG_WARNING, "autocreate_sieve: Invalid sieve path %s, %s, %s", sieve_script_dir, sievename, userid);
151         return 1;
152     }
153     if(snprintf(sieve_bcscript_name, MAX_FILENAME, "%s/%s.bc",sieve_script_dir, sievename) >= MAX_FILENAME) {
154         syslog(LOG_WARNING, "autocreate_sieve: Invalid sieve path %s, %s, %s", sieve_script_dir, sievename, userid);
155         return 1;
156     }
157     if(snprintf(sieve_default, MAX_FILENAME, "%s/%s",sieve_script_dir,"defaultbc") >= MAX_FILENAME) {
158         syslog(LOG_WARNING, "autocreate_sieve: Invalid sieve path %s, %s, %s", sieve_script_dir, sievename, userid);
159         return 1;
160     }
161     /* XXX no directory? umm */
162     if(snprintf(sieve_bclink_name, MAX_FILENAME, "%s.bc", sievename) >= MAX_FILENAME) {
163         syslog(LOG_WARNING, "autocreate_sieve: Invalid sieve path %s, %s, %s", sieve_script_dir, sievename, userid);
164         return 1;
165     }
166 
167     /* Check if a default sieve filter alrady exists */
168     if(!stat(sieve_default,&statbuf)) {
169         syslog(LOG_WARNING,"autocreate_sieve: Default sieve script already exists");
170         return 1;
171     }
172 
173     /* Open the source script. if there is a problem with that exit */
174     in_stream = fopen(source_script, "r");
175     if(!in_stream) {
176         syslog(LOG_WARNING,"autocreate_sieve: Unable to open sieve script %s. Check permissions",source_script);
177         return 1;
178     }
179 
180     /*
181      * At this point we start the modifications of the filesystem
182      */
183 
184     /* Create the directory where the sieve scripts will reside */
185     r = cyrus_mkdir(sieve_bctmpname, 0755);
186     if(r == -1) {
187         /* If this fails we just leave */
188         fclose(in_stream);
189         return 1;
190     }
191 
192     /*
193      * We open the file that will be used as the bc file. If this file exists, overwrite it
194      * since something bad has happened. We open the file here so that this error checking is
195      * done before we try to open the rest of the files to start copying etc.
196      */
197     out_fd = open(sieve_bctmpname, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
198     if(out_fd < 0) {
199         if(errno == EEXIST) {
200             syslog(LOG_WARNING,"autocreate_sieve: File %s already exists. Probably left over. Ignoring",sieve_bctmpname);
201         } else if (errno == EACCES) {
202             syslog(LOG_WARNING,"autocreate_sieve: No access to create file %s. Check permissions",sieve_bctmpname);
203             fclose(in_stream);
204             return 1;
205         } else {
206             syslog(LOG_WARNING,"autocreate_sieve: Unable to create %s: %m",sieve_bctmpname);
207             fclose(in_stream);
208             return 1;
209         }
210     }
211 
212     if(!do_compile && compiled_source_script && (in_fd = open(compiled_source_script, O_RDONLY)) != -1) {
213         while((r = read(in_fd, buf, sizeof(buf))) > 0) {
214             if((k=write(out_fd, buf,r)) < 0) {
215                 syslog(LOG_WARNING, "autocreate_sieve: Error writing to file %s: %m", sieve_bctmpname);
216                 close(out_fd);
217                 close(in_fd);
218                 fclose(in_stream);
219                 unlink(sieve_bctmpname);
220                 return 1;
221            }
222         }
223 
224         if(r == 0) { /* EOF */
225             xclose(out_fd);
226             xclose(in_fd);
227         } else if (r < 0) {
228             syslog(LOG_WARNING, "autocreate_sieve: Error reading compiled script file %s: %m. Will try to compile it",
229                            compiled_source_script);
230             xclose(in_fd);
231             do_compile = 1;
232             if(lseek(out_fd, 0, SEEK_SET)) {
233                 syslog(LOG_WARNING, "autocreate_sieve: Major IO problem (lseek: %m). Aborting");
234                 xclose(out_fd);
235                 return 1;
236             }
237         }
238         xclose(in_fd);
239     } else {
240         if(compiled_source_script)
241               syslog(LOG_WARNING,"autocreate_sieve: Problem opening compiled script file: %s. Compiling it", compiled_source_script);
242         do_compile = 1;
243     }
244 
245 
246     /* Because we failed to open a precompiled bc sieve script, we compile one */
247     if(do_compile) {
248        if(sieve_script_parse_only(in_stream,&err, &s) != SIEVE_OK) {
249             if(err && *err) {
250                syslog(LOG_WARNING,"autocreate_sieve: Error while parsing script %s.",err);
251                free(err);
252             } else
253                 syslog(LOG_WARNING,"autocreate_sieve: Error while parsing script");
254 
255             unlink(sieve_bctmpname);
256             fclose(in_stream);
257             close(out_fd);
258             return 1;
259         }
260 
261         /* generate the bytecode */
262         if(sieve_generate_bytecode(&bc, s) == TIMSIEVE_FAIL) {
263             syslog(LOG_WARNING,"autocreate_sieve: problem compiling sieve script");
264             /* removing the copied script and cleaning up memory */
265             unlink(sieve_bctmpname);
266             sieve_script_free(&s);
267             fclose(in_stream);
268             close(out_fd);
269             return 1;
270         }
271 
272         if(sieve_emit_bytecode(out_fd, bc) == TIMSIEVE_FAIL) {
273             syslog(LOG_WARNING,"autocreate_sieve: problem emitting sieve script");
274             /* removing the copied script and cleaning up memory */
275             unlink(sieve_bctmpname);
276             sieve_free_bytecode(&bc);
277             sieve_script_free(&s);
278             fclose(in_stream);
279             close(out_fd);
280             return 1;
281         }
282 
283         /* clean up the memory */
284         sieve_free_bytecode(&bc);
285         sieve_script_free(&s);
286     }
287 
288     xclose(out_fd);
289     rewind(in_stream);
290 
291     /* Copy the initial script */
292     oldmask = umask(077);
293     if((out_fp = fopen(sieve_tmpname, "w")) == NULL) {
294         syslog(LOG_WARNING,"autocreate_sieve: Unable to open destination sieve script %s: %m", sieve_tmpname);
295         unlink(sieve_bctmpname);
296         umask(oldmask);
297         fclose(in_stream);
298         return 1;
299     }
300     umask(oldmask);
301 
302     while((r = fread(buf,sizeof(char), sizeof(buf), in_stream)) > 0) {
303         if( fwrite(buf,sizeof(char), r, out_fp) != (unsigned)r) {
304             syslog(LOG_WARNING,"autocreate_sieve: Problem writing to sieve script file %s: %m",sieve_tmpname);
305             fclose(out_fp);
306             unlink(sieve_tmpname);
307             unlink(sieve_bctmpname);
308             fclose(in_stream);
309             return 1;
310         }
311     }
312 
313     if(feof(in_stream)) {
314         fclose(out_fp);
315         fclose(in_stream);
316     } else { /* ferror */
317         fclose(out_fp);
318         unlink(sieve_tmpname);
319         unlink(sieve_bctmpname);
320         fclose(in_stream);
321         return 1;
322     }
323 
324     /* Renaming the necessary stuff */
325     if(rename(sieve_tmpname, sieve_script_name)) {
326         unlink(sieve_tmpname);
327         unlink(sieve_bctmpname);
328         return 1;
329     }
330 
331     if(rename(sieve_bctmpname, sieve_bcscript_name)) {
332         unlink(sieve_bctmpname);
333         unlink(sieve_bcscript_name);
334         return 1;
335     }
336 
337     /* end now with the symlink */
338     if(symlink(sieve_bclink_name, sieve_default)) {
339         if(errno != EEXIST) {
340             syslog(LOG_WARNING, "autocreate_sieve: problem making the default link (symlink: %m).");
341             /* Lets delete the files */
342             unlink(sieve_script_name);
343             unlink(sieve_bcscript_name);
344         }
345     }
346 
347     /*
348      * If everything has succeeded AND we have compiled the script AND we have requested
349      * to generate the global script so that it is not compiled each time then we create it.
350      */
351     if(do_compile &&
352           config_getswitch(IMAPOPT_AUTOCREATE_SIEVE_SCRIPT_COMPILE)) {
353 
354         if(!compiled_source_script) {
355             syslog(LOG_WARNING, "autocreate_sieve: To save a compiled sieve script, autocreate_sieve_compiledscript must have been defined in imapd.conf");
356             return 0;
357         }
358 
359         if(snprintf(sieve_tmpname, MAX_FILENAME, "%s.NEW", compiled_source_script) >= MAX_FILENAME)
360             return 0;
361 
362         /*
363          * Copy everything from the newly created bc sieve sieve script.
364          */
365         if((in_fd = open(sieve_bcscript_name, O_RDONLY))<0) {
366             return 0;
367         }
368 
369         if((out_fd = open(sieve_tmpname, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0) {
370             if(errno == EEXIST) {
371                /* Someone is already doing this so just bail out. */
372                syslog(LOG_WARNING, "autocreate_sieve: %s already exists. Some other instance processing it, or it is left over", sieve_tmpname);
373                 close(in_fd);
374                 return 0;
375             } else if (errno == EACCES) {
376                 syslog(LOG_WARNING,"autocreate_sieve: No access to create file %s. Check permissions",sieve_tmpname);
377                 close(in_fd);
378                 return 0;
379             } else {
380                 syslog(LOG_WARNING,"autocreate_sieve: Unable to create %s: %m",sieve_tmpname);
381                 close(in_fd);
382                 return 0;
383             }
384         }
385 
386         while((r = read(in_fd, buf, sizeof(buf))) > 0) {
387             if((k = write(out_fd,buf,r)) < 0) {
388                 syslog(LOG_WARNING, "autocreate_sieve: Error writing to file: %s: %m", sieve_tmpname);
389                 close(out_fd);
390                 close(in_fd);
391                 unlink(sieve_tmpname);
392                 return 0;
393            }
394         }
395 
396         if(r == 0 ) { /*EOF */
397             xclose(out_fd);
398             xclose(in_fd);
399         } else if (r < 0) {
400                 syslog(LOG_WARNING, "autocreate_sieve: Error reading file: %s: %m", sieve_bcscript_name);
401                 xclose(out_fd);
402                 xclose(in_fd);
403                 unlink(sieve_tmpname);
404                 return 0;
405         }
406 
407         /* Rename the temporary created sieve script to its final name. */
408         if(rename(sieve_tmpname, compiled_source_script)) {
409             if(errno != EEXIST) {
410                unlink(sieve_tmpname);
411                unlink(compiled_source_script);
412         }
413             return 0;
414         }
415 
416         syslog(LOG_NOTICE, "autocreate_sieve: Compiled sieve script was successfully saved in %s", compiled_source_script);
417     }
418 
419     return 0;
420 }
421 #endif /* USE_SIEVE */
422 
423 /*
424  * Struct needed to be passed as void *rock to
425  * mboxlist_autochangesub();
426  */
427 struct changesub_rock_st {
428     const char *userid;
429     struct auth_state *auth_state;
430     int was_explicit;
431 };
432 
433 /*
434  * Automatically subscribe user to *ALL* shared folders,
435  * one has permissions to be subscribed to.
436  * INBOX subfolders are excluded.
437  */
autochangesub(struct findall_data * data,void * rock)438 static int autochangesub(struct findall_data *data, void *rock)
439 {
440     if (!data) return 0;
441     struct changesub_rock_st *crock = (struct changesub_rock_st *)rock;
442     const char *userid = crock->userid;
443     struct auth_state *auth_state = crock->auth_state;
444     int was_explicit = crock->was_explicit;
445     const char *name = mbname_intname(data->mbname);
446     int r;
447 
448     /* ignore all user mailboxes, we only want shared */
449     if (mboxname_isusermailbox(name, 0)) return 0;
450 
451     r = mboxlist_changesub(name, userid, auth_state, 1, 0, 1);
452 
453     /* unless this name was explicitly chosen, ignore the failure */
454     if (!was_explicit) return 0;
455 
456     if (r) {
457         syslog(LOG_WARNING,
458                "autosubscribe: User %s to folder %s, subscription failed: %s",
459                userid, name, error_message(r));
460     } else {
461         syslog(LOG_NOTICE,
462                "autosubscribe: User %s to folder %s, subscription succeeded",
463                userid, name);
464     }
465 
466     return 0;
467 }
468 
469 /* string for strarray_split */
470 #define SEP "|"
471 
472 /*
473  * Automatically subscribe user to a shared folder.
474  * Subscription is done successfully, if the shared
475  * folder exists and the user has the necessary
476  * permissions.
477  */
autosubscribe_sharedfolders(struct namespace * namespace,const char * userid,struct auth_state * auth_state)478 static void autosubscribe_sharedfolders(struct namespace *namespace,
479                                         const char *userid,
480                                         struct auth_state *auth_state)
481 {
482     strarray_t *folders = NULL;
483     const char *sub;
484     int i;
485     struct changesub_rock_st changesub_rock;
486 
487     changesub_rock.userid = userid;
488     changesub_rock.auth_state = auth_state;
489     changesub_rock.was_explicit = 0;
490 
491     /*
492      * If subscribeallsharedfolders is set to yes in imapd.conf, then
493      * subscribe user to every shared folder one has the apropriate
494      * permissions.
495      */
496     if (config_getswitch(IMAPOPT_AUTOCREATE_SUBSCRIBE_SHAREDFOLDERS_ALL)) {
497         /* don't care about errors here, the sub will log them */
498         mboxlist_findall(namespace, "*", 0, userid, auth_state,
499                          autochangesub, &changesub_rock);
500         return;
501     }
502 
503     /* otherwise, check if there are particular folders to subscribe */
504 
505     sub = config_getstring(IMAPOPT_AUTOCREATE_SUBSCRIBE_SHAREDFOLDERS);
506     if (!sub) return;
507 
508     changesub_rock.was_explicit = 1;
509 
510     folders = strarray_split(sub, SEP, STRARRAY_TRIM);
511 
512     for (i = 0; i < folders->count; i++) {
513         const char *mboxname = strarray_nth(folders, i);
514         mboxlist_findone(namespace, mboxname, 0, userid, auth_state,
515                          autochangesub, &changesub_rock);
516     }
517 
518     strarray_free(folders);
519 
520     return;
521 }
522 
523 struct autocreate_specialuse_rock {
524     const char *userid;
525     const char *intname;
526     const char *name;
527 };
528 
autocreate_specialuse_cb(const char * key,const char * val,void * rock)529 static void autocreate_specialuse_cb(const char *key, const char *val, void *rock)
530 {
531     struct autocreate_specialuse_rock *ar = (struct autocreate_specialuse_rock *)rock;
532     if (strncmp(key, "xlist-", 6)) return;
533     if (strcmp(val, ar->name)) return;
534 
535     struct buf usebuf = BUF_INITIALIZER;
536     buf_putc(&usebuf, '\\');
537     buf_appendcstr(&usebuf, key + 6);
538 
539     /* we've got an XLIST key that matches the autocreated name */
540     char *existing = mboxlist_find_specialuse(buf_cstring(&usebuf), ar->userid);
541     if (existing) {
542         syslog(LOG_NOTICE, "autocreate: not setting specialuse %s for %s, already exists as %s",
543                buf_cstring(&usebuf), ar->intname, existing);
544         free(existing);
545         goto done;
546     }
547 
548     int r = annotatemore_write(ar->intname, "/specialuse", ar->userid, &usebuf);
549     if (r) {
550         syslog(LOG_WARNING, "autocreate: failed to set specialuse %s for %s",
551                buf_cstring(&usebuf), ar->intname);
552     }
553     else {
554         syslog(LOG_INFO, "autocreate: set specialuse %s for %s",
555                buf_cstring(&usebuf), ar->intname);
556     }
557 
558  done:
559     buf_free(&usebuf);
560 }
561 
autocreate_user(struct namespace * namespace,const char * userid)562 int autocreate_user(struct namespace *namespace,
563                     const char *userid)
564 {
565     int r = IMAP_MAILBOX_NONEXISTENT; /* default error if we break early */
566     int autocreatequota = config_getint(IMAPOPT_AUTOCREATE_QUOTA);
567     int autocreatequotamessage = config_getint(IMAPOPT_AUTOCREATE_QUOTA_MESSAGES);
568     int n;
569     struct auth_state *auth_state = NULL;
570     strarray_t *create = NULL;
571     strarray_t *subscribe = NULL;
572     int numcrt = 0;
573     int numsub = 0;
574 #ifdef USE_SIEVE
575     const char *source_script;
576 #endif
577 
578     /* check for anonymous */
579     if (!strcmp(userid, "anonymous"))
580         return IMAP_MAILBOX_NONEXISTENT;
581 
582     char *inboxname = mboxname_user_mbox(userid, NULL);
583 
584     auth_state = auth_newstate(userid);
585 
586     /* Added this for debug information. */
587     syslog(LOG_DEBUG, "autocreateinbox: autocreate inbox for user %s was called", userid);
588 
589     /*
590      * While this is not needed for admins
591      * and imap_admins accounts, it would be
592      * better to separate *all* admins and
593      * proxyservers from normal accounts
594      * (accounts that have mailboxes).
595      * UOA Specific note(1): Even if we do not
596      * exclude these servers-classes here,
597      * UOA specific code, will neither return
598      * role, nor create INBOX, because none of these
599      * administrative accounts belong to  the
600      * mailRecipient objectclass, or have imapPartition.
601      * UOA Specific note(2): Another good reason for doing
602      * this, is to prevent the code, from getting into
603      * cyrus_ldap.c because of the continues MSA logins to LMTPd.
604      */
605 
606     /*
607      * we need to exclude admins here
608      */
609 
610     /*
611      * Do we really need group membership
612      * for admins or service_admins?
613      */
614     if (global_authisa(auth_state, IMAPOPT_ADMINS)) goto done;
615 
616     /*
617      * Do we really need group membership
618      * for proxyservers?
619      */
620     if (global_authisa(auth_state, IMAPOPT_PROXYSERVERS)) goto done;
621 
622     /*
623      * Check if user belongs to the autocreate_users group. This option
624      * controls for whom the mailbox may be automatically created. Default
625      * value for this option is 'anyone'. So, if not declared, all mailboxes
626      * will be created.
627      */
628     if (!global_authisa(auth_state, IMAPOPT_AUTOCREATE_USERS)) {
629         syslog(LOG_DEBUG, "autocreateinbox: User %s does not belong to the autocreate_users. No mailbox is created",
630                userid);
631         goto done;
632     }
633 
634     r = mboxlist_createmailbox(inboxname, /*mbtype*/0, /*partition*/NULL,
635                                /*isadmin*/1, userid, auth_state,
636                                /*localonly*/0, /*forceuser*/0,
637                                /*dbonly*/0, /*notify*/1,
638                                /*mailboxptr*/NULL);
639 
640     if (!r) r = mboxlist_changesub(inboxname, userid, auth_state, 1, 1, 1);
641     if (r) {
642         syslog(LOG_ERR, "autocreateinbox: User %s, INBOX failed. %s",
643                userid, error_message(r));
644         goto done;
645     }
646 
647     if (autocreatequota >= 0 || autocreatequotamessage >= 0) {
648         quota_t newquotas[QUOTA_NUMRESOURCES];
649         int res;
650 
651         for (res = 0 ; res < QUOTA_NUMRESOURCES ; res++)
652             newquotas[res] = QUOTA_UNLIMITED;
653 
654         if (autocreatequota)
655             newquotas[QUOTA_STORAGE] = autocreatequota;
656 
657         if (autocreatequotamessage)
658             newquotas[QUOTA_MESSAGE] = autocreatequotamessage;
659 
660         r = mboxlist_setquotas(inboxname, newquotas, 0);
661         if (r) {
662             syslog(LOG_ERR, "autocreateinbox: User %s, QUOTA failed. %s",
663                    userid, error_message(r));
664             goto done;
665         }
666     }
667 
668     syslog(LOG_NOTICE, "autocreateinbox: User %s, INBOX was successfully created",
669            userid);
670 
671     create = strarray_split(config_getstring(IMAPOPT_AUTOCREATE_INBOX_FOLDERS), SEP, STRARRAY_TRIM);
672     subscribe = strarray_split(config_getstring(IMAPOPT_AUTOCREATE_SUBSCRIBE_FOLDERS), SEP, STRARRAY_TRIM);
673 
674     for (n = 0; n < create->count; n++) {
675         const char *name = strarray_nth(create, n);
676         char *foldername = mboxname_user_mbox(userid, name);
677         struct autocreate_specialuse_rock specialrock = { userid, foldername, name };
678 
679         r = mboxlist_createmailbox(foldername, /*mbtype*/0, /*partition*/NULL,
680                                    /*isadmin*/1, userid, auth_state,
681                                    /*localonly*/0, /*forceuser*/0,
682                                    /*dbonly*/0, /*notify*/1,
683                                    /*mailboxptr*/NULL);
684 
685         if (!r) {
686             numcrt++;
687             syslog(LOG_NOTICE, "autocreateinbox: User %s, subfolder %s creation succeeded.",
688                    userid, name);
689         } else {
690             syslog(LOG_WARNING, "autocreateinbox: User %s, subfolder %s creation failed. %s",
691                    userid, name, error_message(r));
692             r = 0;
693             continue;
694         }
695 
696         /* subscribe if requested */
697         if (strarray_find(subscribe, name, 0) >= 0) {
698             r = mboxlist_changesub(foldername, userid, auth_state, 1, 1, 1);
699             if (!r) {
700                 numsub++;
701                 syslog(LOG_NOTICE,"autocreateinbox: User %s, subscription to %s succeeded",
702                     userid, name);
703             } else {
704                 syslog(LOG_WARNING, "autocreateinbox: User %s, subscription to  %s failed. %s",
705                     userid, name, error_message(r));
706                 r = 0;
707             }
708         }
709 
710         /* set specialuse if requested */
711         config_foreachoverflowstring(autocreate_specialuse_cb, &specialrock);
712     }
713 
714     if (numcrt)
715         syslog(LOG_INFO, "User %s, Inbox subfolders, created %d, subscribed %d",
716                userid, numcrt, numsub);
717 
718     /*
719      * Check if shared folders are available for subscription.
720      */
721     autosubscribe_sharedfolders(namespace, userid, auth_state);
722 
723 #ifdef USE_SIEVE
724     /*
725      * Here the autocreate sieve script feature is iniated from.
726      */
727     source_script = config_getstring(IMAPOPT_AUTOCREATE_SIEVE_SCRIPT);
728 
729     if (source_script) {
730         if (!autocreate_sieve(userid, source_script))
731             syslog(LOG_NOTICE, "autocreate_sieve: User %s, default sieve script creation succeeded", userid);
732         else
733             syslog(LOG_WARNING, "autocreate_sieve: User %s, default sieve script creation failed", userid);
734     }
735 #endif
736 
737  done:
738     free(inboxname);
739     strarray_free(create);
740     strarray_free(subscribe);
741     auth_freestate(auth_state);
742 
743     return r;
744 }
745