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