1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/extensions/auth/nsAuthGSSAPI.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,607 @@ 1.4 +/* vim:set ts=4 sw=4 sts=4 et cindent: */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +// 1.10 +// GSSAPI Authentication Support Module 1.11 +// 1.12 +// Described by IETF Internet draft: draft-brezak-kerberos-http-00.txt 1.13 +// (formerly draft-brezak-spnego-http-04.txt) 1.14 +// 1.15 +// Also described here: 1.16 +// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnsecure/html/http-sso-1.asp 1.17 +// 1.18 +// 1.19 + 1.20 +#include "mozilla/ArrayUtils.h" 1.21 + 1.22 +#include "prlink.h" 1.23 +#include "nsCOMPtr.h" 1.24 +#include "nsIPrefService.h" 1.25 +#include "nsIPrefBranch.h" 1.26 +#include "nsIServiceManager.h" 1.27 +#include "nsNativeCharsetUtils.h" 1.28 +#include "mozilla/Telemetry.h" 1.29 + 1.30 +#include "nsAuthGSSAPI.h" 1.31 + 1.32 +#ifdef XP_MACOSX 1.33 +#include <Kerberos/Kerberos.h> 1.34 +#endif 1.35 + 1.36 +#ifdef XP_MACOSX 1.37 +typedef KLStatus (*KLCacheHasValidTickets_type)( 1.38 + KLPrincipal, 1.39 + KLKerberosVersion, 1.40 + KLBoolean *, 1.41 + KLPrincipal *, 1.42 + char **); 1.43 +#endif 1.44 + 1.45 +#if defined(HAVE_RES_NINIT) 1.46 +#include <sys/types.h> 1.47 +#include <netinet/in.h> 1.48 +#include <arpa/nameser.h> 1.49 +#include <resolv.h> 1.50 +#endif 1.51 + 1.52 +using namespace mozilla; 1.53 + 1.54 +//----------------------------------------------------------------------------- 1.55 + 1.56 +// We define GSS_C_NT_HOSTBASED_SERVICE explicitly since it may be referenced 1.57 +// by by a different name depending on the implementation of gss but always 1.58 +// has the same value 1.59 + 1.60 +static gss_OID_desc gss_c_nt_hostbased_service = 1.61 + { 10, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04" }; 1.62 + 1.63 +static const char kNegotiateAuthGssLib[] = 1.64 + "network.negotiate-auth.gsslib"; 1.65 +static const char kNegotiateAuthNativeImp[] = 1.66 + "network.negotiate-auth.using-native-gsslib"; 1.67 + 1.68 +static struct GSSFunction { 1.69 + const char *str; 1.70 + PRFuncPtr func; 1.71 +} gssFuncs[] = { 1.72 + { "gss_display_status", nullptr }, 1.73 + { "gss_init_sec_context", nullptr }, 1.74 + { "gss_indicate_mechs", nullptr }, 1.75 + { "gss_release_oid_set", nullptr }, 1.76 + { "gss_delete_sec_context", nullptr }, 1.77 + { "gss_import_name", nullptr }, 1.78 + { "gss_release_buffer", nullptr }, 1.79 + { "gss_release_name", nullptr }, 1.80 + { "gss_wrap", nullptr }, 1.81 + { "gss_unwrap", nullptr } 1.82 +}; 1.83 + 1.84 +static bool gssNativeImp = true; 1.85 +static PRLibrary* gssLibrary = nullptr; 1.86 + 1.87 +#define gss_display_status_ptr ((gss_display_status_type)*gssFuncs[0].func) 1.88 +#define gss_init_sec_context_ptr ((gss_init_sec_context_type)*gssFuncs[1].func) 1.89 +#define gss_indicate_mechs_ptr ((gss_indicate_mechs_type)*gssFuncs[2].func) 1.90 +#define gss_release_oid_set_ptr ((gss_release_oid_set_type)*gssFuncs[3].func) 1.91 +#define gss_delete_sec_context_ptr ((gss_delete_sec_context_type)*gssFuncs[4].func) 1.92 +#define gss_import_name_ptr ((gss_import_name_type)*gssFuncs[5].func) 1.93 +#define gss_release_buffer_ptr ((gss_release_buffer_type)*gssFuncs[6].func) 1.94 +#define gss_release_name_ptr ((gss_release_name_type)*gssFuncs[7].func) 1.95 +#define gss_wrap_ptr ((gss_wrap_type)*gssFuncs[8].func) 1.96 +#define gss_unwrap_ptr ((gss_unwrap_type)*gssFuncs[9].func) 1.97 + 1.98 +#ifdef XP_MACOSX 1.99 +static PRFuncPtr KLCacheHasValidTicketsPtr; 1.100 +#define KLCacheHasValidTickets_ptr \ 1.101 + ((KLCacheHasValidTickets_type)*KLCacheHasValidTicketsPtr) 1.102 +#endif 1.103 + 1.104 +static nsresult 1.105 +gssInit() 1.106 +{ 1.107 + nsXPIDLCString libPath; 1.108 + nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); 1.109 + if (prefs) { 1.110 + prefs->GetCharPref(kNegotiateAuthGssLib, getter_Copies(libPath)); 1.111 + prefs->GetBoolPref(kNegotiateAuthNativeImp, &gssNativeImp); 1.112 + } 1.113 + 1.114 + PRLibrary *lib = nullptr; 1.115 + 1.116 + if (!libPath.IsEmpty()) { 1.117 + LOG(("Attempting to load user specified library [%s]\n", libPath.get())); 1.118 + gssNativeImp = false; 1.119 + lib = PR_LoadLibrary(libPath.get()); 1.120 + } 1.121 + else { 1.122 +#ifdef XP_WIN 1.123 + char *libName = PR_GetLibraryName(nullptr, "gssapi32"); 1.124 + if (libName) { 1.125 + lib = PR_LoadLibrary("gssapi32"); 1.126 + PR_FreeLibraryName(libName); 1.127 + } 1.128 +#elif defined(__OpenBSD__) 1.129 + /* OpenBSD doesn't register inter-library dependencies in basesystem 1.130 + * libs therefor we need to load all the libraries gssapi depends on, 1.131 + * in the correct order and with LD_GLOBAL for GSSAPI auth to work 1.132 + * fine. 1.133 + */ 1.134 + 1.135 + const char *const verLibNames[] = { 1.136 + "libasn1.so", 1.137 + "libcrypto.so", 1.138 + "libroken.so", 1.139 + "libheimbase.so", 1.140 + "libcom_err.so", 1.141 + "libkrb5.so", 1.142 + "libgssapi.so" 1.143 + }; 1.144 + 1.145 + PRLibSpec libSpec; 1.146 + for (size_t i = 0; i < ArrayLength(verLibNames); ++i) { 1.147 + libSpec.type = PR_LibSpec_Pathname; 1.148 + libSpec.value.pathname = verLibNames[i]; 1.149 + lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_GLOBAL); 1.150 + }; 1.151 + 1.152 +#else 1.153 + 1.154 + const char *const libNames[] = { 1.155 + "gss", 1.156 + "gssapi_krb5", 1.157 + "gssapi" 1.158 + }; 1.159 + 1.160 + const char *const verLibNames[] = { 1.161 + "libgssapi_krb5.so.2", /* MIT - FC, Suse10, Debian */ 1.162 + "libgssapi.so.4", /* Heimdal - Suse10, MDK */ 1.163 + "libgssapi.so.1" /* Heimdal - Suse9, CITI - FC, MDK, Suse10*/ 1.164 + }; 1.165 + 1.166 + for (size_t i = 0; i < ArrayLength(verLibNames) && !lib; ++i) { 1.167 + lib = PR_LoadLibrary(verLibNames[i]); 1.168 + 1.169 + /* The CITI libgssapi library calls exit() during 1.170 + * initialization if it's not correctly configured. Try to 1.171 + * ensure that we never use this library for our GSSAPI 1.172 + * support, as its just a wrapper library, anyway. 1.173 + * See Bugzilla #325433 1.174 + */ 1.175 + if (lib && 1.176 + PR_FindFunctionSymbol(lib, 1.177 + "internal_krb5_gss_initialize") && 1.178 + PR_FindFunctionSymbol(lib, "gssd_pname_to_uid")) { 1.179 + LOG(("CITI libgssapi found, which calls exit(). Skipping\n")); 1.180 + PR_UnloadLibrary(lib); 1.181 + lib = nullptr; 1.182 + } 1.183 + } 1.184 + 1.185 + for (size_t i = 0; i < ArrayLength(libNames) && !lib; ++i) { 1.186 + char *libName = PR_GetLibraryName(nullptr, libNames[i]); 1.187 + if (libName) { 1.188 + lib = PR_LoadLibrary(libName); 1.189 + PR_FreeLibraryName(libName); 1.190 + 1.191 + if (lib && 1.192 + PR_FindFunctionSymbol(lib, 1.193 + "internal_krb5_gss_initialize") && 1.194 + PR_FindFunctionSymbol(lib, "gssd_pname_to_uid")) { 1.195 + LOG(("CITI libgssapi found, which calls exit(). Skipping\n")); 1.196 + PR_UnloadLibrary(lib); 1.197 + lib = nullptr; 1.198 + } 1.199 + } 1.200 + } 1.201 +#endif 1.202 + } 1.203 + 1.204 + if (!lib) { 1.205 + LOG(("Fail to load gssapi library\n")); 1.206 + return NS_ERROR_FAILURE; 1.207 + } 1.208 + 1.209 + LOG(("Attempting to load gss functions\n")); 1.210 + 1.211 + for (size_t i = 0; i < ArrayLength(gssFuncs); ++i) { 1.212 + gssFuncs[i].func = PR_FindFunctionSymbol(lib, gssFuncs[i].str); 1.213 + if (!gssFuncs[i].func) { 1.214 + LOG(("Fail to load %s function from gssapi library\n", gssFuncs[i].str)); 1.215 + PR_UnloadLibrary(lib); 1.216 + return NS_ERROR_FAILURE; 1.217 + } 1.218 + } 1.219 +#ifdef XP_MACOSX 1.220 + if (gssNativeImp && 1.221 + !(KLCacheHasValidTicketsPtr = 1.222 + PR_FindFunctionSymbol(lib, "KLCacheHasValidTickets"))) { 1.223 + LOG(("Fail to load KLCacheHasValidTickets function from gssapi library\n")); 1.224 + PR_UnloadLibrary(lib); 1.225 + return NS_ERROR_FAILURE; 1.226 + } 1.227 +#endif 1.228 + 1.229 + gssLibrary = lib; 1.230 + return NS_OK; 1.231 +} 1.232 + 1.233 +#if defined( PR_LOGGING ) 1.234 + 1.235 +// Generate proper GSSAPI error messages from the major and 1.236 +// minor status codes. 1.237 +void 1.238 +LogGssError(OM_uint32 maj_stat, OM_uint32 min_stat, const char *prefix) 1.239 +{ 1.240 + OM_uint32 new_stat; 1.241 + OM_uint32 msg_ctx = 0; 1.242 + gss_buffer_desc status1_string; 1.243 + gss_buffer_desc status2_string; 1.244 + OM_uint32 ret; 1.245 + nsAutoCString errorStr; 1.246 + errorStr.Assign(prefix); 1.247 + 1.248 + if (!gssLibrary) 1.249 + return; 1.250 + 1.251 + errorStr += ": "; 1.252 + do { 1.253 + ret = gss_display_status_ptr(&new_stat, 1.254 + maj_stat, 1.255 + GSS_C_GSS_CODE, 1.256 + GSS_C_NULL_OID, 1.257 + &msg_ctx, 1.258 + &status1_string); 1.259 + errorStr.Append((const char *) status1_string.value, status1_string.length); 1.260 + gss_release_buffer_ptr(&new_stat, &status1_string); 1.261 + 1.262 + errorStr += '\n'; 1.263 + ret = gss_display_status_ptr(&new_stat, 1.264 + min_stat, 1.265 + GSS_C_MECH_CODE, 1.266 + GSS_C_NULL_OID, 1.267 + &msg_ctx, 1.268 + &status2_string); 1.269 + errorStr.Append((const char *) status2_string.value, status2_string.length); 1.270 + errorStr += '\n'; 1.271 + } while (!GSS_ERROR(ret) && msg_ctx != 0); 1.272 + 1.273 + LOG(("%s\n", errorStr.get())); 1.274 +} 1.275 + 1.276 +#else /* PR_LOGGING */ 1.277 + 1.278 +#define LogGssError(x,y,z) 1.279 + 1.280 +#endif /* PR_LOGGING */ 1.281 + 1.282 +//----------------------------------------------------------------------------- 1.283 + 1.284 +nsAuthGSSAPI::nsAuthGSSAPI(pType package) 1.285 + : mServiceFlags(REQ_DEFAULT) 1.286 +{ 1.287 + OM_uint32 minstat; 1.288 + OM_uint32 majstat; 1.289 + gss_OID_set mech_set; 1.290 + gss_OID item; 1.291 + 1.292 + unsigned int i; 1.293 + static gss_OID_desc gss_krb5_mech_oid_desc = 1.294 + { 9, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" }; 1.295 + static gss_OID_desc gss_spnego_mech_oid_desc = 1.296 + { 6, (void *) "\x2b\x06\x01\x05\x05\x02" }; 1.297 + 1.298 + LOG(("entering nsAuthGSSAPI::nsAuthGSSAPI()\n")); 1.299 + 1.300 + mComplete = false; 1.301 + 1.302 + if (!gssLibrary && NS_FAILED(gssInit())) 1.303 + return; 1.304 + 1.305 + mCtx = GSS_C_NO_CONTEXT; 1.306 + mMechOID = &gss_krb5_mech_oid_desc; 1.307 + 1.308 + // if the type is kerberos we accept it as default 1.309 + // and exit 1.310 + 1.311 + if (package == PACKAGE_TYPE_KERBEROS) 1.312 + return; 1.313 + 1.314 + // Now, look at the list of supported mechanisms, 1.315 + // if SPNEGO is found, then use it. 1.316 + // Otherwise, set the desired mechanism to 1.317 + // GSS_C_NO_OID and let the system try to use 1.318 + // the default mechanism. 1.319 + // 1.320 + // Using Kerberos directly (instead of negotiating 1.321 + // with SPNEGO) may work in some cases depending 1.322 + // on how smart the server side is. 1.323 + 1.324 + majstat = gss_indicate_mechs_ptr(&minstat, &mech_set); 1.325 + if (GSS_ERROR(majstat)) 1.326 + return; 1.327 + 1.328 + if (mech_set) { 1.329 + for (i=0; i<mech_set->count; i++) { 1.330 + item = &mech_set->elements[i]; 1.331 + if (item->length == gss_spnego_mech_oid_desc.length && 1.332 + !memcmp(item->elements, gss_spnego_mech_oid_desc.elements, 1.333 + item->length)) { 1.334 + // ok, we found it 1.335 + mMechOID = &gss_spnego_mech_oid_desc; 1.336 + break; 1.337 + } 1.338 + } 1.339 + gss_release_oid_set_ptr(&minstat, &mech_set); 1.340 + } 1.341 +} 1.342 + 1.343 +void 1.344 +nsAuthGSSAPI::Reset() 1.345 +{ 1.346 + if (gssLibrary && mCtx != GSS_C_NO_CONTEXT) { 1.347 + OM_uint32 minor_status; 1.348 + gss_delete_sec_context_ptr(&minor_status, &mCtx, GSS_C_NO_BUFFER); 1.349 + } 1.350 + mCtx = GSS_C_NO_CONTEXT; 1.351 + mComplete = false; 1.352 +} 1.353 + 1.354 +/* static */ void 1.355 +nsAuthGSSAPI::Shutdown() 1.356 +{ 1.357 + if (gssLibrary) { 1.358 + PR_UnloadLibrary(gssLibrary); 1.359 + gssLibrary = nullptr; 1.360 + } 1.361 +} 1.362 + 1.363 +/* Limitations apply to this class's thread safety. See the header file */ 1.364 +NS_IMPL_ISUPPORTS(nsAuthGSSAPI, nsIAuthModule) 1.365 + 1.366 +NS_IMETHODIMP 1.367 +nsAuthGSSAPI::Init(const char *serviceName, 1.368 + uint32_t serviceFlags, 1.369 + const char16_t *domain, 1.370 + const char16_t *username, 1.371 + const char16_t *password) 1.372 +{ 1.373 + // we don't expect to be passed any user credentials 1.374 + NS_ASSERTION(!domain && !username && !password, "unexpected credentials"); 1.375 + 1.376 + // it's critial that the caller supply a service name to be used 1.377 + NS_ENSURE_TRUE(serviceName && *serviceName, NS_ERROR_INVALID_ARG); 1.378 + 1.379 + LOG(("entering nsAuthGSSAPI::Init()\n")); 1.380 + 1.381 + if (!gssLibrary) 1.382 + return NS_ERROR_NOT_INITIALIZED; 1.383 + 1.384 + mServiceName = serviceName; 1.385 + mServiceFlags = serviceFlags; 1.386 + 1.387 + static bool sTelemetrySent = false; 1.388 + if (!sTelemetrySent) { 1.389 + mozilla::Telemetry::Accumulate( 1.390 + mozilla::Telemetry::NTLM_MODULE_USED_2, 1.391 + serviceFlags & nsIAuthModule::REQ_PROXY_AUTH 1.392 + ? NTLM_MODULE_KERBEROS_PROXY 1.393 + : NTLM_MODULE_KERBEROS_DIRECT); 1.394 + sTelemetrySent = true; 1.395 + } 1.396 + 1.397 + return NS_OK; 1.398 +} 1.399 + 1.400 +NS_IMETHODIMP 1.401 +nsAuthGSSAPI::GetNextToken(const void *inToken, 1.402 + uint32_t inTokenLen, 1.403 + void **outToken, 1.404 + uint32_t *outTokenLen) 1.405 +{ 1.406 + OM_uint32 major_status, minor_status; 1.407 + OM_uint32 req_flags = 0; 1.408 + gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; 1.409 + gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; 1.410 + gss_buffer_t in_token_ptr = GSS_C_NO_BUFFER; 1.411 + gss_name_t server; 1.412 + nsAutoCString userbuf; 1.413 + nsresult rv; 1.414 + 1.415 + LOG(("entering nsAuthGSSAPI::GetNextToken()\n")); 1.416 + 1.417 + if (!gssLibrary) 1.418 + return NS_ERROR_NOT_INITIALIZED; 1.419 + 1.420 + // If they've called us again after we're complete, reset to start afresh. 1.421 + if (mComplete) 1.422 + Reset(); 1.423 + 1.424 + if (mServiceFlags & REQ_DELEGATE) 1.425 + req_flags |= GSS_C_DELEG_FLAG; 1.426 + 1.427 + if (mServiceFlags & REQ_MUTUAL_AUTH) 1.428 + req_flags |= GSS_C_MUTUAL_FLAG; 1.429 + 1.430 + input_token.value = (void *)mServiceName.get(); 1.431 + input_token.length = mServiceName.Length() + 1; 1.432 + 1.433 +#if defined(HAVE_RES_NINIT) 1.434 + res_ninit(&_res); 1.435 +#endif 1.436 + major_status = gss_import_name_ptr(&minor_status, 1.437 + &input_token, 1.438 + &gss_c_nt_hostbased_service, 1.439 + &server); 1.440 + input_token.value = nullptr; 1.441 + input_token.length = 0; 1.442 + if (GSS_ERROR(major_status)) { 1.443 + LogGssError(major_status, minor_status, "gss_import_name() failed"); 1.444 + return NS_ERROR_FAILURE; 1.445 + } 1.446 + 1.447 + if (inToken) { 1.448 + input_token.length = inTokenLen; 1.449 + input_token.value = (void *) inToken; 1.450 + in_token_ptr = &input_token; 1.451 + } 1.452 + else if (mCtx != GSS_C_NO_CONTEXT) { 1.453 + // If there is no input token, then we are starting a new 1.454 + // authentication sequence. If we have already initialized our 1.455 + // security context, then we're in trouble because it means that the 1.456 + // first sequence failed. We need to bail or else we might end up in 1.457 + // an infinite loop. 1.458 + LOG(("Cannot restart authentication sequence!")); 1.459 + return NS_ERROR_UNEXPECTED; 1.460 + } 1.461 + 1.462 +#if defined(XP_MACOSX) 1.463 + // Suppress Kerberos prompts to get credentials. See bug 240643. 1.464 + // We can only use Mac OS X specific kerb functions if we are using 1.465 + // the native lib 1.466 + KLBoolean found; 1.467 + bool doingMailTask = mServiceName.Find("imap@") || 1.468 + mServiceName.Find("pop@") || 1.469 + mServiceName.Find("smtp@") || 1.470 + mServiceName.Find("ldap@"); 1.471 + 1.472 + if (!doingMailTask && (gssNativeImp && 1.473 + (KLCacheHasValidTickets_ptr(nullptr, kerberosVersion_V5, &found, nullptr, nullptr) != klNoErr || !found))) 1.474 + { 1.475 + major_status = GSS_S_FAILURE; 1.476 + minor_status = 0; 1.477 + } 1.478 + else 1.479 +#endif /* XP_MACOSX */ 1.480 + major_status = gss_init_sec_context_ptr(&minor_status, 1.481 + GSS_C_NO_CREDENTIAL, 1.482 + &mCtx, 1.483 + server, 1.484 + mMechOID, 1.485 + req_flags, 1.486 + GSS_C_INDEFINITE, 1.487 + GSS_C_NO_CHANNEL_BINDINGS, 1.488 + in_token_ptr, 1.489 + nullptr, 1.490 + &output_token, 1.491 + nullptr, 1.492 + nullptr); 1.493 + 1.494 + if (GSS_ERROR(major_status)) { 1.495 + LogGssError(major_status, minor_status, "gss_init_sec_context() failed"); 1.496 + Reset(); 1.497 + rv = NS_ERROR_FAILURE; 1.498 + goto end; 1.499 + } 1.500 + if (major_status == GSS_S_COMPLETE) { 1.501 + // Mark ourselves as being complete, so that if we're called again 1.502 + // we know to start afresh. 1.503 + mComplete = true; 1.504 + } 1.505 + else if (major_status == GSS_S_CONTINUE_NEEDED) { 1.506 + // 1.507 + // The important thing is that we do NOT reset the 1.508 + // context here because it will be needed on the 1.509 + // next call. 1.510 + // 1.511 + } 1.512 + 1.513 + *outTokenLen = output_token.length; 1.514 + if (output_token.length != 0) 1.515 + *outToken = nsMemory::Clone(output_token.value, output_token.length); 1.516 + else 1.517 + *outToken = nullptr; 1.518 + 1.519 + gss_release_buffer_ptr(&minor_status, &output_token); 1.520 + 1.521 + if (major_status == GSS_S_COMPLETE) 1.522 + rv = NS_SUCCESS_AUTH_FINISHED; 1.523 + else 1.524 + rv = NS_OK; 1.525 + 1.526 +end: 1.527 + gss_release_name_ptr(&minor_status, &server); 1.528 + 1.529 + LOG((" leaving nsAuthGSSAPI::GetNextToken [rv=%x]", rv)); 1.530 + return rv; 1.531 +} 1.532 + 1.533 +NS_IMETHODIMP 1.534 +nsAuthGSSAPI::Unwrap(const void *inToken, 1.535 + uint32_t inTokenLen, 1.536 + void **outToken, 1.537 + uint32_t *outTokenLen) 1.538 +{ 1.539 + OM_uint32 major_status, minor_status; 1.540 + 1.541 + gss_buffer_desc input_token; 1.542 + gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; 1.543 + 1.544 + input_token.value = (void *) inToken; 1.545 + input_token.length = inTokenLen; 1.546 + 1.547 + major_status = gss_unwrap_ptr(&minor_status, 1.548 + mCtx, 1.549 + &input_token, 1.550 + &output_token, 1.551 + nullptr, 1.552 + nullptr); 1.553 + if (GSS_ERROR(major_status)) { 1.554 + LogGssError(major_status, minor_status, "gss_unwrap() failed"); 1.555 + Reset(); 1.556 + gss_release_buffer_ptr(&minor_status, &output_token); 1.557 + return NS_ERROR_FAILURE; 1.558 + } 1.559 + 1.560 + *outTokenLen = output_token.length; 1.561 + 1.562 + if (output_token.length) 1.563 + *outToken = nsMemory::Clone(output_token.value, output_token.length); 1.564 + else 1.565 + *outToken = nullptr; 1.566 + 1.567 + gss_release_buffer_ptr(&minor_status, &output_token); 1.568 + 1.569 + return NS_OK; 1.570 +} 1.571 + 1.572 +NS_IMETHODIMP 1.573 +nsAuthGSSAPI::Wrap(const void *inToken, 1.574 + uint32_t inTokenLen, 1.575 + bool confidential, 1.576 + void **outToken, 1.577 + uint32_t *outTokenLen) 1.578 +{ 1.579 + OM_uint32 major_status, minor_status; 1.580 + 1.581 + gss_buffer_desc input_token; 1.582 + gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; 1.583 + 1.584 + input_token.value = (void *) inToken; 1.585 + input_token.length = inTokenLen; 1.586 + 1.587 + major_status = gss_wrap_ptr(&minor_status, 1.588 + mCtx, 1.589 + confidential, 1.590 + GSS_C_QOP_DEFAULT, 1.591 + &input_token, 1.592 + nullptr, 1.593 + &output_token); 1.594 + 1.595 + if (GSS_ERROR(major_status)) { 1.596 + LogGssError(major_status, minor_status, "gss_wrap() failed"); 1.597 + Reset(); 1.598 + gss_release_buffer_ptr(&minor_status, &output_token); 1.599 + return NS_ERROR_FAILURE; 1.600 + } 1.601 + 1.602 + *outTokenLen = output_token.length; 1.603 + 1.604 + /* it is not possible for output_token.length to be zero */ 1.605 + *outToken = nsMemory::Clone(output_token.value, output_token.length); 1.606 + gss_release_buffer_ptr(&minor_status, &output_token); 1.607 + 1.608 + return NS_OK; 1.609 +} 1.610 +