/* 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; }
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; }
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; }
/* 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; }
/* 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; }
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; }