gsasl_engine.cc 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. #include "hdfspp/locks.h"
  19. #include <sstream>
  20. #include <gsasl.h>
  21. #include "sasl_engine.h"
  22. #include "gsasl_engine.h"
  23. #include "common/logging.h"
  24. namespace hdfs {
  25. /*****************************************************************************
  26. * GSASL UTILITY FUNCTIONS
  27. */
  28. static Mutex *getSaslMutex() {
  29. return LockManager::getGssapiMutex();
  30. }
  31. static Status rc_to_status(int rc)
  32. {
  33. if (rc == GSASL_OK) {
  34. return Status::OK();
  35. } else {
  36. std::ostringstream ss;
  37. ss << "Cannot initialize client (" << rc << "): " << gsasl_strerror(rc);
  38. return Status::Error(ss.str().c_str());
  39. }
  40. }
  41. static
  42. std::pair<Status, std::string> base64_encode(const std::string & in) {
  43. char * temp;
  44. size_t len;
  45. std::string retval;
  46. (void)base64_encode;
  47. int rc = gsasl_base64_to(in.c_str(), in.size(), &temp, &len);
  48. if (rc != GSASL_OK) {
  49. return std::make_pair(rc_to_status(rc), "");
  50. }
  51. if (temp) {
  52. retval = temp;
  53. free(temp);
  54. }
  55. if (!temp || retval.length() != len) {
  56. return std::make_pair(Status::Error("SaslEngine: Failed to encode string to base64"), "");
  57. }
  58. return std::make_pair(Status::OK(), retval);
  59. }
  60. /*****************************************************************************
  61. * GSASL ENGINE
  62. */
  63. GSaslEngine::~GSaslEngine()
  64. {
  65. // These should already be called in this->Finish
  66. try {
  67. LockGuard saslGuard(getSaslMutex());
  68. if (session_ != nullptr) {
  69. gsasl_finish(session_);
  70. }
  71. if (ctx_ != nullptr) {
  72. gsasl_done(ctx_);
  73. }
  74. } catch (const LockFailure& e) {
  75. if(session_ || ctx_) {
  76. LOG_ERROR(kRPC, << "GSaslEngine::~GSaslEngine@" << this << " unable to dispose of gsasl state: " << e.what());
  77. }
  78. }
  79. }
  80. Status GSaslEngine::gsasl_new() {
  81. int status = GSASL_OK;
  82. if (ctx_) return Status::OK();
  83. try {
  84. LockGuard saslGuard(getSaslMutex());
  85. status = gsasl_init( & ctx_);
  86. } catch (const LockFailure& e) {
  87. return Status::MutexError("Mutex that guards gsasl_init unable to lock");
  88. }
  89. switch ( status) {
  90. case GSASL_OK:
  91. return Status::OK();
  92. case GSASL_MALLOC_ERROR:
  93. LOG_WARN(kRPC, << "GSaslEngine: Out of memory.");
  94. return Status::Error("SaslEngine: Out of memory.");
  95. default:
  96. LOG_WARN(kRPC, << "GSaslEngine: Unexpected error." << status);
  97. return Status::Error("SaslEngine: Unexpected error.");
  98. }
  99. } // gsasl_new()
  100. std::pair<Status, std::string>
  101. GSaslEngine::Start()
  102. {
  103. int rc;
  104. Status status;
  105. this->gsasl_new();
  106. /* Create new authentication session. */
  107. try {
  108. LockGuard saslGuard(getSaslMutex());
  109. rc = gsasl_client_start(ctx_, chosen_mech_.mechanism.c_str(), &session_);
  110. } catch (const LockFailure& e) {
  111. state_ = kErrorState;
  112. return std::make_pair(Status::MutexError("Mutex that guards gsasl_client_start unable to lock"), "");
  113. }
  114. if (rc != GSASL_OK) {
  115. state_ = kErrorState;
  116. return std::make_pair( rc_to_status( rc), std::string(""));
  117. }
  118. Status init_status = init_kerberos();
  119. if(!init_status.ok()) {
  120. state_ = kErrorState;
  121. return std::make_pair(init_status, "");
  122. }
  123. state_ = kWaitingForData;
  124. // get from the sasl library the initial token
  125. // that we'll send to the application server:
  126. return this->Step( chosen_mech_.challenge.c_str());
  127. } // start() method
  128. Status GSaslEngine::init_kerberos() {
  129. //TODO: check that we have a principal
  130. try {
  131. LockGuard saslGuard(getSaslMutex());
  132. // these don't return anything that indicates failure
  133. gsasl_property_set(session_, GSASL_AUTHID, principal_.value().c_str());
  134. gsasl_property_set(session_, GSASL_HOSTNAME, chosen_mech_.serverid.c_str());
  135. gsasl_property_set(session_, GSASL_SERVICE, chosen_mech_.protocol.c_str());
  136. } catch (const LockFailure& e) {
  137. return Status::MutexError("Mutex that guards gsasl_property_set in GSaslEngine::init_kerberos unable to lock");
  138. }
  139. return Status::OK();
  140. }
  141. std::pair<Status, std::string> GSaslEngine::Step(const std::string data) {
  142. if (state_ != kWaitingForData)
  143. LOG_WARN(kRPC, << "GSaslEngine::step when state is " << state_);
  144. char * output = NULL;
  145. size_t outputSize;
  146. int rc = 0;
  147. try {
  148. LockGuard saslGuard(getSaslMutex());
  149. rc = gsasl_step(session_, data.c_str(), data.size(), &output,
  150. &outputSize);
  151. } catch (const LockFailure& e) {
  152. state_ = kFailure;
  153. return std::make_pair(Status::MutexError("Mutex that guards gsasl_client_start unable to lock"), "");
  154. }
  155. if (rc == GSASL_NEEDS_MORE || rc == GSASL_OK) {
  156. std::string retval(output, output ? outputSize : 0);
  157. if (output) {
  158. free(output);
  159. }
  160. if (rc == GSASL_OK) {
  161. state_ = kSuccess;
  162. }
  163. return std::make_pair(Status::OK(), retval);
  164. }
  165. else {
  166. if (output) {
  167. free(output);
  168. }
  169. state_ = kFailure;
  170. return std::make_pair(rc_to_status(rc), "");
  171. }
  172. }
  173. Status GSaslEngine::Finish()
  174. {
  175. if (state_ != kSuccess && state_ != kFailure && state_ != kErrorState )
  176. LOG_WARN(kRPC, << "GSaslEngine::finish when state is " << state_);
  177. try {
  178. LockGuard saslGuard(getSaslMutex());
  179. if (session_ != nullptr) {
  180. gsasl_finish(session_);
  181. session_ = NULL;
  182. }
  183. if (ctx_ != nullptr) {
  184. gsasl_done(ctx_);
  185. ctx_ = nullptr;
  186. }
  187. } catch (const LockFailure& e) {
  188. return Status::MutexError("Mutex that guards sasl state cleanup in GSaslEngine::Finish unable to lock");
  189. }
  190. return Status::OK();
  191. } // finish() method
  192. } // namespace hdfs