text: // Licensed to the Apache Software Foundation (ASF) under one
  // or more contributor license agreements.  See the NOTICE file
  // distributed with this work for additional information
  // regarding copyright ownership.  The ASF licenses this file
  // to you under the Apache License, Version 2.0 (the
  // "License"); you may not use this file except in compliance
  // with the License.  You may obtain a copy of the License at
  //
  //   http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing,
  // software distributed under the License is distributed on an
  // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  // KIND, either express or implied.  See the License for the
  // specific language governing permissions and limitations
  // under the License.
  #pragma once
  
  #include <cstddef>
  #include <cstdint>
  #include <functional>
  #include <set>
  #include <string>
  
  #include <sasl/sasl.h>
  
  #include "kudu/gutil/port.h"
  #include "kudu/util/slice.h"
  #include "kudu/util/status.h"
  
  #if defined(__APPLE__)
  // Almost all functions in the SASL API are marked as deprecated
  // since macOS 10.11.
  #pragma GCC diagnostic push
  #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
  #endif // #if defined(__APPLE__)
  
  namespace kudu {
  
  class Sockaddr;
  
  namespace rpc {
  
  // Constants
  extern const char* const kSaslMechPlain;
  extern const char* const kSaslMechGSSAPI;
  extern const size_t kSaslMaxBufSize;
  
  struct SaslMechanism {
    enum Type {
      INVALID,
      PLAIN,
      GSSAPI
    };
    static Type value_of(const std::string& mech);
    static const char* name_of(Type val);
  };
  
  struct SaslProtection {
    enum Type {
      // SASL authentication without integrity or privacy.
      kAuthentication = 0,
      // Integrity protection, i.e. messages are HMAC'd.
      kIntegrity = 1,
      // Privacy protection, i.e. messages are encrypted.
      kPrivacy = 2,
    };
    static const char* name_of(Type val);
  };
  
  // Initialize the SASL library.
  // appname: Name of the application for logging messages & sasl plugin configuration.
  //          Note that this string must remain allocated for the lifetime of the program.
  // This function must be called before using SASL.
  // If the library initializes without error, calling more than once has no effect.
  //
  // Some SASL plugins take time to initialize random number generators and other things,
  // so the first time this function is invoked it may execute for several seconds.
  // After that, it should be very fast. This function should be invoked as early as possible
  // in the application lifetime to avoid SASL initialization taking place in a
  // performance-critical section.
  //
  // This function is thread safe and uses a static lock.
  // This function should NOT be called during static initialization.
  Status SaslInit(bool kerberos_keytab_provided = false) WARN_UNUSED_RESULT;
  
  // Disable Kudu's initialization of SASL. See equivalent method in client.h.
  Status DisableSaslInitialization() WARN_UNUSED_RESULT;
  
  // Wrap a call into the SASL library. 'call' should be a lambda which
  // returns a SASL error code, 'conn' is the SASL connection to perform
  // the operation with (might be null), and 'description' is be a description
  // of the SASL call (e.g., the name of the SASL library function).
  //
  // The result is translated into a Status as follows:
  //
  //  SASL_OK:       Status::OK()
  //  SASL_CONTINUE: Status::Incomplete()
  //  otherwise:     Status::NotAuthorized()
  //
  // The Status message is beautified to be more user-friendly compared
  // to the underlying sasl_errdetails() call.
  Status WrapSaslCall(sasl_conn_t* conn,
                      const std::function<int()>& call,
                      const char* description) WARN_UNUSED_RESULT;
  
  // Return <ip>;<port> string formatted for SASL library use.
  std::string SaslIpPortString(const Sockaddr& addr);
  
  // Return available plugin mechanisms for the given connection.
  std::set<SaslMechanism::Type> SaslListAvailableMechs();
  
  // Initialize and return a libsasl2 callback data structure based on the passed args.
  // id: A SASL callback identifier (e.g., SASL_CB_GETOPT).
  // proc: A C-style callback with appropriate signature based on the callback id, or NULL.
  // context: An object to pass to the callback as the context pointer, or NULL.
  sasl_callback_t SaslBuildCallback(int id, int (*proc)(void), void* context);
  
  // Enable SASL integrity and privacy protection on the connection. Also allows
  // setting the minimum required protection level, and the maximum receive buffer
  // size.
  Status EnableProtection(sasl_conn_t* sasl_conn,
                          SaslProtection::Type minimum_protection = SaslProtection::kAuthentication,
                          size_t max_recv_buf_size = kSaslMaxBufSize) WARN_UNUSED_RESULT;
  
  // Returns true if the SASL connection has been negotiated with auth-int or
  // auth-conf. 'sasl_conn' must already be negotiated.
  bool NeedsWrap(sasl_conn_t* sasl_conn);
  
  // Retrieves the negotiated maximum send buffer size for auth-int or auth-conf
  // protected channels.
  uint32_t GetMaxSendBufferSize(sasl_conn_t* sasl_conn) WARN_UNUSED_RESULT;
  
  // Encode the provided data.
  //
  // The plaintext data must not be longer than the negotiated maximum buffer size.
  //
  // The output 'ciphertext' slice is only valid until the next use of the SASL connection.
  Status SaslEncode(sasl_conn_t* conn,
                    Slice plaintext,
                    Slice* ciphertext) WARN_UNUSED_RESULT;
  
  // Decode the provided SASL-encoded data.
  //
  // The decoded plaintext must not be longer than the negotiated maximum buffer size.
  //
  // The output 'plaintext' slice is only valid until the next use of the SASL connection.
  Status SaslDecode(sasl_conn_t* conn,
                    Slice ciphertext,
                    Slice* plaintext) WARN_UNUSED_RESULT;
  
  // Deleter for sasl_conn_t instances, for use with unique_ptr after calling sasl_*_new().
  struct SaslDeleter {
    inline void operator()(sasl_conn_t* conn) {
      sasl_dispose(&conn);
    }
  };
  
  // Internals exposed in the header for test purposes.
  namespace internal {
  void SaslSetMutex();
  } // namespace internal
  
  } // namespace rpc
  } // namespace kudu
  
  #if defined(__APPLE__)
  #pragma GCC diagnostic pop
  #endif // #if defined(__APPLE__)
  