static int denydb_foreach_cb(void *rock, const char *key, size_t keylen, const char *data, size_t datalen) { struct denydb_rock *dr = (struct denydb_rock *)rock; struct buf user = BUF_INITIALIZER; struct buf buf = BUF_INITIALIZER; char *wild = NULL; const char *msg = NULL; int r; /* ensure we have a nul-terminated user string */ buf_appendmap(&user, key, keylen); buf_cstring(&user); /* get fields from the record */ buf_init_ro(&buf, data, datalen); r = parse_record(&buf, &wild, &msg); if (r) { syslog(LOG_WARNING, "DENYDB_ERROR: invalid entry for '%s'", user.s); r = 0; /* whatever, keep going */ goto out; } r = dr->proc(user.s, wild, msg, dr->rock); out: buf_free(&user); buf_free(&buf); return r; }
EXPORTED void rfc822tok_init(rfc822tok_t *t, const char *base, unsigned int len, unsigned int flags) { buf_init_ro(&t->buf, base, len); t->ptr = base; t->flags = flags; }
EXPORTED int dlist_getbuf(struct dlist *parent, const char *name, struct buf *value) { const char *v = NULL; size_t l = 0; if (dlist_getmap(parent, name, &v, &l)) { buf_init_ro(value, v, l); return 1; } return 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; }
static void on_msg_recv_cb(wslay_event_context_ptr ev, const struct wslay_event_on_msg_recv_arg *arg, void *user_data) { struct transaction_t *txn = (struct transaction_t *) user_data; struct ws_context *ctx = (struct ws_context *) txn->ws_ctx; struct buf inbuf = BUF_INITIALIZER, outbuf = BUF_INITIALIZER; struct wslay_event_msg msgarg = { arg->opcode, NULL, 0 }; uint8_t rsv = WSLAY_RSV_NONE; double cmdtime, nettime; const char *err_msg; int r, err_code = 0; /* Place client request into a buf */ buf_init_ro(&inbuf, (const char *) arg->msg, arg->msg_length); /* Decompress request, if necessary */ if (wslay_get_rsv1(arg->rsv)) { /* Add trailing 4 bytes */ buf_appendmap(&inbuf, "\x00\x00\xff\xff", 4); r = zlib_decompress(txn, buf_base(&inbuf), buf_len(&inbuf)); if (r) { syslog(LOG_ERR, "on_msg_recv_cb(): zlib_decompress() failed"); err_code = WSLAY_CODE_PROTOCOL_ERROR; err_msg = DECOMP_FAILED_ERR; goto err; } buf_move(&inbuf, &txn->zbuf); } /* Log the uncompressed client request */ buf_truncate(&ctx->log, ctx->log_tail); buf_appendcstr(&ctx->log, " ("); if (txn->strm_ctx) { buf_printf(&ctx->log, "stream-id=%d; ", http2_get_streamid(txn->strm_ctx)); } buf_printf(&ctx->log, "opcode=%s; rsv=0x%x; length=%ld", wslay_str_opcode(arg->opcode), arg->rsv, arg->msg_length); switch (arg->opcode) { case WSLAY_CONNECTION_CLOSE: buf_printf(&ctx->log, "; status=%d; msg='%s'", arg->status_code, buf_len(&inbuf) ? buf_cstring(&inbuf)+2 : ""); txn->flags.conn = CONN_CLOSE; break; case WSLAY_TEXT_FRAME: case WSLAY_BINARY_FRAME: if (txn->conn->logfd != -1) { /* Telemetry logging */ struct iovec iov[2]; int niov = 0; assert(!buf_len(&txn->buf)); buf_printf(&txn->buf, "<%ld<", time(NULL)); /* timestamp */ WRITEV_ADD_TO_IOVEC(iov, niov, buf_base(&txn->buf), buf_len(&txn->buf)); WRITEV_ADD_TO_IOVEC(iov, niov, buf_base(&inbuf), buf_len(&inbuf)); writev(txn->conn->logfd, iov, niov); buf_reset(&txn->buf); } /* Process the request */ r = ctx->data_cb(&inbuf, &outbuf, &ctx->log, &ctx->cb_rock); if (r) { err_code = (r == HTTP_SERVER_ERROR ? WSLAY_CODE_INTERNAL_SERVER_ERROR : WSLAY_CODE_INVALID_FRAME_PAYLOAD_DATA); err_msg = error_message(r); goto err; } if (txn->conn->logfd != -1) { /* Telemetry logging */ struct iovec iov[2]; int niov = 0; assert(!buf_len(&txn->buf)); buf_printf(&txn->buf, ">%ld>", time(NULL)); /* timestamp */ WRITEV_ADD_TO_IOVEC(iov, niov, buf_base(&txn->buf), buf_len(&txn->buf)); WRITEV_ADD_TO_IOVEC(iov, niov, buf_base(&outbuf), buf_len(&outbuf)); writev(txn->conn->logfd, iov, niov); buf_reset(&txn->buf); } /* Compress the server response, if supported by the client */ if (ctx->ext & EXT_PMCE_DEFLATE) { r = zlib_compress(txn, ctx->pmce.deflate.no_context ? COMPRESS_START : 0, buf_base(&outbuf), buf_len(&outbuf)); if (r) { syslog(LOG_ERR, "on_msg_recv_cb(): zlib_compress() failed"); err_code = WSLAY_CODE_INTERNAL_SERVER_ERROR; err_msg = COMP_FAILED_ERR; goto err; } /* Trim the trailing 4 bytes */ buf_truncate(&txn->zbuf, buf_len(&txn->zbuf) - 4); buf_move(&outbuf, &txn->zbuf); rsv |= WSLAY_RSV1_BIT; } /* Queue the server response */ msgarg.msg = (const uint8_t *) buf_base(&outbuf); msgarg.msg_length = buf_len(&outbuf); wslay_event_queue_msg_ex(ev, &msgarg, rsv); /* Log the server response */ buf_printf(&ctx->log, ") => \"Success\" (opcode=%s; rsv=0x%x; length=%ld", wslay_str_opcode(msgarg.opcode), rsv, msgarg.msg_length); break; } err: if (err_code) { size_t err_msg_len = strlen(err_msg); syslog(LOG_DEBUG, "wslay_event_queue_close()"); wslay_event_queue_close(ev, err_code, (uint8_t *) err_msg, err_msg_len); /* Log the server response */ buf_printf(&ctx->log, ") => \"Fail\" (opcode=%s; rsv=0x%x; length=%ld" "; status=%d; msg='%s'", wslay_str_opcode(WSLAY_CONNECTION_CLOSE), rsv, err_msg_len, err_code, err_msg); } /* Add timing stats */ cmdtime_endtimer(&cmdtime, &nettime); buf_printf(&ctx->log, ") [timing: cmd=%f net=%f total=%f]", cmdtime, nettime, cmdtime + nettime); syslog(LOG_INFO, "%s", buf_cstring(&ctx->log)); buf_free(&inbuf); buf_free(&outbuf); }