krb5ssp.c revision 05cffdd1e5bacc2be9e9bd3721a3af9fe838769a
/*
* Copyright (c) 2000, Boris Popov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Boris Popov.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Kerberos V Security Support Provider
*
* Based on code previously in ctx.c (from Boris Popov?)
* but then mostly rewritten at Sun.
*/
#include <errno.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>
#include <netdb.h>
#include <libintl.h>
#include <xti.h>
#include <assert.h>
#include <sys/byteorder.h>
#include "private.h"
#include "charsets.h"
#include "spnego.h"
#include "derparse.h"
#include "ssp.h"
#include <kerberosv5/krb5.h>
#include <kerberosv5/com_err.h>
/* RFC 1964 token ID codes */
#define KRB_AP_REQ 1
#define KRB_AP_REP 2
#define KRB_ERROR 3
extern MECH_OID g_stcMechOIDList [];
typedef struct krb5ssp_state {
/* Filled in by krb5ssp_init_client */
/* Filled in by krb5ssp_get_tkt */
/*
* adds a GSSAPI wrapper
*/
int
{
uchar_t *b;
DPRINT("malloc");
return (ENOMEM);
}
b = blob;
b += ASNDerWriteOID(b, spnego_mech_oid_Kerberos_V5);
b += sizeof (krbapreq);
return (0);
}
/*
* See "Windows 2000 Kerberos Interoperability" paper by
* Christopher Nebergall. RC4 HMAC is the W2K default but
* Samba support lagged (not due to Samba itself, but due to OS'
* Kerberos implementations.)
*
* Only session enc type should matter, not ticket enc type,
* per Sam Hartman on krbdev.
*
* Preauthentication failure topics in krb-protocol may help here...
*/
static krb5_enctype kenctypes[] = {
ENCTYPE_ARCFOUR_HMAC, /* defined in krb5.h */
};
static const int rq_opts =
/*
* Obtain a kerberos ticket for the host we're connecting to.
* (This does the KRB_TGS exchange.)
*/
static int
{
krb5_error_code kerr = 0;
/* Should have these from krb5ssp_init_client. */
fn = "null kctx or kcc";
goto out;
}
if (kerr != 0) {
fn = "krb5_set_default_tgs_enctypes";
goto out;
}
/* Override the krb5 library default. */
if (kerr != 0) {
fn = "krb5_mk_req";
goto out;
}
fn = "malloc signing key";
goto out;
}
kerr = 0;
out:
if (kerr) {
fn = "?";
}
/* Free kctx in krb5ssp_destroy */
return (kerr);
}
/*
* Build an RFC 1964 KRB_AP_REQ message
* The caller puts on the SPNEGO wrapper.
*/
int
{
int err;
goto out;
goto out;
goto out;
goto out;
out:
if (gtok)
if (tkt)
return (err);
}
/*
* Unwrap a GSS-API encapsulated RFC 1964 reply message,
* i.e. type KRB_AP_REP or KRB_ERROR.
*/
int
{
long actual_len, token_len;
/* cheating: this mbuf is contiguous */
/*
* Peel off the GSS-API wrapper. Looks like:
* AppToken: 60 81 83
* OID(KRB5): 06 09 2a 86 48 86 f7 12 01 02 02
* KRB_AP_REP: 02 00
*/
if (rc != SPNEGO_E_SUCCESS) {
goto out;
}
if (dlen < actual_len)
goto out;
data += actual_len;
dlen -= actual_len;
/* OID (KRB5) */
dlen, &actual_len);
if (rc != SPNEGO_E_SUCCESS) {
goto out;
}
if (dlen < actual_len)
goto out;
data += actual_len;
dlen -= actual_len;
/* KRB_AP_REP or KRB_ERROR */
if (data[0] != KRB_AP_REP) {
goto out;
}
if (dlen < 2)
goto out;
data += 2;
dlen -= 2;
/*
* Now what's left should be a krb5 reply
* NB: ap is NOT allocated, so don't free it.
*/
if (rc != 0) {
DPRINT("krb5_rd_rep: err 0x%x (%s)",
goto out;
}
/*
* Have the decoded reply. Save anything?
*
* NB: If this returns an error, we will get
* no more calls into this back-end module.
*/
err = 0;
out:
if (err)
return (err);
}
/*
* krb5ssp_final
*
* Called after successful authentication.
* Setup the MAC key for signing.
*/
int
{
/*
* Save the session key, used for SMB signing
* and possibly other consumers (RPC).
*/
if (err != 0) {
DPRINT("_getlocalsubkey, err=0x%x (%s)",
goto out;
}
/*
* Set the MAC key on the first successful auth.
*/
ctx->ct_mackeylen = 0;
goto out;
}
ctx->ct_mackeylen);
/*
* Apparently, the server used seq. no. zero
* for our previous message, so next is two.
*/
}
err = 0;
out:
if (ssn_key)
return (err);
}
/*
* krb5ssp_next_token
*
* See ssp.c: ssp_ctx_next_token
*/
int
{
int err;
/*
* Note: in_mb == NULL on the first call.
*/
if (in_mb) {
if (err)
goto out;
}
if (out_mb) {
} else
out:
if (err)
return (err);
}
/*
* krb5ssp_ctx_destroy
*
* Destroy mechanism-specific data.
*/
void
{
return;
/* from krb5ssp_get_tkt */
/* from krb5ssp_init_client */
if (ss->ss_krb5clp)
}
}
/*
* krb5ssp_init_clnt
*
* Initialize a new Kerberos SSP client context.
*
* The user must already have a TGT in their credential cache,
* as shown by the "klist" command.
*/
int
{
DPRINT("KRB5 not in authflags");
return (ENOTSUP);
}
return (ENOMEM);
if (kerr) {
goto errout;
}
/* non-default would instead use krb5_cc_resolve */
if (kerr) {
goto errout;
}
/*
* Get the client principal (ticket),
* or discover that we don't have one.
*/
if (kerr) {
goto errout;
}
/* Success! */
DPRINT("Ticket cache: %s:%s",
return (0);
return (ENOTSUP);
}