mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-17 20:57:30 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
848
extensions/auth/gssapi.h
Normal file
848
extensions/auth/gssapi.h
Normal file
|
|
@ -0,0 +1,848 @@
|
|||
/* vim:set ts=4 sw=4 sts=4 et cindent: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Copyright 1993 by OpenVision Technologies, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without fee,
|
||||
* provided that the above copyright notice appears in all copies and
|
||||
* that both that copyright notice and this permission notice appear in
|
||||
* supporting documentation, and that the name of OpenVision not be used
|
||||
* in advertising or publicity pertaining to distribution of the software
|
||||
* without specific, written prior permission. OpenVision makes no
|
||||
* representations about the suitability of this software for any
|
||||
* purpose. It is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
|
||||
* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
****** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef GSSAPI_H_
|
||||
#define GSSAPI_H_
|
||||
|
||||
/*
|
||||
* Also define _GSSAPI_H_ as that is what the Kerberos 5 code defines and
|
||||
* what header files on some systems look for.
|
||||
*/
|
||||
#define _GSSAPI_H_
|
||||
|
||||
/*
|
||||
* On Mac OS X, Kerberos/Kerberos.h is used to gain access to certain
|
||||
* system-specific Kerberos functions, but on 10.4, that file also brings
|
||||
* in other headers that conflict with this one.
|
||||
*/
|
||||
#define _GSSAPI_GENERIC_H_
|
||||
#define _GSSAPI_KRB5_H_
|
||||
|
||||
/*
|
||||
* Define windows specific needed parameters.
|
||||
*/
|
||||
|
||||
#ifndef GSS_CALLCONV
|
||||
#if defined(_WIN32)
|
||||
#define GSS_CALLCONV __stdcall
|
||||
#define GSS_CALLCONV_C __cdecl
|
||||
#else
|
||||
#define GSS_CALLCONV
|
||||
#define GSS_CALLCONV_C
|
||||
#endif
|
||||
#endif /* GSS_CALLCONV */
|
||||
|
||||
#ifdef GSS_USE_FUNCTION_POINTERS
|
||||
#ifdef _WIN32
|
||||
#undef GSS_CALLCONV
|
||||
#define GSS_CALLCONV
|
||||
#define GSS_FUNC(f) (__stdcall *f##_type)
|
||||
#else
|
||||
#define GSS_FUNC(f) (*f##_type)
|
||||
#endif
|
||||
#define GSS_MAKE_TYPEDEF typedef
|
||||
#else
|
||||
#define GSS_FUNC(f) f
|
||||
#define GSS_MAKE_TYPEDEF
|
||||
#endif
|
||||
|
||||
/*
|
||||
* First, include stddef.h to get size_t defined.
|
||||
*/
|
||||
#include <stddef.h>
|
||||
|
||||
/*
|
||||
* Configure set the following
|
||||
*/
|
||||
|
||||
#ifndef SIZEOF_LONG
|
||||
#undef SIZEOF_LONG
|
||||
#endif
|
||||
#ifndef SIZEOF_SHORT
|
||||
#undef SIZEOF_SHORT
|
||||
#endif
|
||||
|
||||
#ifndef EXTERN_C_BEGIN
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN_C_BEGIN extern "C" {
|
||||
#define EXTERN_C_END }
|
||||
#else
|
||||
#define EXTERN_C_BEGIN
|
||||
#define EXTERN_C_END
|
||||
#endif
|
||||
#endif
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
# pragma pack(push,2)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If the platform supports the xom.h header file, it should be
|
||||
* included here.
|
||||
*/
|
||||
/* #include <xom.h> */
|
||||
|
||||
|
||||
/*
|
||||
* Now define the three implementation-dependent types.
|
||||
*/
|
||||
|
||||
typedef void * gss_name_t ;
|
||||
typedef void * gss_ctx_id_t ;
|
||||
typedef void * gss_cred_id_t ;
|
||||
|
||||
|
||||
/*
|
||||
* The following type must be defined as the smallest natural
|
||||
* unsigned integer supported by the platform that has at least
|
||||
* 32 bits of precision.
|
||||
*/
|
||||
|
||||
#if SIZEOF_LONG == 4
|
||||
typedef unsigned long gss_uint32;
|
||||
#elif SIZEOF_SHORT == 4
|
||||
typedef unsigned short gss_uint32;
|
||||
#else
|
||||
typedef unsigned int gss_uint32;
|
||||
#endif
|
||||
|
||||
#ifdef OM_STRING
|
||||
|
||||
/*
|
||||
* We have included the xom.h header file. Verify that OM_uint32
|
||||
* is defined correctly.
|
||||
*/
|
||||
|
||||
#if sizeof(gss_uint32) != sizeof(OM_uint32)
|
||||
#error Incompatible definition of OM_uint32 from xom.h
|
||||
#endif
|
||||
|
||||
typedef OM_object_identifier gss_OID_desc, *gss_OID;
|
||||
|
||||
#else /* !OM_STRING */
|
||||
|
||||
/*
|
||||
* We can't use X/Open definitions, so roll our own.
|
||||
*/
|
||||
typedef gss_uint32 OM_uint32;
|
||||
typedef struct gss_OID_desc_struct {
|
||||
OM_uint32 length;
|
||||
void *elements;
|
||||
} gss_OID_desc, *gss_OID;
|
||||
|
||||
#endif /* !OM_STRING */
|
||||
|
||||
typedef struct gss_OID_set_desc_struct {
|
||||
size_t count;
|
||||
gss_OID elements;
|
||||
} gss_OID_set_desc, *gss_OID_set;
|
||||
|
||||
|
||||
/*
|
||||
* For now, define a QOP-type as an OM_uint32
|
||||
*/
|
||||
typedef OM_uint32 gss_qop_t;
|
||||
|
||||
typedef int gss_cred_usage_t;
|
||||
|
||||
|
||||
typedef struct gss_buffer_desc_struct {
|
||||
size_t length;
|
||||
void *value;
|
||||
} gss_buffer_desc, *gss_buffer_t;
|
||||
|
||||
typedef struct gss_channel_bindings_struct {
|
||||
OM_uint32 initiator_addrtype;
|
||||
gss_buffer_desc initiator_address;
|
||||
OM_uint32 acceptor_addrtype;
|
||||
gss_buffer_desc acceptor_address;
|
||||
gss_buffer_desc application_data;
|
||||
} *gss_channel_bindings_t;
|
||||
|
||||
|
||||
/*
|
||||
* Flag bits for context-level services.
|
||||
*/
|
||||
#define GSS_C_DELEG_FLAG 1
|
||||
#define GSS_C_MUTUAL_FLAG 2
|
||||
#define GSS_C_REPLAY_FLAG 4
|
||||
#define GSS_C_SEQUENCE_FLAG 8
|
||||
#define GSS_C_CONF_FLAG 16
|
||||
#define GSS_C_INTEG_FLAG 32
|
||||
#define GSS_C_ANON_FLAG 64
|
||||
#define GSS_C_PROT_READY_FLAG 128
|
||||
#define GSS_C_TRANS_FLAG 256
|
||||
|
||||
/*
|
||||
* Credential usage options
|
||||
*/
|
||||
#define GSS_C_BOTH 0
|
||||
#define GSS_C_INITIATE 1
|
||||
#define GSS_C_ACCEPT 2
|
||||
|
||||
/*
|
||||
* Status code types for gss_display_status
|
||||
*/
|
||||
#define GSS_C_GSS_CODE 1
|
||||
#define GSS_C_MECH_CODE 2
|
||||
|
||||
/*
|
||||
* The constant definitions for channel-bindings address families
|
||||
*/
|
||||
#define GSS_C_AF_UNSPEC 0
|
||||
#define GSS_C_AF_LOCAL 1
|
||||
#define GSS_C_AF_INET 2
|
||||
#define GSS_C_AF_IMPLINK 3
|
||||
#define GSS_C_AF_PUP 4
|
||||
#define GSS_C_AF_CHAOS 5
|
||||
#define GSS_C_AF_NS 6
|
||||
#define GSS_C_AF_NBS 7
|
||||
#define GSS_C_AF_ECMA 8
|
||||
#define GSS_C_AF_DATAKIT 9
|
||||
#define GSS_C_AF_CCITT 10
|
||||
#define GSS_C_AF_SNA 11
|
||||
#define GSS_C_AF_DECnet 12
|
||||
#define GSS_C_AF_DLI 13
|
||||
#define GSS_C_AF_LAT 14
|
||||
#define GSS_C_AF_HYLINK 15
|
||||
#define GSS_C_AF_APPLETALK 16
|
||||
#define GSS_C_AF_BSC 17
|
||||
#define GSS_C_AF_DSS 18
|
||||
#define GSS_C_AF_OSI 19
|
||||
#define GSS_C_AF_X25 21
|
||||
|
||||
#define GSS_C_AF_NULLADDR 255
|
||||
|
||||
/*
|
||||
* Various Null values
|
||||
*/
|
||||
#define GSS_C_NO_NAME ((gss_name_t) 0)
|
||||
#define GSS_C_NO_BUFFER ((gss_buffer_t) 0)
|
||||
#define GSS_C_NO_OID ((gss_OID) 0)
|
||||
#define GSS_C_NO_OID_SET ((gss_OID_set) 0)
|
||||
#define GSS_C_NO_CONTEXT ((gss_ctx_id_t) 0)
|
||||
#define GSS_C_NO_CREDENTIAL ((gss_cred_id_t) 0)
|
||||
#define GSS_C_NO_CHANNEL_BINDINGS ((gss_channel_bindings_t) 0)
|
||||
#define GSS_C_EMPTY_BUFFER {0, nullptr}
|
||||
|
||||
/*
|
||||
* Some alternate names for a couple of the above
|
||||
* values. These are defined for V1 compatibility.
|
||||
*/
|
||||
#define GSS_C_NULL_OID GSS_C_NO_OID
|
||||
#define GSS_C_NULL_OID_SET GSS_C_NO_OID_SET
|
||||
|
||||
/*
|
||||
* Define the default Quality of Protection for per-message
|
||||
* services. Note that an implementation that offers multiple
|
||||
* levels of QOP may define GSS_C_QOP_DEFAULT to be either zero
|
||||
* (as done here) to mean "default protection", or to a specific
|
||||
* explicit QOP value. However, a value of 0 should always be
|
||||
* interpreted by a GSSAPI implementation as a request for the
|
||||
* default protection level.
|
||||
*/
|
||||
#define GSS_C_QOP_DEFAULT 0
|
||||
|
||||
/*
|
||||
* Expiration time of 2^32-1 seconds means infinite lifetime for a
|
||||
* credential or security context
|
||||
*/
|
||||
#define GSS_C_INDEFINITE 0xfffffffful
|
||||
|
||||
/*
|
||||
* The implementation must reserve static storage for a
|
||||
* gss_OID_desc object containing the value
|
||||
* {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
|
||||
* "\x01\x02\x01\x01"},
|
||||
* corresponding to an object-identifier value of
|
||||
* {iso(1) member-body(2) United States(840) mit(113554)
|
||||
* infosys(1) gssapi(2) generic(1) user_name(1)}. The constant
|
||||
* GSS_C_NT_USER_NAME should be initialized to point
|
||||
* to that gss_OID_desc.
|
||||
*/
|
||||
extern gss_OID GSS_C_NT_USER_NAME;
|
||||
|
||||
/*
|
||||
* The implementation must reserve static storage for a
|
||||
* gss_OID_desc object containing the value
|
||||
* {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
|
||||
* "\x01\x02\x01\x02"},
|
||||
* corresponding to an object-identifier value of
|
||||
* {iso(1) member-body(2) United States(840) mit(113554)
|
||||
* infosys(1) gssapi(2) generic(1) machine_uid_name(2)}.
|
||||
* The constant GSS_C_NT_MACHINE_UID_NAME should be
|
||||
* initialized to point to that gss_OID_desc.
|
||||
*/
|
||||
extern gss_OID GSS_C_NT_MACHINE_UID_NAME;
|
||||
|
||||
/*
|
||||
* The implementation must reserve static storage for a
|
||||
* gss_OID_desc object containing the value
|
||||
* {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
|
||||
* "\x01\x02\x01\x03"},
|
||||
* corresponding to an object-identifier value of
|
||||
* {iso(1) member-body(2) United States(840) mit(113554)
|
||||
* infosys(1) gssapi(2) generic(1) string_uid_name(3)}.
|
||||
* The constant GSS_C_NT_STRING_UID_NAME should be
|
||||
* initialized to point to that gss_OID_desc.
|
||||
*/
|
||||
extern gss_OID GSS_C_NT_STRING_UID_NAME;
|
||||
|
||||
/*
|
||||
* The implementation must reserve static storage for a
|
||||
* gss_OID_desc object containing the value
|
||||
* {6, (void *)"\x2b\x06\x01\x05\x06\x02"},
|
||||
* corresponding to an object-identifier value of
|
||||
* {iso(1) org(3) dod(6) internet(1) security(5)
|
||||
* nametypes(6) gss-host-based-services(2)). The constant
|
||||
* GSS_C_NT_HOSTBASED_SERVICE_X should be initialized to point
|
||||
* to that gss_OID_desc. This is a deprecated OID value, and
|
||||
* implementations wishing to support hostbased-service names
|
||||
* should instead use the GSS_C_NT_HOSTBASED_SERVICE OID,
|
||||
* defined below, to identify such names;
|
||||
* GSS_C_NT_HOSTBASED_SERVICE_X should be accepted a synonym
|
||||
* for GSS_C_NT_HOSTBASED_SERVICE when presented as an input
|
||||
* parameter, but should not be emitted by GSSAPI
|
||||
* implementations
|
||||
*/
|
||||
extern gss_OID GSS_C_NT_HOSTBASED_SERVICE_X;
|
||||
|
||||
/*
|
||||
* The implementation must reserve static storage for a
|
||||
* gss_OID_desc object containing the value
|
||||
* {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
|
||||
* "\x01\x02\x01\x04"}, corresponding to an
|
||||
* object-identifier value of {iso(1) member-body(2)
|
||||
* Unites States(840) mit(113554) infosys(1) gssapi(2)
|
||||
* generic(1) service_name(4)}. The constant
|
||||
* GSS_C_NT_HOSTBASED_SERVICE should be initialized
|
||||
* to point to that gss_OID_desc.
|
||||
*/
|
||||
extern gss_OID GSS_C_NT_HOSTBASED_SERVICE;
|
||||
|
||||
|
||||
/*
|
||||
* The implementation must reserve static storage for a
|
||||
* gss_OID_desc object containing the value
|
||||
* {6, (void *)"\x2b\x06\01\x05\x06\x03"},
|
||||
* corresponding to an object identifier value of
|
||||
* {1(iso), 3(org), 6(dod), 1(internet), 5(security),
|
||||
* 6(nametypes), 3(gss-anonymous-name)}. The constant
|
||||
* and GSS_C_NT_ANONYMOUS should be initialized to point
|
||||
* to that gss_OID_desc.
|
||||
*/
|
||||
extern gss_OID GSS_C_NT_ANONYMOUS;
|
||||
|
||||
/*
|
||||
* The implementation must reserve static storage for a
|
||||
* gss_OID_desc object containing the value
|
||||
* {6, (void *)"\x2b\x06\x01\x05\x06\x04"},
|
||||
* corresponding to an object-identifier value of
|
||||
* {1(iso), 3(org), 6(dod), 1(internet), 5(security),
|
||||
* 6(nametypes), 4(gss-api-exported-name)}. The constant
|
||||
* GSS_C_NT_EXPORT_NAME should be initialized to point
|
||||
* to that gss_OID_desc.
|
||||
*/
|
||||
extern gss_OID GSS_C_NT_EXPORT_NAME;
|
||||
|
||||
/* Major status codes */
|
||||
|
||||
#define GSS_S_COMPLETE 0
|
||||
|
||||
/*
|
||||
* Some "helper" definitions to make the status code macros obvious.
|
||||
*/
|
||||
#define GSS_C_CALLING_ERROR_OFFSET 24
|
||||
#define GSS_C_ROUTINE_ERROR_OFFSET 16
|
||||
#define GSS_C_SUPPLEMENTARY_OFFSET 0
|
||||
#define GSS_C_CALLING_ERROR_MASK 0377ul
|
||||
#define GSS_C_ROUTINE_ERROR_MASK 0377ul
|
||||
#define GSS_C_SUPPLEMENTARY_MASK 0177777ul
|
||||
|
||||
/*
|
||||
* The macros that test status codes for error conditions.
|
||||
* Note that the GSS_ERROR() macro has changed slightly from
|
||||
* the V1 GSSAPI so that it now evaluates its argument
|
||||
* only once.
|
||||
*/
|
||||
#define GSS_CALLING_ERROR(x) \
|
||||
(x & (GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET))
|
||||
#define GSS_ROUTINE_ERROR(x) \
|
||||
(x & (GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET))
|
||||
#define GSS_SUPPLEMENTARY_INFO(x) \
|
||||
(x & (GSS_C_SUPPLEMENTARY_MASK << GSS_C_SUPPLEMENTARY_OFFSET))
|
||||
#define GSS_ERROR(x) \
|
||||
(x & ((GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET) | \
|
||||
(GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET)))
|
||||
|
||||
/*
|
||||
* Now the actual status code definitions
|
||||
*/
|
||||
|
||||
/*
|
||||
* Calling errors:
|
||||
*/
|
||||
#define GSS_S_CALL_INACCESSIBLE_READ \
|
||||
(1ul << GSS_C_CALLING_ERROR_OFFSET)
|
||||
#define GSS_S_CALL_INACCESSIBLE_WRITE \
|
||||
(2ul << GSS_C_CALLING_ERROR_OFFSET)
|
||||
#define GSS_S_CALL_BAD_STRUCTURE \
|
||||
(3ul << GSS_C_CALLING_ERROR_OFFSET)
|
||||
|
||||
/*
|
||||
* Routine errors:
|
||||
*/
|
||||
#define GSS_S_BAD_MECH (1ul << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_BAD_NAME (2ul << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_BAD_NAMETYPE (3ul << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_BAD_BINDINGS (4ul << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_BAD_STATUS (5ul << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_BAD_SIG (6ul << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_BAD_MIC GSS_S_BAD_SIG
|
||||
#define GSS_S_NO_CRED (7ul << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_NO_CONTEXT (8ul << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_DEFECTIVE_TOKEN (9ul << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_DEFECTIVE_CREDENTIAL (10ul << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_CREDENTIALS_EXPIRED (11ul << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_CONTEXT_EXPIRED (12ul << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_FAILURE (13ul << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_BAD_QOP (14ul << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_UNAUTHORIZED (15ul << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_UNAVAILABLE (16ul << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_DUPLICATE_ELEMENT (17ul << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_NAME_NOT_MN (18ul << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
|
||||
/*
|
||||
* Supplementary info bits:
|
||||
*/
|
||||
#define GSS_S_CONTINUE_NEEDED (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 0))
|
||||
#define GSS_S_DUPLICATE_TOKEN (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 1))
|
||||
#define GSS_S_OLD_TOKEN (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 2))
|
||||
#define GSS_S_UNSEQ_TOKEN (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 3))
|
||||
#define GSS_S_GAP_TOKEN (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 4))
|
||||
|
||||
/*
|
||||
* Finally, function prototypes for the GSS-API routines.
|
||||
*/
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_acquire_cred)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
const gss_name_t, /* desired_name */
|
||||
OM_uint32, /* time_req */
|
||||
const gss_OID_set, /* desired_mechs */
|
||||
gss_cred_usage_t, /* cred_usage */
|
||||
gss_cred_id_t *, /* output_cred_handle */
|
||||
gss_OID_set *, /* actual_mechs */
|
||||
OM_uint32 * /* time_rec */
|
||||
);
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_release_cred)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
gss_cred_id_t * /* cred_handle */
|
||||
);
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_init_sec_context)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
const gss_cred_id_t, /* initiator_cred_handle */
|
||||
gss_ctx_id_t *, /* context_handle */
|
||||
const gss_name_t, /* target_name */
|
||||
const gss_OID, /* mech_type */
|
||||
OM_uint32, /* req_flags */
|
||||
OM_uint32, /* time_req */
|
||||
const gss_channel_bindings_t, /* input_chan_bindings */
|
||||
const gss_buffer_t, /* input_token */
|
||||
gss_OID *, /* actual_mech_type */
|
||||
gss_buffer_t, /* output_token */
|
||||
OM_uint32 *, /* ret_flags */
|
||||
OM_uint32 * /* time_rec */
|
||||
);
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_accept_sec_context)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
gss_ctx_id_t *, /* context_handle */
|
||||
const gss_cred_id_t, /* acceptor_cred_handle */
|
||||
const gss_buffer_t, /* input_token_buffer */
|
||||
const gss_channel_bindings_t, /* input_chan_bindings */
|
||||
gss_name_t *, /* src_name */
|
||||
gss_OID *, /* mech_type */
|
||||
gss_buffer_t, /* output_token */
|
||||
OM_uint32 *, /* ret_flags */
|
||||
OM_uint32 *, /* time_rec */
|
||||
gss_cred_id_t * /* delegated_cred_handle */
|
||||
);
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_process_context_token)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
const gss_ctx_id_t, /* context_handle */
|
||||
const gss_buffer_t /* token_buffer */
|
||||
);
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_delete_sec_context)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
gss_ctx_id_t *, /* context_handle */
|
||||
gss_buffer_t /* output_token */
|
||||
);
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_context_time)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
const gss_ctx_id_t, /* context_handle */
|
||||
OM_uint32 * /* time_rec */
|
||||
);
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_get_mic)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
const gss_ctx_id_t, /* context_handle */
|
||||
gss_qop_t, /* qop_req */
|
||||
const gss_buffer_t, /* message_buffer */
|
||||
gss_buffer_t /* message_token */
|
||||
);
|
||||
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_verify_mic)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
const gss_ctx_id_t, /* context_handle */
|
||||
const gss_buffer_t, /* message_buffer */
|
||||
const gss_buffer_t, /* token_buffer */
|
||||
gss_qop_t * /* qop_state */
|
||||
);
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_wrap)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
const gss_ctx_id_t, /* context_handle */
|
||||
int, /* conf_req_flag */
|
||||
gss_qop_t, /* qop_req */
|
||||
const gss_buffer_t, /* input_message_buffer */
|
||||
int *, /* conf_state */
|
||||
gss_buffer_t /* output_message_buffer */
|
||||
);
|
||||
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_unwrap)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
const gss_ctx_id_t, /* context_handle */
|
||||
const gss_buffer_t, /* input_message_buffer */
|
||||
gss_buffer_t, /* output_message_buffer */
|
||||
int *, /* conf_state */
|
||||
gss_qop_t * /* qop_state */
|
||||
);
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_display_status)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
OM_uint32, /* status_value */
|
||||
int, /* status_type */
|
||||
const gss_OID, /* mech_type */
|
||||
OM_uint32 *, /* message_context */
|
||||
gss_buffer_t /* status_string */
|
||||
);
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_indicate_mechs)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
gss_OID_set * /* mech_set */
|
||||
);
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_compare_name)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
const gss_name_t, /* name1 */
|
||||
const gss_name_t, /* name2 */
|
||||
int * /* name_equal */
|
||||
);
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_display_name)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
const gss_name_t, /* input_name */
|
||||
gss_buffer_t, /* output_name_buffer */
|
||||
gss_OID * /* output_name_type */
|
||||
);
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_import_name)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
const gss_buffer_t, /* input_name_buffer */
|
||||
const gss_OID, /* input_name_type */
|
||||
gss_name_t * /* output_name */
|
||||
);
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_export_name)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
const gss_name_t, /* input_name */
|
||||
gss_buffer_t /* exported_name */
|
||||
);
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_release_name)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
gss_name_t * /* input_name */
|
||||
);
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_release_buffer)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
gss_buffer_t /* buffer */
|
||||
);
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_release_oid_set)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
gss_OID_set * /* set */
|
||||
);
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_inquire_cred)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
const gss_cred_id_t, /* cred_handle */
|
||||
gss_name_t *, /* name */
|
||||
OM_uint32 *, /* lifetime */
|
||||
gss_cred_usage_t *, /* cred_usage */
|
||||
gss_OID_set * /* mechanisms */
|
||||
);
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_inquire_context)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
const gss_ctx_id_t, /* context_handle */
|
||||
gss_name_t *, /* src_name */
|
||||
gss_name_t *, /* targ_name */
|
||||
OM_uint32 *, /* lifetime_rec */
|
||||
gss_OID *, /* mech_type */
|
||||
OM_uint32 *, /* ctx_flags */
|
||||
int *, /* locally_initiated */
|
||||
int * /* open */
|
||||
);
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_wrap_size_limit)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
const gss_ctx_id_t, /* context_handle */
|
||||
int, /* conf_req_flag */
|
||||
gss_qop_t, /* qop_req */
|
||||
OM_uint32, /* req_output_size */
|
||||
OM_uint32 * /* max_input_size */
|
||||
);
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_add_cred)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
const gss_cred_id_t, /* input_cred_handle */
|
||||
const gss_name_t, /* desired_name */
|
||||
const gss_OID, /* desired_mech */
|
||||
gss_cred_usage_t, /* cred_usage */
|
||||
OM_uint32, /* initiator_time_req */
|
||||
OM_uint32, /* acceptor_time_req */
|
||||
gss_cred_id_t *, /* output_cred_handle */
|
||||
gss_OID_set *, /* actual_mechs */
|
||||
OM_uint32 *, /* initiator_time_rec */
|
||||
OM_uint32 * /* acceptor_time_rec */
|
||||
);
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_inquire_cred_by_mech)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
const gss_cred_id_t, /* cred_handle */
|
||||
const gss_OID, /* mech_type */
|
||||
gss_name_t *, /* name */
|
||||
OM_uint32 *, /* initiator_lifetime */
|
||||
OM_uint32 *, /* acceptor_lifetime */
|
||||
gss_cred_usage_t * /* cred_usage */
|
||||
);
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_export_sec_context)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
gss_ctx_id_t *, /* context_handle */
|
||||
gss_buffer_t /* interprocess_token */
|
||||
);
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_import_sec_context)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
const gss_buffer_t, /* interprocess_token */
|
||||
gss_ctx_id_t * /* context_handle */
|
||||
);
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_create_empty_oid_set)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
gss_OID_set * /* oid_set */
|
||||
);
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_add_oid_set_member)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
const gss_OID, /* member_oid */
|
||||
gss_OID_set * /* oid_set */
|
||||
);
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_test_oid_set_member)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
const gss_OID, /* member */
|
||||
const gss_OID_set, /* set */
|
||||
int * /* present */
|
||||
);
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_inquire_names_for_mech)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
const gss_OID, /* mechanism */
|
||||
gss_OID_set * /* name_types */
|
||||
);
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_inquire_mechs_for_name)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
const gss_name_t, /* input_name */
|
||||
gss_OID_set * /* mech_types */
|
||||
);
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_canonicalize_name)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
const gss_name_t, /* input_name */
|
||||
const gss_OID, /* mech_type */
|
||||
gss_name_t * /* output_name */
|
||||
);
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_duplicate_name)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
const gss_name_t, /* src_name */
|
||||
gss_name_t * /* dest_name */
|
||||
);
|
||||
|
||||
/*
|
||||
* The following routines are obsolete variants of gss_get_mic,
|
||||
* gss_verify_mic, gss_wrap and gss_unwrap. They should be
|
||||
* provided by GSSAPI V2 implementations for backwards
|
||||
* compatibility with V1 applications. Distinct entrypoints
|
||||
* (as opposed to #defines) should be provided, both to allow
|
||||
* GSSAPI V1 applications to link against GSSAPI V2 implementations,
|
||||
* and to retain the slight parameter type differences between the
|
||||
* obsolete versions of these routines and their current forms.
|
||||
*/
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_sign)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
gss_ctx_id_t, /* context_handle */
|
||||
int, /* qop_req */
|
||||
gss_buffer_t, /* message_buffer */
|
||||
gss_buffer_t /* message_token */
|
||||
);
|
||||
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_verify)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
gss_ctx_id_t, /* context_handle */
|
||||
gss_buffer_t, /* message_buffer */
|
||||
gss_buffer_t, /* token_buffer */
|
||||
int * /* qop_state */
|
||||
);
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_seal)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
gss_ctx_id_t, /* context_handle */
|
||||
int, /* conf_req_flag */
|
||||
int, /* qop_req */
|
||||
gss_buffer_t, /* input_message_buffer */
|
||||
int *, /* conf_state */
|
||||
gss_buffer_t /* output_message_buffer */
|
||||
);
|
||||
|
||||
|
||||
GSS_MAKE_TYPEDEF
|
||||
OM_uint32
|
||||
GSS_CALLCONV GSS_FUNC(gss_unseal)
|
||||
(OM_uint32 *, /* minor_status */
|
||||
gss_ctx_id_t, /* context_handle */
|
||||
gss_buffer_t, /* input_message_buffer */
|
||||
gss_buffer_t, /* output_message_buffer */
|
||||
int *, /* conf_state */
|
||||
int * /* qop_state */
|
||||
);
|
||||
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
# pragma pack(pop)
|
||||
#endif
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif /* GSSAPI_H_ */
|
||||
|
||||
27
extensions/auth/moz.build
Normal file
27
extensions/auth/moz.build
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'nsAuthFactory.cpp',
|
||||
'nsAuthGSSAPI.cpp',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'nsAuthSASL.cpp',
|
||||
'nsHttpNegotiateAuth.cpp', # contains constants whose names conflict with constants in other files
|
||||
]
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
SOURCES += [
|
||||
'nsAuthSSPI.cpp',
|
||||
]
|
||||
DEFINES['USE_SSPI'] = True
|
||||
else:
|
||||
UNIFIED_SOURCES += [
|
||||
'nsAuthSambaNTLM.cpp',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
27
extensions/auth/nsAuth.h
Normal file
27
extensions/auth/nsAuth.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsAuth_h__
|
||||
#define nsAuth_h__
|
||||
|
||||
/* types of packages */
|
||||
enum pType {
|
||||
PACKAGE_TYPE_KERBEROS,
|
||||
PACKAGE_TYPE_NEGOTIATE,
|
||||
PACKAGE_TYPE_NTLM
|
||||
};
|
||||
|
||||
#include "mozilla/Logging.h"
|
||||
|
||||
//
|
||||
// in order to do logging, the following environment variables need to be set:
|
||||
//
|
||||
// set NSPR_LOG_MODULES=negotiateauth:4
|
||||
// set NSPR_LOG_FILE=negotiateauth.log
|
||||
//
|
||||
extern mozilla::LazyLogModule gNegotiateLog;
|
||||
|
||||
#define LOG(args) MOZ_LOG(gNegotiateLog, mozilla::LogLevel::Debug, args)
|
||||
|
||||
#endif /* !defined( nsAuth_h__ ) */
|
||||
247
extensions/auth/nsAuthFactory.cpp
Normal file
247
extensions/auth/nsAuthFactory.cpp
Normal file
|
|
@ -0,0 +1,247 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/ModuleUtils.h"
|
||||
#include "nsAuth.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define NS_HTTPNEGOTIATEAUTH_CID \
|
||||
{ /* 75c80fd0-accb-432c-af59-ec60668c3990 */ \
|
||||
0x75c80fd0, \
|
||||
0xaccb, \
|
||||
0x432c, \
|
||||
{0xaf, 0x59, 0xec, 0x60, 0x66, 0x8c, 0x39, 0x90} \
|
||||
}
|
||||
|
||||
#include "nsHttpNegotiateAuth.h"
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsHttpNegotiateAuth)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define NS_NEGOTIATEAUTH_CID \
|
||||
{ /* 96ec4163-efc8-407a-8735-007fb26be4e8 */ \
|
||||
0x96ec4163, \
|
||||
0xefc8, \
|
||||
0x407a, \
|
||||
{0x87, 0x35, 0x00, 0x7f, 0xb2, 0x6b, 0xe4, 0xe8} \
|
||||
}
|
||||
#define NS_GSSAUTH_CID \
|
||||
{ /* dc8e21a0-03e4-11da-8cd6-0800200c9a66 */ \
|
||||
0xdc8e21a0, \
|
||||
0x03e4, \
|
||||
0x11da, \
|
||||
{0x8c, 0xd6, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66} \
|
||||
}
|
||||
|
||||
#include "nsAuthGSSAPI.h"
|
||||
|
||||
#if defined( USE_SSPI )
|
||||
#include "nsAuthSSPI.h"
|
||||
|
||||
static nsresult
|
||||
nsSysNTLMAuthConstructor(nsISupports *outer, REFNSIID iid, void **result)
|
||||
{
|
||||
if (outer)
|
||||
return NS_ERROR_NO_AGGREGATION;
|
||||
|
||||
nsAuthSSPI *auth = new nsAuthSSPI(PACKAGE_TYPE_NTLM);
|
||||
if (!auth)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
NS_ADDREF(auth);
|
||||
nsresult rv = auth->QueryInterface(iid, result);
|
||||
NS_RELEASE(auth);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
nsKerbSSPIAuthConstructor(nsISupports *outer, REFNSIID iid, void **result)
|
||||
{
|
||||
if (outer)
|
||||
return NS_ERROR_NO_AGGREGATION;
|
||||
|
||||
nsAuthSSPI *auth = new nsAuthSSPI(PACKAGE_TYPE_KERBEROS);
|
||||
if (!auth)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
NS_ADDREF(auth);
|
||||
nsresult rv = auth->QueryInterface(iid, result);
|
||||
NS_RELEASE(auth);
|
||||
return rv;
|
||||
}
|
||||
|
||||
#define NS_SYSNTLMAUTH_CID \
|
||||
{ /* dc195987-6e9a-47bc-b1fd-ab895d398833 */ \
|
||||
0xdc195987, \
|
||||
0x6e9a, \
|
||||
0x47bc, \
|
||||
{0xb1, 0xfd, 0xab, 0x89, 0x5d, 0x39, 0x88, 0x33} \
|
||||
}
|
||||
|
||||
#define NS_NEGOTIATEAUTHSSPI_CID \
|
||||
{ /* 78d3b0c0-0241-11da-8cd6-0800200c9a66 */ \
|
||||
0x78d3b0c0, \
|
||||
0x0241, \
|
||||
0x11da, \
|
||||
{0x8c, 0xd6, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66} \
|
||||
}
|
||||
|
||||
#define NS_KERBAUTHSSPI_CID \
|
||||
{ /* 8c3a0e20-03e5-11da-8cd6-0800200c9a66 */ \
|
||||
0x8c3a0e20, \
|
||||
0x03e5, \
|
||||
0x11da, \
|
||||
{0x8c, 0xd6, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66} \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define NS_SAMBANTLMAUTH_CID \
|
||||
{ /* bc54f001-6eb0-4e32-9f49-7e064d8e70ef */ \
|
||||
0xbc54f001, \
|
||||
0x6eb0, \
|
||||
0x4e32, \
|
||||
{0x9f, 0x49, 0x7e, 0x06, 0x4d, 0x8e, 0x70, 0xef} \
|
||||
}
|
||||
|
||||
#include "nsAuthSambaNTLM.h"
|
||||
static nsresult
|
||||
nsSambaNTLMAuthConstructor(nsISupports *outer, REFNSIID iid, void **result)
|
||||
{
|
||||
if (outer)
|
||||
return NS_ERROR_NO_AGGREGATION;
|
||||
|
||||
RefPtr<nsAuthSambaNTLM> auth = new nsAuthSambaNTLM();
|
||||
if (!auth)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsresult rv = auth->SpawnNTLMAuthHelper();
|
||||
if (NS_FAILED(rv)) {
|
||||
// Failure here probably means that cached credentials were not available
|
||||
return rv;
|
||||
}
|
||||
|
||||
return auth->QueryInterface(iid, result);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static nsresult
|
||||
nsKerbGSSAPIAuthConstructor(nsISupports *outer, REFNSIID iid, void **result)
|
||||
{
|
||||
if (outer)
|
||||
return NS_ERROR_NO_AGGREGATION;
|
||||
|
||||
nsAuthGSSAPI *auth = new nsAuthGSSAPI(PACKAGE_TYPE_KERBEROS);
|
||||
if (!auth)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
NS_ADDREF(auth);
|
||||
nsresult rv = auth->QueryInterface(iid, result);
|
||||
NS_RELEASE(auth);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
nsGSSAPIAuthConstructor(nsISupports *outer, REFNSIID iid, void **result)
|
||||
{
|
||||
if (outer)
|
||||
return NS_ERROR_NO_AGGREGATION;
|
||||
|
||||
nsAuthGSSAPI *auth = new nsAuthGSSAPI(PACKAGE_TYPE_NEGOTIATE);
|
||||
if (!auth)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
NS_ADDREF(auth);
|
||||
nsresult rv = auth->QueryInterface(iid, result);
|
||||
NS_RELEASE(auth);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
#if defined( USE_SSPI )
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsAuthSSPI)
|
||||
#endif
|
||||
|
||||
#define NS_AUTHSASL_CID \
|
||||
{ /* 815e42e0-72cc-480f-934b-148e33c228a6 */ \
|
||||
0x815e42e0, \
|
||||
0x72cc, \
|
||||
0x480f, \
|
||||
{0x93, 0x4b, 0x14, 0x8e, 0x33, 0xc2, 0x28, 0xa6} \
|
||||
}
|
||||
|
||||
#include "nsAuthSASL.h"
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsAuthSASL)
|
||||
|
||||
NS_DEFINE_NAMED_CID(NS_GSSAUTH_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_NEGOTIATEAUTH_CID);
|
||||
#if defined( USE_SSPI )
|
||||
NS_DEFINE_NAMED_CID(NS_NEGOTIATEAUTHSSPI_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_KERBAUTHSSPI_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_SYSNTLMAUTH_CID);
|
||||
#else
|
||||
NS_DEFINE_NAMED_CID(NS_SAMBANTLMAUTH_CID);
|
||||
#endif
|
||||
NS_DEFINE_NAMED_CID(NS_HTTPNEGOTIATEAUTH_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_AUTHSASL_CID);
|
||||
|
||||
|
||||
static const mozilla::Module::CIDEntry kAuthCIDs[] = {
|
||||
{ &kNS_GSSAUTH_CID, false, nullptr, nsKerbGSSAPIAuthConstructor },
|
||||
{ &kNS_NEGOTIATEAUTH_CID, false, nullptr, nsGSSAPIAuthConstructor },
|
||||
#if defined( USE_SSPI )
|
||||
{ &kNS_NEGOTIATEAUTHSSPI_CID, false, nullptr, nsAuthSSPIConstructor },
|
||||
{ &kNS_KERBAUTHSSPI_CID, false, nullptr, nsKerbSSPIAuthConstructor },
|
||||
{ &kNS_SYSNTLMAUTH_CID, false, nullptr, nsSysNTLMAuthConstructor },
|
||||
#else
|
||||
{ &kNS_SAMBANTLMAUTH_CID, false, nullptr, nsSambaNTLMAuthConstructor },
|
||||
#endif
|
||||
{ &kNS_HTTPNEGOTIATEAUTH_CID, false, nullptr, nsHttpNegotiateAuthConstructor },
|
||||
{ &kNS_AUTHSASL_CID, false, nullptr, nsAuthSASLConstructor },
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
static const mozilla::Module::ContractIDEntry kAuthContracts[] = {
|
||||
{ NS_AUTH_MODULE_CONTRACTID_PREFIX "kerb-gss", &kNS_GSSAUTH_CID },
|
||||
{ NS_AUTH_MODULE_CONTRACTID_PREFIX "negotiate-gss", &kNS_NEGOTIATEAUTH_CID },
|
||||
#if defined( USE_SSPI )
|
||||
{ NS_AUTH_MODULE_CONTRACTID_PREFIX "negotiate-sspi", &kNS_NEGOTIATEAUTHSSPI_CID },
|
||||
{ NS_AUTH_MODULE_CONTRACTID_PREFIX "kerb-sspi", &kNS_KERBAUTHSSPI_CID },
|
||||
{ NS_AUTH_MODULE_CONTRACTID_PREFIX "sys-ntlm", &kNS_SYSNTLMAUTH_CID },
|
||||
#else
|
||||
{ NS_AUTH_MODULE_CONTRACTID_PREFIX "sys-ntlm", &kNS_SAMBANTLMAUTH_CID },
|
||||
#endif
|
||||
{ NS_HTTP_AUTHENTICATOR_CONTRACTID_PREFIX "negotiate", &kNS_HTTPNEGOTIATEAUTH_CID },
|
||||
{ NS_AUTH_MODULE_CONTRACTID_PREFIX "sasl-gssapi", &kNS_AUTHSASL_CID },
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
mozilla::LazyLogModule gNegotiateLog("negotiateauth");
|
||||
|
||||
// setup nspr logging ...
|
||||
static nsresult
|
||||
InitNegotiateAuth()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
DestroyNegotiateAuth()
|
||||
{
|
||||
nsAuthGSSAPI::Shutdown();
|
||||
}
|
||||
|
||||
static const mozilla::Module kAuthModule = {
|
||||
mozilla::Module::kVersion,
|
||||
kAuthCIDs,
|
||||
kAuthContracts,
|
||||
nullptr,
|
||||
nullptr,
|
||||
InitNegotiateAuth,
|
||||
DestroyNegotiateAuth
|
||||
};
|
||||
|
||||
NSMODULE_DEFN(nsAuthModule) = &kAuthModule;
|
||||
603
extensions/auth/nsAuthGSSAPI.cpp
Normal file
603
extensions/auth/nsAuthGSSAPI.cpp
Normal file
|
|
@ -0,0 +1,603 @@
|
|||
/* vim:set ts=4 sw=4 sts=4 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//
|
||||
// GSSAPI Authentication Support Module
|
||||
//
|
||||
// Described by IETF Internet draft: draft-brezak-kerberos-http-00.txt
|
||||
// (formerly draft-brezak-spnego-http-04.txt)
|
||||
//
|
||||
// Also described here:
|
||||
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnsecure/html/http-sso-1.asp
|
||||
//
|
||||
//
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
|
||||
#include "prlink.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIPrefService.h"
|
||||
#include "nsIPrefBranch.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsNativeCharsetUtils.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
||||
#include "nsAuthGSSAPI.h"
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#include <Kerberos/Kerberos.h>
|
||||
#endif
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
typedef KLStatus (*KLCacheHasValidTickets_type)(
|
||||
KLPrincipal,
|
||||
KLKerberosVersion,
|
||||
KLBoolean *,
|
||||
KLPrincipal *,
|
||||
char **);
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_RES_NINIT)
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/nameser.h>
|
||||
#include <resolv.h>
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// We define GSS_C_NT_HOSTBASED_SERVICE explicitly since it may be referenced
|
||||
// by by a different name depending on the implementation of gss but always
|
||||
// has the same value
|
||||
|
||||
static gss_OID_desc gss_c_nt_hostbased_service =
|
||||
{ 10, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04" };
|
||||
|
||||
static const char kNegotiateAuthGssLib[] =
|
||||
"network.negotiate-auth.gsslib";
|
||||
static const char kNegotiateAuthNativeImp[] =
|
||||
"network.negotiate-auth.using-native-gsslib";
|
||||
|
||||
static struct GSSFunction {
|
||||
const char *str;
|
||||
PRFuncPtr func;
|
||||
} gssFuncs[] = {
|
||||
{ "gss_display_status", nullptr },
|
||||
{ "gss_init_sec_context", nullptr },
|
||||
{ "gss_indicate_mechs", nullptr },
|
||||
{ "gss_release_oid_set", nullptr },
|
||||
{ "gss_delete_sec_context", nullptr },
|
||||
{ "gss_import_name", nullptr },
|
||||
{ "gss_release_buffer", nullptr },
|
||||
{ "gss_release_name", nullptr },
|
||||
{ "gss_wrap", nullptr },
|
||||
{ "gss_unwrap", nullptr }
|
||||
};
|
||||
|
||||
static bool gssNativeImp = true;
|
||||
static PRLibrary* gssLibrary = nullptr;
|
||||
|
||||
#define gss_display_status_ptr ((gss_display_status_type)*gssFuncs[0].func)
|
||||
#define gss_init_sec_context_ptr ((gss_init_sec_context_type)*gssFuncs[1].func)
|
||||
#define gss_indicate_mechs_ptr ((gss_indicate_mechs_type)*gssFuncs[2].func)
|
||||
#define gss_release_oid_set_ptr ((gss_release_oid_set_type)*gssFuncs[3].func)
|
||||
#define gss_delete_sec_context_ptr ((gss_delete_sec_context_type)*gssFuncs[4].func)
|
||||
#define gss_import_name_ptr ((gss_import_name_type)*gssFuncs[5].func)
|
||||
#define gss_release_buffer_ptr ((gss_release_buffer_type)*gssFuncs[6].func)
|
||||
#define gss_release_name_ptr ((gss_release_name_type)*gssFuncs[7].func)
|
||||
#define gss_wrap_ptr ((gss_wrap_type)*gssFuncs[8].func)
|
||||
#define gss_unwrap_ptr ((gss_unwrap_type)*gssFuncs[9].func)
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
static PRFuncPtr KLCacheHasValidTicketsPtr;
|
||||
#define KLCacheHasValidTickets_ptr \
|
||||
((KLCacheHasValidTickets_type)*KLCacheHasValidTicketsPtr)
|
||||
#endif
|
||||
|
||||
static nsresult
|
||||
gssInit()
|
||||
{
|
||||
nsXPIDLCString libPath;
|
||||
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||
if (prefs) {
|
||||
prefs->GetCharPref(kNegotiateAuthGssLib, getter_Copies(libPath));
|
||||
prefs->GetBoolPref(kNegotiateAuthNativeImp, &gssNativeImp);
|
||||
}
|
||||
|
||||
PRLibrary *lib = nullptr;
|
||||
|
||||
if (!libPath.IsEmpty()) {
|
||||
LOG(("Attempting to load user specified library [%s]\n", libPath.get()));
|
||||
gssNativeImp = false;
|
||||
lib = PR_LoadLibrary(libPath.get());
|
||||
}
|
||||
else {
|
||||
#ifdef XP_WIN
|
||||
char *libName = PR_GetLibraryName(nullptr, "gssapi32");
|
||||
if (libName) {
|
||||
lib = PR_LoadLibrary("gssapi32");
|
||||
PR_FreeLibraryName(libName);
|
||||
}
|
||||
#elif defined(__OpenBSD__)
|
||||
/* OpenBSD doesn't register inter-library dependencies in basesystem
|
||||
* libs therefor we need to load all the libraries gssapi depends on,
|
||||
* in the correct order and with LD_GLOBAL for GSSAPI auth to work
|
||||
* fine.
|
||||
*/
|
||||
|
||||
const char *const verLibNames[] = {
|
||||
"libasn1.so",
|
||||
"libcrypto.so",
|
||||
"libroken.so",
|
||||
"libheimbase.so",
|
||||
"libcom_err.so",
|
||||
"libkrb5.so",
|
||||
"libgssapi.so"
|
||||
};
|
||||
|
||||
PRLibSpec libSpec;
|
||||
for (size_t i = 0; i < ArrayLength(verLibNames); ++i) {
|
||||
libSpec.type = PR_LibSpec_Pathname;
|
||||
libSpec.value.pathname = verLibNames[i];
|
||||
lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_GLOBAL);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
const char *const libNames[] = {
|
||||
"gss",
|
||||
"gssapi_krb5",
|
||||
"gssapi"
|
||||
};
|
||||
|
||||
const char *const verLibNames[] = {
|
||||
"libgssapi_krb5.so.2", /* MIT - FC, Suse10, Debian */
|
||||
"libgssapi.so.4", /* Heimdal - Suse10, MDK */
|
||||
"libgssapi.so.1" /* Heimdal - Suse9, CITI - FC, MDK, Suse10*/
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < ArrayLength(verLibNames) && !lib; ++i) {
|
||||
lib = PR_LoadLibrary(verLibNames[i]);
|
||||
|
||||
/* The CITI libgssapi library calls exit() during
|
||||
* initialization if it's not correctly configured. Try to
|
||||
* ensure that we never use this library for our GSSAPI
|
||||
* support, as its just a wrapper library, anyway.
|
||||
* See Bugzilla #325433
|
||||
*/
|
||||
if (lib &&
|
||||
PR_FindFunctionSymbol(lib,
|
||||
"internal_krb5_gss_initialize") &&
|
||||
PR_FindFunctionSymbol(lib, "gssd_pname_to_uid")) {
|
||||
LOG(("CITI libgssapi found, which calls exit(). Skipping\n"));
|
||||
PR_UnloadLibrary(lib);
|
||||
lib = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ArrayLength(libNames) && !lib; ++i) {
|
||||
char *libName = PR_GetLibraryName(nullptr, libNames[i]);
|
||||
if (libName) {
|
||||
lib = PR_LoadLibrary(libName);
|
||||
PR_FreeLibraryName(libName);
|
||||
|
||||
if (lib &&
|
||||
PR_FindFunctionSymbol(lib,
|
||||
"internal_krb5_gss_initialize") &&
|
||||
PR_FindFunctionSymbol(lib, "gssd_pname_to_uid")) {
|
||||
LOG(("CITI libgssapi found, which calls exit(). Skipping\n"));
|
||||
PR_UnloadLibrary(lib);
|
||||
lib = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!lib) {
|
||||
LOG(("Fail to load gssapi library\n"));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
LOG(("Attempting to load gss functions\n"));
|
||||
|
||||
for (size_t i = 0; i < ArrayLength(gssFuncs); ++i) {
|
||||
gssFuncs[i].func = PR_FindFunctionSymbol(lib, gssFuncs[i].str);
|
||||
if (!gssFuncs[i].func) {
|
||||
LOG(("Fail to load %s function from gssapi library\n", gssFuncs[i].str));
|
||||
PR_UnloadLibrary(lib);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
#ifdef XP_MACOSX
|
||||
if (gssNativeImp &&
|
||||
!(KLCacheHasValidTicketsPtr =
|
||||
PR_FindFunctionSymbol(lib, "KLCacheHasValidTickets"))) {
|
||||
LOG(("Fail to load KLCacheHasValidTickets function from gssapi library\n"));
|
||||
PR_UnloadLibrary(lib);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
#endif
|
||||
|
||||
gssLibrary = lib;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Generate proper GSSAPI error messages from the major and
|
||||
// minor status codes.
|
||||
void
|
||||
LogGssError(OM_uint32 maj_stat, OM_uint32 min_stat, const char *prefix)
|
||||
{
|
||||
if (!MOZ_LOG_TEST(gNegotiateLog, LogLevel::Debug)) {
|
||||
return;
|
||||
}
|
||||
|
||||
OM_uint32 new_stat;
|
||||
OM_uint32 msg_ctx = 0;
|
||||
gss_buffer_desc status1_string;
|
||||
gss_buffer_desc status2_string;
|
||||
OM_uint32 ret;
|
||||
nsAutoCString errorStr;
|
||||
errorStr.Assign(prefix);
|
||||
|
||||
if (!gssLibrary)
|
||||
return;
|
||||
|
||||
errorStr += ": ";
|
||||
do {
|
||||
ret = gss_display_status_ptr(&new_stat,
|
||||
maj_stat,
|
||||
GSS_C_GSS_CODE,
|
||||
GSS_C_NULL_OID,
|
||||
&msg_ctx,
|
||||
&status1_string);
|
||||
errorStr.Append((const char *) status1_string.value, status1_string.length);
|
||||
gss_release_buffer_ptr(&new_stat, &status1_string);
|
||||
|
||||
errorStr += '\n';
|
||||
ret = gss_display_status_ptr(&new_stat,
|
||||
min_stat,
|
||||
GSS_C_MECH_CODE,
|
||||
GSS_C_NULL_OID,
|
||||
&msg_ctx,
|
||||
&status2_string);
|
||||
errorStr.Append((const char *) status2_string.value, status2_string.length);
|
||||
errorStr += '\n';
|
||||
} while (!GSS_ERROR(ret) && msg_ctx != 0);
|
||||
|
||||
LOG(("%s\n", errorStr.get()));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
nsAuthGSSAPI::nsAuthGSSAPI(pType package)
|
||||
: mServiceFlags(REQ_DEFAULT)
|
||||
{
|
||||
OM_uint32 minstat;
|
||||
OM_uint32 majstat;
|
||||
gss_OID_set mech_set;
|
||||
gss_OID item;
|
||||
|
||||
unsigned int i;
|
||||
static gss_OID_desc gss_krb5_mech_oid_desc =
|
||||
{ 9, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" };
|
||||
static gss_OID_desc gss_spnego_mech_oid_desc =
|
||||
{ 6, (void *) "\x2b\x06\x01\x05\x05\x02" };
|
||||
|
||||
LOG(("entering nsAuthGSSAPI::nsAuthGSSAPI()\n"));
|
||||
|
||||
mComplete = false;
|
||||
|
||||
if (!gssLibrary && NS_FAILED(gssInit()))
|
||||
return;
|
||||
|
||||
mCtx = GSS_C_NO_CONTEXT;
|
||||
mMechOID = &gss_krb5_mech_oid_desc;
|
||||
|
||||
// if the type is kerberos we accept it as default
|
||||
// and exit
|
||||
|
||||
if (package == PACKAGE_TYPE_KERBEROS)
|
||||
return;
|
||||
|
||||
// Now, look at the list of supported mechanisms,
|
||||
// if SPNEGO is found, then use it.
|
||||
// Otherwise, set the desired mechanism to
|
||||
// GSS_C_NO_OID and let the system try to use
|
||||
// the default mechanism.
|
||||
//
|
||||
// Using Kerberos directly (instead of negotiating
|
||||
// with SPNEGO) may work in some cases depending
|
||||
// on how smart the server side is.
|
||||
|
||||
majstat = gss_indicate_mechs_ptr(&minstat, &mech_set);
|
||||
if (GSS_ERROR(majstat))
|
||||
return;
|
||||
|
||||
if (mech_set) {
|
||||
for (i=0; i<mech_set->count; i++) {
|
||||
item = &mech_set->elements[i];
|
||||
if (item->length == gss_spnego_mech_oid_desc.length &&
|
||||
!memcmp(item->elements, gss_spnego_mech_oid_desc.elements,
|
||||
item->length)) {
|
||||
// ok, we found it
|
||||
mMechOID = &gss_spnego_mech_oid_desc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
gss_release_oid_set_ptr(&minstat, &mech_set);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsAuthGSSAPI::Reset()
|
||||
{
|
||||
if (gssLibrary && mCtx != GSS_C_NO_CONTEXT) {
|
||||
OM_uint32 minor_status;
|
||||
gss_delete_sec_context_ptr(&minor_status, &mCtx, GSS_C_NO_BUFFER);
|
||||
}
|
||||
mCtx = GSS_C_NO_CONTEXT;
|
||||
mComplete = false;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
nsAuthGSSAPI::Shutdown()
|
||||
{
|
||||
if (gssLibrary) {
|
||||
PR_UnloadLibrary(gssLibrary);
|
||||
gssLibrary = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Limitations apply to this class's thread safety. See the header file */
|
||||
NS_IMPL_ISUPPORTS(nsAuthGSSAPI, nsIAuthModule)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAuthGSSAPI::Init(const char *serviceName,
|
||||
uint32_t serviceFlags,
|
||||
const char16_t *domain,
|
||||
const char16_t *username,
|
||||
const char16_t *password)
|
||||
{
|
||||
// we don't expect to be passed any user credentials
|
||||
NS_ASSERTION(!domain && !username && !password, "unexpected credentials");
|
||||
|
||||
// it's critial that the caller supply a service name to be used
|
||||
NS_ENSURE_TRUE(serviceName && *serviceName, NS_ERROR_INVALID_ARG);
|
||||
|
||||
LOG(("entering nsAuthGSSAPI::Init()\n"));
|
||||
|
||||
if (!gssLibrary)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
mServiceName = serviceName;
|
||||
mServiceFlags = serviceFlags;
|
||||
|
||||
static bool sTelemetrySent = false;
|
||||
if (!sTelemetrySent) {
|
||||
mozilla::Telemetry::Accumulate(
|
||||
mozilla::Telemetry::NTLM_MODULE_USED_2,
|
||||
serviceFlags & nsIAuthModule::REQ_PROXY_AUTH
|
||||
? NTLM_MODULE_KERBEROS_PROXY
|
||||
: NTLM_MODULE_KERBEROS_DIRECT);
|
||||
sTelemetrySent = true;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAuthGSSAPI::GetNextToken(const void *inToken,
|
||||
uint32_t inTokenLen,
|
||||
void **outToken,
|
||||
uint32_t *outTokenLen)
|
||||
{
|
||||
OM_uint32 major_status, minor_status;
|
||||
OM_uint32 req_flags = 0;
|
||||
gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
|
||||
gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
|
||||
gss_buffer_t in_token_ptr = GSS_C_NO_BUFFER;
|
||||
gss_name_t server;
|
||||
nsAutoCString userbuf;
|
||||
nsresult rv;
|
||||
|
||||
LOG(("entering nsAuthGSSAPI::GetNextToken()\n"));
|
||||
|
||||
if (!gssLibrary)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
// If they've called us again after we're complete, reset to start afresh.
|
||||
if (mComplete)
|
||||
Reset();
|
||||
|
||||
if (mServiceFlags & REQ_DELEGATE)
|
||||
req_flags |= GSS_C_DELEG_FLAG;
|
||||
|
||||
if (mServiceFlags & REQ_MUTUAL_AUTH)
|
||||
req_flags |= GSS_C_MUTUAL_FLAG;
|
||||
|
||||
input_token.value = (void *)mServiceName.get();
|
||||
input_token.length = mServiceName.Length() + 1;
|
||||
|
||||
#if defined(HAVE_RES_NINIT)
|
||||
res_ninit(&_res);
|
||||
#endif
|
||||
major_status = gss_import_name_ptr(&minor_status,
|
||||
&input_token,
|
||||
&gss_c_nt_hostbased_service,
|
||||
&server);
|
||||
input_token.value = nullptr;
|
||||
input_token.length = 0;
|
||||
if (GSS_ERROR(major_status)) {
|
||||
LogGssError(major_status, minor_status, "gss_import_name() failed");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (inToken) {
|
||||
input_token.length = inTokenLen;
|
||||
input_token.value = (void *) inToken;
|
||||
in_token_ptr = &input_token;
|
||||
}
|
||||
else if (mCtx != GSS_C_NO_CONTEXT) {
|
||||
// If there is no input token, then we are starting a new
|
||||
// authentication sequence. If we have already initialized our
|
||||
// security context, then we're in trouble because it means that the
|
||||
// first sequence failed. We need to bail or else we might end up in
|
||||
// an infinite loop.
|
||||
LOG(("Cannot restart authentication sequence!"));
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
// Suppress Kerberos prompts to get credentials. See bug 240643.
|
||||
// We can only use Mac OS X specific kerb functions if we are using
|
||||
// the native lib
|
||||
KLBoolean found;
|
||||
bool doingMailTask = mServiceName.Find("imap@") ||
|
||||
mServiceName.Find("pop@") ||
|
||||
mServiceName.Find("smtp@") ||
|
||||
mServiceName.Find("ldap@");
|
||||
|
||||
if (!doingMailTask && (gssNativeImp &&
|
||||
(KLCacheHasValidTickets_ptr(nullptr, kerberosVersion_V5, &found, nullptr, nullptr) != klNoErr || !found)))
|
||||
{
|
||||
major_status = GSS_S_FAILURE;
|
||||
minor_status = 0;
|
||||
}
|
||||
else
|
||||
#endif /* XP_MACOSX */
|
||||
major_status = gss_init_sec_context_ptr(&minor_status,
|
||||
GSS_C_NO_CREDENTIAL,
|
||||
&mCtx,
|
||||
server,
|
||||
mMechOID,
|
||||
req_flags,
|
||||
GSS_C_INDEFINITE,
|
||||
GSS_C_NO_CHANNEL_BINDINGS,
|
||||
in_token_ptr,
|
||||
nullptr,
|
||||
&output_token,
|
||||
nullptr,
|
||||
nullptr);
|
||||
|
||||
if (GSS_ERROR(major_status)) {
|
||||
LogGssError(major_status, minor_status, "gss_init_sec_context() failed");
|
||||
Reset();
|
||||
rv = NS_ERROR_FAILURE;
|
||||
goto end;
|
||||
}
|
||||
if (major_status == GSS_S_COMPLETE) {
|
||||
// Mark ourselves as being complete, so that if we're called again
|
||||
// we know to start afresh.
|
||||
mComplete = true;
|
||||
}
|
||||
else if (major_status == GSS_S_CONTINUE_NEEDED) {
|
||||
//
|
||||
// The important thing is that we do NOT reset the
|
||||
// context here because it will be needed on the
|
||||
// next call.
|
||||
//
|
||||
}
|
||||
|
||||
*outTokenLen = output_token.length;
|
||||
if (output_token.length != 0)
|
||||
*outToken = nsMemory::Clone(output_token.value, output_token.length);
|
||||
else
|
||||
*outToken = nullptr;
|
||||
|
||||
gss_release_buffer_ptr(&minor_status, &output_token);
|
||||
|
||||
if (major_status == GSS_S_COMPLETE)
|
||||
rv = NS_SUCCESS_AUTH_FINISHED;
|
||||
else
|
||||
rv = NS_OK;
|
||||
|
||||
end:
|
||||
gss_release_name_ptr(&minor_status, &server);
|
||||
|
||||
LOG((" leaving nsAuthGSSAPI::GetNextToken [rv=%x]", rv));
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAuthGSSAPI::Unwrap(const void *inToken,
|
||||
uint32_t inTokenLen,
|
||||
void **outToken,
|
||||
uint32_t *outTokenLen)
|
||||
{
|
||||
OM_uint32 major_status, minor_status;
|
||||
|
||||
gss_buffer_desc input_token;
|
||||
gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
|
||||
|
||||
input_token.value = (void *) inToken;
|
||||
input_token.length = inTokenLen;
|
||||
|
||||
major_status = gss_unwrap_ptr(&minor_status,
|
||||
mCtx,
|
||||
&input_token,
|
||||
&output_token,
|
||||
nullptr,
|
||||
nullptr);
|
||||
if (GSS_ERROR(major_status)) {
|
||||
LogGssError(major_status, minor_status, "gss_unwrap() failed");
|
||||
Reset();
|
||||
gss_release_buffer_ptr(&minor_status, &output_token);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*outTokenLen = output_token.length;
|
||||
|
||||
if (output_token.length)
|
||||
*outToken = nsMemory::Clone(output_token.value, output_token.length);
|
||||
else
|
||||
*outToken = nullptr;
|
||||
|
||||
gss_release_buffer_ptr(&minor_status, &output_token);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAuthGSSAPI::Wrap(const void *inToken,
|
||||
uint32_t inTokenLen,
|
||||
bool confidential,
|
||||
void **outToken,
|
||||
uint32_t *outTokenLen)
|
||||
{
|
||||
OM_uint32 major_status, minor_status;
|
||||
|
||||
gss_buffer_desc input_token;
|
||||
gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
|
||||
|
||||
input_token.value = (void *) inToken;
|
||||
input_token.length = inTokenLen;
|
||||
|
||||
major_status = gss_wrap_ptr(&minor_status,
|
||||
mCtx,
|
||||
confidential,
|
||||
GSS_C_QOP_DEFAULT,
|
||||
&input_token,
|
||||
nullptr,
|
||||
&output_token);
|
||||
|
||||
if (GSS_ERROR(major_status)) {
|
||||
LogGssError(major_status, minor_status, "gss_wrap() failed");
|
||||
Reset();
|
||||
gss_release_buffer_ptr(&minor_status, &output_token);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*outTokenLen = output_token.length;
|
||||
|
||||
/* it is not possible for output_token.length to be zero */
|
||||
*outToken = nsMemory::Clone(output_token.value, output_token.length);
|
||||
gss_release_buffer_ptr(&minor_status, &output_token);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
63
extensions/auth/nsAuthGSSAPI.h
Normal file
63
extensions/auth/nsAuthGSSAPI.h
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/* vim:set ts=4 sw=4 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsAuthGSSAPI_h__
|
||||
#define nsAuthGSSAPI_h__
|
||||
|
||||
#include "nsAuth.h"
|
||||
#include "nsIAuthModule.h"
|
||||
#include "nsString.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#define GSS_USE_FUNCTION_POINTERS 1
|
||||
|
||||
#include "gssapi.h"
|
||||
|
||||
// The nsAuthGSSAPI class provides responses for the GSS-API Negotiate method
|
||||
// as specified by Microsoft in draft-brezak-spnego-http-04.txt
|
||||
|
||||
/* Some remarks on thread safety ...
|
||||
*
|
||||
* The thread safety of this class depends largely upon the thread safety of
|
||||
* the underlying GSSAPI and Kerberos libraries. This code just loads the
|
||||
* system GSSAPI library, and whilst it avoids loading known bad libraries,
|
||||
* it cannot determine the thread safety of the the code it loads.
|
||||
*
|
||||
* When used with a non-threadsafe library, it is not safe to simultaneously
|
||||
* use multiple instantiations of this class.
|
||||
*
|
||||
* When used with a threadsafe Kerberos library, multiple instantiations of
|
||||
* this class may happily co-exist. Methods may be sequentially called from
|
||||
* multiple threads. The nature of the GSSAPI protocol is such that a correct
|
||||
* implementation will never call methods in parallel, as the results of the
|
||||
* last call are required as input to the next.
|
||||
*/
|
||||
|
||||
class nsAuthGSSAPI final : public nsIAuthModule
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIAUTHMODULE
|
||||
|
||||
explicit nsAuthGSSAPI(pType package);
|
||||
|
||||
static void Shutdown();
|
||||
|
||||
private:
|
||||
~nsAuthGSSAPI() { Reset(); }
|
||||
|
||||
void Reset();
|
||||
gss_OID GetOID() { return mMechOID; }
|
||||
|
||||
private:
|
||||
gss_ctx_id_t mCtx;
|
||||
gss_OID mMechOID;
|
||||
nsCString mServiceName;
|
||||
uint32_t mServiceFlags;
|
||||
nsString mUsername;
|
||||
bool mComplete;
|
||||
};
|
||||
|
||||
#endif /* nsAuthGSSAPI_h__ */
|
||||
151
extensions/auth/nsAuthSASL.cpp
Normal file
151
extensions/auth/nsAuthSASL.cpp
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
/* vim:set ts=4 sw=4 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsNativeCharsetUtils.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIPrefService.h"
|
||||
|
||||
#include "nsAuthSASL.h"
|
||||
|
||||
static const char kNegotiateAuthSSPI[] = "network.auth.use-sspi";
|
||||
|
||||
nsAuthSASL::nsAuthSASL()
|
||||
{
|
||||
mSASLReady = false;
|
||||
}
|
||||
|
||||
void nsAuthSASL::Reset()
|
||||
{
|
||||
mSASLReady = false;
|
||||
}
|
||||
|
||||
/* Limitations apply to this class's thread safety. See the header file */
|
||||
NS_IMPL_ISUPPORTS(nsAuthSASL, nsIAuthModule)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAuthSASL::Init(const char *serviceName,
|
||||
uint32_t serviceFlags,
|
||||
const char16_t *domain,
|
||||
const char16_t *username,
|
||||
const char16_t *password)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
NS_ASSERTION(username, "SASL requires a username");
|
||||
NS_ASSERTION(!domain && !password, "unexpected credentials");
|
||||
|
||||
mUsername = username;
|
||||
|
||||
// If we're doing SASL, we should do mutual auth
|
||||
serviceFlags |= REQ_MUTUAL_AUTH;
|
||||
|
||||
// Find out whether we should be trying SSPI or not
|
||||
const char *contractID = NS_AUTH_MODULE_CONTRACTID_PREFIX "kerb-gss";
|
||||
|
||||
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||
if (prefs) {
|
||||
bool val;
|
||||
rv = prefs->GetBoolPref(kNegotiateAuthSSPI, &val);
|
||||
if (NS_SUCCEEDED(rv) && val)
|
||||
contractID = NS_AUTH_MODULE_CONTRACTID_PREFIX "kerb-sspi";
|
||||
}
|
||||
|
||||
mInnerModule = do_CreateInstance(contractID, &rv);
|
||||
// if we can't create the GSSAPI module, then bail
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mInnerModule->Init(serviceName, serviceFlags, nullptr, nullptr, nullptr);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAuthSASL::GetNextToken(const void *inToken,
|
||||
uint32_t inTokenLen,
|
||||
void **outToken,
|
||||
uint32_t *outTokenLen)
|
||||
{
|
||||
nsresult rv;
|
||||
void *unwrappedToken;
|
||||
char *message;
|
||||
uint32_t unwrappedTokenLen, messageLen;
|
||||
nsAutoCString userbuf;
|
||||
|
||||
if (!mInnerModule)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
if (mSASLReady) {
|
||||
// If the server COMPLETEs with an empty token, Cyrus sends us that token.
|
||||
// I don't think this is correct, but we need to handle that behaviour.
|
||||
// Cyrus ignores the contents of our reply token.
|
||||
if (inTokenLen == 0) {
|
||||
*outToken = nullptr;
|
||||
*outTokenLen = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
// We've completed the GSSAPI portion of the handshake, and are
|
||||
// now ready to do the SASL security layer and authzid negotiation
|
||||
|
||||
// Input packet from the server needs to be unwrapped.
|
||||
rv = mInnerModule->Unwrap(inToken, inTokenLen, &unwrappedToken,
|
||||
&unwrappedTokenLen);
|
||||
if (NS_FAILED(rv)) {
|
||||
Reset();
|
||||
return rv;
|
||||
}
|
||||
|
||||
// If we were doing security layers then we'd care what the
|
||||
// server had sent us. We're not, so all we had to do was make
|
||||
// sure that the signature was correct with the above unwrap()
|
||||
free(unwrappedToken);
|
||||
|
||||
NS_CopyUnicodeToNative(mUsername, userbuf);
|
||||
messageLen = userbuf.Length() + 4 + 1;
|
||||
message = (char *)moz_xmalloc(messageLen);
|
||||
if (!message) {
|
||||
Reset();
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
message[0] = 0x01; // No security layer
|
||||
message[1] = 0x00;
|
||||
message[2] = 0x00;
|
||||
message[3] = 0x00; // Maxbuf must be zero if we've got no sec layer
|
||||
strcpy(message+4, userbuf.get());
|
||||
// Userbuf should not be nullptr terminated, so trim the trailing nullptr
|
||||
// when wrapping the message
|
||||
rv = mInnerModule->Wrap((void *) message, messageLen-1, false,
|
||||
outToken, outTokenLen);
|
||||
free(message);
|
||||
Reset(); // All done
|
||||
return NS_SUCCEEDED(rv) ? NS_SUCCESS_AUTH_FINISHED : rv;
|
||||
}
|
||||
rv = mInnerModule->GetNextToken(inToken, inTokenLen, outToken,
|
||||
outTokenLen);
|
||||
if (rv == NS_SUCCESS_AUTH_FINISHED) {
|
||||
mSASLReady = true;
|
||||
rv = NS_OK;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAuthSASL::Unwrap(const void *inToken,
|
||||
uint32_t inTokenLen,
|
||||
void **outToken,
|
||||
uint32_t *outTokenLen)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAuthSASL::Wrap(const void *inToken,
|
||||
uint32_t inTokenLen,
|
||||
bool confidential,
|
||||
void **outToken,
|
||||
uint32_t *outTokenLen)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
38
extensions/auth/nsAuthSASL.h
Normal file
38
extensions/auth/nsAuthSASL.h
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/* vim:set ts=4 sw=4 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsAuthSASL_h__
|
||||
#define nsAuthSASL_h__
|
||||
|
||||
#include "nsIAuthModule.h"
|
||||
#include "nsString.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
/* This class is implemented using the nsAuthGSSAPI class, and the same
|
||||
* thread safety constraints which are documented in nsAuthGSSAPI.h
|
||||
* apply to this class
|
||||
*/
|
||||
|
||||
class nsAuthSASL final : public nsIAuthModule
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIAUTHMODULE
|
||||
|
||||
nsAuthSASL();
|
||||
|
||||
private:
|
||||
~nsAuthSASL() { Reset(); }
|
||||
|
||||
void Reset();
|
||||
|
||||
nsCOMPtr<nsIAuthModule> mInnerModule;
|
||||
nsString mUsername;
|
||||
bool mSASLReady;
|
||||
};
|
||||
|
||||
#endif /* nsAuthSASL_h__ */
|
||||
|
||||
666
extensions/auth/nsAuthSSPI.cpp
Normal file
666
extensions/auth/nsAuthSSPI.cpp
Normal file
|
|
@ -0,0 +1,666 @@
|
|||
/* vim:set ts=4 sw=4 sts=4 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//
|
||||
// Negotiate Authentication Support Module
|
||||
//
|
||||
// Described by IETF Internet draft: draft-brezak-kerberos-http-00.txt
|
||||
// (formerly draft-brezak-spnego-http-04.txt)
|
||||
//
|
||||
// Also described here:
|
||||
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnsecure/html/http-sso-1.asp
|
||||
//
|
||||
|
||||
#include "nsAuthSSPI.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIDNSService.h"
|
||||
#include "nsIDNSRecord.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsICryptoHash.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#define SEC_SUCCESS(Status) ((Status) >= 0)
|
||||
|
||||
#ifndef KERB_WRAP_NO_ENCRYPT
|
||||
#define KERB_WRAP_NO_ENCRYPT 0x80000001
|
||||
#endif
|
||||
|
||||
#ifndef SECBUFFER_PADDING
|
||||
#define SECBUFFER_PADDING 9
|
||||
#endif
|
||||
|
||||
#ifndef SECBUFFER_STREAM
|
||||
#define SECBUFFER_STREAM 10
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static const wchar_t *const pTypeName [] = {
|
||||
L"Kerberos",
|
||||
L"Negotiate",
|
||||
L"NTLM"
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
#define CASE_(_x) case _x: return # _x;
|
||||
static const char *MapErrorCode(int rc)
|
||||
{
|
||||
switch (rc) {
|
||||
CASE_(SEC_E_OK)
|
||||
CASE_(SEC_I_CONTINUE_NEEDED)
|
||||
CASE_(SEC_I_COMPLETE_NEEDED)
|
||||
CASE_(SEC_I_COMPLETE_AND_CONTINUE)
|
||||
CASE_(SEC_E_INCOMPLETE_MESSAGE)
|
||||
CASE_(SEC_I_INCOMPLETE_CREDENTIALS)
|
||||
CASE_(SEC_E_INVALID_HANDLE)
|
||||
CASE_(SEC_E_TARGET_UNKNOWN)
|
||||
CASE_(SEC_E_LOGON_DENIED)
|
||||
CASE_(SEC_E_INTERNAL_ERROR)
|
||||
CASE_(SEC_E_NO_CREDENTIALS)
|
||||
CASE_(SEC_E_NO_AUTHENTICATING_AUTHORITY)
|
||||
CASE_(SEC_E_INSUFFICIENT_MEMORY)
|
||||
CASE_(SEC_E_INVALID_TOKEN)
|
||||
}
|
||||
return "<unknown>";
|
||||
}
|
||||
#else
|
||||
#define MapErrorCode(_rc) ""
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static PSecurityFunctionTableW sspi;
|
||||
|
||||
static nsresult
|
||||
InitSSPI()
|
||||
{
|
||||
LOG((" InitSSPI\n"));
|
||||
|
||||
sspi = InitSecurityInterfaceW();
|
||||
if (!sspi) {
|
||||
LOG(("InitSecurityInterfaceW failed"));
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static nsresult
|
||||
MakeSN(const char *principal, nsCString &result)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsAutoCString buf(principal);
|
||||
|
||||
// The service name looks like "protocol@hostname", we need to map
|
||||
// this to a value that SSPI expects. To be consistent with IE, we
|
||||
// need to map '@' to '/' and canonicalize the hostname.
|
||||
int32_t index = buf.FindChar('@');
|
||||
if (index == kNotFound)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// This could be expensive if our DNS cache cannot satisfy the request.
|
||||
// However, we should have at least hit the OS resolver once prior to
|
||||
// reaching this code, so provided the OS resolver has this information
|
||||
// cached, we should not have to worry about blocking on this function call
|
||||
// for very long. NOTE: because we ask for the canonical hostname, we
|
||||
// might end up requiring extra network activity in cases where the OS
|
||||
// resolver might not have enough information to satisfy the request from
|
||||
// its cache. This is not an issue in versions of Windows up to WinXP.
|
||||
nsCOMPtr<nsIDNSRecord> record;
|
||||
rv = dns->Resolve(Substring(buf, index + 1),
|
||||
nsIDNSService::RESOLVE_CANONICAL_NAME,
|
||||
getter_AddRefs(record));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
nsAutoCString cname;
|
||||
rv = record->GetCanonicalName(cname);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
result = StringHead(buf, index) + NS_LITERAL_CSTRING("/") + cname;
|
||||
LOG(("Using SPN of [%s]\n", result.get()));
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
nsAuthSSPI::nsAuthSSPI(pType package)
|
||||
: mServiceFlags(REQ_DEFAULT)
|
||||
, mMaxTokenLen(0)
|
||||
, mPackage(package)
|
||||
, mCertDERData(nullptr)
|
||||
, mCertDERLength(0)
|
||||
{
|
||||
memset(&mCred, 0, sizeof(mCred));
|
||||
memset(&mCtxt, 0, sizeof(mCtxt));
|
||||
}
|
||||
|
||||
nsAuthSSPI::~nsAuthSSPI()
|
||||
{
|
||||
Reset();
|
||||
|
||||
if (mCred.dwLower || mCred.dwUpper) {
|
||||
#ifdef __MINGW32__
|
||||
(sspi->FreeCredentialsHandle)(&mCred);
|
||||
#else
|
||||
(sspi->FreeCredentialHandle)(&mCred);
|
||||
#endif
|
||||
memset(&mCred, 0, sizeof(mCred));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsAuthSSPI::Reset()
|
||||
{
|
||||
mIsFirst = true;
|
||||
|
||||
if (mCertDERData){
|
||||
free(mCertDERData);
|
||||
mCertDERData = nullptr;
|
||||
mCertDERLength = 0;
|
||||
}
|
||||
|
||||
if (mCtxt.dwLower || mCtxt.dwUpper) {
|
||||
(sspi->DeleteSecurityContext)(&mCtxt);
|
||||
memset(&mCtxt, 0, sizeof(mCtxt));
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsAuthSSPI, nsIAuthModule)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAuthSSPI::Init(const char *serviceName,
|
||||
uint32_t serviceFlags,
|
||||
const char16_t *domain,
|
||||
const char16_t *username,
|
||||
const char16_t *password)
|
||||
{
|
||||
LOG((" nsAuthSSPI::Init\n"));
|
||||
|
||||
mIsFirst = true;
|
||||
mCertDERLength = 0;
|
||||
mCertDERData = nullptr;
|
||||
|
||||
// The caller must supply a service name to be used. (For why we now require
|
||||
// a service name for NTLM, see bug 487872.)
|
||||
NS_ENSURE_TRUE(serviceName && *serviceName, NS_ERROR_INVALID_ARG);
|
||||
|
||||
nsresult rv;
|
||||
|
||||
// XXX lazy initialization like this assumes that we are single threaded
|
||||
if (!sspi) {
|
||||
rv = InitSSPI();
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
}
|
||||
SEC_WCHAR *package;
|
||||
|
||||
package = (SEC_WCHAR *) pTypeName[(int)mPackage];
|
||||
|
||||
if (mPackage == PACKAGE_TYPE_NTLM) {
|
||||
// (bug 535193) For NTLM, just use the uri host, do not do canonical host lookups.
|
||||
// The incoming serviceName is in the format: "protocol@hostname", SSPI expects
|
||||
// "<service class>/<hostname>", so swap the '@' for a '/'.
|
||||
mServiceName.Assign(serviceName);
|
||||
int32_t index = mServiceName.FindChar('@');
|
||||
if (index == kNotFound)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
mServiceName.Replace(index, 1, '/');
|
||||
}
|
||||
else {
|
||||
// Kerberos requires the canonical host, MakeSN takes care of this through a
|
||||
// DNS lookup.
|
||||
rv = MakeSN(serviceName, mServiceName);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
}
|
||||
|
||||
mServiceFlags = serviceFlags;
|
||||
|
||||
SECURITY_STATUS rc;
|
||||
|
||||
PSecPkgInfoW pinfo;
|
||||
rc = (sspi->QuerySecurityPackageInfoW)(package, &pinfo);
|
||||
if (rc != SEC_E_OK) {
|
||||
LOG(("%s package not found\n", package));
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
mMaxTokenLen = pinfo->cbMaxToken;
|
||||
(sspi->FreeContextBuffer)(pinfo);
|
||||
|
||||
MS_TimeStamp useBefore;
|
||||
|
||||
SEC_WINNT_AUTH_IDENTITY_W ai;
|
||||
SEC_WINNT_AUTH_IDENTITY_W *pai = nullptr;
|
||||
|
||||
// domain, username, and password will be null if nsHttpNTLMAuth's ChallengeReceived
|
||||
// returns false for identityInvalid. Use default credentials in this case by passing
|
||||
// null for pai.
|
||||
if (username && password) {
|
||||
// Keep a copy of these strings for the duration
|
||||
mUsername.Assign(username);
|
||||
mPassword.Assign(password);
|
||||
mDomain.Assign(domain);
|
||||
ai.Domain = reinterpret_cast<unsigned short*>(mDomain.BeginWriting());
|
||||
ai.DomainLength = mDomain.Length();
|
||||
ai.User = reinterpret_cast<unsigned short*>(mUsername.BeginWriting());
|
||||
ai.UserLength = mUsername.Length();
|
||||
ai.Password = reinterpret_cast<unsigned short*>(mPassword.BeginWriting());
|
||||
ai.PasswordLength = mPassword.Length();
|
||||
ai.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
|
||||
pai = &ai;
|
||||
}
|
||||
|
||||
rc = (sspi->AcquireCredentialsHandleW)(nullptr,
|
||||
package,
|
||||
SECPKG_CRED_OUTBOUND,
|
||||
nullptr,
|
||||
pai,
|
||||
nullptr,
|
||||
nullptr,
|
||||
&mCred,
|
||||
&useBefore);
|
||||
if (rc != SEC_E_OK)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
static bool sTelemetrySent = false;
|
||||
if (!sTelemetrySent) {
|
||||
mozilla::Telemetry::Accumulate(
|
||||
mozilla::Telemetry::NTLM_MODULE_USED_2,
|
||||
serviceFlags & nsIAuthModule::REQ_PROXY_AUTH
|
||||
? NTLM_MODULE_WIN_API_PROXY
|
||||
: NTLM_MODULE_WIN_API_DIRECT);
|
||||
sTelemetrySent = true;
|
||||
}
|
||||
|
||||
LOG(("AcquireCredentialsHandle() succeeded.\n"));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// The arguments inToken and inTokenLen are used to pass in the server
|
||||
// certificate (when available) in the first call of the function. The
|
||||
// second time these arguments hold an input token.
|
||||
NS_IMETHODIMP
|
||||
nsAuthSSPI::GetNextToken(const void *inToken,
|
||||
uint32_t inTokenLen,
|
||||
void **outToken,
|
||||
uint32_t *outTokenLen)
|
||||
{
|
||||
// String for end-point bindings.
|
||||
const char end_point[] = "tls-server-end-point:";
|
||||
const int end_point_length = sizeof(end_point) - 1;
|
||||
const int hash_size = 32; // Size of a SHA256 hash.
|
||||
const int cbt_size = hash_size + end_point_length;
|
||||
|
||||
SECURITY_STATUS rc;
|
||||
MS_TimeStamp ignored;
|
||||
|
||||
DWORD ctxAttr, ctxReq = 0;
|
||||
CtxtHandle *ctxIn;
|
||||
SecBufferDesc ibd, obd;
|
||||
// Optional second input buffer for the CBT (Channel Binding Token)
|
||||
SecBuffer ib[2], ob;
|
||||
// Pointer to the block of memory that stores the CBT
|
||||
char* sspi_cbt = nullptr;
|
||||
SEC_CHANNEL_BINDINGS pendpoint_binding;
|
||||
|
||||
LOG(("entering nsAuthSSPI::GetNextToken()\n"));
|
||||
|
||||
if (!mCred.dwLower && !mCred.dwUpper) {
|
||||
LOG(("nsAuthSSPI::GetNextToken(), not initialized. exiting."));
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
if (mServiceFlags & REQ_DELEGATE)
|
||||
ctxReq |= ISC_REQ_DELEGATE;
|
||||
if (mServiceFlags & REQ_MUTUAL_AUTH)
|
||||
ctxReq |= ISC_REQ_MUTUAL_AUTH;
|
||||
|
||||
if (inToken) {
|
||||
if (mIsFirst) {
|
||||
// First time if it comes with a token,
|
||||
// the token represents the server certificate.
|
||||
mIsFirst = false;
|
||||
mCertDERLength = inTokenLen;
|
||||
mCertDERData = moz_xmalloc(inTokenLen);
|
||||
if (!mCertDERData)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
memcpy(mCertDERData, inToken, inTokenLen);
|
||||
|
||||
// We are starting a new authentication sequence.
|
||||
// If we have already initialized our
|
||||
// security context, then we're in trouble because it means that the
|
||||
// first sequence failed. We need to bail or else we might end up in
|
||||
// an infinite loop.
|
||||
if (mCtxt.dwLower || mCtxt.dwUpper) {
|
||||
LOG(("Cannot restart authentication sequence!"));
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
ctxIn = nullptr;
|
||||
// The certificate needs to be erased before being passed
|
||||
// to InitializeSecurityContextW().
|
||||
inToken = nullptr;
|
||||
inTokenLen = 0;
|
||||
} else {
|
||||
ibd.ulVersion = SECBUFFER_VERSION;
|
||||
ibd.cBuffers = 0;
|
||||
ibd.pBuffers = ib;
|
||||
|
||||
// If we have stored a certificate, the Channel Binding Token
|
||||
// needs to be generated and sent in the first input buffer.
|
||||
if (mCertDERLength > 0) {
|
||||
// First we create a proper Endpoint Binding structure.
|
||||
pendpoint_binding.dwInitiatorAddrType = 0;
|
||||
pendpoint_binding.cbInitiatorLength = 0;
|
||||
pendpoint_binding.dwInitiatorOffset = 0;
|
||||
pendpoint_binding.dwAcceptorAddrType = 0;
|
||||
pendpoint_binding.cbAcceptorLength = 0;
|
||||
pendpoint_binding.dwAcceptorOffset = 0;
|
||||
pendpoint_binding.cbApplicationDataLength = cbt_size;
|
||||
pendpoint_binding.dwApplicationDataOffset =
|
||||
sizeof(SEC_CHANNEL_BINDINGS);
|
||||
|
||||
// Then add it to the array of sec buffers accordingly.
|
||||
ib[ibd.cBuffers].BufferType = SECBUFFER_CHANNEL_BINDINGS;
|
||||
ib[ibd.cBuffers].cbBuffer =
|
||||
pendpoint_binding.cbApplicationDataLength
|
||||
+ pendpoint_binding.dwApplicationDataOffset;
|
||||
|
||||
sspi_cbt = (char *) moz_xmalloc(ib[ibd.cBuffers].cbBuffer);
|
||||
if (!sspi_cbt){
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Helper to write in the memory block that stores the CBT
|
||||
char* sspi_cbt_ptr = sspi_cbt;
|
||||
|
||||
ib[ibd.cBuffers].pvBuffer = sspi_cbt;
|
||||
ibd.cBuffers++;
|
||||
|
||||
memcpy(sspi_cbt_ptr, &pendpoint_binding,
|
||||
pendpoint_binding.dwApplicationDataOffset);
|
||||
sspi_cbt_ptr += pendpoint_binding.dwApplicationDataOffset;
|
||||
|
||||
memcpy(sspi_cbt_ptr, end_point, end_point_length);
|
||||
sspi_cbt_ptr += end_point_length;
|
||||
|
||||
// Start hashing. We are always doing SHA256, but depending
|
||||
// on the certificate, a different alogirthm might be needed.
|
||||
nsAutoCString hashString;
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsICryptoHash> crypto;
|
||||
crypto = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = crypto->Init(nsICryptoHash::SHA256);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = crypto->Update((unsigned char*)mCertDERData, mCertDERLength);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = crypto->Finish(false, hashString);
|
||||
if (NS_FAILED(rv)) {
|
||||
free(mCertDERData);
|
||||
mCertDERData = nullptr;
|
||||
mCertDERLength = 0;
|
||||
free(sspi_cbt);
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Once the hash has been computed, we store it in memory right
|
||||
// after the Endpoint structure and the "tls-server-end-point:"
|
||||
// char array.
|
||||
memcpy(sspi_cbt_ptr, hashString.get(), hash_size);
|
||||
|
||||
// Free memory used to store the server certificate
|
||||
free(mCertDERData);
|
||||
mCertDERData = nullptr;
|
||||
mCertDERLength = 0;
|
||||
} // End of CBT computation.
|
||||
|
||||
// We always need this SECBUFFER.
|
||||
ib[ibd.cBuffers].BufferType = SECBUFFER_TOKEN;
|
||||
ib[ibd.cBuffers].cbBuffer = inTokenLen;
|
||||
ib[ibd.cBuffers].pvBuffer = (void *) inToken;
|
||||
ibd.cBuffers++;
|
||||
ctxIn = &mCtxt;
|
||||
}
|
||||
} else { // First time and without a token (no server certificate)
|
||||
// We are starting a new authentication sequence. If we have already
|
||||
// initialized our security context, then we're in trouble because it
|
||||
// means that the first sequence failed. We need to bail or else we
|
||||
// might end up in an infinite loop.
|
||||
if (mCtxt.dwLower || mCtxt.dwUpper || mCertDERData || mCertDERLength) {
|
||||
LOG(("Cannot restart authentication sequence!"));
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
ctxIn = nullptr;
|
||||
mIsFirst = false;
|
||||
}
|
||||
|
||||
obd.ulVersion = SECBUFFER_VERSION;
|
||||
obd.cBuffers = 1;
|
||||
obd.pBuffers = &ob;
|
||||
ob.BufferType = SECBUFFER_TOKEN;
|
||||
ob.cbBuffer = mMaxTokenLen;
|
||||
ob.pvBuffer = moz_xmalloc(ob.cbBuffer);
|
||||
if (!ob.pvBuffer){
|
||||
if (sspi_cbt)
|
||||
free(sspi_cbt);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
memset(ob.pvBuffer, 0, ob.cbBuffer);
|
||||
|
||||
NS_ConvertUTF8toUTF16 wSN(mServiceName);
|
||||
SEC_WCHAR *sn = (SEC_WCHAR *) wSN.get();
|
||||
|
||||
rc = (sspi->InitializeSecurityContextW)(&mCred,
|
||||
ctxIn,
|
||||
sn,
|
||||
ctxReq,
|
||||
0,
|
||||
SECURITY_NATIVE_DREP,
|
||||
inToken ? &ibd : nullptr,
|
||||
0,
|
||||
&mCtxt,
|
||||
&obd,
|
||||
&ctxAttr,
|
||||
&ignored);
|
||||
if (rc == SEC_I_CONTINUE_NEEDED || rc == SEC_E_OK) {
|
||||
|
||||
if (rc == SEC_E_OK)
|
||||
LOG(("InitializeSecurityContext: succeeded.\n"));
|
||||
else
|
||||
LOG(("InitializeSecurityContext: continue.\n"));
|
||||
|
||||
if (sspi_cbt)
|
||||
free(sspi_cbt);
|
||||
|
||||
if (!ob.cbBuffer) {
|
||||
free(ob.pvBuffer);
|
||||
ob.pvBuffer = nullptr;
|
||||
}
|
||||
*outToken = ob.pvBuffer;
|
||||
*outTokenLen = ob.cbBuffer;
|
||||
|
||||
if (rc == SEC_E_OK)
|
||||
return NS_SUCCESS_AUTH_FINISHED;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
LOG(("InitializeSecurityContext failed [rc=%d:%s]\n", rc, MapErrorCode(rc)));
|
||||
Reset();
|
||||
free(ob.pvBuffer);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAuthSSPI::Unwrap(const void *inToken,
|
||||
uint32_t inTokenLen,
|
||||
void **outToken,
|
||||
uint32_t *outTokenLen)
|
||||
{
|
||||
SECURITY_STATUS rc;
|
||||
SecBufferDesc ibd;
|
||||
SecBuffer ib[2];
|
||||
|
||||
ibd.cBuffers = 2;
|
||||
ibd.pBuffers = ib;
|
||||
ibd.ulVersion = SECBUFFER_VERSION;
|
||||
|
||||
// SSPI Buf
|
||||
ib[0].BufferType = SECBUFFER_STREAM;
|
||||
ib[0].cbBuffer = inTokenLen;
|
||||
ib[0].pvBuffer = moz_xmalloc(ib[0].cbBuffer);
|
||||
if (!ib[0].pvBuffer)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
memcpy(ib[0].pvBuffer, inToken, inTokenLen);
|
||||
|
||||
// app data
|
||||
ib[1].BufferType = SECBUFFER_DATA;
|
||||
ib[1].cbBuffer = 0;
|
||||
ib[1].pvBuffer = nullptr;
|
||||
|
||||
rc = (sspi->DecryptMessage)(
|
||||
&mCtxt,
|
||||
&ibd,
|
||||
0, // no sequence numbers
|
||||
nullptr
|
||||
);
|
||||
|
||||
if (SEC_SUCCESS(rc)) {
|
||||
// check if ib[1].pvBuffer is really just ib[0].pvBuffer, in which
|
||||
// case we can let the caller free it. Otherwise, we need to
|
||||
// clone it, and free the original
|
||||
if (ib[0].pvBuffer == ib[1].pvBuffer) {
|
||||
*outToken = ib[1].pvBuffer;
|
||||
}
|
||||
else {
|
||||
*outToken = nsMemory::Clone(ib[1].pvBuffer, ib[1].cbBuffer);
|
||||
free(ib[0].pvBuffer);
|
||||
if (!*outToken)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
*outTokenLen = ib[1].cbBuffer;
|
||||
}
|
||||
else
|
||||
free(ib[0].pvBuffer);
|
||||
|
||||
if (!SEC_SUCCESS(rc))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// utility class used to free memory on exit
|
||||
class secBuffers
|
||||
{
|
||||
public:
|
||||
|
||||
SecBuffer ib[3];
|
||||
|
||||
secBuffers() { memset(&ib, 0, sizeof(ib)); }
|
||||
|
||||
~secBuffers()
|
||||
{
|
||||
if (ib[0].pvBuffer)
|
||||
free(ib[0].pvBuffer);
|
||||
|
||||
if (ib[1].pvBuffer)
|
||||
free(ib[1].pvBuffer);
|
||||
|
||||
if (ib[2].pvBuffer)
|
||||
free(ib[2].pvBuffer);
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAuthSSPI::Wrap(const void *inToken,
|
||||
uint32_t inTokenLen,
|
||||
bool confidential,
|
||||
void **outToken,
|
||||
uint32_t *outTokenLen)
|
||||
{
|
||||
SECURITY_STATUS rc;
|
||||
|
||||
SecBufferDesc ibd;
|
||||
secBuffers bufs;
|
||||
SecPkgContext_Sizes sizes;
|
||||
|
||||
rc = (sspi->QueryContextAttributesW)(
|
||||
&mCtxt,
|
||||
SECPKG_ATTR_SIZES,
|
||||
&sizes);
|
||||
|
||||
if (!SEC_SUCCESS(rc))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
ibd.cBuffers = 3;
|
||||
ibd.pBuffers = bufs.ib;
|
||||
ibd.ulVersion = SECBUFFER_VERSION;
|
||||
|
||||
// SSPI
|
||||
bufs.ib[0].cbBuffer = sizes.cbSecurityTrailer;
|
||||
bufs.ib[0].BufferType = SECBUFFER_TOKEN;
|
||||
bufs.ib[0].pvBuffer = moz_xmalloc(sizes.cbSecurityTrailer);
|
||||
|
||||
if (!bufs.ib[0].pvBuffer)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// APP Data
|
||||
bufs.ib[1].BufferType = SECBUFFER_DATA;
|
||||
bufs.ib[1].pvBuffer = moz_xmalloc(inTokenLen);
|
||||
bufs.ib[1].cbBuffer = inTokenLen;
|
||||
|
||||
if (!bufs.ib[1].pvBuffer)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
memcpy(bufs.ib[1].pvBuffer, inToken, inTokenLen);
|
||||
|
||||
// SSPI
|
||||
bufs.ib[2].BufferType = SECBUFFER_PADDING;
|
||||
bufs.ib[2].cbBuffer = sizes.cbBlockSize;
|
||||
bufs.ib[2].pvBuffer = moz_xmalloc(bufs.ib[2].cbBuffer);
|
||||
|
||||
if (!bufs.ib[2].pvBuffer)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
rc = (sspi->EncryptMessage)(&mCtxt,
|
||||
confidential ? 0 : KERB_WRAP_NO_ENCRYPT,
|
||||
&ibd, 0);
|
||||
|
||||
if (SEC_SUCCESS(rc)) {
|
||||
int len = bufs.ib[0].cbBuffer + bufs.ib[1].cbBuffer + bufs.ib[2].cbBuffer;
|
||||
char *p = (char *) moz_xmalloc(len);
|
||||
|
||||
if (!p)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
*outToken = (void *) p;
|
||||
*outTokenLen = len;
|
||||
|
||||
memcpy(p, bufs.ib[0].pvBuffer, bufs.ib[0].cbBuffer);
|
||||
p += bufs.ib[0].cbBuffer;
|
||||
|
||||
memcpy(p,bufs.ib[1].pvBuffer, bufs.ib[1].cbBuffer);
|
||||
p += bufs.ib[1].cbBuffer;
|
||||
|
||||
memcpy(p,bufs.ib[2].pvBuffer, bufs.ib[2].cbBuffer);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
59
extensions/auth/nsAuthSSPI.h
Normal file
59
extensions/auth/nsAuthSSPI.h
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/* vim:set ts=4 sw=4 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsAuthSSPI_h__
|
||||
#define nsAuthSSPI_h__
|
||||
|
||||
#include "nsAuth.h"
|
||||
#include "nsIAuthModule.h"
|
||||
#include "nsString.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#define SECURITY_WIN32 1
|
||||
#include <ntsecapi.h>
|
||||
#include <security.h>
|
||||
#include <rpc.h>
|
||||
|
||||
// The nsNegotiateAuth class provides responses for the GSS-API Negotiate method
|
||||
// as specified by Microsoft in draft-brezak-spnego-http-04.txt
|
||||
|
||||
// It can also be configured to talk raw NTLM. This implementation of NTLM has
|
||||
// the advantage of being able to access the user's logon credentials. This
|
||||
// implementation of NTLM should only be used for single-signon. It should be
|
||||
// avoided when authenticating over the internet since it may use a lower-grade
|
||||
// version of password hashing depending on the version of Windows being used.
|
||||
|
||||
class nsAuthSSPI final : public nsIAuthModule
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIAUTHMODULE
|
||||
|
||||
nsAuthSSPI(pType package = PACKAGE_TYPE_NEGOTIATE);
|
||||
|
||||
private:
|
||||
~nsAuthSSPI();
|
||||
|
||||
void Reset();
|
||||
|
||||
typedef TimeStamp MS_TimeStamp;
|
||||
|
||||
private:
|
||||
CredHandle mCred;
|
||||
CtxtHandle mCtxt;
|
||||
nsCString mServiceName;
|
||||
uint32_t mServiceFlags;
|
||||
uint32_t mMaxTokenLen;
|
||||
pType mPackage;
|
||||
nsString mDomain;
|
||||
nsString mUsername;
|
||||
nsString mPassword;
|
||||
bool mIsFirst;
|
||||
void* mCertDERData;
|
||||
uint32_t mCertDERLength;
|
||||
};
|
||||
|
||||
#endif /* nsAuthSSPI_h__ */
|
||||
296
extensions/auth/nsAuthSambaNTLM.cpp
Normal file
296
extensions/auth/nsAuthSambaNTLM.cpp
Normal file
|
|
@ -0,0 +1,296 @@
|
|||
/* vim:set ts=4 sw=4 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsAuth.h"
|
||||
#include "nsAuthSambaNTLM.h"
|
||||
#include "prenv.h"
|
||||
#include "plbase64.h"
|
||||
#include "prerror.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
nsAuthSambaNTLM::nsAuthSambaNTLM()
|
||||
: mInitialMessage(nullptr), mChildPID(nullptr), mFromChildFD(nullptr),
|
||||
mToChildFD(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
nsAuthSambaNTLM::~nsAuthSambaNTLM()
|
||||
{
|
||||
// ntlm_auth reads from stdin regularly so closing our file handles
|
||||
// should cause it to exit.
|
||||
Shutdown();
|
||||
free(mInitialMessage);
|
||||
}
|
||||
|
||||
void
|
||||
nsAuthSambaNTLM::Shutdown()
|
||||
{
|
||||
if (mFromChildFD) {
|
||||
PR_Close(mFromChildFD);
|
||||
mFromChildFD = nullptr;
|
||||
}
|
||||
if (mToChildFD) {
|
||||
PR_Close(mToChildFD);
|
||||
mToChildFD = nullptr;
|
||||
}
|
||||
if (mChildPID) {
|
||||
int32_t exitCode;
|
||||
PR_WaitProcess(mChildPID, &exitCode);
|
||||
mChildPID = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsAuthSambaNTLM, nsIAuthModule)
|
||||
|
||||
static bool
|
||||
SpawnIOChild(char* const* aArgs, PRProcess** aPID,
|
||||
PRFileDesc** aFromChildFD, PRFileDesc** aToChildFD)
|
||||
{
|
||||
PRFileDesc* toChildPipeRead;
|
||||
PRFileDesc* toChildPipeWrite;
|
||||
if (PR_CreatePipe(&toChildPipeRead, &toChildPipeWrite) != PR_SUCCESS)
|
||||
return false;
|
||||
PR_SetFDInheritable(toChildPipeRead, true);
|
||||
PR_SetFDInheritable(toChildPipeWrite, false);
|
||||
|
||||
PRFileDesc* fromChildPipeRead;
|
||||
PRFileDesc* fromChildPipeWrite;
|
||||
if (PR_CreatePipe(&fromChildPipeRead, &fromChildPipeWrite) != PR_SUCCESS) {
|
||||
PR_Close(toChildPipeRead);
|
||||
PR_Close(toChildPipeWrite);
|
||||
return false;
|
||||
}
|
||||
PR_SetFDInheritable(fromChildPipeRead, false);
|
||||
PR_SetFDInheritable(fromChildPipeWrite, true);
|
||||
|
||||
PRProcessAttr* attr = PR_NewProcessAttr();
|
||||
if (!attr) {
|
||||
PR_Close(fromChildPipeRead);
|
||||
PR_Close(fromChildPipeWrite);
|
||||
PR_Close(toChildPipeRead);
|
||||
PR_Close(toChildPipeWrite);
|
||||
return false;
|
||||
}
|
||||
|
||||
PR_ProcessAttrSetStdioRedirect(attr, PR_StandardInput, toChildPipeRead);
|
||||
PR_ProcessAttrSetStdioRedirect(attr, PR_StandardOutput, fromChildPipeWrite);
|
||||
|
||||
PRProcess* process = PR_CreateProcess(aArgs[0], aArgs, nullptr, attr);
|
||||
PR_DestroyProcessAttr(attr);
|
||||
PR_Close(fromChildPipeWrite);
|
||||
PR_Close(toChildPipeRead);
|
||||
if (!process) {
|
||||
LOG(("ntlm_auth exec failure [%d]", PR_GetError()));
|
||||
PR_Close(fromChildPipeRead);
|
||||
PR_Close(toChildPipeWrite);
|
||||
return false;
|
||||
}
|
||||
|
||||
*aPID = process;
|
||||
*aFromChildFD = fromChildPipeRead;
|
||||
*aToChildFD = toChildPipeWrite;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool WriteString(PRFileDesc* aFD, const nsACString& aString)
|
||||
{
|
||||
int32_t length = aString.Length();
|
||||
const char* s = aString.BeginReading();
|
||||
LOG(("Writing to ntlm_auth: %s", s));
|
||||
|
||||
while (length > 0) {
|
||||
int result = PR_Write(aFD, s, length);
|
||||
if (result <= 0)
|
||||
return false;
|
||||
s += result;
|
||||
length -= result;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ReadLine(PRFileDesc* aFD, nsACString& aString)
|
||||
{
|
||||
// ntlm_auth is defined to only send one line in response to each of our
|
||||
// input lines. So this simple unbuffered strategy works as long as we
|
||||
// read the response immediately after sending one request.
|
||||
aString.Truncate();
|
||||
for (;;) {
|
||||
char buf[1024];
|
||||
int result = PR_Read(aFD, buf, sizeof(buf));
|
||||
if (result <= 0)
|
||||
return false;
|
||||
aString.Append(buf, result);
|
||||
if (buf[result - 1] == '\n') {
|
||||
LOG(("Read from ntlm_auth: %s", nsPromiseFlatCString(aString).get()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a heap-allocated array of PRUint8s, and stores the length in aLen.
|
||||
* Returns nullptr if there's an error of any kind.
|
||||
*/
|
||||
static uint8_t* ExtractMessage(const nsACString& aLine, uint32_t* aLen)
|
||||
{
|
||||
// ntlm_auth sends blobs to us as base64-encoded strings after the "xx "
|
||||
// preamble on the response line.
|
||||
int32_t length = aLine.Length();
|
||||
// The caller should verify there is a valid "xx " prefix and the line
|
||||
// is terminated with a \n
|
||||
NS_ASSERTION(length >= 4, "Line too short...");
|
||||
const char* line = aLine.BeginReading();
|
||||
const char* s = line + 3;
|
||||
length -= 4; // lose first 3 chars plus trailing \n
|
||||
NS_ASSERTION(s[length] == '\n', "aLine not newline-terminated");
|
||||
|
||||
if (length & 3) {
|
||||
// The base64 encoded block must be multiple of 4. If not, something
|
||||
// screwed up.
|
||||
NS_WARNING("Base64 encoded block should be a multiple of 4 chars");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Calculate the exact length. I wonder why there isn't a function for this
|
||||
// in plbase64.
|
||||
int32_t numEquals;
|
||||
for (numEquals = 0; numEquals < length; ++numEquals) {
|
||||
if (s[length - 1 - numEquals] != '=')
|
||||
break;
|
||||
}
|
||||
*aLen = (length/4)*3 - numEquals;
|
||||
return reinterpret_cast<uint8_t*>(PL_Base64Decode(s, length, nullptr));
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAuthSambaNTLM::SpawnNTLMAuthHelper()
|
||||
{
|
||||
const char* username = PR_GetEnv("USER");
|
||||
if (!username)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
const char* const args[] = {
|
||||
"ntlm_auth",
|
||||
"--helper-protocol", "ntlmssp-client-1",
|
||||
"--use-cached-creds",
|
||||
"--username", username,
|
||||
nullptr
|
||||
};
|
||||
|
||||
bool isOK = SpawnIOChild(const_cast<char* const*>(args), &mChildPID, &mFromChildFD, &mToChildFD);
|
||||
if (!isOK)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (!WriteString(mToChildFD, NS_LITERAL_CSTRING("YR\n")))
|
||||
return NS_ERROR_FAILURE;
|
||||
nsCString line;
|
||||
if (!ReadLine(mFromChildFD, line))
|
||||
return NS_ERROR_FAILURE;
|
||||
if (!StringBeginsWith(line, NS_LITERAL_CSTRING("YR "))) {
|
||||
// Something went wrong. Perhaps no credentials are accessible.
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// It gave us an initial client-to-server request packet. Save that
|
||||
// because we'll need it later.
|
||||
mInitialMessage = ExtractMessage(line, &mInitialMessageLen);
|
||||
if (!mInitialMessage)
|
||||
return NS_ERROR_FAILURE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAuthSambaNTLM::Init(const char *serviceName,
|
||||
uint32_t serviceFlags,
|
||||
const char16_t *domain,
|
||||
const char16_t *username,
|
||||
const char16_t *password)
|
||||
{
|
||||
NS_ASSERTION(!username && !domain && !password, "unexpected credentials");
|
||||
|
||||
static bool sTelemetrySent = false;
|
||||
if (!sTelemetrySent) {
|
||||
mozilla::Telemetry::Accumulate(
|
||||
mozilla::Telemetry::NTLM_MODULE_USED_2,
|
||||
serviceFlags & nsIAuthModule::REQ_PROXY_AUTH
|
||||
? NTLM_MODULE_SAMBA_AUTH_PROXY
|
||||
: NTLM_MODULE_SAMBA_AUTH_DIRECT);
|
||||
sTelemetrySent = true;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAuthSambaNTLM::GetNextToken(const void *inToken,
|
||||
uint32_t inTokenLen,
|
||||
void **outToken,
|
||||
uint32_t *outTokenLen)
|
||||
{
|
||||
if (!inToken) {
|
||||
/* someone wants our initial message */
|
||||
*outToken = nsMemory::Clone(mInitialMessage, mInitialMessageLen);
|
||||
if (!*outToken)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
*outTokenLen = mInitialMessageLen;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* inToken must be a type 2 message. Get ntlm_auth to generate our response */
|
||||
char* encoded = PL_Base64Encode(static_cast<const char*>(inToken), inTokenLen, nullptr);
|
||||
if (!encoded)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsCString request;
|
||||
request.AssignLiteral("TT ");
|
||||
request.Append(encoded);
|
||||
free(encoded);
|
||||
request.Append('\n');
|
||||
|
||||
if (!WriteString(mToChildFD, request))
|
||||
return NS_ERROR_FAILURE;
|
||||
nsCString line;
|
||||
if (!ReadLine(mFromChildFD, line))
|
||||
return NS_ERROR_FAILURE;
|
||||
if (!StringBeginsWith(line, NS_LITERAL_CSTRING("KK ")) &&
|
||||
!StringBeginsWith(line, NS_LITERAL_CSTRING("AF "))) {
|
||||
// Something went wrong. Perhaps no credentials are accessible.
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
uint8_t* buf = ExtractMessage(line, outTokenLen);
|
||||
if (!buf)
|
||||
return NS_ERROR_FAILURE;
|
||||
*outToken = nsMemory::Clone(buf, *outTokenLen);
|
||||
free(buf);
|
||||
if (!*outToken) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// We're done. Close our file descriptors now and reap the helper
|
||||
// process.
|
||||
Shutdown();
|
||||
return NS_SUCCESS_AUTH_FINISHED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAuthSambaNTLM::Unwrap(const void *inToken,
|
||||
uint32_t inTokenLen,
|
||||
void **outToken,
|
||||
uint32_t *outTokenLen)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAuthSambaNTLM::Wrap(const void *inToken,
|
||||
uint32_t inTokenLen,
|
||||
bool confidential,
|
||||
void **outToken,
|
||||
uint32_t *outTokenLen)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
52
extensions/auth/nsAuthSambaNTLM.h
Normal file
52
extensions/auth/nsAuthSambaNTLM.h
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/* vim:set ts=4 sw=4 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsAuthSambaNTLM_h__
|
||||
#define nsAuthSambaNTLM_h__
|
||||
|
||||
#include "nsIAuthModule.h"
|
||||
#include "nsString.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "prio.h"
|
||||
#include "prproces.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
/**
|
||||
* This is an implementation of NTLM authentication that does single-signon
|
||||
* by obtaining the user's Unix username, parsing it into DOMAIN\name format,
|
||||
* and then asking Samba's ntlm_auth tool to do the authentication for us
|
||||
* using the user's password cached in winbindd, if available. If the
|
||||
* password is not available then this component fails to instantiate so
|
||||
* nsHttpNTLMAuth will fall back to a different NTLM implementation.
|
||||
* NOTE: at time of writing, this requires patches to be added to the stock
|
||||
* Samba winbindd and ntlm_auth!
|
||||
*/
|
||||
class nsAuthSambaNTLM final : public nsIAuthModule
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIAUTHMODULE
|
||||
|
||||
nsAuthSambaNTLM();
|
||||
|
||||
// We spawn the ntlm_auth helper from the module constructor, because
|
||||
// that lets us fail to instantiate the module if ntlm_auth isn't
|
||||
// available, triggering fallback to the built-in NTLM support (which
|
||||
// doesn't support single signon, of course)
|
||||
nsresult SpawnNTLMAuthHelper();
|
||||
|
||||
private:
|
||||
~nsAuthSambaNTLM();
|
||||
|
||||
void Shutdown();
|
||||
|
||||
uint8_t* mInitialMessage; /* free with free() */
|
||||
uint32_t mInitialMessageLen;
|
||||
PRProcess* mChildPID;
|
||||
PRFileDesc* mFromChildFD;
|
||||
PRFileDesc* mToChildFD;
|
||||
};
|
||||
|
||||
#endif /* nsAuthSambaNTLM_h__ */
|
||||
731
extensions/auth/nsHttpNegotiateAuth.cpp
Normal file
731
extensions/auth/nsHttpNegotiateAuth.cpp
Normal file
|
|
@ -0,0 +1,731 @@
|
|||
/* vim:set ts=4 sw=4 sts=4 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//
|
||||
// HTTP Negotiate Authentication Support Module
|
||||
//
|
||||
// Described by IETF Internet draft: draft-brezak-kerberos-http-00.txt
|
||||
// (formerly draft-brezak-spnego-http-04.txt)
|
||||
//
|
||||
// Also described here:
|
||||
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnsecure/html/http-sso-1.asp
|
||||
//
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "nsAuth.h"
|
||||
#include "nsHttpNegotiateAuth.h"
|
||||
|
||||
#include "nsIHttpAuthenticableChannel.h"
|
||||
#include "nsIProxiedChannel.h"
|
||||
#include "nsIAuthModule.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIPrefService.h"
|
||||
#include "nsIPrefBranch.h"
|
||||
#include "nsIProxyInfo.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "plbase64.h"
|
||||
#include "plstr.h"
|
||||
#include "mozilla/Base64.h"
|
||||
#include "prprf.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "prmem.h"
|
||||
#include "prnetdb.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "mozilla/Sprintf.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsIHttpAuthenticatorCallback.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "nsICancelable.h"
|
||||
|
||||
using mozilla::Base64Decode;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static const char kNegotiate[] = "Negotiate";
|
||||
static const char kNegotiateAuthTrustedURIs[] = "network.negotiate-auth.trusted-uris";
|
||||
static const char kNegotiateAuthDelegationURIs[] = "network.negotiate-auth.delegation-uris";
|
||||
static const char kNegotiateAuthAllowProxies[] = "network.negotiate-auth.allow-proxies";
|
||||
static const char kNegotiateAuthAllowNonFqdn[] = "network.negotiate-auth.allow-non-fqdn";
|
||||
static const char kNegotiateAuthSSPI[] = "network.auth.use-sspi";
|
||||
static const char kSSOinPBmode[] = "network.auth.private-browsing-sso";
|
||||
|
||||
#define kNegotiateLen (sizeof(kNegotiate)-1)
|
||||
#define DEFAULT_THREAD_TIMEOUT_MS 30000
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Return false when the channel comes from a Private browsing window.
|
||||
static bool
|
||||
TestNotInPBMode(nsIHttpAuthenticableChannel *authChannel, bool proxyAuth)
|
||||
{
|
||||
// Proxy should go all the time, it's not considered a privacy leak
|
||||
// to send default credentials to a proxy.
|
||||
if (proxyAuth) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIChannel> bareChannel = do_QueryInterface(authChannel);
|
||||
MOZ_ASSERT(bareChannel);
|
||||
|
||||
if (!NS_UsePrivateBrowsing(bareChannel)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||
if (prefs) {
|
||||
bool ssoInPb;
|
||||
if (NS_SUCCEEDED(prefs->GetBoolPref(kSSOinPBmode, &ssoInPb)) && ssoInPb) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// When the "Never remember history" option is set, all channels are
|
||||
// set PB mode flag, but here we want to make an exception, users
|
||||
// want their credentials go out.
|
||||
bool dontRememberHistory;
|
||||
if (NS_SUCCEEDED(prefs->GetBoolPref("browser.privatebrowsing.autostart",
|
||||
&dontRememberHistory)) &&
|
||||
dontRememberHistory) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHttpNegotiateAuth::GetAuthFlags(uint32_t *flags)
|
||||
{
|
||||
//
|
||||
// Negotiate Auth creds should not be reused across multiple requests.
|
||||
// Only perform the negotiation when it is explicitly requested by the
|
||||
// server. Thus, do *NOT* use the "REUSABLE_CREDENTIALS" flag here.
|
||||
//
|
||||
// CONNECTION_BASED is specified instead of REQUEST_BASED since we need
|
||||
// to complete a sequence of transactions with the server over the same
|
||||
// connection.
|
||||
//
|
||||
*flags = CONNECTION_BASED | IDENTITY_IGNORED;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// Always set *identityInvalid == FALSE here. This
|
||||
// will prevent the browser from popping up the authentication
|
||||
// prompt window. Because GSSAPI does not have an API
|
||||
// for fetching initial credentials (ex: A Kerberos TGT),
|
||||
// there is no correct way to get the users credentials.
|
||||
//
|
||||
NS_IMETHODIMP
|
||||
nsHttpNegotiateAuth::ChallengeReceived(nsIHttpAuthenticableChannel *authChannel,
|
||||
const char *challenge,
|
||||
bool isProxyAuth,
|
||||
nsISupports **sessionState,
|
||||
nsISupports **continuationState,
|
||||
bool *identityInvalid)
|
||||
{
|
||||
nsIAuthModule *module = (nsIAuthModule *) *continuationState;
|
||||
|
||||
*identityInvalid = false;
|
||||
if (module)
|
||||
return NS_OK;
|
||||
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
rv = authChannel->GetURI(getter_AddRefs(uri));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
uint32_t req_flags = nsIAuthModule::REQ_DEFAULT;
|
||||
nsAutoCString service;
|
||||
|
||||
if (isProxyAuth) {
|
||||
if (!TestBoolPref(kNegotiateAuthAllowProxies)) {
|
||||
LOG(("nsHttpNegotiateAuth::ChallengeReceived proxy auth blocked\n"));
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
|
||||
req_flags |= nsIAuthModule::REQ_PROXY_AUTH;
|
||||
nsCOMPtr<nsIProxyInfo> proxyInfo;
|
||||
authChannel->GetProxyInfo(getter_AddRefs(proxyInfo));
|
||||
NS_ENSURE_STATE(proxyInfo);
|
||||
|
||||
proxyInfo->GetHost(service);
|
||||
}
|
||||
else {
|
||||
bool allowed = TestNotInPBMode(authChannel, isProxyAuth) &&
|
||||
(TestNonFqdn(uri) ||
|
||||
TestPref(uri, kNegotiateAuthTrustedURIs));
|
||||
if (!allowed) {
|
||||
LOG(("nsHttpNegotiateAuth::ChallengeReceived URI blocked\n"));
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
|
||||
bool delegation = TestPref(uri, kNegotiateAuthDelegationURIs);
|
||||
if (delegation) {
|
||||
LOG((" using REQ_DELEGATE\n"));
|
||||
req_flags |= nsIAuthModule::REQ_DELEGATE;
|
||||
}
|
||||
|
||||
rv = uri->GetAsciiHost(service);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
}
|
||||
|
||||
LOG((" service = %s\n", service.get()));
|
||||
|
||||
//
|
||||
// The correct service name for IIS servers is "HTTP/f.q.d.n", so
|
||||
// construct the proper service name for passing to "gss_import_name".
|
||||
//
|
||||
// TODO: Possibly make this a configurable service name for use
|
||||
// with non-standard servers that use stuff like "khttp/f.q.d.n"
|
||||
// instead.
|
||||
//
|
||||
service.Insert("HTTP@", 0);
|
||||
|
||||
const char *contractID;
|
||||
if (TestBoolPref(kNegotiateAuthSSPI)) {
|
||||
LOG((" using negotiate-sspi\n"));
|
||||
contractID = NS_AUTH_MODULE_CONTRACTID_PREFIX "negotiate-sspi";
|
||||
}
|
||||
else {
|
||||
LOG((" using negotiate-gss\n"));
|
||||
contractID = NS_AUTH_MODULE_CONTRACTID_PREFIX "negotiate-gss";
|
||||
}
|
||||
|
||||
rv = CallCreateInstance(contractID, &module);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG((" Failed to load Negotiate Module \n"));
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = module->Init(service.get(), req_flags, nullptr, nullptr, nullptr);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_RELEASE(module);
|
||||
return rv;
|
||||
}
|
||||
|
||||
*continuationState = module;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsHttpNegotiateAuth, nsIHttpAuthenticator)
|
||||
|
||||
namespace {
|
||||
|
||||
//
|
||||
// GetNextTokenCompleteEvent
|
||||
//
|
||||
// This event is fired on main thread when async call of
|
||||
// nsHttpNegotiateAuth::GenerateCredentials is finished. During the Run()
|
||||
// method the nsIHttpAuthenticatorCallback::OnCredsAvailable is called with
|
||||
// obtained credentials, flags and NS_OK when successful, otherwise
|
||||
// NS_ERROR_FAILURE is returned as a result of failed operation.
|
||||
//
|
||||
class GetNextTokenCompleteEvent final : public nsIRunnable,
|
||||
public nsICancelable
|
||||
{
|
||||
virtual ~GetNextTokenCompleteEvent()
|
||||
{
|
||||
if (mCreds) {
|
||||
free(mCreds);
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
explicit GetNextTokenCompleteEvent(nsIHttpAuthenticatorCallback* aCallback)
|
||||
: mCallback(aCallback)
|
||||
, mCreds(nullptr)
|
||||
, mCancelled(false)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP DispatchSuccess(char *aCreds,
|
||||
uint32_t aFlags,
|
||||
already_AddRefed<nsISupports> aSessionState,
|
||||
already_AddRefed<nsISupports> aContinuationState)
|
||||
{
|
||||
// Called from worker thread
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
mCreds = aCreds;
|
||||
mFlags = aFlags;
|
||||
mResult = NS_OK;
|
||||
mSessionState = aSessionState;
|
||||
mContinuationState = aContinuationState;
|
||||
return NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP DispatchError(already_AddRefed<nsISupports> aSessionState,
|
||||
already_AddRefed<nsISupports> aContinuationState)
|
||||
{
|
||||
// Called from worker thread
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
mResult = NS_ERROR_FAILURE;
|
||||
mSessionState = aSessionState;
|
||||
mContinuationState = aContinuationState;
|
||||
return NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP Run() override
|
||||
{
|
||||
// Runs on main thread
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!mCancelled) {
|
||||
nsCOMPtr<nsIHttpAuthenticatorCallback> callback;
|
||||
callback.swap(mCallback);
|
||||
callback->OnCredsGenerated(mCreds, mFlags, mResult, mSessionState, mContinuationState);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP Cancel(nsresult aReason) override
|
||||
{
|
||||
// Supposed to be called from main thread
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mCancelled = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIHttpAuthenticatorCallback> mCallback;
|
||||
char *mCreds; // This class owns it, freed in destructor
|
||||
uint32_t mFlags;
|
||||
nsresult mResult;
|
||||
bool mCancelled;
|
||||
nsCOMPtr<nsISupports> mSessionState;
|
||||
nsCOMPtr<nsISupports> mContinuationState;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(GetNextTokenCompleteEvent, nsIRunnable, nsICancelable)
|
||||
|
||||
//
|
||||
// GetNextTokenRunnable
|
||||
//
|
||||
// This runnable is created by GenerateCredentialsAsync and it runs
|
||||
// in nsHttpNegotiateAuth::mNegotiateThread and calling GenerateCredentials.
|
||||
//
|
||||
class GetNextTokenRunnable final : public mozilla::Runnable
|
||||
{
|
||||
virtual ~GetNextTokenRunnable() {}
|
||||
public:
|
||||
GetNextTokenRunnable(nsIHttpAuthenticableChannel *authChannel,
|
||||
const char *challenge,
|
||||
bool isProxyAuth,
|
||||
const char16_t *domain,
|
||||
const char16_t *username,
|
||||
const char16_t *password,
|
||||
nsISupports *sessionState,
|
||||
nsISupports *continuationState,
|
||||
GetNextTokenCompleteEvent *aCompleteEvent
|
||||
)
|
||||
: mAuthChannel(authChannel)
|
||||
, mChallenge(challenge)
|
||||
, mIsProxyAuth(isProxyAuth)
|
||||
, mDomain(domain)
|
||||
, mUsername(username)
|
||||
, mPassword(password)
|
||||
, mSessionState(sessionState)
|
||||
, mContinuationState(continuationState)
|
||||
, mCompleteEvent(aCompleteEvent)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP Run() override
|
||||
{
|
||||
// Runs on worker thread
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
char *creds;
|
||||
uint32_t flags;
|
||||
nsresult rv = ObtainCredentialsAndFlags(&creds, &flags);
|
||||
|
||||
// Passing session and continuation state this way to not touch
|
||||
// referencing of the object that may not be thread safe.
|
||||
// Not having a thread safe referencing doesn't mean the object
|
||||
// cannot be used on multiple threads (one example is nsAuthSSPI.)
|
||||
// This ensures state objects will be destroyed on the main thread
|
||||
// when not changed by GenerateCredentials.
|
||||
if (NS_FAILED(rv)) {
|
||||
return mCompleteEvent->DispatchError(mSessionState.forget(),
|
||||
mContinuationState.forget());
|
||||
}
|
||||
|
||||
return mCompleteEvent->DispatchSuccess(creds, flags,
|
||||
mSessionState.forget(),
|
||||
mContinuationState.forget());
|
||||
}
|
||||
|
||||
NS_IMETHODIMP ObtainCredentialsAndFlags(char **aCreds, uint32_t *aFlags)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
// Use negotiate service to call GenerateCredentials outside of main thread
|
||||
nsAutoCString contractId;
|
||||
contractId.Assign(NS_HTTP_AUTHENTICATOR_CONTRACTID_PREFIX);
|
||||
contractId.Append("negotiate");
|
||||
nsCOMPtr<nsIHttpAuthenticator> authenticator =
|
||||
do_GetService(contractId.get(), &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsISupports *sessionState = mSessionState;
|
||||
nsISupports *continuationState = mContinuationState;
|
||||
// The continuationState is for the sake of completeness propagated
|
||||
// to the caller (despite it is not changed in any GenerateCredentials
|
||||
// implementation).
|
||||
//
|
||||
// The only implementation that use sessionState is the
|
||||
// nsHttpDigestAuth::GenerateCredentials. Since there's no reason
|
||||
// to implement nsHttpDigestAuth::GenerateCredentialsAsync
|
||||
// because digest auth does not block the main thread, we won't
|
||||
// propagate changes to sessionState to the caller because of
|
||||
// the change is too complicated on the caller side.
|
||||
//
|
||||
// Should any of the session or continuation states change inside
|
||||
// this method, they must be threadsafe.
|
||||
rv = authenticator->GenerateCredentials(mAuthChannel,
|
||||
mChallenge.get(),
|
||||
mIsProxyAuth,
|
||||
mDomain.get(),
|
||||
mUsername.get(),
|
||||
mPassword.get(),
|
||||
&sessionState,
|
||||
&continuationState,
|
||||
aFlags,
|
||||
aCreds);
|
||||
if (mSessionState != sessionState) {
|
||||
mSessionState = sessionState;
|
||||
}
|
||||
if (mContinuationState != continuationState) {
|
||||
mContinuationState = continuationState;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
private:
|
||||
nsCOMPtr<nsIHttpAuthenticableChannel> mAuthChannel;
|
||||
nsCString mChallenge;
|
||||
bool mIsProxyAuth;
|
||||
nsString mDomain;
|
||||
nsString mUsername;
|
||||
nsString mPassword;
|
||||
nsCOMPtr<nsISupports> mSessionState;
|
||||
nsCOMPtr<nsISupports> mContinuationState;
|
||||
RefPtr<GetNextTokenCompleteEvent> mCompleteEvent;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHttpNegotiateAuth::GenerateCredentialsAsync(nsIHttpAuthenticableChannel *authChannel,
|
||||
nsIHttpAuthenticatorCallback* aCallback,
|
||||
const char *challenge,
|
||||
bool isProxyAuth,
|
||||
const char16_t *domain,
|
||||
const char16_t *username,
|
||||
const char16_t *password,
|
||||
nsISupports *sessionState,
|
||||
nsISupports *continuationState,
|
||||
nsICancelable **aCancelable)
|
||||
{
|
||||
NS_ENSURE_ARG(aCallback);
|
||||
NS_ENSURE_ARG_POINTER(aCancelable);
|
||||
|
||||
RefPtr<GetNextTokenCompleteEvent> cancelEvent =
|
||||
new GetNextTokenCompleteEvent(aCallback);
|
||||
|
||||
|
||||
nsCOMPtr<nsIRunnable> getNextTokenRunnable =
|
||||
new GetNextTokenRunnable(authChannel,
|
||||
challenge,
|
||||
isProxyAuth,
|
||||
domain,
|
||||
username,
|
||||
password,
|
||||
sessionState,
|
||||
continuationState,
|
||||
cancelEvent);
|
||||
cancelEvent.forget(aCancelable);
|
||||
|
||||
nsresult rv;
|
||||
if (!mNegotiateThread) {
|
||||
mNegotiateThread =
|
||||
new mozilla::LazyIdleThread(DEFAULT_THREAD_TIMEOUT_MS,
|
||||
NS_LITERAL_CSTRING("NegotiateAuth"));
|
||||
NS_ENSURE_TRUE(mNegotiateThread, NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
rv = mNegotiateThread->Dispatch(getNextTokenRunnable, NS_DISPATCH_NORMAL);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// GenerateCredentials
|
||||
//
|
||||
// This routine is responsible for creating the correct authentication
|
||||
// blob to pass to the server that requested "Negotiate" authentication.
|
||||
//
|
||||
NS_IMETHODIMP
|
||||
nsHttpNegotiateAuth::GenerateCredentials(nsIHttpAuthenticableChannel *authChannel,
|
||||
const char *challenge,
|
||||
bool isProxyAuth,
|
||||
const char16_t *domain,
|
||||
const char16_t *username,
|
||||
const char16_t *password,
|
||||
nsISupports **sessionState,
|
||||
nsISupports **continuationState,
|
||||
uint32_t *flags,
|
||||
char **creds)
|
||||
{
|
||||
// ChallengeReceived must have been called previously.
|
||||
nsIAuthModule *module = (nsIAuthModule *) *continuationState;
|
||||
NS_ENSURE_TRUE(module, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
*flags = USING_INTERNAL_IDENTITY;
|
||||
|
||||
LOG(("nsHttpNegotiateAuth::GenerateCredentials() [challenge=%s]\n", challenge));
|
||||
|
||||
NS_ASSERTION(creds, "null param");
|
||||
|
||||
#ifdef DEBUG
|
||||
bool isGssapiAuth =
|
||||
!PL_strncasecmp(challenge, kNegotiate, kNegotiateLen);
|
||||
NS_ASSERTION(isGssapiAuth, "Unexpected challenge");
|
||||
#endif
|
||||
|
||||
//
|
||||
// If the "Negotiate:" header had some data associated with it,
|
||||
// that data should be used as the input to this call. This may
|
||||
// be a continuation of an earlier call because GSSAPI authentication
|
||||
// often takes multiple round-trips to complete depending on the
|
||||
// context flags given. We want to use MUTUAL_AUTHENTICATION which
|
||||
// generally *does* require multiple round-trips. Don't assume
|
||||
// auth can be completed in just 1 call.
|
||||
//
|
||||
unsigned int len = strlen(challenge);
|
||||
|
||||
void *inToken, *outToken;
|
||||
uint32_t inTokenLen, outTokenLen;
|
||||
|
||||
if (len > kNegotiateLen) {
|
||||
challenge += kNegotiateLen;
|
||||
while (*challenge == ' ')
|
||||
challenge++;
|
||||
len = strlen(challenge);
|
||||
|
||||
// strip off any padding (see bug 230351)
|
||||
while (challenge[len - 1] == '=')
|
||||
len--;
|
||||
|
||||
//
|
||||
// Decode the response that followed the "Negotiate" token
|
||||
//
|
||||
nsresult rv =
|
||||
Base64Decode(challenge, len, (char**)&inToken, &inTokenLen);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
else {
|
||||
//
|
||||
// Initializing, don't use an input token.
|
||||
//
|
||||
inToken = nullptr;
|
||||
inTokenLen = 0;
|
||||
}
|
||||
|
||||
nsresult rv = module->GetNextToken(inToken, inTokenLen, &outToken, &outTokenLen);
|
||||
|
||||
free(inToken);
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if (outTokenLen == 0) {
|
||||
LOG((" No output token to send, exiting"));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
//
|
||||
// base64 encode the output token.
|
||||
//
|
||||
char *encoded_token = PL_Base64Encode((char *)outToken, outTokenLen, nullptr);
|
||||
|
||||
free(outToken);
|
||||
|
||||
if (!encoded_token)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
LOG((" Sending a token of length %d\n", outTokenLen));
|
||||
|
||||
// allocate a buffer sizeof("Negotiate" + " " + b64output_token + "\0")
|
||||
const int bufsize = kNegotiateLen + 1 + strlen(encoded_token) + 1;
|
||||
*creds = (char *) moz_xmalloc(bufsize);
|
||||
if (MOZ_UNLIKELY(!*creds))
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
else
|
||||
snprintf(*creds, bufsize, "%s %s", kNegotiate, encoded_token);
|
||||
|
||||
PR_Free(encoded_token);
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool
|
||||
nsHttpNegotiateAuth::TestBoolPref(const char *pref)
|
||||
{
|
||||
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||
if (!prefs)
|
||||
return false;
|
||||
|
||||
bool val;
|
||||
nsresult rv = prefs->GetBoolPref(pref, &val);
|
||||
if (NS_FAILED(rv))
|
||||
return false;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
bool
|
||||
nsHttpNegotiateAuth::TestNonFqdn(nsIURI *uri)
|
||||
{
|
||||
nsAutoCString host;
|
||||
PRNetAddr addr;
|
||||
|
||||
if (!TestBoolPref(kNegotiateAuthAllowNonFqdn))
|
||||
return false;
|
||||
|
||||
if (NS_FAILED(uri->GetAsciiHost(host)))
|
||||
return false;
|
||||
|
||||
// return true if host does not contain a dot and is not an ip address
|
||||
return !host.IsEmpty() && !host.Contains('.') &&
|
||||
PR_StringToNetAddr(host.BeginReading(), &addr) != PR_SUCCESS;
|
||||
}
|
||||
|
||||
bool
|
||||
nsHttpNegotiateAuth::TestPref(nsIURI *uri, const char *pref)
|
||||
{
|
||||
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||
if (!prefs)
|
||||
return false;
|
||||
|
||||
nsAutoCString scheme, host;
|
||||
int32_t port;
|
||||
|
||||
if (NS_FAILED(uri->GetScheme(scheme)))
|
||||
return false;
|
||||
if (NS_FAILED(uri->GetAsciiHost(host)))
|
||||
return false;
|
||||
if (NS_FAILED(uri->GetPort(&port)))
|
||||
return false;
|
||||
|
||||
char *hostList;
|
||||
if (NS_FAILED(prefs->GetCharPref(pref, &hostList)) || !hostList)
|
||||
return false;
|
||||
|
||||
// pseudo-BNF
|
||||
// ----------
|
||||
//
|
||||
// url-list base-url ( base-url "," LWS )*
|
||||
// base-url ( scheme-part | host-part | scheme-part host-part )
|
||||
// scheme-part scheme "://"
|
||||
// host-part host [":" port]
|
||||
//
|
||||
// for example:
|
||||
// "https://, http://office.foo.com"
|
||||
//
|
||||
|
||||
char *start = hostList, *end;
|
||||
for (;;) {
|
||||
// skip past any whitespace
|
||||
while (*start == ' ' || *start == '\t')
|
||||
++start;
|
||||
end = strchr(start, ',');
|
||||
if (!end)
|
||||
end = start + strlen(start);
|
||||
if (start == end)
|
||||
break;
|
||||
if (MatchesBaseURI(scheme, host, port, start, end))
|
||||
return true;
|
||||
if (*end == '\0')
|
||||
break;
|
||||
start = end + 1;
|
||||
}
|
||||
|
||||
free(hostList);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
nsHttpNegotiateAuth::MatchesBaseURI(const nsCSubstring &matchScheme,
|
||||
const nsCSubstring &matchHost,
|
||||
int32_t matchPort,
|
||||
const char *baseStart,
|
||||
const char *baseEnd)
|
||||
{
|
||||
// check if scheme://host:port matches baseURI
|
||||
|
||||
// parse the base URI
|
||||
const char *hostStart, *schemeEnd = strstr(baseStart, "://");
|
||||
if (schemeEnd) {
|
||||
// the given scheme must match the parsed scheme exactly
|
||||
if (!matchScheme.Equals(Substring(baseStart, schemeEnd)))
|
||||
return false;
|
||||
hostStart = schemeEnd + 3;
|
||||
}
|
||||
else
|
||||
hostStart = baseStart;
|
||||
|
||||
// XXX this does not work for IPv6-literals
|
||||
const char *hostEnd = strchr(hostStart, ':');
|
||||
if (hostEnd && hostEnd < baseEnd) {
|
||||
// the given port must match the parsed port exactly
|
||||
int port = atoi(hostEnd + 1);
|
||||
if (matchPort != (int32_t) port)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
hostEnd = baseEnd;
|
||||
|
||||
|
||||
// if we didn't parse out a host, then assume we got a match.
|
||||
if (hostStart == hostEnd)
|
||||
return true;
|
||||
|
||||
uint32_t hostLen = hostEnd - hostStart;
|
||||
|
||||
// matchHost must either equal host or be a subdomain of host
|
||||
if (matchHost.Length() < hostLen)
|
||||
return false;
|
||||
|
||||
const char *end = matchHost.EndReading();
|
||||
if (PL_strncasecmp(end - hostLen, hostStart, hostLen) == 0) {
|
||||
// if matchHost ends with host from the base URI, then make sure it is
|
||||
// either an exact match, or prefixed with a dot. we don't want
|
||||
// "foobar.com" to match "bar.com"
|
||||
if (matchHost.Length() == hostLen ||
|
||||
*(end - hostLen) == '.' ||
|
||||
*(end - hostLen - 1) == '.')
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
44
extensions/auth/nsHttpNegotiateAuth.h
Normal file
44
extensions/auth/nsHttpNegotiateAuth.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/* vim:set ts=4 sw=4 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsHttpNegotiateAuth_h__
|
||||
#define nsHttpNegotiateAuth_h__
|
||||
|
||||
#include "nsIHttpAuthenticator.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsSubstring.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/LazyIdleThread.h"
|
||||
|
||||
// The nsHttpNegotiateAuth class provides responses for the GSS-API Negotiate method
|
||||
// as specified by Microsoft in draft-brezak-spnego-http-04.txt
|
||||
|
||||
class nsHttpNegotiateAuth final : public nsIHttpAuthenticator
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIHTTPAUTHENTICATOR
|
||||
|
||||
private:
|
||||
~nsHttpNegotiateAuth() {}
|
||||
|
||||
// returns the value of the given boolean pref
|
||||
bool TestBoolPref(const char *pref);
|
||||
|
||||
// tests if the host part of an uri is fully qualified
|
||||
bool TestNonFqdn(nsIURI *uri);
|
||||
|
||||
// returns true if URI is accepted by the list of hosts in the pref
|
||||
bool TestPref(nsIURI *, const char *pref);
|
||||
|
||||
bool MatchesBaseURI(const nsCSubstring &scheme,
|
||||
const nsCSubstring &host,
|
||||
int32_t port,
|
||||
const char *baseStart,
|
||||
const char *baseEnd);
|
||||
// Thread for GenerateCredentialsAsync
|
||||
RefPtr<mozilla::LazyIdleThread> mNegotiateThread;
|
||||
};
|
||||
#endif /* nsHttpNegotiateAuth_h__ */
|
||||
Loading…
Add table
Add a link
Reference in a new issue