178f776d5STrond Norbye/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
278f776d5STrond Norbye/*
378f776d5STrond Norbye *     Copyright 2015 Couchbase, Inc.
478f776d5STrond Norbye *
578f776d5STrond Norbye *   Licensed under the Apache License, Version 2.0 (the "License");
678f776d5STrond Norbye *   you may not use this file except in compliance with the License.
778f776d5STrond Norbye *   You may obtain a copy of the License at
878f776d5STrond Norbye *
978f776d5STrond Norbye *       http://www.apache.org/licenses/LICENSE-2.0
1078f776d5STrond Norbye *
1178f776d5STrond Norbye *   Unless required by applicable law or agreed to in writing, software
1278f776d5STrond Norbye *   distributed under the License is distributed on an "AS IS" BASIS,
1378f776d5STrond Norbye *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1478f776d5STrond Norbye *   See the License for the specific language governing permissions and
1578f776d5STrond Norbye *   limitations under the License.
1678f776d5STrond Norbye */
179738c807STrond Norbye#include "connection.h"
189738c807STrond Norbye
199738c807STrond Norbye#include "buckets.h"
20bf74734dSTrond Norbye#include "connections.h"
2111c4e41cSTrond Norbye#include "cookie.h"
224e37ea4dSTrond Norbye#include "external_auth_manager_thread.h"
23cad3ea13STrond Norbye#include "front_end_thread.h"
24edd2d65bSTrond Norbye#include "listening_port.h"
25bf74734dSTrond Norbye#include "mc_time.h"
2632e7ac32STrond Norbye#include "mcaudit.h"
2778f776d5STrond Norbye#include "memcached.h"
288d8ad4ccSJim Walker#include "protocol/mcbp/dcp_snapshot_marker_codec.h"
29080485a3STrond Norbye#include "protocol/mcbp/engine_wrapper.h"
30bf38ae96STrond Norbye#include "runtime.h"
31bf3926e0STrond Norbye#include "server_event.h"
32c4b6868aSDave Rigby#include "settings.h"
33a21009eeSTrond Norbye
349f29a7f6SDave Rigby#include <logger/logger.h>
35bf74734dSTrond Norbye#include <mcbp/mcbp.h>
36911e83e9STrond Norbye#include <mcbp/protocol/framebuilder.h>
37650d2dd9STrond Norbye#include <mcbp/protocol/header.h>
38c35f9873SDave Rigby#include <memcached/durability_spec.h>
39291a7539STim Bradgate#include <nlohmann/json.hpp>
40bf74734dSTrond Norbye#include <phosphor/phosphor.h>
4124922815STrond Norbye#include <platform/cbassert.h>
426ba7682eSTrond Norbye#include <platform/checked_snprintf.h>
43bf74734dSTrond Norbye#include <platform/socket.h>
4434e0f7f7STrond Norbye#include <platform/strerror.h>
456a8c4a90STrond Norbye#include <platform/string_hex.h>
46bf74734dSTrond Norbye#include <platform/timeutils.h>
4787507b8fSPremkumar#include <utilities/logtags.h>
489c34d9c3SDave Rigby#include <gsl/gsl>
499c34d9c3SDave Rigby
50bf74734dSTrond Norbye#include <cctype>
51650d2dd9STrond Norbye#include <exception>
529c34d9c3SDave Rigby#ifndef WIN32
539c34d9c3SDave Rigby#include <netinet/tcp.h> // For TCP_NODELAY etc
549c34d9c3SDave Rigby#endif
5578f776d5STrond Norbye
564caaa1b8STrond Norbye/// The TLS packet is using the following format:
574caaa1b8STrond Norbye/// Byte 0 - Content type
584caaa1b8STrond Norbye/// Byte 1 and 2 - Version
594caaa1b8STrond Norbye/// Byte 3 and 4 - length
604caaa1b8STrond Norbye///   n bytes of user payload
614caaa1b8STrond Norbye///   m bytes of MAC
624caaa1b8STrond Norbye///   o bytes of padding for block ciphers
634caaa1b8STrond Norbye/// Create a constant which represents the maxium amount of data we
644caaa1b8STrond Norbye/// may put in a single TLS frame
654caaa1b8STrond Norbyestatic constexpr std::size_t TlsFrameSize = 16 * 1024;
664caaa1b8STrond Norbye
6785d35f8eSTrond Norbyestd::string to_string(Connection::Priority priority) {
68668794c4STrond Norbye    switch (priority) {
69668794c4STrond Norbye    case Connection::Priority::High:
70668794c4STrond Norbye        return "High";
71668794c4STrond Norbye    case Connection::Priority::Medium:
72668794c4STrond Norbye        return "Medium";
73668794c4STrond Norbye    case Connection::Priority::Low:
74668794c4STrond Norbye        return "Low";
75668794c4STrond Norbye    }
76668794c4STrond Norbye    throw std::invalid_argument("No such priority: " +
77668794c4STrond Norbye                                std::to_string(int(priority)));
7878f776d5STrond Norbye}
7978f776d5STrond Norbye
8034e0f7f7STrond Norbyebool Connection::setTcpNoDelay(bool enable) {
8127cdfa6cSTrond Norbye    if (socketDescriptor == INVALID_SOCKET) {
8227cdfa6cSTrond Norbye        // Our unit test run without a connected socket (and there is
8327cdfa6cSTrond Norbye        // no point of running setsockopt on an invalid socket and
8427cdfa6cSTrond Norbye        // get the error message from there).. But we don't want them
8527cdfa6cSTrond Norbye        // (the unit tests) to flood the console with error messages
8627cdfa6cSTrond Norbye        // that setsockopt failed
8727cdfa6cSTrond Norbye        return false;
8827cdfa6cSTrond Norbye    }
8927cdfa6cSTrond Norbye
9041f62c77STrond Norbye    const int flags = enable ? 1 : 0;
9141f62c77STrond Norbye    int error = cb::net::setsockopt(socketDescriptor,
9241f62c77STrond Norbye                                    IPPROTO_TCP,
9341f62c77STrond Norbye                                    TCP_NODELAY,
9441f62c77STrond Norbye                                    reinterpret_cast<const void*>(&flags),
9541f62c77STrond Norbye                                    sizeof(flags));
9634e0f7f7STrond Norbye
9734e0f7f7STrond Norbye    if (error != 0) {
9841f62c77STrond Norbye        std::string errmsg = cb_strerror(cb::net::get_socket_error());
994dd9b0f4STrond Norbye        LOG_WARNING("setsockopt(TCP_NODELAY): {}", errmsg);
10034e0f7f7STrond Norbye        nodelay = false;
10134e0f7f7STrond Norbye        return false;
10234e0f7f7STrond Norbye    } else {
10334e0f7f7STrond Norbye        nodelay = enable;
10434e0f7f7STrond Norbye    }
10534e0f7f7STrond Norbye
10634e0f7f7STrond Norbye    return true;
10734e0f7f7STrond Norbye}
10834e0f7f7STrond Norbye
109bf74734dSTrond Norbye/**
110bf74734dSTrond Norbye * Get a JSON representation of an event mask
111bf74734dSTrond Norbye *
112bf74734dSTrond Norbye * @param mask the mask to convert to JSON
113291a7539STim Bradgate * @return the json representation.
114bf74734dSTrond Norbye */
115291a7539STim Bradgatestatic nlohmann::json event_mask_to_json(const short mask) {
116291a7539STim Bradgate    nlohmann::json ret;
117291a7539STim Bradgate    nlohmann::json array = nlohmann::json::array();
118291a7539STim Bradgate
1196a8c4a90STrond Norbye    ret["raw"] = cb::to_hex(uint16_t(mask));
120bf74734dSTrond Norbye
121bf74734dSTrond Norbye    if (mask & EV_READ) {
122291a7539STim Bradgate        array.push_back("read");
123bf74734dSTrond Norbye    }
124bf74734dSTrond Norbye    if (mask & EV_WRITE) {
125291a7539STim Bradgate        array.push_back("write");
126bf74734dSTrond Norbye    }
127bf74734dSTrond Norbye    if (mask & EV_PERSIST) {
128291a7539STim Bradgate        array.push_back("persist");
129bf74734dSTrond Norbye    }
130bf74734dSTrond Norbye    if (mask & EV_TIMEOUT) {
131291a7539STim Bradgate        array.push_back("timeout");
132bf74734dSTrond Norbye    }
133bf74734dSTrond Norbye
134291a7539STim Bradgate    ret["decoded"] = array;
135bf74734dSTrond Norbye    return ret;
136bf74734dSTrond Norbye}
137bf74734dSTrond Norbye
138291a7539STim Bradgatenlohmann::json Connection::toJSON() const {
139291a7539STim Bradgate    nlohmann::json ret;
140291a7539STim Bradgate
1416a8c4a90STrond Norbye    ret["connection"] = cb::to_hex(uint64_t(this));
142291a7539STim Bradgate
1438629facbSTrond Norbye    if (socketDescriptor == INVALID_SOCKET) {
144291a7539STim Bradgate        ret["socket"] = "disconnected";
145bf74734dSTrond Norbye        return ret;
146bf74734dSTrond Norbye    }
147bf74734dSTrond Norbye
148291a7539STim Bradgate    ret["socket"] = socketDescriptor;
149291a7539STim Bradgate    ret["yields"] = yields.load();
150291a7539STim Bradgate    ret["protocol"] = "memcached";
151291a7539STim Bradgate    ret["peername"] = getPeername().c_str();
152291a7539STim Bradgate    ret["sockname"] = getSockname().c_str();
153291a7539STim Bradgate    ret["parent_port"] = parent_port;
154291a7539STim Bradgate    ret["bucket_index"] = getBucketIndex();
155291a7539STim Bradgate    ret["internal"] = isInternal();
156291a7539STim Bradgate
157bf74734dSTrond Norbye    if (authenticated) {
15862769ea3STrond Norbye        if (internal) {
15962769ea3STrond Norbye            // We want to be able to map these connections, and given
16062769ea3STrond Norbye            // that it is internal we don't reveal any user data
16162769ea3STrond Norbye            ret["username"] = username;
16262769ea3STrond Norbye        } else {
16362769ea3STrond Norbye            ret["username"] = cb::tagUserData(username);
16462769ea3STrond Norbye        }
1652382bc00STrond Norbye    }
1662382bc00STrond Norbye
167291a7539STim Bradgate    ret["refcount"] = refcount;
1682382bc00STrond Norbye
169b4067907STrond Norbye    nlohmann::json features = nlohmann::json::array();
170b4067907STrond Norbye    if (isSupportsMutationExtras()) {
171b4067907STrond Norbye        features.push_back("mutation extras");
172b4067907STrond Norbye    }
173b4067907STrond Norbye    if (isXerrorSupport()) {
174b4067907STrond Norbye        features.push_back("xerror");
175b4067907STrond Norbye    }
176b4067907STrond Norbye    if (nodelay) {
177b4067907STrond Norbye        features.push_back("tcp nodelay");
178b4067907STrond Norbye    }
179b4067907STrond Norbye    if (allowUnorderedExecution()) {
180b4067907STrond Norbye        features.push_back("unordered execution");
181b4067907STrond Norbye    }
182b4067907STrond Norbye    if (tracingEnabled) {
183b4067907STrond Norbye        features.push_back("tracing");
184b4067907STrond Norbye    }
185b4067907STrond Norbye
186b4067907STrond Norbye    if (isCollectionsSupported()) {
187b4067907STrond Norbye        features.push_back("collections");
188b4067907STrond Norbye    }
189b4067907STrond Norbye
190b4067907STrond Norbye    if (isDuplexSupported()) {
191b4067907STrond Norbye        features.push_back("duplex");
192b4067907STrond Norbye    }
193b4067907STrond Norbye
194b4067907STrond Norbye    if (isClustermapChangeNotificationSupported()) {
195b4067907STrond Norbye        features.push_back("CCN");
196b4067907STrond Norbye    }
197b4067907STrond Norbye
198291a7539STim Bradgate    ret["features"] = features;
1992382bc00STrond Norbye
2009e8f5bb7STrond Norbye    ret["thread"] = getThread().index;
201291a7539STim Bradgate    ret["priority"] = to_string(priority);
2022382bc00STrond Norbye
2032382bc00STrond Norbye    if (clustermap_revno == -2) {
204291a7539STim Bradgate        ret["clustermap_revno"] = "unknown";
2052382bc00STrond Norbye    } else {
206291a7539STim Bradgate        ret["clustermap_revno"] = clustermap_revno;
2072382bc00STrond Norbye    }
2082382bc00STrond Norbye
209291a7539STim Bradgate    ret["total_cpu_time"] = std::to_string(total_cpu_time.count());
210291a7539STim Bradgate    ret["min_sched_time"] = std::to_string(min_sched_time.count());
211291a7539STim Bradgate    ret["max_sched_time"] = std::to_string(max_sched_time.count());
2122382bc00STrond Norbye
213291a7539STim Bradgate    nlohmann::json arr = nlohmann::json::array();
2142382bc00STrond Norbye    for (const auto& c : cookies) {
215291a7539STim Bradgate        arr.push_back(c->toJSON());
2162382bc00STrond Norbye    }
217291a7539STim Bradgate    ret["cookies"] = arr;
2182382bc00STrond Norbye
2192382bc00STrond Norbye    if (agentName.front() != '\0') {
220291a7539STim Bradgate        ret["agent_name"] = std::string(agentName.data());
2212382bc00STrond Norbye    }
2222382bc00STrond Norbye    if (connectionId.front() != '\0') {
223291a7539STim Bradgate        ret["connection_id"] = std::string(connectionId.data());
2242382bc00STrond Norbye    }
2252382bc00STrond Norbye
226291a7539STim Bradgate    ret["sasl_enabled"] = saslAuthEnabled;
227291a7539STim Bradgate    ret["dcp"] = isDCP();
228291a7539STim Bradgate    ret["dcp_xattr_aware"] = isDcpXattrAware();
229c3663847SPaolo Cocchi    ret["dcp_deleted_user_xattr"] = isDcpDeletedUserXattr();
230291a7539STim Bradgate    ret["dcp_no_value"] = isDcpNoValue();
231291a7539STim Bradgate    ret["max_reqs_per_event"] = max_reqs_per_event;
232291a7539STim Bradgate    ret["nevents"] = numEvents;
233291a7539STim Bradgate    ret["state"] = getStateName();
2342382bc00STrond Norbye
235291a7539STim Bradgate    nlohmann::json libevt;
236291a7539STim Bradgate    libevt["registered"] = isRegisteredInLibevent();
237291a7539STim Bradgate    libevt["ev_flags"] = event_mask_to_json(ev_flags);
238291a7539STim Bradgate    libevt["which"] = event_mask_to_json(currentEvent);
239291a7539STim Bradgate    ret["libevent"] = libevt;
2402382bc00STrond Norbye
2412382bc00STrond Norbye    if (read) {
242291a7539STim Bradgate        ret["read"] = read->to_json();
2432382bc00STrond Norbye    }
2442382bc00STrond Norbye
2452382bc00STrond Norbye    if (write) {
246291a7539STim Bradgate        ret["write"] = write->to_json();
2472382bc00STrond Norbye    }
2482382bc00STrond Norbye
249291a7539STim Bradgate    ret["write_and_go"] = std::string(stateMachine.getStateName(write_and_go));
2502382bc00STrond Norbye
251291a7539STim Bradgate    nlohmann::json iovobj;
252291a7539STim Bradgate    iovobj["size"] = iov.size();
253291a7539STim Bradgate    iovobj["used"] = iovused;
254291a7539STim Bradgate    ret["iov"] = iovobj;
2552382bc00STrond Norbye
256291a7539STim Bradgate    nlohmann::json msg;
257291a7539STim Bradgate    msg["used"] = msglist.size();
258291a7539STim Bradgate    msg["curr"] = msgcurr;
259291a7539STim Bradgate    msg["bytes"] = msgbytes;
260291a7539STim Bradgate    ret["msglist"] = msg;
261291a7539STim Bradgate
262291a7539STim Bradgate    nlohmann::json ilist;
263291a7539STim Bradgate    ilist["size"] = reservedItems.size();
264291a7539STim Bradgate    ret["itemlist"] = ilist;
265291a7539STim Bradgate
266291a7539STim Bradgate    nlohmann::json talloc;
267291a7539STim Bradgate    talloc["size"] = temp_alloc.size();
268291a7539STim Bradgate    ret["temp_alloc_list"] = talloc;
2692382bc00STrond Norbye
270291a7539STim Bradgate    ret["ssl"] = ssl.toJSON();
271291a7539STim Bradgate    ret["total_recv"] = totalRecv;
272291a7539STim Bradgate    ret["total_send"] = totalSend;
273291a7539STim Bradgate
274291a7539STim Bradgate    ret["datatype"] = mcbp::datatype::to_string(datatype.getRaw()).c_str();
275291a7539STim Bradgate
2762382bc00STrond Norbye    return ret;
277a7de3cd0STrond Norbye}
278b73a9caaSDave Rigby
2794caaa1b8STrond Norbyevoid Connection::setDCP(bool dcp) {
2804caaa1b8STrond Norbye    Connection::dcp = dcp;
2814caaa1b8STrond Norbye
2824caaa1b8STrond Norbye    if (isSslEnabled()) {
2834caaa1b8STrond Norbye        try {
2844caaa1b8STrond Norbye            // Make sure that we have space for up to a single TLS frame
2854caaa1b8STrond Norbye            // in our send buffer (so that we can stick all of the mutations
2864caaa1b8STrond Norbye            // in that buffer)
2874caaa1b8STrond Norbye            write->ensureCapacity(TlsFrameSize);
2884caaa1b8STrond Norbye        } catch (const std::bad_alloc&) {
2894caaa1b8STrond Norbye        }
2904caaa1b8STrond Norbye    }
2914caaa1b8STrond Norbye}
2924caaa1b8STrond Norbye
29307a55912STrond Norbyevoid Connection::restartAuthentication() {
2944e37ea4dSTrond Norbye    if (authenticated && domain == cb::sasl::Domain::External) {
2954e37ea4dSTrond Norbye        externalAuthManager->logoff(username);
2964e37ea4dSTrond Norbye    }
297c28ca74cSTrond Norbye    sasl_conn.reset();
2989850da39STrond Norbye    setInternal(false);
29907a55912STrond Norbye    authenticated = false;
30007a55912STrond Norbye    username = "";
3013b2a836dSTrond Norbye}
3023b2a836dSTrond Norbye
30374c314eaSTrond Norbyecb::engine_errc Connection::dropPrivilege(cb::rbac::Privilege privilege) {
30474c314eaSTrond Norbye    if (privilegeContext.dropPrivilege(privilege)) {
30574c314eaSTrond Norbye        return cb::engine_errc::success;
30674c314eaSTrond Norbye    }
30774c314eaSTrond Norbye
30874c314eaSTrond Norbye    return cb::engine_errc::no_access;
30974c314eaSTrond Norbye}
31074c314eaSTrond Norbye
31180f0b6a0STrond Norbyecb::rbac::PrivilegeAccess Connection::checkPrivilege(
31280f0b6a0STrond Norbye        cb::rbac::Privilege privilege, Cookie& cookie) {
313bcc7d962STrond Norbye    cb::rbac::PrivilegeAccess ret;
31488d2f9a0STrond Norbye    unsigned int retries = 0;
31588d2f9a0STrond Norbye    const unsigned int max_retries = 100;
316bcc7d962STrond Norbye
31788d2f9a0STrond Norbye    while ((ret = privilegeContext.check(privilege)) ==
31888d2f9a0STrond Norbye                   cb::rbac::PrivilegeAccess::Stale &&
31988d2f9a0STrond Norbye           retries < max_retries) {
32088d2f9a0STrond Norbye        ++retries;
3219811584cSTrond Norbye        const auto opcode = cookie.getRequest(Cookie::PacketContent::Header)
3229811584cSTrond Norbye                                    .getClientOpcode();
3239811584cSTrond Norbye        const std::string command(to_string(opcode));
324bcc7d962STrond Norbye
325bcc7d962STrond Norbye        // The privilege context we had could have been a dummy entry
326bcc7d962STrond Norbye        // (created when the client connected, and used until the
327bcc7d962STrond Norbye        // connection authenticates). Let's try to automatically update it,
328bcc7d962STrond Norbye        // but let the client deal with whatever happens after
329bcc7d962STrond Norbye        // a single update.
330bcc7d962STrond Norbye        try {
3311467b7d1STrond Norbye            privilegeContext = cb::rbac::createContext(
3321467b7d1STrond Norbye                    getUsername(), getDomain(), all_buckets[bucketIndex].name);
333682d2e38STim Bradgate        } catch (const cb::rbac::NoSuchBucketException&) {
334bcc7d962STrond Norbye            // Remove all access to the bucket
3351467b7d1STrond Norbye            privilegeContext =
3361467b7d1STrond Norbye                    cb::rbac::createContext(getUsername(), getDomain(), "");
3374dd9b0f4STrond Norbye            LOG_INFO(
338bf74734dSTrond Norbye                    "{}: RBAC: Connection::checkPrivilege({}) {} No access "
339bf74734dSTrond Norbye                    "to "
3404dd9b0f4STrond Norbye                    "bucket [{}]. command: [{}] new privilege set: {}",
3414dd9b0f4STrond Norbye                    getId(),
3424dd9b0f4STrond Norbye                    to_string(privilege),
3434dd9b0f4STrond Norbye                    getDescription(),
3444dd9b0f4STrond Norbye                    all_buckets[bucketIndex].name,
3454dd9b0f4STrond Norbye                    command,
3464dd9b0f4STrond Norbye                    privilegeContext.to_string());
347bcc7d962STrond Norbye        } catch (const cb::rbac::Exception& error) {
3484dd9b0f4STrond Norbye            LOG_WARNING(
3494dd9b0f4STrond Norbye                    "{}: RBAC: Connection::checkPrivilege({}) {}: An "
3504dd9b0f4STrond Norbye                    "exception occurred. command: [{}] bucket: [{}] UUID:"
3514dd9b0f4STrond Norbye                    "[{}] message: {}",
3524dd9b0f4STrond Norbye                    getId(),
3534dd9b0f4STrond Norbye                    to_string(privilege),
3544dd9b0f4STrond Norbye                    getDescription(),
3554dd9b0f4STrond Norbye                    command,
3564dd9b0f4STrond Norbye                    all_buckets[bucketIndex].name,
3574dd9b0f4STrond Norbye                    cookie.getEventId(),
3584dd9b0f4STrond Norbye                    error.what());
35980f0b6a0STrond Norbye            // Add a textual error as well
36080f0b6a0STrond Norbye            cookie.setErrorContext("An exception occurred. command: [" +
36180f0b6a0STrond Norbye                                   command + "]");
362bcc7d962STrond Norbye            return cb::rbac::PrivilegeAccess::Fail;
363bcc7d962STrond Norbye        }
36488d2f9a0STrond Norbye    }
3653b2a836dSTrond Norbye
36688d2f9a0STrond Norbye    if (retries == max_retries) {
3674dd9b0f4STrond Norbye        LOG_INFO(
3684dd9b0f4STrond Norbye                "{}: RBAC: Gave up rebuilding privilege context after {} "
3694dd9b0f4STrond Norbye                "times. Let the client handle the stale authentication "
3704dd9b0f4STrond Norbye                "context",
3714dd9b0f4STrond Norbye                getId(),
3724dd9b0f4STrond Norbye                retries);
37388d2f9a0STrond Norbye
37488d2f9a0STrond Norbye    } else if (retries > 1) {
3754dd9b0f4STrond Norbye        LOG_INFO("{}: RBAC: Had to rebuild privilege context {} times",
3764dd9b0f4STrond Norbye                 getId(),
3774dd9b0f4STrond Norbye                 retries);
3783b2a836dSTrond Norbye    }
3793b2a836dSTrond Norbye
380bcc7d962STrond Norbye    if (ret == cb::rbac::PrivilegeAccess::Fail) {
3819811584cSTrond Norbye        const auto opcode = cookie.getRequest(Cookie::PacketContent::Header)
3829811584cSTrond Norbye                                    .getClientOpcode();
3839811584cSTrond Norbye        const std::string command(to_string(opcode));
38432e7ac32STrond Norbye        const std::string privilege_string = cb::rbac::to_string(privilege);
38532e7ac32STrond Norbye        const std::string context = privilegeContext.to_string();
38632e7ac32STrond Norbye
38719748396SDave Rigby        if (Settings::instance().isPrivilegeDebug()) {
388ae68161aSTrond Norbye            audit_privilege_debug(*this,
38988d2f9a0STrond Norbye                                  command,
39088d2f9a0STrond Norbye                                  all_buckets[bucketIndex].name,
39188d2f9a0STrond Norbye                                  privilege_string,
39288d2f9a0STrond Norbye                                  context);
39332e7ac32STrond Norbye
3944dd9b0f4STrond Norbye            LOG_INFO(
3954dd9b0f4STrond Norbye                    "{}: RBAC privilege debug:{} command:[{}] bucket:[{}] "
3964dd9b0f4STrond Norbye                    "privilege:[{}] context:{}",
3974dd9b0f4STrond Norbye                    getId(),
3984dd9b0f4STrond Norbye                    getDescription(),
3994dd9b0f4STrond Norbye                    command,
4004dd9b0f4STrond Norbye                    all_buckets[bucketIndex].name,
4014dd9b0f4STrond Norbye                    privilege_string,
4024dd9b0f4STrond Norbye                    context);
403a7697f09STrond Norbye
404bcc7d962STrond Norbye            return cb::rbac::PrivilegeAccess::Ok;
405bcc7d962STrond Norbye        } else {
4064dd9b0f4STrond Norbye            LOG_INFO(
4074dd9b0f4STrond Norbye                    "{} RBAC {} missing privilege {} for {} in bucket:[{}] "
4084dd9b0f4STrond Norbye                    "with context: "
409248da911STrond Norbye                    "{} UUID:[{}]",
4104dd9b0f4STrond Norbye                    getId(),
4114dd9b0f4STrond Norbye                    getDescription(),
4124dd9b0f4STrond Norbye                    privilege_string,
4134dd9b0f4STrond Norbye                    command,
4144dd9b0f4STrond Norbye                    all_buckets[bucketIndex].name,
4154dd9b0f4STrond Norbye                    context,
4164dd9b0f4STrond Norbye                    cookie.getEventId());
41780f0b6a0STrond Norbye            // Add a textual error as well
41880f0b6a0STrond Norbye            cookie.setErrorContext("Authorization failure: can't execute " +
41980f0b6a0STrond Norbye                                   command + " operation without the " +
42080f0b6a0STrond Norbye                                   privilege_string + " privilege");
421bcc7d962STrond Norbye        }
4223b2a836dSTrond Norbye    }
4233b2a836dSTrond Norbye
424bcc7d962STrond Norbye    return ret;
42507a55912STrond Norbye}
42637950946STrond Norbye
42737950946STrond NorbyeBucket& Connection::getBucket() const {
42837950946STrond Norbye    return all_buckets[getBucketIndex()];
42937950946STrond Norbye}
430cede2f7fSTrond Norbye
43136bef511STrond NorbyeEngineIface* Connection::getBucketEngine() const {
43236bef511STrond Norbye    return getBucket().getEngine();
43336bef511STrond Norbye}
43436bef511STrond Norbye
43530f89a8dSTrond NorbyeENGINE_ERROR_CODE Connection::remapErrorCode(ENGINE_ERROR_CODE code) {
436cede2f7fSTrond Norbye    if (xerror_support) {
437cede2f7fSTrond Norbye        return code;
438cede2f7fSTrond Norbye    }
439cede2f7fSTrond Norbye
440cede2f7fSTrond Norbye    // Check our whitelist
441cede2f7fSTrond Norbye    switch (code) {
442cede2f7fSTrond Norbye    case ENGINE_SUCCESS: // FALLTHROUGH
443cede2f7fSTrond Norbye    case ENGINE_KEY_ENOENT: // FALLTHROUGH
444cede2f7fSTrond Norbye    case ENGINE_KEY_EEXISTS: // FALLTHROUGH
445cede2f7fSTrond Norbye    case ENGINE_ENOMEM: // FALLTHROUGH
446cede2f7fSTrond Norbye    case ENGINE_NOT_STORED: // FALLTHROUGH
447cede2f7fSTrond Norbye    case ENGINE_EINVAL: // FALLTHROUGH
448cede2f7fSTrond Norbye    case ENGINE_ENOTSUP: // FALLTHROUGH
449cede2f7fSTrond Norbye    case ENGINE_EWOULDBLOCK: // FALLTHROUGH
450cede2f7fSTrond Norbye    case ENGINE_E2BIG: // FALLTHROUGH
451cede2f7fSTrond Norbye    case ENGINE_DISCONNECT: // FALLTHROUGH
452cede2f7fSTrond Norbye    case ENGINE_NOT_MY_VBUCKET: // FALLTHROUGH
453cede2f7fSTrond Norbye    case ENGINE_TMPFAIL: // FALLTHROUGH
454cede2f7fSTrond Norbye    case ENGINE_ERANGE: // FALLTHROUGH
455cede2f7fSTrond Norbye    case ENGINE_ROLLBACK: // FALLTHROUGH
456cede2f7fSTrond Norbye    case ENGINE_EBUSY: // FALLTHROUGH
457cede2f7fSTrond Norbye    case ENGINE_DELTA_BADVAL: // FALLTHROUGH
4588f9005d0SJim Walker    case ENGINE_PREDICATE_FAILED:
459cede2f7fSTrond Norbye    case ENGINE_FAILED:
460cede2f7fSTrond Norbye        return code;
461463b4257STrond Norbye
462463b4257STrond Norbye    case ENGINE_LOCKED:
463463b4257STrond Norbye        return ENGINE_KEY_EEXISTS;
464463b4257STrond Norbye    case ENGINE_LOCKED_TMPFAIL:
465463b4257STrond Norbye        return ENGINE_TMPFAIL;
466e9b529a1SJim Walker    case ENGINE_UNKNOWN_COLLECTION:
4680fba613eSJim Walker        return isCollectionsSupported() ? code : ENGINE_EINVAL;
469463b4257STrond Norbye
4707bbec2a4STrond Norbye    case ENGINE_EACCESS:break;
4717bbec2a4STrond Norbye    case ENGINE_NO_BUCKET:break;
4727bbec2a4STrond Norbye    case ENGINE_AUTH_STALE:break;
473d94c783aSBen Huddleston    case ENGINE_DURABILITY_INVALID_LEVEL:
4747b392b1fSTrond Norbye    case ENGINE_DURABILITY_IMPOSSIBLE:
4759c27fb91SJim Walker    case ENGINE_SYNC_WRITE_PENDING:
4767b392b1fSTrond Norbye        break;
4777b392b1fSTrond Norbye    case ENGINE_SYNC_WRITE_IN_PROGRESS:
4797b392b1fSTrond Norbye        // we can return tmpfail to old clients and have them retry the
4807b392b1fSTrond Norbye        // operation
4817b392b1fSTrond Norbye        return ENGINE_TMPFAIL;
4827b392b1fSTrond Norbye    case ENGINE_SYNC_WRITE_AMBIGUOUS:
48308f0680dSJim Walker    case ENGINE_DCP_STREAMID_INVALID:
4847b392b1fSTrond Norbye        break;
4857bbec2a4STrond Norbye    }
4867bbec2a4STrond Norbye
4875e05a536STrond Norbye    // Seems like the rest of the components in our system isn't
4885e05a536STrond Norbye    // prepared to receive access denied or authentincation stale.
4895e05a536STrond Norbye    // For now we should just disconnect them
4907bbec2a4STrond Norbye    auto errc = cb::make_error_condition(cb::engine_errc(code));
4912c5306dbSPaolo Cocchi    LOG_WARNING(
4924dd9b0f4STrond Norbye            "{} - Client {} not aware of extended error code ({}). "
4934dd9b0f4STrond Norbye            "Disconnecting",
4944dd9b0f4STrond Norbye            getId(),
4954dd9b0f4STrond Norbye            getDescription().c_str(),
4964dd9b0f4STrond Norbye            errc.message().c_str());
49730f89a8dSTrond Norbye    setTerminationReason("XError not enabled on client");
498cede2f7fSTrond Norbye
4997bbec2a4STrond Norbye    return ENGINE_DISCONNECT;
500cede2f7fSTrond Norbye}
501a969c7dcSTrond Norbye
502b177f95dSTrond Norbyevoid Connection::resetUsernameCache() {
503c28ca74cSTrond Norbye    if (sasl_conn.isInitialized()) {
504c28ca74cSTrond Norbye        username = sasl_conn.getUsername();
505c28ca74cSTrond Norbye        domain = sasl_conn.getDomain();
506c28ca74cSTrond Norbye    } else {
507c28ca74cSTrond Norbye        username = "unknown";
508c28ca74cSTrond Norbye        domain = cb::sasl::Domain::Local;
509b177f95dSTrond Norbye    }
510b177f95dSTrond Norbye
511b177f95dSTrond Norbye    updateDescription();
512b177f95dSTrond Norbye}
513b177f95dSTrond Norbye
514a969c7dcSTrond Norbyevoid Connection::updateDescription() {
515a969c7dcSTrond Norbye    description.assign("[ " + getPeername() + " - " + getSockname());
516a969c7dcSTrond Norbye    if (authenticated) {
517a969c7dcSTrond Norbye        description += " (";
518a969c7dcSTrond Norbye        if (isInternal()) {
519a969c7dcSTrond Norbye            description += "System, ";
520a969c7dcSTrond Norbye        }
521f085f6ecSChristopher Farman        description += cb::tagUserData(getUsername());
522d887bf62STrond Norbye
523077fcf9aSTrond Norbye        if (domain == cb::sasl::Domain::External) {
524d887bf62STrond Norbye            description += " (LDAP)";
525d887bf62STrond Norbye        }
526a969c7dcSTrond Norbye        description += ")";
527a969c7dcSTrond Norbye    } else {
528a969c7dcSTrond Norbye        description += " (not authenticated)";
529a969c7dcSTrond Norbye    }
530a969c7dcSTrond Norbye    description += " ]";
531a969c7dcSTrond Norbye}
53288898db5STrond Norbye
53388898db5STrond Norbyevoid Connection::setBucketIndex(int bucketIndex) {
53488898db5STrond Norbye    Connection::bucketIndex.store(bucketIndex, std::memory_order_relaxed);
53588898db5STrond Norbye
53688898db5STrond Norbye    // Update the privilege context. If a problem occurs within the RBAC
53788898db5STrond Norbye    // module we'll assign an empty privilege context to the connection.
53888898db5STrond Norbye    try {
53988898db5STrond Norbye        if (authenticated) {