/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
/*
* NT Lan Manager Security Support Provider (NTLMSSP)
*
* Based on information from the "Davenport NTLM" page:
*/
#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 "smb_crypt.h"
#include "spnego.h"
#include "derparse.h"
#include "ssp.h"
#include "ntlm.h"
#include "ntlmssp.h"
/* A shorter alias for a crazy long name from [MS-NLMP] */
#define NTLMSSP_NEGOTIATE_NTLM2 \
typedef struct ntlmssp_state {
/*
* So called "security buffer".
* A lot like an RPC string.
*/
struct sec_buf {
};
static int
/*
* Get a "security buffer" (header part)
*/
static int
{
int err;
return (err);
}
/*
* Get a "security buffer" (data part), where
* the data is delivered as an mbuf.
*/
static int
{
int err;
/*
* Setup tmp_mb to point to the start of the header.
* This is a dup ref - do NOT free it.
*/
/* Skip data up to the offset. */
if (err)
return (err);
/* Get the data (as an mbuf). */
return (err);
}
/*
* Put a "security buffer" (header part)
*/
static int
{
int err;
return (err);
}
/*
* Put a "security buffer" (data part), where
* the data is an mbuf. Note: consumes m.
*/
static int
{
int cnt0;
int err = 0;
if (m != NULL)
return (err);
}
/*
* Put a "security buffer" (data part), where
* the data is a string (OEM or unicode).
*
* The string is NOT null terminated.
*/
static int
{
/*
* Put the string into a temp. mbuf,
* then chop off the null terminator
* before appending to caller's mbp.
*/
if (err)
return (err);
if (err)
return (err);
trim = 0;
}
/*
* Note: tmp_mb.mb_top (if any) is consumed,
* so do NOT free it (no mb_done)
*/
return (err);
}
/*
* Build a Type 1 message
*
* This message has a header section containing offsets to
* data later in the message. We use the common trick of
* building it in two parts and then concatenatening.
*/
int
{
struct type1hdr {
} hdr;
int err;
return (err);
/*
* The initial negotiation flags represent the union of all
* options we support. The server selects from these.
* See: [MS-NLMP 2.2.2.5 NEGOTIATE]
*/
/* NTLMSSP_NEGOTIATE_LM_KEY (never) */
/* NTLMSSP_NEGOTIATE_ALWAYS_SIGN (set below) */
}
/*
* We could put the client domain, client name strings
* here, (always in OEM format, upper-case), and set
* NTLMSSP_NEGOTIATE_OEM_..._SUPPLIED, but Windows
* leaves these NULL so let's do the same.
*/
/*
* Marshal the header (in LE order)
* then concatenate the 2nd part.
*/
return (err);
}
/*
* Parse a Type 2 message
*/
int
{
struct type2hdr {
} hdr;
struct mbuf *m;
goto out;
}
/*
* Save the mbdata pointers before we consume anything.
* Careful to NOT free this (would be dup. free)
* We use this below to find data based on offsets
* from the start of the header.
*/
/* Parse the fixed size header stuff. */
goto out;
}
/*
* Save flags, server challenge for later.
*/
/*
* Turn off flags that might have been given but
* that we don't want to send with authenticate.
*/
/*
* Now find out if the optional parts are there.
*/
}
/*
* Get the target name string. (Server name or
* Primary domain name.) First get a copy of the
* security buffer header; then parse the string.
*/
if (err)
goto out;
/*
* Get the target info blob, if present.
*/
&ssp_st->ss_target_info);
}
out:
return (err);
}
/*
* Build a Type 3 message
*
* This message has a header section containing offsets to
* data later in the message. We use the common trick of
* building it in two parts and then concatenatening.
*/
int
{
struct type3hdr {
/* Version struct (ommitted) */
} hdr;
/*
* Fill in the NTLMSSP header, etc.
*/
goto out;
/*
* and compute the session key, etc.
*/
/*
* We're setting up a NULL session, meaning
* the lm_mbc, nt_mbc parts remain empty.
* Let's add the "anon" flag (hint).
* As there is no session key, disable the
* fancy session key stuff.
*/
err = 0;
/*
*/
if (err)
goto out;
if (err)
goto out;
/* The "key exg. key" is the session base key */
/*
* Doing NTLM ("v1x") which is NTLM with
* "Extended Session Security"
*/
if (err)
goto out;
/* Compute the "Key exchange key". */
} else {
/*
* Doing plain old NTLM (and LM if enabled)
*/
if (err)
goto out;
/* The "key exg. key" is the session base key */
}
/*
* Compute the "Exported Session Key" and (possibly)
* the "Encrypted Random Sesion Key".
* [MS-NLMP 3.1.5.1.2]
*/
if (err)
goto out;
} else {
/* ExportedSessionKey is the KeyExchangeKey */
/* EncryptedRandomSessionKey remains NULL */
}
if (err)
goto out;
if (err)
goto out;
/*
* Put the "target" (domain), user, workstation
*/
if (err)
goto out;
if (err)
goto out;
if (err)
goto out;
/*
* Put the "Encrypted Random Session Key", if any.
* (ek_mbc.mb_top may be NULL)
*/
if (err)
goto out;
/*
* Marshal the header (in LE order)
* then concatenate the 2nd part.
*/
/* Put zeros for the MIC - filled in later */
/* Put the payload. */
/*
* Compute the MIC and stuff that in...
* The MIC is apparently optional.
*/
(void) pmic;
out:
return (err);
}
/*
* Helper for ntlmssp_put_type3 when doing key exchange.
*
* "ExportedSessionKey" is what we give to the "application"
* layer, which in here means the MAC key for SMB signing.
* With "key exchange", we replace the ExportedSessionKey
* with random data and send that (encrypted) to the peer.
*/
static int
{
int err;
return (err);
/* Set "ExportedSessionKey to NONCE(16) */
/* Set "EncryptedRandomSessionKey" to RC4(...) */
return (err);
}
/*
* ntlmssp_final
*
* Called after successful authentication.
* Setup the MAC key for signing.
*/
int
{
int err = 0;
/*
* MAC_key is just the session key, but
* Only on the first successful auth.
*/
ctx->ct_mackeylen = 0;
goto out;
}
/*
* Apparently, the server used seq. no. zero
* for our previous message, so next is two.
*/
}
out:
return (err);
}
/*
* ntlmssp_next_token
*
* See ssp.c: ssp_ctx_next_token
*/
int
{
int err;
/* final call on successful auth. */
goto out;
}
/* Will build an ouptut token. */
if (err)
goto out;
/*
* When called with in_mb == NULL, it means
* this is the first call for this session,
* so put a Type 1 (initialize) token.
*/
goto out;
}
/*
* This is not the first call, so
* parse the response token we received.
* It should be a Type 2 (challenge).
* Then put a Type 3 (authenticate)
*/
if (err)
goto out;
out:
if (err)
return (err);
}
/*
* ntlmssp_ctx_destroy
*
* Destroy mechanism-specific data.
*/
void
{
}
}
/*
* ntlmssp_init_clnt
*
* Initialize a new NTLMSSP client context.
*/
int
{
DPRINT("No NTLM authflags");
return (EINVAL);
}
return (ENOMEM);
return (0);
}