Пример #1
0
EXPORTED void quotadb_open(const char *fname)
{
    int ret;
    char *tofree = NULL;
    int flags = CYRUSDB_CREATE;

    if (!fname)
        fname = config_getstring(IMAPOPT_QUOTA_DB_PATH);

    /* create db file name */
    if (!fname) {
        tofree = strconcat(config_dir, FNAME_QUOTADB, (char *)NULL);
        fname = tofree;
    }

    if (config_getswitch(IMAPOPT_IMPROVED_MBOXLIST_SORT))
        flags |= CYRUSDB_MBOXSORT;

    ret = cyrusdb_open(QDB, fname, flags, &qdb);
    if (ret != 0) {
        syslog(LOG_ERR, "DBERROR: opening %s: %s", fname,
               cyrusdb_strerror(ret));
            /* Exiting TEMPFAIL because Sendmail thinks this
               EC_OSFILE == permanent failure. */
        fatal("can't read quotas file", EC_TEMPFAIL);
    }

    free(tofree);

    quota_dbopen = 1;
}
Пример #2
0
static int user_deletesieve(const char *user) 
{
    const char *sieve_path;
    char filename[2048];
    DIR *mbdir;
    struct dirent *next = NULL;
    
    /* oh well */
    if(config_getswitch(IMAPOPT_SIEVEUSEHOMEDIR)) return 0;

    sieve_path = user_sieve_path(user);

    mbdir = opendir(sieve_path);

    if (mbdir) {
	while((next = readdir(mbdir)) != NULL) {
	    if (!strcmp(next->d_name, ".")
	        || !strcmp(next->d_name, "..")) continue;

	    snprintf(filename, sizeof(filename), "%s/%s",
		     sieve_path, next->d_name);

	    unlink(filename);
	}
	
	closedir(mbdir);

	/* remove mbdir */
	rmdir(sieve_path);
    }

    return 0;
}
Пример #3
0
static int sync_log_enabled(const char *channel)
{
    if (!config_getswitch(IMAPOPT_SYNC_LOG))
	return 0;	/* entire mechanism is disabled */
    if (!sync_log_suppressed)
	return 1;	/* _suppress() wasn't called */
    if (unsuppressable && strarray_find(unsuppressable, channel, 0) >= 0)
	return 1;	/* channel is unsuppressable */
    return 0;		/* suppressed */
}
Пример #4
0
static int compact_closerename(struct backup **originalp,
                               struct backup **compactp,
                               time_t now)
{
    struct backup *original = *originalp;
    struct backup *compact = *compactp;
    struct buf ts_data_fname = BUF_INITIALIZER;
    struct buf ts_index_fname = BUF_INITIALIZER;
    int r;

    buf_printf(&ts_data_fname, "%s.%ld", original->data_fname, now);
    buf_printf(&ts_index_fname, "%s.%ld", original->index_fname, now);

    /* link original files into timestamped names */
    r = link(original->data_fname, buf_cstring(&ts_data_fname));
    if (!r) link(original->index_fname, buf_cstring(&ts_index_fname));

    if (r) {
        /* on error, trash the new links and bail out */
        unlink(buf_cstring(&ts_data_fname));
        unlink(buf_cstring(&ts_index_fname));
        goto done;
    }

    /* replace original files with compacted files */
    r = rename(compact->data_fname, original->data_fname);
    if (!r) r = rename(compact->index_fname, original->index_fname);

    if (r) {
        /* on error, put original files back */
        unlink(original->data_fname);
        unlink(original->index_fname);
        link(buf_cstring(&ts_data_fname), original->data_fname);
        link(buf_cstring(&ts_index_fname), original->index_fname);
        goto done;
    }

    /* finally, clean up the timestamped ones */
    if (!config_getswitch(IMAPOPT_BACKUP_KEEP_PREVIOUS)) {
        unlink(buf_cstring(&ts_data_fname));
        unlink(buf_cstring(&ts_index_fname));
    }

    /* release our locks */
    backup_close(originalp);
    backup_close(compactp);

done:
    buf_free(&ts_data_fname);
    buf_free(&ts_index_fname);
    return r;
}
Пример #5
0
EXPORTED int tls_enabled(void)
{
    const char *val;

    val = config_getstring(IMAPOPT_TLS_SERVER_CERT);
    if (!val || !strcasecmp(val, "disabled")) return 0;

    val = config_getstring(IMAPOPT_TLS_SERVER_KEY);
    if (!val || !strcasecmp(val, "disabled")) return 0;

    if (config_getswitch(IMAPOPT_CHATTY))
            syslog(LOG_INFO, "TLS is available.");

    return 1;
}
Пример #6
0
int actions_init(void)
{
  int sieve_usehomedir = 0;

  sieve_usehomedir = config_getswitch(IMAPOPT_SIEVEUSEHOMEDIR);
  
  if (!sieve_usehomedir) {
      sieve_dir = (char *) config_getstring(IMAPOPT_SIEVEDIR);
  } else {
      /* can't use home directories with timsieved */
      syslog(LOG_ERR, "can't use home directories");

      return TIMSIEVE_FAIL;
  }
  
  return TIMSIEVE_OK;
}
Пример #7
0
/*
 * Convert 'identifier' into canonical form.
 * Returns a pointer to a static buffer containing the canonical form
 * or NULL if 'identifier' is invalid.
 */
static char *afspts_canonifyid(const char *identifier, size_t len)
{
    static char *retbuf = NULL;
    char *tmp = NULL;
    krb5_context context;
    krb5_principal princ, princ_dummy;
    char *realm;
    char *realmbegin;
    int striprealm = 0;
    char *identifier2;

    if(retbuf) free(retbuf);
    retbuf = NULL;

    if(!identifier) return NULL;
    if(!len) len = strlen(identifier);

    if (strcasecmp(identifier, "anonymous") == 0)
        return "anonymous";

    if (strcasecmp(identifier, "anyone") == 0)
        return "anyone";

    identifier2 = strdup(identifier);
    if (tmp = strchr(identifier2, '+')) {
        syslog(LOG_DEBUG, "afspts_canonifyid stripping: %s", identifier2);
        tmp[0] = 0;
        syslog(LOG_DEBUG, "afspts_canonifyid stripped: %s", identifier2);
    }

    if (krb5_init_context(&context)) {
        syslog(LOG_ERR, "afspts_canonifyid krb5_init_context failed");
        return NULL;
    }

    if (krb5_parse_name(context,identifier2,&princ))
    {
        krb5_free_context(context);
        free(identifier2);
        syslog(LOG_ERR, "afspts_canonifyid krb5_parse_name failed");
        return NULL;
    }
    free(identifier2);

    if(config_getswitch(IMAPOPT_PTSKRB5_STRIP_DEFAULT_REALM)) {
        /* get local realm */
        if (krb5_get_default_realm(context,&realm))
        {
            krb5_free_principal(context,princ);
            krb5_free_context(context);
            syslog(LOG_ERR, "afspts_canonifyid krb5_get_default_realm failed");
            return NULL;
        }

        /* build dummy princ to compare realms */
        if (krb5_build_principal(context,&princ_dummy,
                                 strlen(realm),realm,"dummy",0))
        {
            krb5_free_principal(context,princ);
            krb5_free_context(context);
            free(realm);
            syslog(LOG_ERR, "afspts_canonifyid krb5_build_principal failed");
            return NULL;
        }

        /* is this principal local ? */
        if (krb5_realm_compare(context,princ,princ_dummy))
        {
            striprealm = 1;
        }

        /* done w/ dummy princ free it & realm */
        krb5_free_principal(context,princ_dummy);
        free(realm);
    }

    if (config_getswitch(IMAPOPT_PTSKRB5_CONVERT524)) {
        char nbuf[64], ibuf[64], rbuf[64];

        if (krb5_524_conv_principal(context, princ, nbuf, ibuf, rbuf)) {
            krb5_free_principal(context,princ);
            krb5_free_context(context);
            return NULL;
        }

        retbuf = xmalloc(3*64 + 3);
        sprintf(retbuf, "%s%s%s%s%s", nbuf,
                ibuf[0] ? "." : "", ibuf,
                rbuf[0] ? "@" : "", rbuf);
    } else {
        /* get the text version of princ */
        if (krb5_unparse_name(context,princ,&retbuf))
        {
            krb5_free_principal(context,princ);
            krb5_free_context(context);
            syslog(LOG_ERR, "afspts_canonifyid krb5_unparse_name failed");
            return NULL;
        }
    }

    /* we have the canonical name pointed to by p -- strip realm if local */
    realmbegin = strrchr(retbuf, '@');
    if(realmbegin) {
        if(!striprealm) {
            realm = realmbegin+1;
            if(is_local_realm(realm))
                striprealm = 1;
        }

        if(striprealm) {
            *realmbegin = '\0';
        } else {
            /* Force realm to uppercase */
            while(*(++realmbegin)) {
                *realmbegin = toupper(*realmbegin);
            }
        }
    }

    krb5_free_principal(context,princ);
    krb5_free_context(context);
    return retbuf;
}
Пример #8
0
struct backend *backend_connect(struct backend *ret_backend, const char *server,
				struct protocol_t *prot, const char *userid,
				sasl_callback_t *cb, const char **auth_status)
{
    /* need to (re)establish connection to server or create one */
    int sock = -1;
    int r;
    int err = -1;
    int ask = 1; /* should we explicitly ask for capabilities? */
    struct addrinfo hints, *res0 = NULL, *res;
    struct sockaddr_un sunsock;
    char buf[2048];
    struct sigaction action;
    struct backend *ret;
    char rsessionid[MAX_SESSIONID_SIZE];

    if (!ret_backend) {
	ret = xzmalloc(sizeof(struct backend));
	strlcpy(ret->hostname, server, sizeof(ret->hostname));
	ret->timeout = NULL;
    }
    else
	ret = ret_backend;

    if (server[0] == '/') { /* unix socket */
	res0 = &hints;
	memset(res0, 0, sizeof(struct addrinfo));
	res0->ai_family = PF_UNIX;
	res0->ai_socktype = SOCK_STREAM;

 	res0->ai_addr = (struct sockaddr *) &sunsock;
 	res0->ai_addrlen = sizeof(sunsock.sun_family) + strlen(server) + 1;
#ifdef SIN6_LEN
 	res0->ai_addrlen += sizeof(sunsock.sun_len);
 	sunsock.sun_len = res0->ai_addrlen;
#endif
	sunsock.sun_family = AF_UNIX;
	strlcpy(sunsock.sun_path, server, sizeof(sunsock.sun_path));

	/* XXX set that we are preauthed */

	/* change hostname to 'config_servername' */
	strlcpy(ret->hostname, config_servername, sizeof(ret->hostname));
    }
    else { /* inet socket */
	memset(&hints, 0, sizeof(hints));
	hints.ai_family = PF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	err = getaddrinfo(server, prot->service, &hints, &res0);
	if (err) {
	    syslog(LOG_ERR, "getaddrinfo(%s) failed: %s",
		   server, gai_strerror(err));
	    goto error;
	}
    }

    /* Setup timeout */
    timedout = 0;
    action.sa_flags = 0;
    action.sa_handler = timed_out;
    sigemptyset(&action.sa_mask);
    if(sigaction(SIGALRM, &action, NULL) < 0) 
    {
	syslog(LOG_ERR, "Setting timeout in backend_connect failed: sigaction: %m");
	/* continue anyway */
    }
    
    for (res = res0; res; res = res->ai_next) {
	sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
	if (sock < 0)
	    continue;
	alarm(config_getint(IMAPOPT_CLIENT_TIMEOUT));
	if (connect(sock, res->ai_addr, res->ai_addrlen) >= 0)
	    break;
	if(errno == EINTR && timedout == 1)
	    errno = ETIMEDOUT;
	close(sock);
	sock = -1;
    }

    /* Remove timeout code */
    alarm(0);
    signal(SIGALRM, SIG_IGN);
    
    if (sock < 0) {
	if (res0 != &hints)
	    freeaddrinfo(res0);
	syslog(LOG_ERR, "connect(%s) failed: %m", server);
	goto error;
    }
    memcpy(&ret->addr, res->ai_addr, res->ai_addrlen);
    if (res0 != &hints)
	freeaddrinfo(res0);

    ret->in = prot_new(sock, 0);
    ret->out = prot_new(sock, 1);
    ret->sock = sock;
    prot_setflushonread(ret->in, ret->out);
    ret->prot = prot;

    /* use literal+ to send literals */
    prot_setisclient(ret->in, 1);
    prot_setisclient(ret->out, 1);
    
    if (prot->banner.auto_capa) {
	/* try to get the capabilities from the banner */
	r = ask_capability(ret, /*dobanner*/1, AUTO_CAPA_BANNER);
	if (r) {
	    /* found capabilities in banner -> don't ask */
	    ask = 0;
	}
    }
    else {
	do { /* read the initial greeting */
	    if (!prot_fgets(buf, sizeof(buf), ret->in)) {
		syslog(LOG_ERR,
		       "backend_connect(): couldn't read initial greeting: %s",
		       ret->in->error ? ret->in->error : "(null)");
		goto error;
	    }
	} while (strncasecmp(buf, prot->banner.resp,
			     strlen(prot->banner.resp)));
	strncpy(ret->banner, buf, 2048);
    }

    if (ask) {
	/* get the capabilities */
	ask_capability(ret, /*dobanner*/0, AUTO_CAPA_NO);
    }

    /* now need to authenticate to backend server,
       unless we're doing LMTP/CSYNC on a UNIX socket (deliver/sync_client) */
    if ((server[0] != '/') ||
	(strcmp(prot->sasl_service, "lmtp") &&
	 strcmp(prot->sasl_service, "csync"))) {
	char *old_mechlist = backend_get_cap_params(ret, CAPA_AUTH);
	const char *my_status;

	if ((r = backend_authenticate(ret, userid, cb, &my_status))) {
	    syslog(LOG_ERR, "couldn't authenticate to backend server: %s",
		   sasl_errstring(r, NULL, NULL));
	    free(old_mechlist);
	    goto error;
	}
	else {
	    const void *ssf;

	    sasl_getprop(ret->saslconn, SASL_SSF, &ssf);
	    if (*((sasl_ssf_t *) ssf)) {
		/* if we have a SASL security layer, compare SASL mech lists
		   before/after AUTH to check for a MITM attack */
		char *new_mechlist;
		int auto_capa = (prot->sasl_cmd.auto_capa == AUTO_CAPA_AUTH_SSF);

		if (!strcmp(prot->service, "sieve")) {
		    /* XXX  Hack to handle ManageSieve servers.
		     * No way to tell from protocol if server will
		     * automatically send capabilities, so we treat it
		     * as optional.
		     */
		    char ch;

		    /* wait and probe for possible auto-capability response */
		    usleep(250000);
		    prot_NONBLOCK(ret->in);
		    if ((ch = prot_getc(ret->in)) != EOF) {
			prot_ungetc(ch, ret->in);
		    } else {
			auto_capa = AUTO_CAPA_AUTH_NO;
		    }
		    prot_BLOCK(ret->in);
		}

		ask_capability(ret, /*dobanner*/0, auto_capa);
		new_mechlist = backend_get_cap_params(ret, CAPA_AUTH);
		if (new_mechlist &&
		    old_mechlist &&
		    strcmp(new_mechlist, old_mechlist)) {
		    syslog(LOG_ERR, "possible MITM attack:"
			   "list of available SASL mechanisms changed");
		    free(new_mechlist);
		    free(old_mechlist);
		    goto error;
		}
		free(new_mechlist);
	    }
	    else if (prot->sasl_cmd.auto_capa == AUTO_CAPA_AUTH_OK) {
		/* try to get the capabilities from the AUTH success response */
		forget_capabilities(ret);
		parse_capability(ret, my_status);
		post_parse_capability(ret);
	    }

	    if (!(strcmp(prot->service, "imap") &&
		 (strcmp(prot->service, "pop3")))) {
		parse_sessionid(my_status, rsessionid);
		syslog(LOG_NOTICE, "proxy %s sessionid=<%s> remote=<%s>", userid, session_id(), rsessionid);
	    }
	}

	if (auth_status) *auth_status = my_status;
	free(old_mechlist);
    }

    /* start compression if requested and both client/server support it */
    if (config_getswitch(IMAPOPT_PROXY_COMPRESS) && ret &&
	CAPA(ret, CAPA_COMPRESS) &&
	prot->compress_cmd.cmd &&
	do_compress(ret, &prot->compress_cmd)) {

	syslog(LOG_ERR, "couldn't enable compression on backend server");
	goto error;
    }

    return ret;

error:
    forget_capabilities(ret);
    if (ret->in) {
	prot_free(ret->in);
	ret->in = NULL;
    }
    if (ret->out) {
	prot_free(ret->out);
	ret->out = NULL;
    }
    if (sock >= 0)
	close(sock);
    if (ret->saslconn) {
	sasl_dispose(&ret->saslconn);
	ret->saslconn = NULL;
    }
    if (!ret_backend)
	free(ret);
    return NULL;
}
Пример #9
0
static int user_renamesieve(char *olduser, char *newuser)
{
    char hash, *domain;
    char oldpath[2048], newpath[2048];
    int r;
    
    /* oh well */
    if(config_getswitch(IMAPOPT_SIEVEUSEHOMEDIR)) return 0;
    
    if (config_virtdomains && (domain = strchr(olduser, '@'))) {
	char d = (char) dir_hash_c(domain+1, config_fulldirhash);
	*domain = '\0';  /* split user@domain */
	hash = (char) dir_hash_c(olduser, config_fulldirhash);
	snprintf(oldpath, sizeof(oldpath), "%s%s%c/%s/%c/%s",
		 config_getstring(IMAPOPT_SIEVEDIR),
		 FNAME_DOMAINDIR, d, domain+1, hash, olduser);
	*domain = '@';  /* reassemble user@domain */
    }
    else {
	hash = (char) dir_hash_c(olduser, config_fulldirhash);

	snprintf(oldpath, sizeof(oldpath), "%s/%c/%s",
		 config_getstring(IMAPOPT_SIEVEDIR), hash, olduser);
    }

    if (config_virtdomains && (domain = strchr(newuser, '@'))) {
	char d = (char) dir_hash_c(domain+1, config_fulldirhash);
	*domain = '\0';  /* split user@domain */
	hash = (char) dir_hash_c(newuser, config_fulldirhash);
	snprintf(newpath, sizeof(newpath), "%s%s%c/%s/%c/%s",
		 config_getstring(IMAPOPT_SIEVEDIR),
		 FNAME_DOMAINDIR, d, domain+1, hash, newuser);
	*domain = '@';  /* reassemble user@domain */
    }
    else {
	hash = (char) dir_hash_c(newuser, config_fulldirhash);

	snprintf(newpath, sizeof(newpath), "%s/%c/%s",
		 config_getstring(IMAPOPT_SIEVEDIR), hash, newuser);
    }

    /* rename sieve directory
     *
     * XXX this doesn't rename sieve scripts
     */
    r = rename(oldpath, newpath);
    if (r < 0) {
	if (errno == ENOENT) {
	    syslog(LOG_WARNING, "error renaming %s to %s: %m",
		   oldpath, newpath);
	    /* but maybe the user doesn't have any scripts ? */
	    r = 0;
	}
	else if (errno == EXDEV) {
	    syslog(LOG_ERR, "error renaming %s to %s: different filesystems",
		   oldpath, newpath);
	    /* doh!  need to copy entire directory tree */
	}
	else {
	    syslog(LOG_ERR, "error renaming %s to %s: %m", oldpath, newpath);
	}
    }

    return r;
}
Пример #10
0
/* Called before a cyrus application starts (but after command line parameters
 * are read) */
int cyrus_init(const char *alt_config, const char *ident, unsigned flags)
{
    char *p;
    const char *val;
    const char *prefix;
    int umaskval = 0;

    if(cyrus_init_run != NOT_RUNNING) {
        fatal("cyrus_init called twice!", EC_CONFIG);
    } else {
        cyrus_init_run = RUNNING;
    }

    cyrus_init_nodb = (flags & CYRUSINIT_NODB);

    initialize_imap_error_table();
    initialize_mupd_error_table();

    if(!ident)
        fatal("service name was not specified to cyrus_init", EC_CONFIG);

    config_ident = ident;

    /* xxx we lose here since we can't have the prefix until we load the
     * config file */
    openlog(config_ident, LOG_PID, SYSLOG_FACILITY);

    /* Load configuration file.  This will set config_dir when it finds it */
    config_read(alt_config);

    prefix = config_getstring(IMAPOPT_SYSLOG_PREFIX);

    /* Reopen the log with the new prefix, if needed  */
    if(prefix) {
        int size = strlen(prefix) + 1 + strlen(ident) + 1;
        char *ident_buf = xmalloc(size);

        strlcpy(ident_buf, prefix, size);
        strlcat(ident_buf, "/", size);
        strlcat(ident_buf, ident, size);

        closelog();
        openlog(ident_buf, LOG_PID, SYSLOG_FACILITY);

        /* don't free the openlog() string! */
    }

    /* Look up default partition */
    config_defpartition = config_getstring(IMAPOPT_DEFAULTPARTITION);
    for (p = (char *)config_defpartition; p && *p; p++) {
        if (!Uisalnum(*p))
            fatal("defaultpartition option contains non-alphanumeric character",
                  EC_CONFIG);
        if (Uisupper(*p)) *p = tolower((unsigned char) *p);
    }

    /* Look up umask */
    val = config_getstring(IMAPOPT_UMASK);
    while (*val) {
        if (*val >= '0' && *val <= '7') umaskval = umaskval*8 + *val - '0';
        val++;
    }
    umask(umaskval);

    config_fulldirhash = config_getswitch(IMAPOPT_FULLDIRHASH);

    /* look up and canonify the implicit rights of mailbox owners */
    config_implicitrights =
        cyrus_acl_strtomask(config_getstring(IMAPOPT_IMPLICIT_OWNER_RIGHTS));

    config_metapartition_files = config_getbitfield(IMAPOPT_METAPARTITION_FILES);

    if (!cyrus_init_nodb) {
        /* lookup the database backends */
        config_mboxlist_db =
            cyrusdb_fromname(config_getstring(IMAPOPT_MBOXLIST_DB));
        config_quota_db =
            cyrusdb_fromname(config_getstring(IMAPOPT_QUOTA_DB));
        config_subscription_db =
            cyrusdb_fromname(config_getstring(IMAPOPT_SUBSCRIPTION_DB));
        config_annotation_db =
            cyrusdb_fromname(config_getstring(IMAPOPT_ANNOTATION_DB));
        config_seenstate_db =
            cyrusdb_fromname(config_getstring(IMAPOPT_SEENSTATE_DB));
        config_mboxkey_db =
            cyrusdb_fromname(config_getstring(IMAPOPT_MBOXKEY_DB));
        config_duplicate_db =
            cyrusdb_fromname(config_getstring(IMAPOPT_DUPLICATE_DB));
        config_tlscache_db =
            cyrusdb_fromname(config_getstring(IMAPOPT_TLSCACHE_DB));
        config_ptscache_db =
            cyrusdb_fromname(config_getstring(IMAPOPT_PTSCACHE_DB));
        config_statuscache_db =
            cyrusdb_fromname(config_getstring(IMAPOPT_STATUSCACHE_DB));
        config_userdeny_db =
            cyrusdb_fromname(config_getstring(IMAPOPT_USERDENY_DB));

        /* configure libcyrus as needed */
        libcyrus_config_setstring(CYRUSOPT_CONFIG_DIR, config_dir);
        libcyrus_config_setswitch(CYRUSOPT_AUTH_UNIX_GROUP_ENABLE,
                                  config_getswitch(IMAPOPT_UNIX_GROUP_ENABLE));
        libcyrus_config_setswitch(CYRUSOPT_USERNAME_TOLOWER,
                                  config_getswitch(IMAPOPT_USERNAME_TOLOWER));
        libcyrus_config_setswitch(CYRUSOPT_SKIPLIST_UNSAFE,
                                  config_getswitch(IMAPOPT_SKIPLIST_UNSAFE));
        libcyrus_config_setstring(CYRUSOPT_TEMP_PATH,
                                  config_getstring(IMAPOPT_TEMP_PATH));
        libcyrus_config_setint(CYRUSOPT_PTS_CACHE_TIMEOUT,
                               config_getint(IMAPOPT_PTSCACHE_TIMEOUT));
        libcyrus_config_setswitch(CYRUSOPT_FULLDIRHASH,
                                  config_getswitch(IMAPOPT_FULLDIRHASH));
        libcyrus_config_setstring(CYRUSOPT_PTSCACHE_DB,
                                  config_getstring(IMAPOPT_PTSCACHE_DB));
        libcyrus_config_setstring(CYRUSOPT_PTSCACHE_DB_PATH,
                                  config_getstring(IMAPOPT_PTSCACHE_DB_PATH));
        libcyrus_config_setstring(CYRUSOPT_PTLOADER_SOCK,
                                  config_getstring(IMAPOPT_PTLOADER_SOCK));
        libcyrus_config_setswitch(CYRUSOPT_VIRTDOMAINS,
                                  config_getenum(IMAPOPT_VIRTDOMAINS));
        libcyrus_config_setint(CYRUSOPT_BERKELEY_CACHESIZE,
                               config_getint(IMAPOPT_BERKELEY_CACHESIZE));
        libcyrus_config_setstring(CYRUSOPT_AUTH_MECH,
                                  config_getstring(IMAPOPT_AUTH_MECH));
        libcyrus_config_setint(CYRUSOPT_BERKELEY_LOCKS_MAX,
                               config_getint(IMAPOPT_BERKELEY_LOCKS_MAX));
        libcyrus_config_setint(CYRUSOPT_BERKELEY_TXNS_MAX,
                               config_getint(IMAPOPT_BERKELEY_TXNS_MAX));
        libcyrus_config_setstring(CYRUSOPT_DELETERIGHT,
                                  config_getstring(IMAPOPT_DELETERIGHT));
        libcyrus_config_setstring(CYRUSOPT_SQL_DATABASE,
                                  config_getstring(IMAPOPT_SQL_DATABASE));
        libcyrus_config_setstring(CYRUSOPT_SQL_ENGINE,
                                  config_getstring(IMAPOPT_SQL_ENGINE));
        libcyrus_config_setstring(CYRUSOPT_SQL_HOSTNAMES,
                                  config_getstring(IMAPOPT_SQL_HOSTNAMES));
        libcyrus_config_setstring(CYRUSOPT_SQL_USER,
                                  config_getstring(IMAPOPT_SQL_USER));
        libcyrus_config_setstring(CYRUSOPT_SQL_PASSWD,
                                  config_getstring(IMAPOPT_SQL_PASSWD));
        libcyrus_config_setswitch(CYRUSOPT_SQL_USESSL,
                                  config_getswitch(IMAPOPT_SQL_USESSL));

        /* Not until all configuration parameters are set! */
        libcyrus_init();
    }

    return 0;
}
Пример #11
0
static void send_lmtp_error(struct protstream *pout, int r)
{
    switch (r) {
    case 0:
	prot_printf(pout, "250 2.1.5 Ok SESSIONID=<%s>\r\n", session_id());
	break;

    case IMAP_IOERROR:
	prot_printf(pout, "451 4.3.0 System I/O error\r\n");
	break;

    case IMAP_SERVER_UNAVAILABLE:
    case MUPDATE_NOCONN:
    case MUPDATE_NOAUTH:
    case MUPDATE_TIMEOUT:
    case MUPDATE_PROTOCOL_ERROR:
	prot_printf(pout, "451 4.4.3 Remote server unavailable\r\n");
	break;

    case IMAP_NOSPACE:
	prot_printf(pout, "451 4.3.1 cannot create file: out of space\r\n");
	break;

    case IMAP_AGAIN:
	prot_printf(pout, "451 4.3.0 transient system error\r\n");
	break;

    case IMAP_PERMISSION_DENIED:
	if (LMTP_LONG_ERROR_MSGS) {
	    prot_printf(pout, 
"550-You do not have permission to post a message to this mailbox.\r\n"
"550-Please contact the owner of this mailbox in order to submit\r\n"
"550-your message, or %s if you believe you\r\n"
"550-received this message in error.\r\n"
"550 5.7.1 Permission denied\r\n", 
			config_getstring(IMAPOPT_POSTMASTER));
	} else {
	    prot_printf(pout, "550 5.7.1 Permission denied\r\n");
	}
	break;

    case IMAP_QUOTA_EXCEEDED:
	if(config_getswitch(IMAPOPT_LMTP_OVER_QUOTA_PERM_FAILURE)) {
	    /* Not Default - Perm Failure */
	    prot_printf(pout, "552 5.2.2 Over quota SESSIONID=<%s>\r\n", session_id());
	} else {
	    /* Default - Temp Failure */
	    prot_printf(pout, "452 4.2.2 Over quota SESSIONID=<%s>\r\n", session_id());
	}
	break;

    case IMAP_MAILBOX_BADFORMAT:
    case IMAP_MAILBOX_NOTSUPPORTED:
	prot_printf(pout, "451 4.2.0 Mailbox has an invalid format\r\n");
	break;

    case IMAP_MAILBOX_MOVED:
	prot_printf(pout, "451 4.2.1 Mailbox Moved\r\n");
	break;

    case IMAP_MESSAGE_CONTAINSNULL:
	prot_printf(pout, "554 5.6.0 Message contains NUL characters\r\n");
	break;

    case IMAP_MESSAGE_CONTAINSNL:
	prot_printf(pout, "554 5.6.0 Message contains bare newlines\r\n");
	break;

    case IMAP_MESSAGE_CONTAINS8BIT:
	prot_printf(pout, "554 5.6.0 Message contains non-ASCII characters in headers\r\n");
	break;

    case IMAP_MESSAGE_BADHEADER:
	prot_printf(pout, "554 5.6.0 Message contains invalid header\r\n");
	break;

    case IMAP_MESSAGE_NOBLANKLINE:
	prot_printf(pout, 
		    "554 5.6.0 Message has no header/body separator\r\n");
	break;

    case IMAP_MAILBOX_NONEXISTENT:
	/* XXX Might have been moved to other server */
	if (LMTP_LONG_ERROR_MSGS) {
	    prot_printf(pout, 
"550-Mailbox unknown.  Either there is no mailbox associated with this\r\n"
"550-name or you do not have authorization to see it.\r\n"
"550 5.1.1 User unknown\r\n");
	} else {
	    prot_printf(pout, "550 5.1.1 User unknown\r\n");
	}
	break;

    case IMAP_PROTOCOL_BAD_PARAMETERS:
	prot_printf(pout, "501 5.5.4 Syntax error in parameters\r\n");
	break;

    case MUPDATE_BADPARAM:
    default:
	/* Some error we're not expecting. */
	prot_printf(pout, "451 4.3.0 Unexpected internal error\r\n");
	break;
    }
}
Пример #12
0
/* see if 'addr' exists. if so, fill in 'ad' appropriately.
   on success, return NULL.
   on failure, return the error. */
static int process_recipient(char *addr, struct namespace *namespace,
			     int ignorequota,
			     int (*verify_user)(const char *, const char *,
						char *, quota_t, quota_t,
						struct auth_state *),
			     message_data_t *msg)
{
    char *dest;
    char *rcpt;
    int r, sl;
    address_data_t *ret = (address_data_t *) xmalloc(sizeof(address_data_t));
    int forcedowncase = config_getswitch(IMAPOPT_LMTP_DOWNCASE_RCPT);
    int quoted, detail;

    assert(addr != NULL && msg != NULL);

    if (*addr == '<') addr++;
    dest = rcpt = addr;
    
    /* preserve the entire address */
    ret->all = xstrdup(addr);
    sl = strlen(ret->all);
    if (ret->all[sl-1] == '>')
	ret->all[sl-1] = '\0';

    /* now find just the user */
    
Пример #13
0
static int backend_login(struct backend *ret, const char *userid,
			 sasl_callback_t *cb, const char **auth_status,
			 int noauth)
{
    int r = 0;
    int ask = 1; /* should we explicitly ask for capabilities? */
    char buf[2048];
    struct protocol_t *prot = ret->prot;

    if (prot->type != TYPE_STD) return -1;

    if (prot->u.std.banner.auto_capa) {
	/* try to get the capabilities from the banner */
	r = ask_capability(ret, /*dobanner*/1, AUTO_CAPA_BANNER);
	if (r) {
	    /* found capabilities in banner -> don't ask */
	    ask = 0;
	}
    }
    else {
	do { /* read the initial greeting */
	    if (!prot_fgets(buf, sizeof(buf), ret->in)) {
		syslog(LOG_ERR,
		       "backend_login(): couldn't read initial greeting: %s",
		       ret->in->error ? ret->in->error : "(null)");
		return -1;
	    }
	} while (strncasecmp(buf, prot->u.std.banner.resp,
			     strlen(prot->u.std.banner.resp)));
	xstrncpy(ret->banner, buf, 2048);
    }

    if (ask) {
	/* get the capabilities */
	ask_capability(ret, /*dobanner*/0, AUTO_CAPA_NO);
    }

    /* now need to authenticate to backend server,
       unless we're doing LMTP/CSYNC on a UNIX socket (deliver/sync_client) */
    if (!noauth) {
	char *old_mechlist = backend_get_cap_params(ret, CAPA_AUTH);
	const char *my_status;

	if ((r = backend_authenticate(ret, userid, cb, &my_status))) {
	    syslog(LOG_ERR, "couldn't authenticate to backend server: %s",
		   sasl_errstring(r, NULL, NULL));
	    free(old_mechlist);
	    return -1;
	}
	else {
	    const void *ssf;

	    sasl_getprop(ret->saslconn, SASL_SSF, &ssf);
	    if (*((sasl_ssf_t *) ssf)) {
		/* if we have a SASL security layer, compare SASL mech lists
		   before/after AUTH to check for a MITM attack */
		char *new_mechlist;
		int auto_capa = (prot->u.std.sasl_cmd.auto_capa == AUTO_CAPA_AUTH_SSF);

		if (!strcmp(prot->service, "sieve")) {
		    /* XXX  Hack to handle ManageSieve servers.
		     * No way to tell from protocol if server will
		     * automatically send capabilities, so we treat it
		     * as optional.
		     */
		    char ch;

		    /* wait and probe for possible auto-capability response */
		    usleep(250000);
		    prot_NONBLOCK(ret->in);
		    if ((ch = prot_getc(ret->in)) != EOF) {
			prot_ungetc(ch, ret->in);
		    } else {
			auto_capa = AUTO_CAPA_AUTH_NO;
		    }
		    prot_BLOCK(ret->in);
		}

		ask_capability(ret, /*dobanner*/0, auto_capa);
		new_mechlist = backend_get_cap_params(ret, CAPA_AUTH);
		if (new_mechlist &&
		    old_mechlist &&
		    strcmp(new_mechlist, old_mechlist)) {
		    syslog(LOG_ERR, "possible MITM attack:"
			   "list of available SASL mechanisms changed");

		    if (new_mechlist) free(new_mechlist);
		    if (old_mechlist) free(old_mechlist);
		    return -1;
		}
		free(new_mechlist);
	    }
	    else if (prot->u.std.sasl_cmd.auto_capa == AUTO_CAPA_AUTH_OK) {
		/* try to get the capabilities from the AUTH success response */
		forget_capabilities(ret);
		parse_capability(ret, my_status);
		post_parse_capability(ret);
	    }

	    if (!(strcmp(prot->service, "imap") &&
		 (strcmp(prot->service, "pop3")))) {
		char rsessionid[MAX_SESSIONID_SIZE];
		parse_sessionid(my_status, rsessionid);
		syslog(LOG_NOTICE, "auditlog: proxy %s sessionid=<%s> remote=<%s>", userid, session_id(), rsessionid);
	    }
	}

	if (auth_status) *auth_status = my_status;
	free(old_mechlist);
    }

    /* start compression if requested and both client/server support it */
    if (config_getswitch(IMAPOPT_PROXY_COMPRESS) &&
	CAPA(ret, CAPA_COMPRESS) &&
	prot->u.std.compress_cmd.cmd) {
	r = do_compress(ret, &prot->u.std.compress_cmd);
	if (r) {
	    syslog(LOG_NOTICE, "couldn't enable compression on backend server: %s", error_message(r));
	    r = 0; /* not a fail-level error */
	}
    }

    return 0;
}
Пример #14
0
/* Returns TRUE if we are done */
int parser(struct protstream *sieved_out, struct protstream *sieved_in)
{
  int token = EOL;
  const char *error_msg = "Generic Error";

  struct buf mechanism_name = BUF_INITIALIZER;
  struct buf initial_challenge = BUF_INITIALIZER;
  struct buf sieve_name = BUF_INITIALIZER;
  struct buf sieve_data = BUF_INITIALIZER;
  unsigned long num;
  int ret = FALSE;

  /* get one token from the lexer */
  while(token == EOL)
      token = timlex(NULL, NULL, sieved_in);

  if (!authenticated && (token > 255) && (token!=AUTHENTICATE) &&
      (token!=LOGOUT) && (token!=CAPABILITY) &&
      (token!=NOOP) && (token!=CHECKSCRIPT) &&
      (!tls_enabled() || (token!=STARTTLS)))
  {
    error_msg = "Authenticate first";
    if (token!=EOL)
      lex_setrecovering();

    goto error;
  }

  if (verify_only && (token > 255) && (token!=CHECKSCRIPT)
    && (token!=PUTSCRIPT) && (token!=LOGOUT))
  {
    error_msg = "Script verification only";
    if (token!=EOL)
      lex_setrecovering();

    goto error;
  }

  switch (token)
  {
  case EOF:
      /* timlex() will return EOF when the remote disconnects badly */
      syslog(LOG_WARNING, "Lost connection to client -- exiting");
      prot_printf(sieved_out, "BYE \"Shutdown TCP timeout\"\r\n");
      ret = TRUE;
      goto done;
      break;

  case AUTHENTICATE:
    if (!starttls_done && config_getswitch(IMAPOPT_FORCETLSAUTH)) {
      error_msg = "AUTHENTICATE only available under a layer";
      goto error;
    }
    if (timlex(NULL, NULL, sieved_in)!=SPACE)
    {
      error_msg = "SPACE must occur after AUTHENTICATE";
      goto error;
    }

    if (timlex(&mechanism_name, NULL, sieved_in)!=STRING)
    {
      error_msg = "Did not specify mechanism name";
      goto error;
    }

    token = timlex(NULL, NULL, sieved_in);

    if (token != EOL)
    {
      /* optional client first challenge */
      if (token!=SPACE)
      {
        error_msg = "Expected SPACE";
        goto error;
      }

      if (timlex(&initial_challenge, NULL, sieved_in)!=STRING)
      {
        error_msg = "Expected string";
        goto error;
      }

      token = timlex(NULL, NULL, sieved_in);
    }

    if (token != EOL)
    {
      error_msg = "Expected EOL";
      goto error;
    }

    if (authenticated)
        prot_printf(sieved_out, "NO \"Already authenticated\"\r\n");
    else if (cmd_authenticate(sieved_out, sieved_in, mechanism_name.s,
                              &initial_challenge, &error_msg)==FALSE)
    {
        error_msg = "Authentication Error";
        goto error;
    }

#if 0 /* XXX - not implemented in sieveshell*/
    /* referral_host is non-null only once we are authenticated */
    if(referral_host)
        goto do_referral;
#endif
    break;

  case CAPABILITY:
      if (timlex(NULL, NULL, sieved_in)!=EOL)
      {
          error_msg = "Expected EOL";
          goto error;
      }

      if(referral_host)
          goto do_referral;

      capabilities(sieved_out, sieved_saslconn, starttls_done, authenticated,
                   sasl_ssf);
      break;

  case CHECKSCRIPT:
      if (timlex(NULL, NULL, sieved_in)!=SPACE)
      {
          error_msg = "SPACE must occur after CHECKSCRIPT";
          goto error;
      }

      if (timlex(&sieve_data, NULL, sieved_in)!=STRING)
      {
          error_msg = "Expected script content as second parameter";
          goto error;
      }

      if (timlex(NULL, NULL, sieved_in)!=EOL)
      {
        error_msg = "Expected EOL";
        goto error;
      }

      /* f stands for "f"aked name, it could be any valid script name */
      buf_reset(&sieve_name);
      buf_appendcstr(&sieve_name, "f");
      putscript(sieved_out, &sieve_name, &sieve_data, /* verify_only */ 1);
      break;

  case HAVESPACE:
      if (timlex(NULL, NULL, sieved_in)!=SPACE)
      {
          error_msg = "SPACE must occur after HAVESPACE";
          goto error;
      }

      if (timlex(&sieve_name, NULL, sieved_in)!=STRING)
      {
          error_msg = "Did not specify script name";
          goto error;
      }

      if (timlex(NULL, NULL, sieved_in)!=SPACE)
      {
          error_msg = "Expected SPACE after SCRIPTNAME";
          goto error;
      }

      if (timlex(NULL, &num, sieved_in)!=NUMBER)
      {
          error_msg = "Expected Number";
          goto error;
      }

      if (timlex(NULL, NULL, sieved_in)!=EOL)
      {
          error_msg = "Expected EOL";
          goto error;
      }

      if(referral_host)
          goto do_referral;

      cmd_havespace(sieved_out, &sieve_name, num);

      break;

  case LOGOUT:
      token = timlex(NULL, NULL, sieved_in);

      /* timlex() will return LOGOUT when the remote disconnects badly */
      if (token!=EOL && token!=EOF && token!=LOGOUT)
      {
          error_msg = "Garbage after logout command";
          goto error;
      }

      /* no referral for logout */

      cmd_logout(sieved_out, sieved_in);

      ret = TRUE;
      goto done;
      break;

  case GETSCRIPT:
    if (timlex(NULL, NULL, sieved_in)!=SPACE)
    {
      error_msg = "SPACE must occur after GETSCRIPT";
      goto error;
    }

    if (timlex(&sieve_name, NULL, sieved_in)!=STRING)
    {
      error_msg = "Did not specify script name";
      goto error;
    }

    if (timlex(NULL, NULL, sieved_in)!=EOL)
    {
      error_msg = "Expected EOL";
      goto error;
    }

    if(referral_host)
        goto do_referral;

    getscript(sieved_out, &sieve_name);

    break;


  case PUTSCRIPT:
    if (timlex(NULL, NULL, sieved_in)!=SPACE)
    {
      error_msg = "SPACE must occur after PUTSCRIPT";
      goto error;
    }

    if (timlex(&sieve_name, NULL, sieved_in)!=STRING)
    {
      error_msg = "Did not specify script name";
      goto error;
    }

    if (timlex(NULL, NULL, sieved_in)!=SPACE)
    {
      error_msg = "Expected SPACE";
      goto error;
    }

    if (timlex(&sieve_data, NULL, sieved_in)!=STRING)
    {
      error_msg = "Did not specify legal script data length";
      goto error;
    }

    if (timlex(NULL, NULL, sieved_in)!=EOL)
    {
      error_msg = "Expected EOL";
      goto error;
    }

    if(referral_host)
        goto do_referral;

    putscript(sieved_out, &sieve_name, &sieve_data, verify_only);

    break;

  case SETACTIVE:
    if (timlex(NULL, NULL, sieved_in)!=SPACE)
    {
      error_msg = "SPACE must occur after SETACTIVE";
      goto error;
    }

    if (timlex(&sieve_name, NULL, sieved_in)!=STRING)
    {
      error_msg = "Did not specify script name";
      goto error;
    }

    if (timlex(NULL, NULL, sieved_in)!=EOL)
    {
      error_msg = "Expected EOL";
      goto error;
    }

    if(referral_host)
        goto do_referral;

    setactive(sieved_out, &sieve_name);

    break;

  case DELETESCRIPT:
    if (timlex(NULL, NULL, sieved_in)!=SPACE)
    {
      error_msg = "SPACE must occur after DELETESCRIPT";
      goto error;
    }

    if (timlex(&sieve_name, NULL, sieved_in)!=STRING)
    {
      error_msg = "Did not specify script name";
      goto error;
    }

    if (timlex(NULL, NULL, sieved_in)!=EOL)
    {
      error_msg = "Expected EOL";
      goto error;
    }

    if(referral_host)
        goto do_referral;

    deletescript(sieved_out, &sieve_name);

    break;

  case LISTSCRIPTS:

    if (timlex(NULL, NULL, sieved_in)!=EOL)
    {
      error_msg = "Expected EOL";
      goto error;
    }

    if(referral_host)
        goto do_referral;

    listscripts(sieved_out);

    break;

  case STARTTLS:

    if (timlex(NULL, NULL, sieved_in)!=EOL)
    {
      error_msg = "Expected EOL";
      goto error;
    }

    /* XXX  discard any input pipelined after STARTTLS */
    prot_flush(sieved_in);

    if(referral_host)
        goto do_referral;

    cmd_starttls(sieved_out, sieved_in);

    break;

  case NOOP:

    token = timlex(NULL, NULL, sieved_in);
    if (token != EOL)
    {
      /* optional string parameter */
      if (token!=SPACE)
      {
        error_msg = "Expected SPACE";
        goto error;
      }

      if (timlex(&sieve_name, NULL, sieved_in)!=STRING)
      {
        error_msg = "Expected string";
        goto error;
      }

      token = timlex(NULL, NULL, sieved_in);
    }

    if (token != EOL)
    {
      error_msg = "Expected EOL";
      goto error;
    }

    if (sieve_name.len) {
      prot_printf(sieved_out, "OK (TAG ");
      prot_printliteral(sieved_out, sieve_name.s, sieve_name.len);
      prot_printf(sieved_out, ") \"Done\"\r\n");
    } else
      prot_printf(sieved_out, "OK \"Done\"\r\n");
    break;

  case UNAUTHENTICATE:
      if (timlex(NULL, NULL, sieved_in)!=EOL)
      {
          error_msg = "Expected EOL";
          goto error;
      }
      cmd_unauthenticate(sieved_out, sieved_in);
      break;

  default:
    error_msg="Expected a command. Got something else.";
    goto error;
    break;

  }

 done:
  /* free memory */
  buf_free(&mechanism_name);
  buf_free(&initial_challenge);
  buf_free(&sieve_name);
  buf_free(&sieve_data);

  prot_flush(sieved_out);

  return ret;

 error:

  /* free memory */
  buf_free(&mechanism_name);
  buf_free(&initial_challenge);
  buf_free(&sieve_name);
  buf_free(&sieve_data);

  prot_printf(sieved_out, "NO \"%s\"\r\n",error_msg);
  prot_flush(sieved_out);

  return FALSE;

 do_referral:
  {
      char buf[4096];
      char *c;

      /* Truncate the hostname if necessary */
      strlcpy(buf, referral_host, sizeof(buf));
      c = strchr(buf, '!');
      if(c) *c = '\0';

      prot_printf(sieved_out, "BYE (REFERRAL \"sieve://%s\") \"Try Remote.\"\r\n",
                  buf);
      ret = TRUE;
      goto done;
  }

}
Пример #15
0
/* Called before a cyrus application starts (but after command line parameters
 * are read) */
EXPORTED int cyrus_init(const char *alt_config, const char *ident, unsigned flags, int config_need_data)
{
    char *p;
    const char *val;
    const char *prefix;
    int umaskval = 0;
    int syslog_opts = LOG_PID;
    const char *facility;

    if(cyrus_init_run != NOT_RUNNING) {
        fatal("cyrus_init called twice!", EC_CONFIG);
    } else {
        cyrus_init_run = RUNNING;
    }

    cyrus_init_nodb = (flags & CYRUSINIT_NODB);
#ifdef LOG_PERROR
    if ((flags & CYRUSINIT_PERROR))
        syslog_opts |= LOG_PERROR;
#endif

    initialize_imap_error_table();
    initialize_mupd_error_table();

    if(!ident)
        fatal("service name was not specified to cyrus_init", EC_CONFIG);

    config_ident = ident;

    /* xxx we lose here since we can't have the prefix until we load the
     * config file */
    openlog(config_ident, syslog_opts, SYSLOG_FACILITY);

    /* Load configuration file.  This will set config_dir when it finds it */
    config_read(alt_config, config_need_data);

    prefix = config_getstring(IMAPOPT_SYSLOG_PREFIX);
    facility = config_getstring(IMAPOPT_SYSLOG_FACILITY);

    /* Reopen the log with the new prefix, if needed  */
    if (prefix || facility) {
        char *ident_buf;
        int facnum = facility ? get_facility(facility) : SYSLOG_FACILITY;

        if (prefix)
            ident_buf = strconcat(prefix, "/", ident, (char *)NULL);
        else
            ident_buf = xstrdup(ident);

        closelog();
        openlog(ident_buf, syslog_opts, facnum);

        /* don't free the openlog() string! */
    }

    /* allow debug logging */
    if (!config_debug)
        setlogmask(~LOG_MASK(LOG_DEBUG));

    /* Look up default partition */
    config_defpartition = config_getstring(IMAPOPT_DEFAULTPARTITION);
    for (p = (char *)config_defpartition; p && *p; p++) {
        if (!Uisalnum(*p))
          fatal("defaultpartition option contains non-alphanumeric character",
                EC_CONFIG);
        if (Uisupper(*p)) *p = tolower((unsigned char) *p);
    }

    /* Look up umask */
    val = config_getstring(IMAPOPT_UMASK);
    while (*val) {
        if (*val >= '0' && *val <= '7') umaskval = umaskval*8 + *val - '0';
        val++;
    }
    umask(umaskval);

    config_fulldirhash = config_getswitch(IMAPOPT_FULLDIRHASH);

    /* look up and canonify the implicit rights of mailbox owners */
    cyrus_acl_strtomask(config_getstring(IMAPOPT_IMPLICIT_OWNER_RIGHTS),
                        &config_implicitrights);
    /* XXX and if strtomask fails? */

    config_metapartition_files = config_getbitfield(IMAPOPT_METAPARTITION_FILES);

    val = config_getstring(IMAPOPT_SUPPRESS_CAPABILITIES);
    if (val)
        suppressed_capabilities = strarray_split(val, NULL, 0);
    if (config_getswitch(IMAPOPT_SEARCH_SKIPDIACRIT))
        charset_flags |= CHARSET_SKIPDIACRIT;

    switch (config_getenum(IMAPOPT_SEARCH_WHITESPACE)) {
        case IMAP_ENUM_SEARCH_WHITESPACE_MERGE:
            charset_flags |= CHARSET_MERGESPACE;
            break;
        case IMAP_ENUM_SEARCH_WHITESPACE_SKIP:
            charset_flags |= CHARSET_SKIPSPACE;
            break;
        default:
            break;
    }

    if (config_getswitch(IMAPOPT_SEARCH_SKIPHTML))
        charset_flags |= CHARSET_SKIPHTML;

    if (config_getswitch(IMAPOPT_RFC2047_UTF8))
        charset_flags |= CHARSET_MIME_UTF8;

    /* Set snippet conversion flags. */
    charset_snippet_flags = CHARSET_SNIPPET;
    if (config_getenum(IMAPOPT_SEARCH_ENGINE) != IMAP_ENUM_SEARCH_ENGINE_XAPIAN) {
        /* All search engines other than Xapian require escaped HTML */
        charset_snippet_flags |= CHARSET_ESCAPEHTML;
    }

    if (!cyrus_init_nodb) {
        /* lookup the database backends */
        config_mboxlist_db = config_getstring(IMAPOPT_MBOXLIST_DB);
        config_quota_db = config_getstring(IMAPOPT_QUOTA_DB);
        config_subscription_db = config_getstring(IMAPOPT_SUBSCRIPTION_DB);
        config_annotation_db = config_getstring(IMAPOPT_ANNOTATION_DB);
        config_seenstate_db = config_getstring(IMAPOPT_SEENSTATE_DB);
        config_mboxkey_db = config_getstring(IMAPOPT_MBOXKEY_DB);
        config_duplicate_db = config_getstring(IMAPOPT_DUPLICATE_DB);
        config_tls_sessions_db = config_getstring(IMAPOPT_TLS_SESSIONS_DB);
        config_ptscache_db = config_getstring(IMAPOPT_PTSCACHE_DB);
        config_statuscache_db = config_getstring(IMAPOPT_STATUSCACHE_DB);
        config_userdeny_db = config_getstring(IMAPOPT_USERDENY_DB);
        config_zoneinfo_db = config_getstring(IMAPOPT_ZONEINFO_DB);
        config_conversations_db = config_getstring(IMAPOPT_CONVERSATIONS_DB);
        config_backup_db = config_getstring(IMAPOPT_BACKUP_DB);

        /* configure libcyrus as needed */
        libcyrus_config_setstring(CYRUSOPT_CONFIG_DIR, config_dir);
        libcyrus_config_setswitch(CYRUSOPT_AUTH_UNIX_GROUP_ENABLE,
                                  config_getswitch(IMAPOPT_UNIX_GROUP_ENABLE));
        libcyrus_config_setswitch(CYRUSOPT_USERNAME_TOLOWER,
                                  config_getswitch(IMAPOPT_USERNAME_TOLOWER));
        libcyrus_config_setswitch(CYRUSOPT_SKIPLIST_UNSAFE,
                                  config_getswitch(IMAPOPT_SKIPLIST_UNSAFE));
        libcyrus_config_setstring(CYRUSOPT_TEMP_PATH,
                                  config_getstring(IMAPOPT_TEMP_PATH));
        libcyrus_config_setint(CYRUSOPT_PTS_CACHE_TIMEOUT,
                               config_getint(IMAPOPT_PTSCACHE_TIMEOUT));
        libcyrus_config_setswitch(CYRUSOPT_FULLDIRHASH,
                                  config_getswitch(IMAPOPT_FULLDIRHASH));
        libcyrus_config_setstring(CYRUSOPT_PTSCACHE_DB,
                                  config_getstring(IMAPOPT_PTSCACHE_DB));
        libcyrus_config_setstring(CYRUSOPT_PTSCACHE_DB_PATH,
                                  config_getstring(IMAPOPT_PTSCACHE_DB_PATH));
        libcyrus_config_setstring(CYRUSOPT_PTLOADER_SOCK,
                                  config_getstring(IMAPOPT_PTLOADER_SOCK));
        libcyrus_config_setswitch(CYRUSOPT_VIRTDOMAINS,
                                  config_getenum(IMAPOPT_VIRTDOMAINS));
        libcyrus_config_setstring(CYRUSOPT_AUTH_MECH,
                                  config_getstring(IMAPOPT_AUTH_MECH));
        libcyrus_config_setstring(CYRUSOPT_DELETERIGHT,
                                  config_getstring(IMAPOPT_DELETERIGHT));
        libcyrus_config_setstring(CYRUSOPT_SQL_DATABASE,
                                  config_getstring(IMAPOPT_SQL_DATABASE));
        libcyrus_config_setstring(CYRUSOPT_SQL_ENGINE,
                                  config_getstring(IMAPOPT_SQL_ENGINE));
        libcyrus_config_setstring(CYRUSOPT_SQL_HOSTNAMES,
                                  config_getstring(IMAPOPT_SQL_HOSTNAMES));
        libcyrus_config_setstring(CYRUSOPT_SQL_USER,
                                  config_getstring(IMAPOPT_SQL_USER));
        libcyrus_config_setstring(CYRUSOPT_SQL_PASSWD,
                                  config_getstring(IMAPOPT_SQL_PASSWD));
        libcyrus_config_setswitch(CYRUSOPT_SQL_USESSL,
                                  config_getswitch(IMAPOPT_SQL_USESSL));
        libcyrus_config_setswitch(CYRUSOPT_SKIPLIST_ALWAYS_CHECKPOINT,
                                  config_getswitch(IMAPOPT_SKIPLIST_ALWAYS_CHECKPOINT));

        /* Not until all configuration parameters are set! */
        libcyrus_init();
    }

    return 0;
}
Пример #16
0
/*
 * Performs a STATUS command - note: state MAY be NULL here.
 */
int status_lookup(const char *mboxname, const char *userid,
		  unsigned statusitems, struct statusdata *sdata)
{
    struct mailbox *mailbox = NULL;
    unsigned numrecent = 0;
    unsigned numunseen = 0;
    unsigned c_statusitems;
    int r;

    /* Check status cache if possible */
    if (config_getswitch(IMAPOPT_STATUSCACHE)) {
	/* Do actual lookup of cache item. */
	r = statuscache_lookup(mboxname, userid, statusitems, sdata);

	/* Seen/recent status uses "push" invalidation events from
	 * seen_db.c.   This avoids needing to open cyrus.header to get
	 * the mailbox uniqueid to open the seen db and get the
	 * unseen_mtime and recentuid.
	 */

	if (!r) {
	    syslog(LOG_DEBUG, "statuscache, '%s', '%s', '0x%02x', 'yes'",
		   mboxname, userid, statusitems);
	    return 0;
	}

	syslog(LOG_DEBUG, "statuscache, '%s', '%s', '0x%02x', 'no'",
	       mboxname, userid, statusitems);
    }

    /* Missing or invalid cache entry */
    r = mailbox_open_irl(mboxname, &mailbox);
    if (r) return r;

    /* We always have message count, uidnext,
       uidvalidity, and highestmodseq for cache */
     c_statusitems = STATUS_MESSAGES | STATUS_UIDNEXT |
		     STATUS_UIDVALIDITY | STATUS_HIGHESTMODSEQ;

    if (!mailbox->i.exists) {
	/* no messages, so these two must also be zero */
	c_statusitems |= STATUS_RECENT | STATUS_UNSEEN;
    }
    else if (statusitems & (STATUS_RECENT | STATUS_UNSEEN)) {
	/* Read \Seen state */
	struct seqset *seq = NULL;
	uint32_t recno;
	struct index_record record;
	int internalseen = mailbox_internal_seen(mailbox, userid);
	unsigned recentuid;

	if (internalseen) {
	    recentuid = mailbox->i.recentuid;
	} else {
	    struct seen *seendb = NULL;
	    struct seendata sd = SEENDATA_INITIALIZER;

	    r = seen_open(userid, SEEN_CREATE, &seendb);
	    if (!r) r = seen_read(seendb, mailbox->uniqueid, &sd);
	    seen_close(&seendb);
	    if (r) goto done;

	    recentuid = sd.lastuid;
	    seq = seqset_parse(sd.seenuids, NULL, recentuid);
	    seen_freedata(&sd);
	}

	for (recno = 1; recno <= mailbox->i.num_records; recno++) {
	    if (mailbox_read_index_record(mailbox, recno, &record))
		continue;
	    if (record.system_flags & FLAG_EXPUNGED)
		continue;
	    if (record.uid > recentuid)
		numrecent++;
	    if (internalseen) {
		if (!(record.system_flags & FLAG_SEEN))
		    numunseen++;
	    }
	    else {
		if (!seqset_ismember(seq, record.uid))
		    numunseen++;
	    }
	}

	/* we've calculated the correct values for both */
	c_statusitems |= STATUS_RECENT | STATUS_UNSEEN;
    }

    statuscache_fill(sdata, userid, mailbox, c_statusitems,
		     numrecent, numunseen);

    /* cache the new value while unlocking */
    mailbox_unlock_index(mailbox, sdata);

  done:
    mailbox_close(&mailbox);
    return r;
}
Пример #17
0
static void replica_connect(const char *channel)
{
    int wait;
    struct protoent *proto;
    sasl_callback_t *cb;
    int timeout;
    const char *port, *auth_status = NULL;

    cb = mysasl_callbacks(NULL,
                          get_config(channel, "sync_authname"),
                          get_config(channel, "sync_realm"),
                          get_config(channel, "sync_password"));

    /* get the right port */
    port = get_config(channel, "sync_port");
    if (port) {
        imap_csync_protocol.service = port;
        csync_protocol.service = port;
    }

    for (wait = 15;; wait *= 2) {
        sync_backend = backend_connect(sync_backend, servername,
                                       &imap_csync_protocol, "", cb, &auth_status,
                                       (verbose > 1 ? fileno(stderr) : -1));

        if (sync_backend) {
            if (sync_backend->capability & CAPA_REPLICATION) {
                /* attach our IMAP tag buffer to our protstreams as userdata */
                sync_backend->in->userdata = sync_backend->out->userdata = &tagbuf;
                break;
            }
            else {
                backend_disconnect(sync_backend);
                sync_backend = NULL;
            }
        }

        sync_backend = backend_connect(sync_backend, servername,
                                       &csync_protocol, "", cb, NULL,
                                       (verbose > 1 ? fileno(stderr) : -1));

        if (sync_backend || auth_status || connect_once || wait > 1000) break;

        fprintf(stderr,
                "Can not connect to server '%s', retrying in %d seconds\n",
                servername, wait);
        sleep(wait);
    }

    free_callbacks(cb);
    cb = NULL;

    if (!sync_backend) {
        fprintf(stderr, "Can not connect to server '%s'\n",
                servername);
        syslog(LOG_ERR, "Can not connect to server '%s'", servername);
        _exit(1);
    }

    /* Disable Nagle's Algorithm => increase throughput
     *
     * http://en.wikipedia.org/wiki/Nagle's_algorithm
     */
    if (servername[0] != '/') {
        if (sync_backend->sock >= 0 && (proto = getprotobyname("tcp")) != NULL) {
            int on = 1;

            if (setsockopt(sync_backend->sock, proto->p_proto, TCP_NODELAY,
                           (void *) &on, sizeof(on)) != 0) {
                syslog(LOG_ERR, "unable to setsocketopt(TCP_NODELAY): %m");
            }

            /* turn on TCP keepalive if set */
            if (config_getswitch(IMAPOPT_TCP_KEEPALIVE)) {
                int r;
                int optval = 1;
                socklen_t optlen = sizeof(optval);
                struct protoent *proto = getprotobyname("TCP");

                r = setsockopt(sync_backend->sock, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen);
                if (r < 0) {
                    syslog(LOG_ERR, "unable to setsocketopt(SO_KEEPALIVE): %m");
                }
#ifdef TCP_KEEPCNT
                optval = config_getint(IMAPOPT_TCP_KEEPALIVE_CNT);
                if (optval) {
                    r = setsockopt(sync_backend->sock, proto->p_proto, TCP_KEEPCNT, &optval, optlen);
                    if (r < 0) {
                        syslog(LOG_ERR, "unable to setsocketopt(TCP_KEEPCNT): %m");
                    }
                }
#endif
#ifdef TCP_KEEPIDLE
                optval = config_getint(IMAPOPT_TCP_KEEPALIVE_IDLE);
                if (optval) {
                    r = setsockopt(sync_backend->sock, proto->p_proto, TCP_KEEPIDLE, &optval, optlen);
                    if (r < 0) {
                        syslog(LOG_ERR, "unable to setsocketopt(TCP_KEEPIDLE): %m");
                    }
                }
#endif
#ifdef TCP_KEEPINTVL
                optval = config_getint(IMAPOPT_TCP_KEEPALIVE_INTVL);
                if (optval) {
                    r = setsockopt(sync_backend->sock, proto->p_proto, TCP_KEEPINTVL, &optval, optlen);
                    if (r < 0) {
                        syslog(LOG_ERR, "unable to setsocketopt(TCP_KEEPINTVL): %m");
                    }
                }
#endif
            }
        } else {
            syslog(LOG_ERR, "unable to getprotobyname(\"tcp\"): %m");
        }
    }

#ifdef HAVE_ZLIB
    /* Does the backend support compression? */
    if (CAPA(sync_backend, CAPA_COMPRESS)) {
        prot_printf(sync_backend->out, "%s\r\n",
                    sync_backend->prot->u.std.compress_cmd.cmd);
        prot_flush(sync_backend->out);

        if (sync_parse_response("COMPRESS", sync_backend->in, NULL)) {
            if (do_compress) fatal("Failed to enable compression, aborting", EC_SOFTWARE);
            syslog(LOG_NOTICE, "Failed to enable compression, continuing uncompressed");
        }
        else {
            prot_setcompress(sync_backend->in);
            prot_setcompress(sync_backend->out);
        }
    }
    else if (do_compress) fatal("Backend does not support compression, aborting", EC_SOFTWARE);
#endif

    /* links to sockets */
    sync_in = sync_backend->in;
    sync_out = sync_backend->out;

    if (verbose > 1) {
        prot_setlog(sync_in, fileno(stderr));
        prot_setlog(sync_out, fileno(stderr));
    }

    /* Set inactivity timer */
    timeout = config_getint(IMAPOPT_SYNC_TIMEOUT);
    if (timeout < 3) timeout = 3;
    prot_settimeout(sync_in, timeout);

    /* Force use of LITERAL+ so we don't need two way communications */
    prot_setisclient(sync_in, 1);
    prot_setisclient(sync_out, 1);
}
Пример #18
0
/* return malloc'd string containing the address */
static char *parseaddr(char *s)
{
    char *p, *ret;
    int len;
    int lmtp_strict_rfc2821 = config_getswitch(IMAPOPT_LMTP_STRICT_RFC2821);

    p = s;

    if (*p++ != '<') return 0;

    /* at-domain-list */
    while (*p == '@') {
	p++;
	if (*p == '[') {
	    p++;
	    while (Uisdigit(*p) || *p == '.') p++;
	    if (*p++ != ']') return 0;
	}
	else {
	    while (Uisalnum(*p) || *p == '.' || *p == '-') p++;
	}
	if (*p == ',' && p[1] == '@') p++;
	else if (*p == ':' && p[1] != '@') p++;
	else return 0;
    }
    
    /* local-part */
    if (*p == '\"') {
	p++;
	while (*p && *p != '\"') {
	    if (*p == '\\') {
		if (!*++p) return 0;
	    }
	    p++;
	}
	if (!*p++) return 0;
    }
    else {
	while (*p && *p != '@' && *p != '>') {
	    if (*p == '\\') {
		if (!*++p) return 0;
	    }
	    else {
		if (*p & 128 && !lmtp_strict_rfc2821) {
		    /* this prevents us from becoming a backscatter
		       source if our MTA allows 8bit in local-part
		       of adresses. */
		    *p = 'X';
		}
		if (*p <= ' ' || (*p & 128) ||
		    strchr("<>()[]\\,;:\"", *p)) return 0;
	    }
	    p++;
	}
    }

    /* @domain */
    if (*p == '@') {
	p++;
	if (*p == '[') {
	    p++;
	    while (Uisdigit(*p) || *p == '.') p++;
	    if (*p++ != ']') return 0;
	}
	else {
	    while (Uisalnum(*p) || *p == '.' || *p == '-') p++;
	}
    }
    
    if (*p++ != '>') return 0;
    if (*p && *p != ' ') return 0;
    len = p - s;

    ret = xmalloc(len + 1);
    memcpy(ret, s, len);
    ret[len] = '\0';
    return ret;
}
Пример #19
0
int main(int argc,char **argv)
{
    int opt;
    int i;
    int fflag = 0;
    int r, code = 0;
    int do_report = 1;
    char *alt_config = NULL, *domain = NULL;

    if ((geteuid()) == 0 && (become_cyrus(/*is_master*/0) != 0)) {
	fatal("must run as the Cyrus user", EC_USAGE);
    }

    while ((opt = getopt(argc, argv, "C:d:fqZ")) != EOF) {
	switch (opt) {
	case 'C': /* alt config file */
	    alt_config = optarg;
	    break;

	case 'q':
	    do_report = 0;
	    break;

	case 'd':
	    domain = optarg;
	    break;

	case 'f':
	    fflag = 1;
	    break;

	/* deliberately undocumented option for testing */
	case 'Z':
	    test_sync_mode = 1;
	    break;

	default:
	    usage();
	}
    }

    /* always report if not fixing, otherwise we do nothing */
    if (!fflag)
	do_report = 1;

    cyrus_init(alt_config, "quota", 0, CONFIG_NEED_PARTITION_DATA);

    /* Set namespace -- force standard (internal) */
    if ((r = mboxname_init_namespace(&quota_namespace, 1)) != 0) {
	syslog(LOG_ERR, "%s", error_message(r));
	fatal(error_message(r), EC_CONFIG);
    }

    if (config_getswitch(IMAPOPT_IMPROVED_MBOXLIST_SORT))
	compar = bsearch_compare_mbox;
    else
	compar = strcmp;

    /*
     * Lock mailbox list to prevent mailbox creation/deletion
     * during work
     */
    mboxlist_init(0);
    mboxlist_open(NULL);

    quotadb_init(0);
    quotadb_open(NULL);

    quota_changelock();

    if (!r)
	r = buildquotalist(domain, argv+optind, argc-optind);

    if (!r && fflag)
	r = fixquotas(domain, argv+optind, argc-optind);

    quota_changelockrelease();

    if (r) code = convert_code(r);
    else if (do_report) reportquota();

    quotadb_close();
    quotadb_done();

    mboxlist_close();
    mboxlist_done();

    /* just for neatness */
    for (i = 0; i < quota_num; i++)
	free(quotaroots[i].name);
    free(quotaroots);

    cyrus_done();

    return code;
}
Пример #20
0
static int autocreate_sieve(const char *userid, const char *source_script)
{
    /* XXX - this is really ugly, but too much work to tidy up right now -- Bron */
    sieve_script_t *s = NULL;
    bytecode_info_t *bc = NULL;
    char *err = NULL;
    FILE *in_stream, *out_fp;
    int out_fd, in_fd, r, k;
    int do_compile = 0;
    const char *compiled_source_script = NULL;
    const char *sievename = get_script_name(source_script);
    const char *sieve_script_dir = NULL;
    char sieve_script_name[MAX_FILENAME];
    char sieve_bcscript_name[MAX_FILENAME];
    char sieve_default[MAX_FILENAME];
    char sieve_tmpname[MAX_FILENAME];
    char sieve_bctmpname[MAX_FILENAME];
    char sieve_bclink_name[MAX_FILENAME];
    char buf[4096];
    mode_t oldmask;
    struct stat statbuf;

    /* We don't support using the homedirectory, like timsieved */
    if (config_getswitch(IMAPOPT_SIEVEUSEHOMEDIR)) {
        syslog(LOG_WARNING,"autocreate_sieve: autocreate_sieve does not work with sieveusehomedir option in imapd.conf");
        return 1;
    }

    /* Check if sievedir is defined in imapd.conf */
    if(!config_getstring(IMAPOPT_SIEVEDIR)) {
        syslog(LOG_WARNING, "autocreate_sieve: sievedir option is not defined. Check imapd.conf");
        return 1;
    }

    /* Check if autocreate_sieve_compiledscript is defined in imapd.conf */
    if(!(compiled_source_script = config_getstring(IMAPOPT_AUTOCREATE_SIEVE_SCRIPT_COMPILED))) {
        syslog(LOG_WARNING, "autocreate_sieve: autocreate_sieve_compiledscript option is not defined. Compiling it");
        do_compile = 1;
    }

    if (!(sieve_script_dir = user_sieve_path(userid))) {
        syslog(LOG_WARNING, "autocreate_sieve: unable to determine sieve directory for user %s", userid);
        return 1;
    }

    if(snprintf(sieve_tmpname, MAX_FILENAME, "%s/%s.script.NEW",sieve_script_dir, sievename) >= MAX_FILENAME) {
        syslog(LOG_WARNING, "autocreate_sieve: Invalid sieve path %s, %s, %s", sieve_script_dir, sievename, userid);
        return 1;
    }
    if(snprintf(sieve_bctmpname, MAX_FILENAME, "%s/%s.bc.NEW",sieve_script_dir, sievename) >= MAX_FILENAME) {
        syslog(LOG_WARNING, "autocreate_sieve: Invalid sieve path %s, %s, %s", sieve_script_dir, sievename, userid);
        return 1;
    }
    if(snprintf(sieve_script_name, MAX_FILENAME, "%s/%s.script",sieve_script_dir, sievename) >= MAX_FILENAME) {
        syslog(LOG_WARNING, "autocreate_sieve: Invalid sieve path %s, %s, %s", sieve_script_dir, sievename, userid);
        return 1;
    }
    if(snprintf(sieve_bcscript_name, MAX_FILENAME, "%s/%s.bc",sieve_script_dir, sievename) >= MAX_FILENAME) {
        syslog(LOG_WARNING, "autocreate_sieve: Invalid sieve path %s, %s, %s", sieve_script_dir, sievename, userid);
        return 1;
    }
    if(snprintf(sieve_default, MAX_FILENAME, "%s/%s",sieve_script_dir,"defaultbc") >= MAX_FILENAME) {
        syslog(LOG_WARNING, "autocreate_sieve: Invalid sieve path %s, %s, %s", sieve_script_dir, sievename, userid);
        return 1;
    }
    /* XXX no directory? umm */
    if(snprintf(sieve_bclink_name, MAX_FILENAME, "%s.bc", sievename) >= MAX_FILENAME) {
        syslog(LOG_WARNING, "autocreate_sieve: Invalid sieve path %s, %s, %s", sieve_script_dir, sievename, userid);
        return 1;
    }

    /* Check if a default sieve filter alrady exists */
    if(!stat(sieve_default,&statbuf)) {
        syslog(LOG_WARNING,"autocreate_sieve: Default sieve script already exists");
        return 1;
    }

    /* Open the source script. if there is a problem with that exit */
    in_stream = fopen(source_script, "r");
    if(!in_stream) {
        syslog(LOG_WARNING,"autocreate_sieve: Unable to open sieve script %s. Check permissions",source_script);
        return 1;
    }

    /*
     * At this point we start the modifications of the filesystem
     */

    /* Create the directory where the sieve scripts will reside */
    r = cyrus_mkdir(sieve_bctmpname, 0755);
    if(r == -1) {
        /* If this fails we just leave */
        fclose(in_stream);
        return 1;
    }

    /*
     * We open the file that will be used as the bc file. If this file exists, overwrite it
     * since something bad has happened. We open the file here so that this error checking is
     * done before we try to open the rest of the files to start copying etc.
     */
    out_fd = open(sieve_bctmpname, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
    if(out_fd < 0) {
        if(errno == EEXIST) {
            syslog(LOG_WARNING,"autocreate_sieve: File %s already exists. Probaly left over. Ignoring",sieve_bctmpname);
        } else if (errno == EACCES) {
            syslog(LOG_WARNING,"autocreate_sieve: No access to create file %s. Check permissions",sieve_bctmpname);
            fclose(in_stream);
            return 1;
        } else {
            syslog(LOG_WARNING,"autocreate_sieve: Unable to create %s: %m",sieve_bctmpname);
            fclose(in_stream);
            return 1;
        }
    }

    if(!do_compile && compiled_source_script && (in_fd = open(compiled_source_script, O_RDONLY)) != -1) {
        while((r = read(in_fd, buf, sizeof(buf))) > 0) {
            if((k=write(out_fd, buf,r)) < 0) {
                syslog(LOG_WARNING, "autocreate_sieve: Error writing to file %s: %m", sieve_bctmpname);
                close(out_fd);
                close(in_fd);
                fclose(in_stream);
                unlink(sieve_bctmpname);
                return 1;
           }
        }

        if(r == 0) { /* EOF */
            xclose(out_fd);
            xclose(in_fd);
        } else if (r < 0) {
            syslog(LOG_WARNING, "autocreate_sieve: Error reading compiled script file %s: %m. Will try to compile it",
                           compiled_source_script);
            xclose(in_fd);
            do_compile = 1;
            if(lseek(out_fd, 0, SEEK_SET)) {
                syslog(LOG_WARNING, "autocreate_sieve: Major IO problem (lseek: %m). Aborting");
                xclose(out_fd);
                return 1;
            }
        }
        xclose(in_fd);
    } else {
        if(compiled_source_script)
              syslog(LOG_WARNING,"autocreate_sieve: Problem opening compiled script file: %s. Compiling it", compiled_source_script);
        do_compile = 1;
    }


    /* Because we failed to open a precompiled bc sieve script, we compile one */
    if(do_compile) {
       if(is_script_parsable(in_stream,&err, &s) == TIMSIEVE_FAIL) {
            if(err && *err) {
               syslog(LOG_WARNING,"autocreate_sieve: Error while parsing script %s.",err);
               free(err);
            } else
                syslog(LOG_WARNING,"autocreate_sieve: Error while parsing script");

            unlink(sieve_bctmpname);
            fclose(in_stream);
            close(out_fd);
            return 1;
        }

        /* generate the bytecode */
        if(sieve_generate_bytecode(&bc, s) == TIMSIEVE_FAIL) {
            syslog(LOG_WARNING,"autocreate_sieve: problem compiling sieve script");
            /* removing the copied script and cleaning up memory */
            unlink(sieve_bctmpname);
            sieve_script_free(&s);
            fclose(in_stream);
            close(out_fd);
            return 1;
        }

        if(sieve_emit_bytecode(out_fd, bc) == TIMSIEVE_FAIL) {
            syslog(LOG_WARNING,"autocreate_sieve: problem emiting sieve script");
            /* removing the copied script and cleaning up memory */
            unlink(sieve_bctmpname);
            sieve_free_bytecode(&bc);
            sieve_script_free(&s);
            fclose(in_stream);
            close(out_fd);
            return 1;
        }

        /* clean up the memory */
        sieve_free_bytecode(&bc);
        sieve_script_free(&s);
    }

    xclose(out_fd);
    rewind(in_stream);

    /* Copy the initial script */
    oldmask = umask(077);
    if((out_fp = fopen(sieve_tmpname, "w")) == NULL) {
        syslog(LOG_WARNING,"autocreate_sieve: Unable to open destination sieve script %s: %m", sieve_tmpname);
        unlink(sieve_bctmpname);
        umask(oldmask);
        fclose(in_stream);
        return 1;
    }
    umask(oldmask);

    while((r = fread(buf,sizeof(char), sizeof(buf), in_stream)) > 0) {
        if( fwrite(buf,sizeof(char), r, out_fp) != (unsigned)r) {
            syslog(LOG_WARNING,"autocreate_sieve: Problem writing to sieve script file %s: %m",sieve_tmpname);
            fclose(out_fp);
            unlink(sieve_tmpname);
            unlink(sieve_bctmpname);
            fclose(in_stream);
            return 1;
        }
    }

    if(feof(in_stream)) {
        fclose(out_fp);
        fclose(in_stream);
    } else { /* ferror */
        fclose(out_fp);
        unlink(sieve_tmpname);
        unlink(sieve_bctmpname);
        fclose(in_stream);
        return 1;
    }

    /* Renaming the necessary stuff */
    if(rename(sieve_tmpname, sieve_script_name)) {
        unlink(sieve_tmpname);
        unlink(sieve_bctmpname);
        return 1;
    }

    if(rename(sieve_bctmpname, sieve_bcscript_name)) {
        unlink(sieve_bctmpname);
        unlink(sieve_bcscript_name);
        return 1;
    }

    /* end now with the symlink */
    if(symlink(sieve_bclink_name, sieve_default)) {
        if(errno != EEXIST) {
            syslog(LOG_WARNING, "autocreate_sieve: problem making the default link (symlink: %m).");
            /* Lets delete the files */
            unlink(sieve_script_name);
            unlink(sieve_bcscript_name);
        }
    }

    /*
     * If everything has succeeded AND we have compiled the script AND we have requested
     * to generate the global script so that it is not compiled each time then we create it.
     */
    if(do_compile &&
          config_getswitch(IMAPOPT_AUTOCREATE_SIEVE_SCRIPT_COMPILE)) {

        if(!compiled_source_script) {
            syslog(LOG_WARNING, "autocreate_sieve: To save a compiled sieve script, autocreate_sieve_compiledscript must have been defined in imapd.conf");
            return 0;
        }

        if(snprintf(sieve_tmpname, MAX_FILENAME, "%s.NEW", compiled_source_script) >= MAX_FILENAME)
            return 0;

        /*
         * Copy everything from the newly created bc sieve sieve script.
         */
        if((in_fd = open(sieve_bcscript_name, O_RDONLY))<0) {
            return 0;
        }

        if((out_fd = open(sieve_tmpname, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0) {
            if(errno == EEXIST) {
               /* Someone is already doing this so just bail out. */
               syslog(LOG_WARNING, "autocreate_sieve: %s already exists. Some other instance processing it, or it is left over", sieve_tmpname);
                close(in_fd);
                return 0;
            } else if (errno == EACCES) {
                syslog(LOG_WARNING,"autocreate_sieve: No access to create file %s. Check permissions",sieve_tmpname);
                close(in_fd);
                return 0;
            } else {
                syslog(LOG_WARNING,"autocreate_sieve: Unable to create %s: %m",sieve_tmpname);
                close(in_fd);
                return 0;
            }
        }

        while((r = read(in_fd, buf, sizeof(buf))) > 0) {
            if((k = write(out_fd,buf,r)) < 0) {
                syslog(LOG_WARNING, "autocreate_sieve: Error writing to file: %s: %m", sieve_tmpname);
                close(out_fd);
                close(in_fd);
                unlink(sieve_tmpname);
                return 0;
           }
        }

        if(r == 0 ) { /*EOF */
            xclose(out_fd);
            xclose(in_fd);
        } else if (r < 0) {
                syslog(LOG_WARNING, "autocreate_sieve: Error reading file: %s: %m", sieve_bcscript_name);
                xclose(out_fd);
                xclose(in_fd);
                unlink(sieve_tmpname);
                return 0;
        }

        /* Rename the temporary created sieve script to its final name. */
        if(rename(sieve_tmpname, compiled_source_script)) {
            if(errno != EEXIST) {
               unlink(sieve_tmpname);
               unlink(compiled_source_script);
        }
            return 0;
        }

        syslog(LOG_NOTICE, "autocreate_sieve: Compiled sieve script was successfully saved in %s", compiled_source_script);
    }

    return 0;
}