/* 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; }
/* Returns 0 on success */ static int ptload(const char *identifier, struct auth_state **state) { struct auth_state *fetched = NULL; size_t id_len; const char *data = NULL; int dsize; char fnamebuf[1024]; struct db *ptdb; int s; struct sockaddr_un srvaddr; int r, rc=0; static char response[1024]; struct iovec iov[10]; int niov, n; unsigned int start; const char *config_dir = libcyrus_config_getstring(CYRUSOPT_CONFIG_DIR); /* xxx this sucks, but it seems to be the only way to satisfy the linker */ if(the_ptscache_db == NULL) { the_ptscache_db = cyrusdb_fromname(libcyrus_config_getstring(CYRUSOPT_PTSCACHE_DB)); } if(!state || *state) { fatal("bad state pointer passed to ptload()", EC_TEMPFAIL); } strcpy(fnamebuf, config_dir); strcat(fnamebuf, PTS_DBFIL); r = (the_ptscache_db->open)(fnamebuf, CYRUSDB_CREATE, &ptdb); if (r != 0) { syslog(LOG_ERR, "DBERROR: opening %s: %s", fnamebuf, cyrusdb_strerror(ret)); *state = NULL; return -1; } id_len = strlen(identifier); if(id_len > PTS_DB_KEYSIZE) { syslog(LOG_ERR, "identifier too long in auth_newstate"); *state = NULL; return -1; } /* fetch the current record for the user */ r = the_ptscache_db->fetch(ptdb, identifier, id_len, &data, &dsize, NULL); if (r && r != CYRUSDB_NOTFOUND) { syslog(LOG_ERR, "auth_newstate: error fetching record: %s", cyrusdb_strerror(r)); rc = -1; goto done; } /* if it's expired (or nonexistant), * ask the ptloader to reload it and reread it */ fetched = (struct auth_state *) data; if(fetched) { time_t now = time(NULL); int timeout = libcyrus_config_getint(CYRUSOPT_PTS_CACHE_TIMEOUT); syslog(LOG_DEBUG, "ptload(): fetched cache record (%s)" \ "(mark %ld, current %ld, limit %ld)", identifier, fetched->mark, now, now - timeout); if (fetched->mark > (now - timeout)) { /* not expired; let's return it */ goto done; } } syslog(LOG_DEBUG, "ptload(): pinging ptloader"); s = socket(AF_UNIX, SOCK_STREAM, 0); if (s == -1) { syslog(LOG_ERR, "ptload(): unable to create socket for ptloader: %m"); rc = -1; goto done; } if (libcyrus_config_getstring(CYRUSOPT_PTLOADER_SOCK)) strcpy(fnamebuf, libcyrus_config_getstring(CYRUSOPT_PTLOADER_SOCK)); else { strcpy(fnamebuf, config_dir); strcat(fnamebuf, PTS_DBSOCKET); } memset((char *)&srvaddr, 0, sizeof(srvaddr)); srvaddr.sun_family = AF_UNIX; strcpy(srvaddr.sun_path, fnamebuf); r = nb_connect(s, (struct sockaddr *)&srvaddr, sizeof(srvaddr), PT_TIMEOUT_SEC); if (r == -1) { syslog(LOG_ERR, "ptload(): can't connect to ptloader server: %m"); close(s); rc = -1; goto done; } syslog(LOG_DEBUG, "ptload(): connected"); niov = 0; WRITEV_ADD_TO_IOVEC(iov, niov, (char *) &id_len, sizeof(id_len)); WRITEV_ADD_TO_IOVEC(iov, niov, (char *) identifier, id_len); if (timeout_select(s, TS_WRITE, PT_TIMEOUT_SEC) < 0) { syslog(LOG_ERR, "timeoutselect: writing to ptloader %m"); rc = -1; goto done; } retry_writev(s, iov, niov); syslog(LOG_DEBUG, "ptload sent data"); start = 0; while (start < sizeof(response) - 1) { if (timeout_select(s, TS_READ, PT_TIMEOUT_SEC) < 0) { syslog(LOG_ERR, "timeout_select: reading from ptloader: %m"); rc = -1; goto done; } n = read(s, response+start, sizeof(response) - 1 - start); if (n < 1) break; start += n; } close(s); syslog(LOG_DEBUG, "ptload read data back"); if (start <= 1 || strncmp(response, "OK", 2)) { if(start > 1) { syslog(LOG_ERR, "ptload(): bad response from ptloader server: %s", response); } else { syslog(LOG_ERR, "ptload(): empty response from ptloader server"); } rc = -1; goto done; } /* fetch the current record for the user */ r = the_ptscache_db->fetch(ptdb, identifier, id_len, &data, &dsize, NULL); if (r != 0 || !data) { syslog(LOG_ERR, "ptload(): error fetching record: %s" "(did ptloader add the record?)", cyrusdb_strerror(r)); data = NULL; rc = -1; goto done; } done: /* ok, we got real data, let's use it */ if (data != NULL) { fetched = (struct auth_state *) data; } if (fetched == NULL) { *state = NULL; syslog(LOG_DEBUG, "No data available at all from ptload()"); } else { /* copy it into our structure */ *state = (struct auth_state *)xmalloc(dsize); memcpy(*state, fetched, dsize); syslog(LOG_DEBUG, "ptload returning data"); } /* close and unlock the database */ (the_ptscache_db->close)(ptdb); return rc; }
EXPORTED int cyrusdb_open(const char *backend, const char *fname, int flags, struct db **ret) { const char *realname; struct db *db = xzmalloc(sizeof(struct db)); int r; if (!backend) backend = DEFAULT_BACKEND; /* not used yet, later */ db->backend = cyrusdb_fromname(backend); /* This whole thing is a fricking critical section. We don't have the API * in place for a safe rename of a locked database, so the choices are * basically: * a) convert each DB layer to support locked database renames while still * in the transaction. Best, but lots of work. * b) rename and hope... unreliable * c) global lock around this block of code. Safest and least efficient. */ /* check if it opens normally. Horray */ r = db->backend->open(fname, flags, &db->engine); if (r == CYRUSDB_NOTFOUND) goto done; /* no open flags */ if (!r) goto done; /* magic time - we need to work out if the file was created by a different * backend and convert if possible */ realname = cyrusdb_detect(fname); if (!realname) { syslog(LOG_ERR, "DBERROR: failed to detect DB type for %s (backend %s) (r was %d)", fname, backend, r); /* r is still set */ goto done; } /* different type */ if (strcmp(realname, backend)) { if (flags & CYRUSDB_CONVERT) { r = cyrusdb_convert(fname, fname, realname, backend); if (r) { syslog(LOG_ERR, "DBERROR: failed to convert %s from %s to %s, maybe someone beat us", fname, realname, backend); } else { syslog(LOG_NOTICE, "cyrusdb: converted %s from %s to %s", fname, realname, backend); } } else { syslog(LOG_NOTICE, "cyrusdb: opening %s with backend %s (requested %s)", fname, realname, backend); db->backend = cyrusdb_fromname(realname); } } r = db->backend->open(fname, flags, &db->engine); done: if (r) free(db); else *ret = db; return r; }