text: /*    Copyright 2012 10gen Inc.
   *
   *    Licensed 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 <string>
  
  #include "mongo/base/disallow_copying.h"
  #include "mongo/base/status.h"
  #include "mongo/base/string_data.h"
  #include "mongo/platform/cstdint.h"  // Must be included before <gsasl.h> because of SERVER-8086
  
  #include <gsasl.h>  // Must be included after "mongo/platform/cstdint.h" because of SERVER-8086.
  
  namespace mongo {
  
      /**
       * C++ wrapper around Gsasl_session.
       */
      class GsaslSession {
          MONGO_DISALLOW_COPYING(GsaslSession);
      public:
          GsaslSession();
          ~GsaslSession();
  
          /**
           * Initializes "this" as a client sasl session.
           *
           * May only be called once on an instance of GsaslSession, and may not be called on an
           * instance on which initializeServerSession has been called.
           *
           * "gsasl" is a pointer to a Gsasl library context that will exist for the rest of
           * the lifetime of "this".
           *
           * "mechanism" is a SASL mechanism name.
           *
           * "sessionHook" is user-supplied data associated with this session.  If is accessible in
           * the gsasl callback set on "gsasl" using gsasl_session_hook_get().  May be NULL.  Owned
           * by caller, and must stay in scope as long as this object.
           *
           * Returns Status::OK() on success, some other status on errors.
           */
          Status initializeClientSession(Gsasl* gsasl,
                                         const StringData& mechanism,
                                         void* sessionHook);
  
          /**
           * Initializes "this" as a server sasl session.
           *
           * May only be called once on an instance of GsaslSession, and may not be called on an
           * instance on which initializeClientSession has been called.
           *
           * "gsasl" is a pointer to a Gsasl library context that will exist for the rest of
           * the lifetime of "this".
           *
           * "mechanism" is a SASL mechanism name.
           *
           * "sessionHook" is user-supplied data associated with this session.  If is accessible in
           * the gsasl callback set on "gsasl" using gsasl_session_hook_get().  May be NULL.  Owned
           * by caller, and must stay in scope as long as this object.
           *
           * Returns Status::OK() on success, some other status on errors.
           */
          Status initializeServerSession(Gsasl* gsasl,
                                         const StringData& mechanism,
                                         void* sessionHook);
  
          /**
           * Returns the string name of the SASL mechanism in use in this session.
           *
           * Not valid before initializeServerSession() or initializeClientSession().
           */
          std::string getMechanism() const;
  
          /**
           * Sets a property on this session.
           *
           * Not valid before initializeServerSession() or initializeClientSession().
           */
          void setProperty(Gsasl_property property, const StringData& value);
  
          /**
           * Gets a property on this session.  Return an empty string if the property isn't set.
           *
           * Not valid before initializeServerSession() or initializeClientSession().
           */
          const std::string getProperty(Gsasl_property property) const;
  
          /**
           * Performs one more step on this session.
           *
           * Receives "inputData" from the other side and produces "*outputData" to send.
           *
           * Both "inputData" and "*outputData" are logically strings of bytes, not characters.
           *
           * For the first step by the authentication initiator, "inputData" should have 0 length.
           *
           * Returns Status::OK() on success.  In that case, isDone() can be queried to see if the
           * session expects another call to step().  If isDone() is true, the authentication has
           * completed successfully.
           *
           * Any return other than Status::OK() means that authentication has failed, but the specific
           * code or reason message may provide insight as to why.
           */
          Status step(const StringData& inputData, std::string* outputData);
  
          /**
           * Returns true if this session has completed successfully.
           *
           * That is, returns true if the session expects no more calls to step(), and all previous
           * calls to step() and initializeClientSession()/initializeServerSession() have returned
           * Status::OK().
           */
          bool isDone() const { return _done; }
  
      private:
          // Signature of gsas session start functions.
          typedef int (*GsaslSessionStartFn)(Gsasl*, const char*, Gsasl_session**);
  
          /**
           * Common helper code for initializing a session.
           *
           * Uses "sessionStartFn" to initialize the underlying Gsasl_session.
           */
          Status _initializeSession(GsaslSessionStartFn sessionStartFn,
                                    Gsasl* gsasl, const StringData& mechanism, void* sessionHook);
  
          /// Underlying C-library gsasl session object.
          Gsasl_session* _gsaslSession;
  
          /// See isDone(), above.
          bool _done;
      };
  
  }  // namespace mongo
  