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