Esempio n. 1
0
int statuscache_lookup(const char *mboxname, const char *userid,
		       unsigned statusitems, struct statusdata *sdata)
{
    size_t keylen, datalen;
    int r = 0;
    const char *data = NULL, *dend;
    char *p, *key = statuscache_buildkey(mboxname, userid, &keylen);
    unsigned version;

    /* Don't access DB if it hasn't been opened */
    if (!statuscache_dbopen)
	return IMAP_NO_NOSUCHMSG;

    memset(sdata, 0, sizeof(struct statusdata));

    /* Check if there is an entry in the database */
    do {
	r = cyrusdb_fetch(statuscachedb, key, keylen, &data, &datalen, NULL);
    } while (r == CYRUSDB_AGAIN);

    if (r || !data || ((size_t) datalen < sizeof(unsigned))) {
	return IMAP_NO_NOSUCHMSG;
    }

    dend = data + datalen;

    version = (unsigned) strtoul(data, &p, 10);
    if (version != (unsigned) STATUSCACHE_VERSION) {
	/* Wrong version */
	return IMAP_NO_NOSUCHMSG;
    }

    if (p < dend) sdata->statusitems = strtoul(p, &p, 10);
    if (p < dend) sdata->messages = strtoul(p, &p, 10);
    if (p < dend) sdata->recent = strtoul(p, &p, 10);
    if (p < dend) sdata->uidnext = strtoul(p, &p, 10);
    if (p < dend) sdata->uidvalidity = strtoul(p, &p, 10);
    if (p < dend) sdata->unseen = strtoul(p, &p, 10);
    if (p < dend) sdata->highestmodseq = strtoull(p, &p, 10);

    /* Sanity check the data */
    if (!sdata->statusitems || !sdata->uidnext || !sdata->uidvalidity) {
	return IMAP_NO_NOSUCHMSG;
    }

    if ((sdata->statusitems & statusitems) != statusitems) {
	/* Don't have all of the requested information */
	return IMAP_NO_NOSUCHMSG;
    }

    return 0;
}
Esempio n. 2
0
/*
 * Find the mailbox 'name' 's quotaroot, and return it in 'ret'.
 * 'ret' must be at least MAX_MAILBOX_NAME.
 *
 * returns true if a quotaroot is found, 0 otherwise.
*/
EXPORTED int quota_findroot(char *ret, size_t retlen, const char *name)
{
    char *tail, *p, *mbox;

    strlcpy(ret, name, retlen);

    /* find the start of the unqualified mailbox name */
    mbox = (config_virtdomains && (p = strchr(ret, '!'))) ? p+1 : ret;
    tail = mbox + strlen(mbox);

    while (cyrusdb_fetch(qdb, ret, strlen(ret), NULL, NULL, NULL)) {
        tail = strrchr(mbox, '.');
        if (!tail) break;
        *tail = '\0';
    }
    if (tail) return 1;
    if (mbox == ret) return 0;

    /* check for a domain quota */
    *mbox = '\0';
    return (cyrusdb_fetch(qdb, ret, strlen(ret), NULL, NULL, NULL) == 0);
}
Esempio n. 3
0
static int mboxkey_readit(struct mboxkey *mboxkeydb, const char *mailbox,
			  const char **mboxkey, size_t *mboxkeylen,
			  int rw)
{
    int r;
    const char *data;
    size_t datalen;
    unsigned short version, s;

    assert(mboxkeydb && mailbox);
    if (rw || mboxkeydb->tid) {
	r = cyrusdb_fetchlock(mboxkeydb->db, mailbox, strlen(mailbox),
			  &data, &datalen, &mboxkeydb->tid);
    } else {
	r = cyrusdb_fetch(mboxkeydb->db, mailbox, strlen(mailbox),
		      &data, &datalen, NULL);
    }
    switch (r) {
    case 0:
	break;
    case CYRUSDB_AGAIN:
	syslog(LOG_DEBUG, "deadlock in mboxkey database for '%s/%s'",
	       mboxkeydb->user, mailbox);
	return IMAP_AGAIN;
	break;
    case CYRUSDB_IOERROR:
	syslog(LOG_ERR, "DBERROR: error fetching txn %s",
	       cyrusdb_strerror(r));
	return IMAP_IOERROR;
	break;
    case CYRUSDB_NOTFOUND:
	*mboxkey = NULL;
	*mboxkeylen = 0;

	return 0;
	break;
    }

    /* 'data' is <version><mboxkey> */
    memcpy(&s, data, sizeof(s));
    version = ntohs(s);
    assert(version == MBOXKEY_VERSION);
    *mboxkey = data + sizeof(s);
    *mboxkeylen = datalen - sizeof(s);

    return 0;
}
Esempio n. 4
0
static int seen_readit(struct seen *seendb, const char *uniqueid,
		       struct seendata *sd, int rw)
{
    int r;
    const char *data;
    size_t datalen;

    assert(seendb && uniqueid);
    if (rw || seendb->tid) {
	r = cyrusdb_fetchlock(seendb->db, uniqueid, strlen(uniqueid),
			  &data, &datalen, &seendb->tid);
    } else {
	r = cyrusdb_fetch(seendb->db, uniqueid, strlen(uniqueid),
		      &data, &datalen, NULL);
    }
    switch (r) {
    case 0:
	break;
    case CYRUSDB_AGAIN:
	syslog(LOG_DEBUG, "deadlock in seen database for '%s/%s'",
	       seendb->user, uniqueid);
	return IMAP_AGAIN;
	break;
    case CYRUSDB_NOTFOUND:
	memset(sd, 0, sizeof(struct seendata));
	sd->seenuids = xstrdup("");
	return 0;
	break;
    default:
	syslog(LOG_ERR, "DBERROR: error fetching txn %s",
	       cyrusdb_strerror(r));
	return IMAP_IOERROR;
	break;
    }

    parse_data(data, datalen, sd);
    if (sd->seenuids[0] && !imparse_issequence(sd->seenuids)) {
	syslog(LOG_ERR, "DBERROR: invalid sequence <%s> for %s %s - nuking",
	       sd->seenuids, seendb->user, uniqueid);
	free(sd->seenuids);
	sd->seenuids = xstrdup("");
    }

    return 0;
}
Esempio n. 5
0
/*
 * Read the quota entry 'quota'
 */
EXPORTED int quota_read(struct quota *quota, struct txn **tid, int wrlock)
{
    int r;
    size_t qrlen;
    const char *data;
    size_t datalen;

    if (!quota->root || !(qrlen = strlen(quota->root)))
        return IMAP_QUOTAROOT_NONEXISTENT;

    if (wrlock)
        r = cyrusdb_fetchlock(qdb, quota->root, qrlen, &data, &datalen, tid);
    else
        r = cyrusdb_fetch(qdb, quota->root, qrlen, &data, &datalen, tid);

    if (!datalen) /* zero byte file can cause no data to be mapped */
        return IMAP_QUOTAROOT_NONEXISTENT;

    switch (r) {
    case CYRUSDB_OK:
        if (!*data) return IMAP_QUOTAROOT_NONEXISTENT;
        r = quota_parseval(data, datalen, quota, wrlock);
        if (r) {
            syslog(LOG_ERR, "DBERROR: error fetching quota "
                            "root=<%s> value=<%s>",
                   quota->root, data);
            return r;
        }
        break;

    case CYRUSDB_AGAIN:
        return IMAP_AGAIN;

    case CYRUSDB_NOTFOUND:
        return IMAP_QUOTAROOT_NONEXISTENT;
    }

    if (r) {
        syslog(LOG_ERR, "DBERROR: error fetching quota %s: %s",
               quota->root, cyrusdb_strerror(r));
        return IMAP_IOERROR;
    }

    return 0;
}
Esempio n. 6
0
EXPORTED time_t duplicate_check(const duplicate_key_t *dkey)
{
    struct buf key = BUF_INITIALIZER;
    int r;
    const char *data = NULL;
    size_t len = 0;
    time_t mark = 0;

    if (!duplicate_dbopen) return 0;

    r = make_key(&key, dkey);
    if (r) return 0;

    do {
	r = cyrusdb_fetch(dupdb, key.s, key.len,
		      &data, &len, NULL);
    } while (r == CYRUSDB_AGAIN);

    if (!r && data) {
	assert((len == sizeof(time_t)) ||
	       (len == sizeof(time_t) + sizeof(unsigned long)));

	/* found the record */
	memcpy(&mark, data, sizeof(time_t));
    } else if (r != CYRUSDB_OK) {
	if (r != CYRUSDB_NOTFOUND) {
	    syslog(LOG_ERR, "duplicate_check: error looking up %s/%s/%s: %s",
		   dkey->id, dkey->to, dkey->date,
		   cyrusdb_strerror(r));
	}
	mark = 0;
    }

#if DEBUG
    syslog(LOG_DEBUG, "duplicate_check: %-40s %-20s %-40s %ld",
	   dkey->id, dkey->to, dkey->date, mark);
#endif

    buf_free(&key);
    return mark;
}
Esempio n. 7
0
/*
 * userdeny() checks to see if 'user' is denied access to 'service'
 * Returns 1 if a matching deny entry exists in DB, otherwise returns 0.
 */
EXPORTED int userdeny(const char *user, const char *service, char *msgbuf, size_t bufsiz)
{
    int r, ret = 0; /* allow access by default */
    const char *data = NULL;
    size_t datalen;
    struct buf buf = BUF_INITIALIZER;
    char *wild = NULL;
    const char *msg = NULL;
    tok_t tok;
    char *pat;
    int not;

    if (!denydb) denydb_open(/*create*/0);
    if (!denydb) return 0;

    memset(&tok, 0, sizeof(tok));

    /* fetch entry for user */
    syslog(LOG_DEBUG, "fetching user_deny.db entry for '%s'", user);
    do {
	r = cyrusdb_fetch(denydb, user, strlen(user), &data, &datalen, NULL);
    } while (r == CYRUSDB_AGAIN);

    /* XXX  Should we try to reopen the DB if we get IOERROR?
	    This might be necessary when using SQL backend
	    and we lose the connection.
    */

    if (r || !data || !datalen) {
	/* ignore non-existent/empty entry, report all other errors */
	if (r != CYRUSDB_NOTFOUND) {
	    syslog(LOG_WARNING,
		   "DENYDB_ERROR: error reading entry '%s': %s",
		   user, cyrusdb_strerror(r));
	}
	goto out;
    }
    buf_init_ro(&buf, data, datalen);

	/* parse the data */
    r = parse_record(&buf, &wild, &msg);
    if (r) {
	syslog(LOG_WARNING,
	       "DENYDB_ERROR: invalid entry for '%s'", user);
	goto out;
    }

    /* scan wildmat right to left for a match against our service */
    syslog(LOG_DEBUG, "wild: '%s'   service: '%s'", wild, service);
    tok_initm(&tok, wild, ",", 0);
    while ((pat = tok_next(&tok))) {
	/* XXX  trim leading & trailing whitespace? */

	/* is it a negated pattern? */
	not = (*pat == '!');
	if (not) ++pat;

	syslog(LOG_DEBUG, "pat %d:'%s'", not, pat);

	/* see if pattern matches our service */
	if (wildmat(service, pat)) {
	    /* match ==> we're done */
	    ret = !not;
	    if (msgbuf) strlcpy(msgbuf, msg, bufsiz);
	    break;
	}
    }

out:
    tok_fini(&tok);
    buf_free(&buf);
    return ret;
}
Esempio n. 8
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;
    size_t dsize;
    const char *fname = NULL;
    char *tofree = NULL;
    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 = libcyrus_config_getstring(CYRUSOPT_PTSCACHE_DB);
    }

    if(!state || *state) {
        fatal("bad state pointer passed to ptload()", EC_TEMPFAIL);
    }

    fname = libcyrus_config_getstring(CYRUSOPT_PTSCACHE_DB_PATH);

    if (!fname) {
        tofree = strconcat(config_dir, PTS_DBFIL, (char *)NULL);
        fname = tofree;
    }
    r = cyrusdb_open(the_ptscache_db, fname, CYRUSDB_CREATE, &ptdb);
    if (r != 0) {
        syslog(LOG_ERR, "DBERROR: opening %s: %s", fname,
               cyrusdb_strerror(ret));
        free(tofree);
        *state = NULL;
        return -1;
    }
    free(tofree);
    tofree = NULL;

    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 = cyrusdb_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 nonexistent),
     * 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;
    }

    fname = libcyrus_config_getstring(CYRUSOPT_PTLOADER_SOCK);
    if (!fname) {
        tofree = strconcat(config_dir, PTS_DBSOCKET, (char *)NULL);
        fname = tofree;
    }

    if (strlen(fname) >= sizeof(srvaddr.sun_path)) {
        syslog(LOG_ERR, "ptload(): socket filename %s too long for " SIZE_T_FMT "-byte buffer",
                        fname, sizeof(srvaddr.sun_path));
        rc = -1;
        goto done;
    }

    memset((char *)&srvaddr, 0, sizeof(srvaddr));
    srvaddr.sun_family = AF_UNIX;
    strlcpy(srvaddr.sun_path, fname, sizeof(srvaddr.sun_path));
    r = nb_connect(s, (struct sockaddr *)&srvaddr, sizeof(srvaddr), PT_TIMEOUT_SEC);
    free(tofree);

    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;
    }
    response[sizeof(response)-1] = '\0';

    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 = cyrusdb_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 */
    (cyrusdb_close)(ptdb);

    return rc;
}
Esempio n. 9
0
int main(int argc, char *argv[])
{
    int iter;
    int seed;
    int i;
    char *key;
    char *val;
    struct db *db;
    int r;
    struct txn *txn;
    const char *data;
    int datalen;
    struct timeval t1, t2;
    int initsize;

    if (argc > 1) {
	iter = atoi(argv[1]);
    } else {
      printf("%s [iterations] [rndseed] [initsize]\n", argv[0]);
      printf("if iterations is negative, run forever and report every -iter\n");
      exit(1);
    }
    TRY(DB->init(".", 0));

    if (argc > 2) {
	srand(atoi(argv[2]));
    }

    TRY(cyrusdb_open(DB, "scratch", &db));

    if (cyrusdb_consistent) {
	TRY(cyrusdb_consistent(db));
    }

    if (argc > 3) {
      initsize = atoi(argv[3]);
      
      txn = NULL;
      for (i = 0; i < initsize; i++) {
	/* generate a random key */
	key = genrand(10 + (rand() % 10));
	
	/* generate a random value */
	val = genrand(10 + (rand() % 100));
	
	TRY(cyrusdb_store(db, key, strlen(key), val, strlen(val), &txn));
      }

      TRY(cyrusdb_commit(db, txn));
      if (cyrusdb_consistent) {
	TRY(cyrusdb_consistent(db));
      }
    }

    printf("starting...\n");

    /* repeat for ever if iter < 0 */
    for (i = 0; iter > 0 ? (i < iter) : 1; i++) {
	int oper = rand() % 10;

	if (i > 0 && iter < 0 && ((i % -iter) == 0)) {
	  do_report();
	}

	switch (oper) {
	case 0:
	    /* do an ADD */
	    
	    if (verbose) printf("A");

	    /* insert it */
	    gettimeofday(&t1, NULL);

	    /* generate a random key */
	    key = genrand(10 + (rand() % 10));

	    /* generate a random value */
	    val = genrand(10 + (rand() % 100));

	    txn = NULL;
	    TRY(cyrusdb_store(db, key, strlen(key), val, strlen(val), &txn));
	    TRY(cyrusdb_commit(db, txn));
	    gettimeofday(&t2, NULL);

	    ADDDIFF(t_add, t1, t2);
	    c_add++;

	    free(key);
	    free(val);

	    break;

	case 1: /* do a modify */
	    if (verbose) printf("M");

	    gettimeofday(&t1, NULL);

	    /* pick a random victim */
	    count = 0;
	    victim = NULL;
	    txn = NULL;
	    TRY(cyrusdb_foreach(db, NULL, 0, &countem, NULL, NULL, &txn));
	    
	    if (count == 0) continue;

	    TRY(cyrusdb_foreach(db, NULL, 0, &findvictim, NULL, NULL, &txn));

	    assert(victim != NULL);

	    /* generate a random value */
	    val = genrand(10 + (rand() % 100));
	    
	    /* do an add */
	    TRY(cyrusdb_store(db, victim, strlen(victim), val, strlen(val), &txn));
	    free(val);

	    TRY(cyrusdb_commit(db, txn));
	    free(victim); victim = NULL;

	    gettimeofday(&t2, NULL);

	    ADDDIFF(t_mod, t1, t2);
	    c_mod++;

	    break;

	case 2: /* do a delete */
	    if (verbose) printf("D");

	    gettimeofday(&t1, NULL);

	    /* pick a random victim */
	    count = 0;
	    victim = NULL;
	    txn = NULL;
	    TRY(cyrusdb_foreach(db, NULL, 0, &countem, NULL, NULL, &txn));
	    
	    if (count == 0) continue;

	    TRY(cyrusdb_foreach(db, NULL, 0, &findvictim, NULL, NULL, &txn));
	    assert(victim != NULL);

	    /* delete it */
	    TRY(cyrusdb_delete(db, victim, strlen(victim), &txn, 0));

	    TRY(cyrusdb_commit(db, txn));
	    free(victim); victim = NULL;

	    gettimeofday(&t2, NULL);

	    ADDDIFF(t_del, t1, t2);
	    c_del++;

	    break;
	    
	default:
	    /* do a "read" */
	    if (verbose) printf("R");

	    gettimeofday(&t1, NULL);

	    /* generate a random key */
	    key = genrand(10 + (rand() % 10));

	    txn = NULL;
	    TRY(cyrusdb_fetch(db, key, strlen(key), &data, &datalen, &txn));
	    TRY(cyrusdb_commit(db, txn));

	    gettimeofday(&t2, NULL);

	    ADDDIFF(t_find, t1, t2);
	    c_find++;

	    free(key);
	}

	fflush(stdout);

#if 0
	/* run the consistency function, if any */
	if (cyrusdb_consistent) {
	    TRY(cyrusdb_consistent(db));
	}
#endif
    }

    TRY(cyrusdb_close(db));
    TRY(DB->done());

    do_report();
    return 0;
}