extensions/auth/nsAuthGSSAPI.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* vim:set ts=4 sw=4 sts=4 et cindent: */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 //
michael@0 7 // GSSAPI Authentication Support Module
michael@0 8 //
michael@0 9 // Described by IETF Internet draft: draft-brezak-kerberos-http-00.txt
michael@0 10 // (formerly draft-brezak-spnego-http-04.txt)
michael@0 11 //
michael@0 12 // Also described here:
michael@0 13 // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnsecure/html/http-sso-1.asp
michael@0 14 //
michael@0 15 //
michael@0 16
michael@0 17 #include "mozilla/ArrayUtils.h"
michael@0 18
michael@0 19 #include "prlink.h"
michael@0 20 #include "nsCOMPtr.h"
michael@0 21 #include "nsIPrefService.h"
michael@0 22 #include "nsIPrefBranch.h"
michael@0 23 #include "nsIServiceManager.h"
michael@0 24 #include "nsNativeCharsetUtils.h"
michael@0 25 #include "mozilla/Telemetry.h"
michael@0 26
michael@0 27 #include "nsAuthGSSAPI.h"
michael@0 28
michael@0 29 #ifdef XP_MACOSX
michael@0 30 #include <Kerberos/Kerberos.h>
michael@0 31 #endif
michael@0 32
michael@0 33 #ifdef XP_MACOSX
michael@0 34 typedef KLStatus (*KLCacheHasValidTickets_type)(
michael@0 35 KLPrincipal,
michael@0 36 KLKerberosVersion,
michael@0 37 KLBoolean *,
michael@0 38 KLPrincipal *,
michael@0 39 char **);
michael@0 40 #endif
michael@0 41
michael@0 42 #if defined(HAVE_RES_NINIT)
michael@0 43 #include <sys/types.h>
michael@0 44 #include <netinet/in.h>
michael@0 45 #include <arpa/nameser.h>
michael@0 46 #include <resolv.h>
michael@0 47 #endif
michael@0 48
michael@0 49 using namespace mozilla;
michael@0 50
michael@0 51 //-----------------------------------------------------------------------------
michael@0 52
michael@0 53 // We define GSS_C_NT_HOSTBASED_SERVICE explicitly since it may be referenced
michael@0 54 // by by a different name depending on the implementation of gss but always
michael@0 55 // has the same value
michael@0 56
michael@0 57 static gss_OID_desc gss_c_nt_hostbased_service =
michael@0 58 { 10, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04" };
michael@0 59
michael@0 60 static const char kNegotiateAuthGssLib[] =
michael@0 61 "network.negotiate-auth.gsslib";
michael@0 62 static const char kNegotiateAuthNativeImp[] =
michael@0 63 "network.negotiate-auth.using-native-gsslib";
michael@0 64
michael@0 65 static struct GSSFunction {
michael@0 66 const char *str;
michael@0 67 PRFuncPtr func;
michael@0 68 } gssFuncs[] = {
michael@0 69 { "gss_display_status", nullptr },
michael@0 70 { "gss_init_sec_context", nullptr },
michael@0 71 { "gss_indicate_mechs", nullptr },
michael@0 72 { "gss_release_oid_set", nullptr },
michael@0 73 { "gss_delete_sec_context", nullptr },
michael@0 74 { "gss_import_name", nullptr },
michael@0 75 { "gss_release_buffer", nullptr },
michael@0 76 { "gss_release_name", nullptr },
michael@0 77 { "gss_wrap", nullptr },
michael@0 78 { "gss_unwrap", nullptr }
michael@0 79 };
michael@0 80
michael@0 81 static bool gssNativeImp = true;
michael@0 82 static PRLibrary* gssLibrary = nullptr;
michael@0 83
michael@0 84 #define gss_display_status_ptr ((gss_display_status_type)*gssFuncs[0].func)
michael@0 85 #define gss_init_sec_context_ptr ((gss_init_sec_context_type)*gssFuncs[1].func)
michael@0 86 #define gss_indicate_mechs_ptr ((gss_indicate_mechs_type)*gssFuncs[2].func)
michael@0 87 #define gss_release_oid_set_ptr ((gss_release_oid_set_type)*gssFuncs[3].func)
michael@0 88 #define gss_delete_sec_context_ptr ((gss_delete_sec_context_type)*gssFuncs[4].func)
michael@0 89 #define gss_import_name_ptr ((gss_import_name_type)*gssFuncs[5].func)
michael@0 90 #define gss_release_buffer_ptr ((gss_release_buffer_type)*gssFuncs[6].func)
michael@0 91 #define gss_release_name_ptr ((gss_release_name_type)*gssFuncs[7].func)
michael@0 92 #define gss_wrap_ptr ((gss_wrap_type)*gssFuncs[8].func)
michael@0 93 #define gss_unwrap_ptr ((gss_unwrap_type)*gssFuncs[9].func)
michael@0 94
michael@0 95 #ifdef XP_MACOSX
michael@0 96 static PRFuncPtr KLCacheHasValidTicketsPtr;
michael@0 97 #define KLCacheHasValidTickets_ptr \
michael@0 98 ((KLCacheHasValidTickets_type)*KLCacheHasValidTicketsPtr)
michael@0 99 #endif
michael@0 100
michael@0 101 static nsresult
michael@0 102 gssInit()
michael@0 103 {
michael@0 104 nsXPIDLCString libPath;
michael@0 105 nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
michael@0 106 if (prefs) {
michael@0 107 prefs->GetCharPref(kNegotiateAuthGssLib, getter_Copies(libPath));
michael@0 108 prefs->GetBoolPref(kNegotiateAuthNativeImp, &gssNativeImp);
michael@0 109 }
michael@0 110
michael@0 111 PRLibrary *lib = nullptr;
michael@0 112
michael@0 113 if (!libPath.IsEmpty()) {
michael@0 114 LOG(("Attempting to load user specified library [%s]\n", libPath.get()));
michael@0 115 gssNativeImp = false;
michael@0 116 lib = PR_LoadLibrary(libPath.get());
michael@0 117 }
michael@0 118 else {
michael@0 119 #ifdef XP_WIN
michael@0 120 char *libName = PR_GetLibraryName(nullptr, "gssapi32");
michael@0 121 if (libName) {
michael@0 122 lib = PR_LoadLibrary("gssapi32");
michael@0 123 PR_FreeLibraryName(libName);
michael@0 124 }
michael@0 125 #elif defined(__OpenBSD__)
michael@0 126 /* OpenBSD doesn't register inter-library dependencies in basesystem
michael@0 127 * libs therefor we need to load all the libraries gssapi depends on,
michael@0 128 * in the correct order and with LD_GLOBAL for GSSAPI auth to work
michael@0 129 * fine.
michael@0 130 */
michael@0 131
michael@0 132 const char *const verLibNames[] = {
michael@0 133 "libasn1.so",
michael@0 134 "libcrypto.so",
michael@0 135 "libroken.so",
michael@0 136 "libheimbase.so",
michael@0 137 "libcom_err.so",
michael@0 138 "libkrb5.so",
michael@0 139 "libgssapi.so"
michael@0 140 };
michael@0 141
michael@0 142 PRLibSpec libSpec;
michael@0 143 for (size_t i = 0; i < ArrayLength(verLibNames); ++i) {
michael@0 144 libSpec.type = PR_LibSpec_Pathname;
michael@0 145 libSpec.value.pathname = verLibNames[i];
michael@0 146 lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_GLOBAL);
michael@0 147 };
michael@0 148
michael@0 149 #else
michael@0 150
michael@0 151 const char *const libNames[] = {
michael@0 152 "gss",
michael@0 153 "gssapi_krb5",
michael@0 154 "gssapi"
michael@0 155 };
michael@0 156
michael@0 157 const char *const verLibNames[] = {
michael@0 158 "libgssapi_krb5.so.2", /* MIT - FC, Suse10, Debian */
michael@0 159 "libgssapi.so.4", /* Heimdal - Suse10, MDK */
michael@0 160 "libgssapi.so.1" /* Heimdal - Suse9, CITI - FC, MDK, Suse10*/
michael@0 161 };
michael@0 162
michael@0 163 for (size_t i = 0; i < ArrayLength(verLibNames) && !lib; ++i) {
michael@0 164 lib = PR_LoadLibrary(verLibNames[i]);
michael@0 165
michael@0 166 /* The CITI libgssapi library calls exit() during
michael@0 167 * initialization if it's not correctly configured. Try to
michael@0 168 * ensure that we never use this library for our GSSAPI
michael@0 169 * support, as its just a wrapper library, anyway.
michael@0 170 * See Bugzilla #325433
michael@0 171 */
michael@0 172 if (lib &&
michael@0 173 PR_FindFunctionSymbol(lib,
michael@0 174 "internal_krb5_gss_initialize") &&
michael@0 175 PR_FindFunctionSymbol(lib, "gssd_pname_to_uid")) {
michael@0 176 LOG(("CITI libgssapi found, which calls exit(). Skipping\n"));
michael@0 177 PR_UnloadLibrary(lib);
michael@0 178 lib = nullptr;
michael@0 179 }
michael@0 180 }
michael@0 181
michael@0 182 for (size_t i = 0; i < ArrayLength(libNames) && !lib; ++i) {
michael@0 183 char *libName = PR_GetLibraryName(nullptr, libNames[i]);
michael@0 184 if (libName) {
michael@0 185 lib = PR_LoadLibrary(libName);
michael@0 186 PR_FreeLibraryName(libName);
michael@0 187
michael@0 188 if (lib &&
michael@0 189 PR_FindFunctionSymbol(lib,
michael@0 190 "internal_krb5_gss_initialize") &&
michael@0 191 PR_FindFunctionSymbol(lib, "gssd_pname_to_uid")) {
michael@0 192 LOG(("CITI libgssapi found, which calls exit(). Skipping\n"));
michael@0 193 PR_UnloadLibrary(lib);
michael@0 194 lib = nullptr;
michael@0 195 }
michael@0 196 }
michael@0 197 }
michael@0 198 #endif
michael@0 199 }
michael@0 200
michael@0 201 if (!lib) {
michael@0 202 LOG(("Fail to load gssapi library\n"));
michael@0 203 return NS_ERROR_FAILURE;
michael@0 204 }
michael@0 205
michael@0 206 LOG(("Attempting to load gss functions\n"));
michael@0 207
michael@0 208 for (size_t i = 0; i < ArrayLength(gssFuncs); ++i) {
michael@0 209 gssFuncs[i].func = PR_FindFunctionSymbol(lib, gssFuncs[i].str);
michael@0 210 if (!gssFuncs[i].func) {
michael@0 211 LOG(("Fail to load %s function from gssapi library\n", gssFuncs[i].str));
michael@0 212 PR_UnloadLibrary(lib);
michael@0 213 return NS_ERROR_FAILURE;
michael@0 214 }
michael@0 215 }
michael@0 216 #ifdef XP_MACOSX
michael@0 217 if (gssNativeImp &&
michael@0 218 !(KLCacheHasValidTicketsPtr =
michael@0 219 PR_FindFunctionSymbol(lib, "KLCacheHasValidTickets"))) {
michael@0 220 LOG(("Fail to load KLCacheHasValidTickets function from gssapi library\n"));
michael@0 221 PR_UnloadLibrary(lib);
michael@0 222 return NS_ERROR_FAILURE;
michael@0 223 }
michael@0 224 #endif
michael@0 225
michael@0 226 gssLibrary = lib;
michael@0 227 return NS_OK;
michael@0 228 }
michael@0 229
michael@0 230 #if defined( PR_LOGGING )
michael@0 231
michael@0 232 // Generate proper GSSAPI error messages from the major and
michael@0 233 // minor status codes.
michael@0 234 void
michael@0 235 LogGssError(OM_uint32 maj_stat, OM_uint32 min_stat, const char *prefix)
michael@0 236 {
michael@0 237 OM_uint32 new_stat;
michael@0 238 OM_uint32 msg_ctx = 0;
michael@0 239 gss_buffer_desc status1_string;
michael@0 240 gss_buffer_desc status2_string;
michael@0 241 OM_uint32 ret;
michael@0 242 nsAutoCString errorStr;
michael@0 243 errorStr.Assign(prefix);
michael@0 244
michael@0 245 if (!gssLibrary)
michael@0 246 return;
michael@0 247
michael@0 248 errorStr += ": ";
michael@0 249 do {
michael@0 250 ret = gss_display_status_ptr(&new_stat,
michael@0 251 maj_stat,
michael@0 252 GSS_C_GSS_CODE,
michael@0 253 GSS_C_NULL_OID,
michael@0 254 &msg_ctx,
michael@0 255 &status1_string);
michael@0 256 errorStr.Append((const char *) status1_string.value, status1_string.length);
michael@0 257 gss_release_buffer_ptr(&new_stat, &status1_string);
michael@0 258
michael@0 259 errorStr += '\n';
michael@0 260 ret = gss_display_status_ptr(&new_stat,
michael@0 261 min_stat,
michael@0 262 GSS_C_MECH_CODE,
michael@0 263 GSS_C_NULL_OID,
michael@0 264 &msg_ctx,
michael@0 265 &status2_string);
michael@0 266 errorStr.Append((const char *) status2_string.value, status2_string.length);
michael@0 267 errorStr += '\n';
michael@0 268 } while (!GSS_ERROR(ret) && msg_ctx != 0);
michael@0 269
michael@0 270 LOG(("%s\n", errorStr.get()));
michael@0 271 }
michael@0 272
michael@0 273 #else /* PR_LOGGING */
michael@0 274
michael@0 275 #define LogGssError(x,y,z)
michael@0 276
michael@0 277 #endif /* PR_LOGGING */
michael@0 278
michael@0 279 //-----------------------------------------------------------------------------
michael@0 280
michael@0 281 nsAuthGSSAPI::nsAuthGSSAPI(pType package)
michael@0 282 : mServiceFlags(REQ_DEFAULT)
michael@0 283 {
michael@0 284 OM_uint32 minstat;
michael@0 285 OM_uint32 majstat;
michael@0 286 gss_OID_set mech_set;
michael@0 287 gss_OID item;
michael@0 288
michael@0 289 unsigned int i;
michael@0 290 static gss_OID_desc gss_krb5_mech_oid_desc =
michael@0 291 { 9, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" };
michael@0 292 static gss_OID_desc gss_spnego_mech_oid_desc =
michael@0 293 { 6, (void *) "\x2b\x06\x01\x05\x05\x02" };
michael@0 294
michael@0 295 LOG(("entering nsAuthGSSAPI::nsAuthGSSAPI()\n"));
michael@0 296
michael@0 297 mComplete = false;
michael@0 298
michael@0 299 if (!gssLibrary && NS_FAILED(gssInit()))
michael@0 300 return;
michael@0 301
michael@0 302 mCtx = GSS_C_NO_CONTEXT;
michael@0 303 mMechOID = &gss_krb5_mech_oid_desc;
michael@0 304
michael@0 305 // if the type is kerberos we accept it as default
michael@0 306 // and exit
michael@0 307
michael@0 308 if (package == PACKAGE_TYPE_KERBEROS)
michael@0 309 return;
michael@0 310
michael@0 311 // Now, look at the list of supported mechanisms,
michael@0 312 // if SPNEGO is found, then use it.
michael@0 313 // Otherwise, set the desired mechanism to
michael@0 314 // GSS_C_NO_OID and let the system try to use
michael@0 315 // the default mechanism.
michael@0 316 //
michael@0 317 // Using Kerberos directly (instead of negotiating
michael@0 318 // with SPNEGO) may work in some cases depending
michael@0 319 // on how smart the server side is.
michael@0 320
michael@0 321 majstat = gss_indicate_mechs_ptr(&minstat, &mech_set);
michael@0 322 if (GSS_ERROR(majstat))
michael@0 323 return;
michael@0 324
michael@0 325 if (mech_set) {
michael@0 326 for (i=0; i<mech_set->count; i++) {
michael@0 327 item = &mech_set->elements[i];
michael@0 328 if (item->length == gss_spnego_mech_oid_desc.length &&
michael@0 329 !memcmp(item->elements, gss_spnego_mech_oid_desc.elements,
michael@0 330 item->length)) {
michael@0 331 // ok, we found it
michael@0 332 mMechOID = &gss_spnego_mech_oid_desc;
michael@0 333 break;
michael@0 334 }
michael@0 335 }
michael@0 336 gss_release_oid_set_ptr(&minstat, &mech_set);
michael@0 337 }
michael@0 338 }
michael@0 339
michael@0 340 void
michael@0 341 nsAuthGSSAPI::Reset()
michael@0 342 {
michael@0 343 if (gssLibrary && mCtx != GSS_C_NO_CONTEXT) {
michael@0 344 OM_uint32 minor_status;
michael@0 345 gss_delete_sec_context_ptr(&minor_status, &mCtx, GSS_C_NO_BUFFER);
michael@0 346 }
michael@0 347 mCtx = GSS_C_NO_CONTEXT;
michael@0 348 mComplete = false;
michael@0 349 }
michael@0 350
michael@0 351 /* static */ void
michael@0 352 nsAuthGSSAPI::Shutdown()
michael@0 353 {
michael@0 354 if (gssLibrary) {
michael@0 355 PR_UnloadLibrary(gssLibrary);
michael@0 356 gssLibrary = nullptr;
michael@0 357 }
michael@0 358 }
michael@0 359
michael@0 360 /* Limitations apply to this class's thread safety. See the header file */
michael@0 361 NS_IMPL_ISUPPORTS(nsAuthGSSAPI, nsIAuthModule)
michael@0 362
michael@0 363 NS_IMETHODIMP
michael@0 364 nsAuthGSSAPI::Init(const char *serviceName,
michael@0 365 uint32_t serviceFlags,
michael@0 366 const char16_t *domain,
michael@0 367 const char16_t *username,
michael@0 368 const char16_t *password)
michael@0 369 {
michael@0 370 // we don't expect to be passed any user credentials
michael@0 371 NS_ASSERTION(!domain && !username && !password, "unexpected credentials");
michael@0 372
michael@0 373 // it's critial that the caller supply a service name to be used
michael@0 374 NS_ENSURE_TRUE(serviceName && *serviceName, NS_ERROR_INVALID_ARG);
michael@0 375
michael@0 376 LOG(("entering nsAuthGSSAPI::Init()\n"));
michael@0 377
michael@0 378 if (!gssLibrary)
michael@0 379 return NS_ERROR_NOT_INITIALIZED;
michael@0 380
michael@0 381 mServiceName = serviceName;
michael@0 382 mServiceFlags = serviceFlags;
michael@0 383
michael@0 384 static bool sTelemetrySent = false;
michael@0 385 if (!sTelemetrySent) {
michael@0 386 mozilla::Telemetry::Accumulate(
michael@0 387 mozilla::Telemetry::NTLM_MODULE_USED_2,
michael@0 388 serviceFlags & nsIAuthModule::REQ_PROXY_AUTH
michael@0 389 ? NTLM_MODULE_KERBEROS_PROXY
michael@0 390 : NTLM_MODULE_KERBEROS_DIRECT);
michael@0 391 sTelemetrySent = true;
michael@0 392 }
michael@0 393
michael@0 394 return NS_OK;
michael@0 395 }
michael@0 396
michael@0 397 NS_IMETHODIMP
michael@0 398 nsAuthGSSAPI::GetNextToken(const void *inToken,
michael@0 399 uint32_t inTokenLen,
michael@0 400 void **outToken,
michael@0 401 uint32_t *outTokenLen)
michael@0 402 {
michael@0 403 OM_uint32 major_status, minor_status;
michael@0 404 OM_uint32 req_flags = 0;
michael@0 405 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
michael@0 406 gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
michael@0 407 gss_buffer_t in_token_ptr = GSS_C_NO_BUFFER;
michael@0 408 gss_name_t server;
michael@0 409 nsAutoCString userbuf;
michael@0 410 nsresult rv;
michael@0 411
michael@0 412 LOG(("entering nsAuthGSSAPI::GetNextToken()\n"));
michael@0 413
michael@0 414 if (!gssLibrary)
michael@0 415 return NS_ERROR_NOT_INITIALIZED;
michael@0 416
michael@0 417 // If they've called us again after we're complete, reset to start afresh.
michael@0 418 if (mComplete)
michael@0 419 Reset();
michael@0 420
michael@0 421 if (mServiceFlags & REQ_DELEGATE)
michael@0 422 req_flags |= GSS_C_DELEG_FLAG;
michael@0 423
michael@0 424 if (mServiceFlags & REQ_MUTUAL_AUTH)
michael@0 425 req_flags |= GSS_C_MUTUAL_FLAG;
michael@0 426
michael@0 427 input_token.value = (void *)mServiceName.get();
michael@0 428 input_token.length = mServiceName.Length() + 1;
michael@0 429
michael@0 430 #if defined(HAVE_RES_NINIT)
michael@0 431 res_ninit(&_res);
michael@0 432 #endif
michael@0 433 major_status = gss_import_name_ptr(&minor_status,
michael@0 434 &input_token,
michael@0 435 &gss_c_nt_hostbased_service,
michael@0 436 &server);
michael@0 437 input_token.value = nullptr;
michael@0 438 input_token.length = 0;
michael@0 439 if (GSS_ERROR(major_status)) {
michael@0 440 LogGssError(major_status, minor_status, "gss_import_name() failed");
michael@0 441 return NS_ERROR_FAILURE;
michael@0 442 }
michael@0 443
michael@0 444 if (inToken) {
michael@0 445 input_token.length = inTokenLen;
michael@0 446 input_token.value = (void *) inToken;
michael@0 447 in_token_ptr = &input_token;
michael@0 448 }
michael@0 449 else if (mCtx != GSS_C_NO_CONTEXT) {
michael@0 450 // If there is no input token, then we are starting a new
michael@0 451 // authentication sequence. If we have already initialized our
michael@0 452 // security context, then we're in trouble because it means that the
michael@0 453 // first sequence failed. We need to bail or else we might end up in
michael@0 454 // an infinite loop.
michael@0 455 LOG(("Cannot restart authentication sequence!"));
michael@0 456 return NS_ERROR_UNEXPECTED;
michael@0 457 }
michael@0 458
michael@0 459 #if defined(XP_MACOSX)
michael@0 460 // Suppress Kerberos prompts to get credentials. See bug 240643.
michael@0 461 // We can only use Mac OS X specific kerb functions if we are using
michael@0 462 // the native lib
michael@0 463 KLBoolean found;
michael@0 464 bool doingMailTask = mServiceName.Find("imap@") ||
michael@0 465 mServiceName.Find("pop@") ||
michael@0 466 mServiceName.Find("smtp@") ||
michael@0 467 mServiceName.Find("ldap@");
michael@0 468
michael@0 469 if (!doingMailTask && (gssNativeImp &&
michael@0 470 (KLCacheHasValidTickets_ptr(nullptr, kerberosVersion_V5, &found, nullptr, nullptr) != klNoErr || !found)))
michael@0 471 {
michael@0 472 major_status = GSS_S_FAILURE;
michael@0 473 minor_status = 0;
michael@0 474 }
michael@0 475 else
michael@0 476 #endif /* XP_MACOSX */
michael@0 477 major_status = gss_init_sec_context_ptr(&minor_status,
michael@0 478 GSS_C_NO_CREDENTIAL,
michael@0 479 &mCtx,
michael@0 480 server,
michael@0 481 mMechOID,
michael@0 482 req_flags,
michael@0 483 GSS_C_INDEFINITE,
michael@0 484 GSS_C_NO_CHANNEL_BINDINGS,
michael@0 485 in_token_ptr,
michael@0 486 nullptr,
michael@0 487 &output_token,
michael@0 488 nullptr,
michael@0 489 nullptr);
michael@0 490
michael@0 491 if (GSS_ERROR(major_status)) {
michael@0 492 LogGssError(major_status, minor_status, "gss_init_sec_context() failed");
michael@0 493 Reset();
michael@0 494 rv = NS_ERROR_FAILURE;
michael@0 495 goto end;
michael@0 496 }
michael@0 497 if (major_status == GSS_S_COMPLETE) {
michael@0 498 // Mark ourselves as being complete, so that if we're called again
michael@0 499 // we know to start afresh.
michael@0 500 mComplete = true;
michael@0 501 }
michael@0 502 else if (major_status == GSS_S_CONTINUE_NEEDED) {
michael@0 503 //
michael@0 504 // The important thing is that we do NOT reset the
michael@0 505 // context here because it will be needed on the
michael@0 506 // next call.
michael@0 507 //
michael@0 508 }
michael@0 509
michael@0 510 *outTokenLen = output_token.length;
michael@0 511 if (output_token.length != 0)
michael@0 512 *outToken = nsMemory::Clone(output_token.value, output_token.length);
michael@0 513 else
michael@0 514 *outToken = nullptr;
michael@0 515
michael@0 516 gss_release_buffer_ptr(&minor_status, &output_token);
michael@0 517
michael@0 518 if (major_status == GSS_S_COMPLETE)
michael@0 519 rv = NS_SUCCESS_AUTH_FINISHED;
michael@0 520 else
michael@0 521 rv = NS_OK;
michael@0 522
michael@0 523 end:
michael@0 524 gss_release_name_ptr(&minor_status, &server);
michael@0 525
michael@0 526 LOG((" leaving nsAuthGSSAPI::GetNextToken [rv=%x]", rv));
michael@0 527 return rv;
michael@0 528 }
michael@0 529
michael@0 530 NS_IMETHODIMP
michael@0 531 nsAuthGSSAPI::Unwrap(const void *inToken,
michael@0 532 uint32_t inTokenLen,
michael@0 533 void **outToken,
michael@0 534 uint32_t *outTokenLen)
michael@0 535 {
michael@0 536 OM_uint32 major_status, minor_status;
michael@0 537
michael@0 538 gss_buffer_desc input_token;
michael@0 539 gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
michael@0 540
michael@0 541 input_token.value = (void *) inToken;
michael@0 542 input_token.length = inTokenLen;
michael@0 543
michael@0 544 major_status = gss_unwrap_ptr(&minor_status,
michael@0 545 mCtx,
michael@0 546 &input_token,
michael@0 547 &output_token,
michael@0 548 nullptr,
michael@0 549 nullptr);
michael@0 550 if (GSS_ERROR(major_status)) {
michael@0 551 LogGssError(major_status, minor_status, "gss_unwrap() failed");
michael@0 552 Reset();
michael@0 553 gss_release_buffer_ptr(&minor_status, &output_token);
michael@0 554 return NS_ERROR_FAILURE;
michael@0 555 }
michael@0 556
michael@0 557 *outTokenLen = output_token.length;
michael@0 558
michael@0 559 if (output_token.length)
michael@0 560 *outToken = nsMemory::Clone(output_token.value, output_token.length);
michael@0 561 else
michael@0 562 *outToken = nullptr;
michael@0 563
michael@0 564 gss_release_buffer_ptr(&minor_status, &output_token);
michael@0 565
michael@0 566 return NS_OK;
michael@0 567 }
michael@0 568
michael@0 569 NS_IMETHODIMP
michael@0 570 nsAuthGSSAPI::Wrap(const void *inToken,
michael@0 571 uint32_t inTokenLen,
michael@0 572 bool confidential,
michael@0 573 void **outToken,
michael@0 574 uint32_t *outTokenLen)
michael@0 575 {
michael@0 576 OM_uint32 major_status, minor_status;
michael@0 577
michael@0 578 gss_buffer_desc input_token;
michael@0 579 gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
michael@0 580
michael@0 581 input_token.value = (void *) inToken;
michael@0 582 input_token.length = inTokenLen;
michael@0 583
michael@0 584 major_status = gss_wrap_ptr(&minor_status,
michael@0 585 mCtx,
michael@0 586 confidential,
michael@0 587 GSS_C_QOP_DEFAULT,
michael@0 588 &input_token,
michael@0 589 nullptr,
michael@0 590 &output_token);
michael@0 591
michael@0 592 if (GSS_ERROR(major_status)) {
michael@0 593 LogGssError(major_status, minor_status, "gss_wrap() failed");
michael@0 594 Reset();
michael@0 595 gss_release_buffer_ptr(&minor_status, &output_token);
michael@0 596 return NS_ERROR_FAILURE;
michael@0 597 }
michael@0 598
michael@0 599 *outTokenLen = output_token.length;
michael@0 600
michael@0 601 /* it is not possible for output_token.length to be zero */
michael@0 602 *outToken = nsMemory::Clone(output_token.value, output_token.length);
michael@0 603 gss_release_buffer_ptr(&minor_status, &output_token);
michael@0 604
michael@0 605 return NS_OK;
michael@0 606 }
michael@0 607

mercurial