static int do_indexfrom(const char *fromfile) { int r; FILE *fp; unsigned lineno = 0; const char *p; tok_t tok; const char *mboxname; uint32_t uid; char buf[MAX_MAILBOX_BUFFER+128]; rx = search_begin_update(verbose); if (rx == NULL) /* no indexer defined */ return 0; fp = fopen(fromfile, "r"); if (!fp) { r = errno; perror(fromfile); goto out; } while (fgets(buf, sizeof(buf), fp)) { lineno++; if (buf[0] == '#') continue; tok_initm(&tok, buf, "\t", TOK_EMPTY|TOK_TRIMRIGHT); /* first token is an mboxname */ mboxname = tok_next(&tok); if (!mboxname) { syntax_error: fprintf(stderr, "%s:%u: syntax error, skipping\n", fromfile, lineno); continue; } /* 2nd token is a uid */ p = tok_next(&tok); if (!p) goto syntax_error; uid = strtoul(p, NULL, 0); if (!uid) goto syntax_error; /* no more tokens on the line */ p = tok_next(&tok); if (p) goto syntax_error; r = index_single_message(mboxname, uid); if (r) { fprintf(stderr, "Failed to index mailbox \"%s\" uid %u: %s\n", mboxname, uid, error_message(r)); /* ignore errors */ r = 0; } } out: if (fp) fclose(fp); search_end_update(rx); return r; }
/* * Add iCalendar recur-rule-parts to a structured element. */ void icalrecurrencetype_add_as_xxx(struct icalrecurrencetype *recur, void *obj, void (*add_int)(void *, const char *, int), void (*add_str)(void *, const char *, const char *)) { char *rrule, *rpart; tok_t rparts; /* generate an iCal RRULE string */ rrule = icalrecurrencetype_as_string_r(recur); /* split string into rparts & values */ tok_initm(&rparts, rrule, "=;", TOK_TRIMLEFT|TOK_TRIMRIGHT); while ((rpart = tok_next(&rparts))) { if (!strcmp(rpart, "UNTIL")) { /* need to translate date format to ISO */ struct icaltimetype until = icaltime_from_string(tok_next(&rparts)); add_str(obj, "until", icaltime_as_iso_string(until)); } else { /* assume the rpart has multiple values - split them */ tok_t vlist; char *val, *p; tok_init(&vlist, tok_next(&rparts), ",", TOK_TRIMLEFT|TOK_TRIMRIGHT); while ((val = tok_next(&vlist))) { if (add_int) { /* try converting value to integer */ int n = strtol(val, &p, 10); if (n && !*p) { add_int(obj, lcase(rpart), n); continue; } } add_str(obj, lcase(rpart), val); } tok_fini(&vlist); } } tok_fini(&rparts); free(rrule); }
/* * 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; }
EXPORTED void tok_init(tok_t *t, const char *str, const char *sep, int flags) { tok_initm(t, str ? xstrdup(str) : NULL, sep, flags|TOK_FREEBUFFER); }
EXPORTED 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, int logfd) { /* need to (re)establish connection to server or create one */ int sock = -1; int r; int err = -1; int do_tls = 0; int noauth = 0; struct addrinfo hints, *res0 = NULL, *res; struct sockaddr_un sunsock; struct backend *ret; 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)); if (!strcmp(prot->sasl_service, "lmtp") || !strcmp(prot->sasl_service, "csync")) { noauth = 1; } } else { /* inet socket */ char host[1024], *p; const char *service = prot->service; /* Parse server string for possible port and options */ strlcpy(host, server, sizeof(host)); if ((p = strchr(host, ':'))) { *p++ = '\0'; service = p; if ((p = strchr(service, '/'))) { tok_t tok; char *opt; *p++ = '\0'; tok_initm(&tok, p, "/", 0); while ((opt = tok_next(&tok))) { if (!strcmp(opt, "tls")) do_tls = 1; else if (!strcmp(opt, "noauth")) noauth = 1; } tok_fini(&tok); } } memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; err = getaddrinfo(host, service, &hints, &res0); if (err) { syslog(LOG_ERR, "getaddrinfo(%s) failed: %s", server, gai_strerror(err)); goto error; } } for (res = res0; res; res = res->ai_next) { sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (sock < 0) continue; /* Do a non-blocking connect() */ nonblock(sock, 1); if (!connect(sock, res->ai_addr, res->ai_addrlen)) { /* connect() succeeded immediately */ break; } else if (errno == EINPROGRESS) { /* connect() in progress */ int n; fd_set wfds, rfds; time_t now = time(NULL); time_t timeout = now + config_getint(IMAPOPT_CLIENT_TIMEOUT); struct timeval waitfor; /* select() socket for writing until we succeed, fail, or timeout */ do { FD_ZERO(&wfds); FD_SET(sock, &wfds); rfds = wfds; waitfor.tv_sec = timeout - now; waitfor.tv_usec = 0; n = select(sock + 1, &rfds, &wfds, NULL, &waitfor); now = time(NULL); /* Retry select() if interrupted */ } while (n < 0 && errno == EINTR && now < timeout); if (!n) { /* select() timed out */ errno = ETIMEDOUT; } else if (FD_ISSET(sock, &rfds) || FD_ISSET(sock, &wfds)) { /* Socket is ready for I/O - get SO_ERROR to determine status */ socklen_t errlen = sizeof(err); if (!getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &errlen) && !(errno = err)) { /* connect() succeeded */ break; } } } close(sock); sock = -1; } if (sock < 0) { if (res0 != &hints) freeaddrinfo(res0); syslog(LOG_ERR, "connect(%s) failed: %m", server); goto error; } /* Reset socket to blocking */ nonblock(sock, 0); 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_settimeout(ret->in, config_getint(IMAPOPT_CLIENT_TIMEOUT)); prot_setflushonread(ret->in, ret->out); ret->prot = prot; /* use literal+ to send literals */ prot_setisclient(ret->in, 1); prot_setisclient(ret->out, 1); /* Start TLS if required */ if (do_tls) r = backend_starttls(ret, NULL, NULL, NULL); /* Login to the server */ if (prot->type == TYPE_SPEC) r = prot->u.spec.login(ret, userid, cb, auth_status, noauth); else r = backend_login(ret, userid, cb, auth_status, noauth); if (r) goto error; if (logfd >= 0) { prot_setlog(ret->in, logfd); prot_setlog(ret->out, logfd); } else prot_settimeout(ret->in, 0); 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; }
/* Parse Sec-WebSocket-Extensions header(s) for interesting extensions */ static void parse_extensions(struct transaction_t *txn) { struct ws_context *ctx = (struct ws_context *) txn->ws_ctx; const char **ext_hdr = spool_getheader(txn->req_hdrs, "Sec-WebSocket-Extensions"); int i; /* Look for interesting extensions. Unknown == ignore */ for (i = 0; ext_hdr && ext_hdr[i]; i++) { tok_t ext = TOK_INITIALIZER(ext_hdr[i], ",", TOK_TRIMLEFT|TOK_TRIMRIGHT); char *token; while ((token = tok_next(&ext))) { struct ws_extension *extp = extensions; tok_t param; tok_initm(¶m, token, ";", TOK_TRIMLEFT|TOK_TRIMRIGHT); token = tok_next(¶m); /* Locate a matching extension */ while (extp->name && strcmp(token, extp->name)) extp++; /* Check if client wants per-message compression */ if (extp->flag == EXT_PMCE_DEFLATE) { unsigned client_max_wbits = MAX_WBITS; ctx->pmce.deflate.max_wbits = MAX_WBITS; /* Process parameters */ while ((token = tok_next(¶m))) { char *value = strchr(token, '='); if (value) *value++ = '\0'; if (!strcmp(token, "server_no_context_takeover")) { ctx->pmce.deflate.no_context = 1; } else if (!strcmp(token, "client_no_context_takeover")) { /* Don't HAVE to do anything here */ } else if (!strcmp(token, "server_max_window_bits")) { if (value) { if (*value == '"') value++; ctx->pmce.deflate.max_wbits = atoi(value); } else ctx->pmce.deflate.max_wbits = 0; /* force error */ } else if (!strcmp(token, "client_max_window_bits")) { if (value) { if (*value == '"') value++; client_max_wbits = atoi(value); } } } #ifdef HAVE_ZLIB /* Reconfigure compression context for raw deflate */ if (txn->zstrm) deflateEnd(txn->zstrm); else txn->zstrm = xmalloc(sizeof(z_stream)); if (deflateInit2(txn->zstrm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -ctx->pmce.deflate.max_wbits, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY) != Z_OK) { free(txn->zstrm); txn->zstrm = NULL; } if (txn->zstrm) { /* Configure decompression context for raw deflate */ ctx->pmce.deflate.zstrm = xmalloc(sizeof(z_stream)); if (inflateInit2(ctx->pmce.deflate.zstrm, -client_max_wbits) != Z_OK) { free(ctx->pmce.deflate.zstrm); ctx->pmce.deflate.zstrm = NULL; } } #endif /* HAVE_ZLIB */ if (ctx->pmce.deflate.zstrm) { /* Compression has been enabled */ wslay_event_config_set_allowed_rsv_bits(ctx->event, WSLAY_RSV1_BIT); ctx->ext = extp->flag; } } tok_fini(¶m); } tok_fini(&ext); } }