Example #1
0
 /* pwcheck daemon-authenticated login */
 int pwcheck_verify_password(const char *userid,
                                  const char *passwd,
                                  const char **reply)
 {
     int s, start, r, n;
     struct sockaddr_un srvaddr;
     struct iovec iov[2];
     static char response[1024];

     *reply = NULL;

     s = socket(AF_UNIX, SOCK_STREAM, 0);
     if (s == -1) { return PWCHECK_FAIL; }

     memset((char *)&srvaddr, 0, sizeof(srvaddr));
     srvaddr.sun_family = AF_UNIX;
     strncpy(srvaddr.sun_path, CYRUS_PWCHECK_SOCKET, sizeof(srvaddr.sun_path));
     r = connect(s, (struct sockaddr *)&srvaddr, sizeof(srvaddr));
     if (r == -1) {
        DEBUG(D_auth)
            debug_printf("Cannot connect to pwcheck daemon (at '%s')\n",CYRUS_PWCHECK_SOCKET);
       *reply = "cannot connect to pwcheck daemon";
       return PWCHECK_FAIL;
     }

     iov[0].iov_base = (char *)userid;
     iov[0].iov_len = strlen(userid)+1;
     iov[1].iov_base = (char *)passwd;
     iov[1].iov_len = strlen(passwd)+1;

     retry_writev(s, iov, 2);

     start = 0;
     while (start < sizeof(response) - 1) {
       n = read(s, response+start, sizeof(response) - 1 - start);
       if (n < 1) break;
       start += n;
     }

     (void)close(s);

     if (start > 1 && !strncmp(response, "OK", 2)) {
       return PWCHECK_OK;
     }

     response[start] = '\0';
     *reply = response;
     return PWCHECK_NO;
 }
Example #2
0
static int write_string(int fd, const uschar *string, int len) {
    unsigned short count;
    int rc;
    struct iovec iov[2];

    count = htons(len);

    iov[0].iov_base = (void *) &count;
    iov[0].iov_len = sizeof(count);
    iov[1].iov_base = (void *) string;
    iov[1].iov_len = len;

    rc = retry_writev(fd, iov, 2);

    return rc;
}
Example #3
0
EXPORTED ssize_t mappedfile_pwritev(struct mappedfile *mf,
                                    const struct iovec *iov, int nio,
                                    off_t offset)
{
    ssize_t written;
    off_t pos;

    assert(mf->is_rw);
    assert(mf->fd != -1);
    assert(iov);

    if (!nio) return 0; /* nothing to write! */

    /* XXX - memcmp and don't both writing if it matches? */

    mf->dirty++;

    /* locate the file handle */
    pos = lseek(mf->fd, offset, SEEK_SET);
    if (pos < 0) {
        syslog(LOG_ERR, "IOERROR: %s seek to %llX: %m", mf->fname,
               (long long unsigned int)offset);
        return -1;
    }

    /* write the buffer */
    written = retry_writev(mf->fd, iov, nio);
    if (written < 0) {
        size_t len = 0;
        int i;
        for (i = 0; i < nio; i++) {
            len += iov[i].iov_len;
        }
        syslog(LOG_ERR, "IOERROR: %s write %llu bytes at %llX: %m",
               mf->fname, (long long unsigned int)len,
               (long long unsigned int)offset);
        return -1;
    }

    _ensure_mapped(mf, pos+written, /*update*/1);

    return written;
}
Example #4
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;
}
Example #5
0
/* saslauthd-authenticated login */
static int saslauthd_verify_password(const char *saslauthd_path,
                                     const char *userid,
                                     const char *passwd,
                                     const char *service,
                                     const char *user_realm)
{
    char response[1024];
    char query[8192];
    char *query_end = query;
    int s;
    struct sockaddr_un srvaddr;
    int r;
    unsigned short count;
    char pwpath[sizeof(srvaddr.sun_path)];
#ifdef USE_DOORS
    door_arg_t arg;
#endif

    if(!service) service = "imap";
    if(!user_realm) user_realm = "";
    if(!userid || !passwd) return -1;

    if (saslauthd_path) {
        strncpy(pwpath, saslauthd_path, sizeof(pwpath));
    } else {
        if (strlen(PATH_SASLAUTHD_RUNDIR) + 4 + 1 > sizeof(pwpath))
            return -1;

        strcpy(pwpath, PATH_SASLAUTHD_RUNDIR);
        strcat(pwpath, "/mux");
    }

    /*
     * build request of the form:
     *
     * count authid count password count service count realm
     */
    {
        unsigned short u_len, p_len, s_len, r_len;

        u_len = htons(strlen(userid));
        p_len = htons(strlen(passwd));
        s_len = htons(strlen(service));
        r_len = htons((user_realm ? strlen(user_realm) : 0));

        memcpy(query_end, &u_len, sizeof(unsigned short));
        query_end += sizeof(unsigned short);
        while (*userid) *query_end++ = *userid++;

        memcpy(query_end, &p_len, sizeof(unsigned short));
        query_end += sizeof(unsigned short);
        while (*passwd) *query_end++ = *passwd++;

        memcpy(query_end, &s_len, sizeof(unsigned short));
        query_end += sizeof(unsigned short);
        while (*service) *query_end++ = *service++;

        memcpy(query_end, &r_len, sizeof(unsigned short));
        query_end += sizeof(unsigned short);
        if (user_realm) while (*user_realm) *query_end++ = *user_realm++;
    }

#ifdef USE_DOORS
    s = open(pwpath, O_RDONLY);
    if (s < 0) {
        perror("open");
        return -1;
    }

    arg.data_ptr = query;
    arg.data_size = query_end - query;
    arg.desc_ptr = NULL;
    arg.desc_num = 0;
    arg.rbuf = response;
    arg.rsize = sizeof(response);

    if(door_call(s, &arg) != 0) {
        printf("NO \"door_call failed\"\n");
        return -1;
    }

    assert(arg.data_size < sizeof(response));
    response[arg.data_size] = '\0';

    close(s);
#else
    s = socket(AF_UNIX, SOCK_STREAM, 0);
    if (s == -1) {
        perror("socket() ");
        return -1;
    }

    memset((char *)&srvaddr, 0, sizeof(srvaddr));
    srvaddr.sun_family = AF_UNIX;
    strncpy(srvaddr.sun_path, pwpath, sizeof(srvaddr.sun_path));

    r = connect(s, (struct sockaddr *) &srvaddr, sizeof(srvaddr));
    if (r == -1) {
        perror("connect() ");
        return -1;
    }

    {
        struct iovec iov[8];

        iov[0].iov_len = query_end - query;
        iov[0].iov_base = query;

        if (retry_writev(s, iov, 1) == -1) {
            fprintf(stderr,"write failed\n");
            return -1;
        }
    }

    /*
     * read response of the form:
     *
     * count result
     */
    if (retry_read(s, &count, sizeof(count)) < (int) sizeof(count)) {
        fprintf(stderr,"size read failed\n");
        return -1;
    }

    count = ntohs(count);
    if (count < 2) { /* MUST have at least "OK" or "NO" */
        close(s);
        fprintf(stderr,"bad response from saslauthd\n");
        return -1;
    }

    count = (int)sizeof(response) < count ? sizeof(response) : count;
    if (retry_read(s, response, count) < count) {
        close(s);
        fprintf(stderr,"read failed\n");
        return -1;
    }
    response[count] = '\0';

    close(s);
#endif /* USE_DOORS */

    if (!strncmp(response, "OK", 2)) {
        printf("OK \"Success.\"\n");
        return 0;
    }

    printf("NO \"authentication failed\"\n");
    return -1;
}
Example #6
0
static int mystore(struct dbengine *db,
                   const char *key, size_t keylen,
                   const char *data, size_t datalen,
                   struct txn **mytid, int overwrite)
{
    int r = 0;
    char fnamebuf[1024];
    int offset;
    unsigned long len;
    const char *lockfailaction;
    int writefd;
    struct iovec iov[10];
    int niov;
    struct stat sbuf;
    struct buf keybuf = BUF_INITIALIZER;
    struct buf databuf = BUF_INITIALIZER;

    /* lock file, if needed */
    if (!mytid || !*mytid) {
        r = lock_reopen(db->fd, db->fname, &sbuf, &lockfailaction);
        if (r < 0) {
            syslog(LOG_ERR, "IOERROR: %s %s: %m", lockfailaction, db->fname);
            return CYRUSDB_IOERROR;
        }

        if (sbuf.st_ino != db->ino) {
            db->ino = sbuf.st_ino;
            map_free(&db->base, &db->len);
            map_refresh(db->fd, 0, &db->base, &db->len,
                        sbuf.st_size, db->fname, 0);
            db->size = sbuf.st_size;
        }

        if (mytid) {
            *mytid = new_txn();
        }
    }

    encode(key, keylen, &keybuf);

    /* find entry, if it exists */
    offset = bsearch_mem_mbox(keybuf.s, db->base, db->size, 0, &len);

    /* overwrite? */
    if (len && !overwrite) {
        if (mytid) abort_txn(db, *mytid);
        buf_free(&keybuf);
        buf_free(&databuf);
        return CYRUSDB_EXISTS;
    }

    /* write new file */
    if (mytid && (*mytid)->fnamenew) {
        strlcpy(fnamebuf, (*mytid)->fnamenew, sizeof(fnamebuf));
    } else {
        strlcpy(fnamebuf, db->fname, sizeof(fnamebuf));
        strlcat(fnamebuf, ".NEW", sizeof(fnamebuf));
    }

    unlink(fnamebuf);
    r = writefd = open(fnamebuf, O_RDWR | O_CREAT, 0666);
    if (r < 0) {
        syslog(LOG_ERR, "opening %s for writing failed: %m", fnamebuf);
        if (mytid) abort_txn(db, *mytid);
        buf_free(&keybuf);
        buf_free(&databuf);
        return CYRUSDB_IOERROR;
    }

    niov = 0;
    if (offset) {
        WRITEV_ADD_TO_IOVEC(iov, niov, (char *) db->base, offset);
    }

    if (data) {
        /* new entry */
        encode(data, datalen, &databuf);
        WRITEV_ADD_TO_IOVEC(iov, niov, keybuf.s, keybuf.len);
        WRITEV_ADD_TO_IOVEC(iov, niov, "\t", 1);
        WRITEV_ADD_TO_IOVEC(iov, niov, databuf.s, databuf.len);
        WRITEV_ADD_TO_IOVEC(iov, niov, "\n", 1);
    }

    if (db->size - (offset + len) > 0) {
        WRITEV_ADD_TO_IOVEC(iov, niov, (char *) db->base + offset + len,
                            db->size - (offset + len));
    }

    /* do the write */
    r = retry_writev(writefd, iov, niov);
    if (r == -1) {
        syslog(LOG_ERR, "IOERROR: writing %s: %m", fnamebuf);
        close(writefd);
        if (mytid) abort_txn(db, *mytid);
        buf_free(&keybuf);
        buf_free(&databuf);
        return CYRUSDB_IOERROR;
    }
    r = 0;

    if (mytid) {
        /* setup so further accesses will be against fname.NEW */
        if (fstat(writefd, &sbuf) == -1) {
            /* xxx ? */
        }

        if (!(*mytid)->fnamenew) (*mytid)->fnamenew = xstrdup(fnamebuf);
        if ((*mytid)->fd) close((*mytid)->fd);
        (*mytid)->fd = writefd;
        map_free(&db->base, &db->len);
        map_refresh(writefd, 0, &db->base, &db->len, sbuf.st_size,
                    fnamebuf, 0);
        db->size = sbuf.st_size;
    } else {
        /* commit immediately */
        if (fsync(writefd) ||
            fstat(writefd, &sbuf) == -1 ||
            rename(fnamebuf, db->fname) == -1) {
            syslog(LOG_ERR, "IOERROR: writing %s: %m", fnamebuf);
            close(writefd);
            buf_free(&keybuf);
            buf_free(&databuf);
            return CYRUSDB_IOERROR;
        }

        close(db->fd);
        db->fd = writefd;

        /* release lock */
        r = lock_unlock(db->fd, db->fname);
        if (r == -1) {
            syslog(LOG_ERR, "IOERROR: unlocking db %s: %m", db->fname);
            r = CYRUSDB_IOERROR;
        }

        db->ino = sbuf.st_ino;
        map_free(&db->base, &db->len);
        map_refresh(writefd, 0, &db->base, &db->len, sbuf.st_size,
            db->fname, 0);
        db->size = sbuf.st_size;
    }

    buf_free(&keybuf);
    buf_free(&databuf);

    return r;
}