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