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