};
const gss_OID_set_desc * const gss_mech_set_spnego = spnego_oidsets+0;
-static int make_NegHints(OM_uint32 *, spnego_gss_cred_id_t, gss_buffer_t *);
+static int make_NegHints(OM_uint32 *, gss_buffer_t *);
static int put_neg_hints(unsigned char **, gss_buffer_t, unsigned int);
static OM_uint32
acc_ctx_hints(OM_uint32 *, gss_ctx_id_t *, spnego_gss_cred_id_t,
#define HOST_PREFIX "host@"
#define HOST_PREFIX_LEN (sizeof(HOST_PREFIX) - 1)
+/* Encode the dummy hintname string (as specified in [MS-SPNG]) into a
+ * DER-encoded [0] tagged GeneralString, and place the result in *outbuf. */
static int
-make_NegHints(OM_uint32 *minor_status,
- spnego_gss_cred_id_t spcred, gss_buffer_t *outbuf)
+make_NegHints(OM_uint32 *minor_status, gss_buffer_t *outbuf)
{
- gss_buffer_desc hintNameBuf;
- gss_name_t hintName = GSS_C_NO_NAME;
- gss_name_t hintKerberosName;
- gss_OID hintNameType;
OM_uint32 major_status;
- OM_uint32 minor;
unsigned int tlen = 0;
unsigned int hintNameSize = 0;
unsigned char *ptr;
unsigned char *t;
+ const char *hintname = "not_defined_in_RFC4178@please_ignore";
+ const size_t hintname_len = strlen(hintname);
*outbuf = GSS_C_NO_BUFFER;
-
- if (spcred != NULL) {
- major_status = gss_inquire_cred(minor_status,
- spcred->mcred,
- &hintName,
- NULL,
- NULL,
- NULL);
- if (major_status != GSS_S_COMPLETE)
- return (major_status);
- }
-
- if (hintName == GSS_C_NO_NAME) {
- krb5_error_code code;
- krb5int_access kaccess;
- char hostname[HOST_PREFIX_LEN + MAXHOSTNAMELEN + 1] = HOST_PREFIX;
-
- code = krb5int_accessor(&kaccess, KRB5INT_ACCESS_VERSION);
- if (code != 0) {
- *minor_status = code;
- return (GSS_S_FAILURE);
- }
-
- /* this breaks mutual authentication but Samba relies on it */
- code = (*kaccess.clean_hostname)(NULL, NULL,
- &hostname[HOST_PREFIX_LEN],
- MAXHOSTNAMELEN);
- if (code != 0) {
- *minor_status = code;
- return (GSS_S_FAILURE);
- }
-
- hintNameBuf.value = hostname;
- hintNameBuf.length = strlen(hostname);
-
- major_status = gss_import_name(minor_status,
- &hintNameBuf,
- GSS_C_NT_HOSTBASED_SERVICE,
- &hintName);
- if (major_status != GSS_S_COMPLETE) {
- return (major_status);
- }
- }
-
- hintNameBuf.value = NULL;
- hintNameBuf.length = 0;
-
- major_status = gss_canonicalize_name(minor_status,
- hintName,
- (gss_OID)&gss_mech_krb5_oid,
- &hintKerberosName);
- if (major_status != GSS_S_COMPLETE) {
- gss_release_name(&minor, &hintName);
- return (major_status);
- }
- gss_release_name(&minor, &hintName);
-
- major_status = gss_display_name(minor_status,
- hintKerberosName,
- &hintNameBuf,
- &hintNameType);
- if (major_status != GSS_S_COMPLETE) {
- gss_release_name(&minor, &hintName);
- return (major_status);
- }
- gss_release_name(&minor, &hintKerberosName);
-
- /*
- * Now encode the name hint into a NegHints ASN.1 type
- */
major_status = GSS_S_FAILURE;
/* Length of DER encoded GeneralString */
- tlen = 1 + gssint_der_length_size(hintNameBuf.length) +
- hintNameBuf.length;
+ tlen = 1 + gssint_der_length_size(hintname_len) + hintname_len;
hintNameSize = tlen;
/* Length of DER encoded hintName */
goto errout;
*ptr++ = GENERAL_STRING;
- if (gssint_put_der_length(hintNameBuf.length,
- &ptr, tlen - (int)(ptr-t)))
+ if (gssint_put_der_length(hintname_len, &ptr, tlen - (int)(ptr-t)))
goto errout;
- memcpy(ptr, hintNameBuf.value, hintNameBuf.length);
- ptr += hintNameBuf.length;
+ memcpy(ptr, hintname, hintname_len);
+ ptr += hintname_len;
*outbuf = (gss_buffer_t)malloc(sizeof(gss_buffer_desc));
if (*outbuf == NULL) {
free(t);
}
- gss_release_buffer(&minor, &hintNameBuf);
-
return (major_status);
}
if (ret != GSS_S_COMPLETE)
goto cleanup;
- ret = make_NegHints(minor_status, spcred, mechListMIC);
+ ret = make_NegHints(minor_status, mechListMIC);
if (ret != GSS_S_COMPLETE)
goto cleanup;
free(stok.value);
}
+/* Check that we return a compatibility NegTokenInit2 message containing
+ * NegHints for an empty initiator token. */
+static void
+test_neghints()
+{
+ OM_uint32 major, minor;
+ gss_buffer_desc itok = GSS_C_EMPTY_BUFFER, atok;
+ gss_ctx_id_t actx = GSS_C_NO_CONTEXT;
+ const char *expected =
+ /* RFC 2743 token framing: [APPLICATION 0] IMPLICIT SEQUENCE followed
+ * by OBJECT IDENTIFIER and the SPNEGO OID */
+ "\x60\x47\x06\x06" "\x2B\x06\x01\x05\x05\x02"
+ /* [0] SEQUENCE for the NegotiationToken negtokenInit choice */
+ "\xA0\x3D\x30\x3B"
+ /* [0] MechTypeList containing the krb5 OID */
+ "\xA0\x0D\x30\x0B\x06\x09" "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"
+ /* [3] NegHints containing [0] GeneralString containing the dummy
+ * hintName string defined in [MS-SPNG] */
+ "\xA3\x2A\x30\x28\xA0\x26\x1B\x24"
+ "not_defined_in_RFC4178@please_ignore";
+
+ /* Produce a hint token. */
+ major = gss_accept_sec_context(&minor, &actx, GSS_C_NO_CREDENTIAL, &itok,
+ GSS_C_NO_CHANNEL_BINDINGS, NULL, NULL,
+ &atok, NULL, NULL, NULL);
+ check_gsserr("gss_accept_sec_context(neghints)", major, minor);
+
+ /* Verify it against the expected contents, which are fixed as long as we
+ * only list the krb5 mech in the token. */
+ assert(atok.length == strlen(expected));
+ assert(memcmp(atok.value, expected, atok.length) == 0);
+
+ (void)gss_release_buffer(&minor, &atok);
+ (void)gss_delete_sec_context(&minor, &actx, NULL);
+}
+
int
main(int argc, char *argv[])
{
test_mskrb_oid(target_name, verifier_cred_handle);
test_mskrb_oid(target_name, GSS_C_NO_CREDENTIAL);
+ test_neghints();
+
(void)gss_delete_sec_context(&minor, &initiator_context, NULL);
(void)gss_delete_sec_context(&minor, &acceptor_context, NULL);
(void)gss_release_name(&minor, &source_name);