1
0
mirror of https://github.com/samba-team/samba.git synced 2025-03-24 10:50:22 +03:00

Merge from HEAD:

- NTLMSSP over SPENGO (sesssion-setup-and-x) cleanup and code refactor.
  - also consequential changes to the NTLMSSP and SPNEGO parsing functions
  - and the client code that uses the same functions
 - Add ntlm_auth, a NTLMSSP authentication interface for use by applications
   like Squid and Apache.
  - also consquential changes to use common code for base64 encode/decode.
 - Winbind changes to support ntlm_auth (I don't want this program to need
   to read smb.conf, instead getting all it's details over the pipe).
 - nmbd changes for fstrcat() instead of fstrcpy().

Andrew Bartlett
(This used to be commit fbb46da79cf322570a7e3318100c304bbf33409e)
This commit is contained in:
Andrew Bartlett 2003-01-28 12:07:02 +00:00
parent 2326525950
commit 1cba0a7579
14 changed files with 338 additions and 367 deletions

View File

@ -111,7 +111,7 @@ BIN_PROGS1 = bin/smbclient@EXEEXT@ bin/net@EXEEXT@ bin/smbspool@EXEEXT@ \
BIN_PROGS2 = bin/smbcontrol@EXEEXT@ bin/smbtree@EXEEXT@ bin/tdbbackup@EXEEXT@ \
bin/nmblookup@EXEEXT@ bin/pdbedit@EXEEXT@
BIN_PROGS3 = bin/smbpasswd@EXEEXT@ bin/rpcclient@EXEEXT@ bin/smbcacls@EXEEXT@ \
bin/profiles@EXEEXT@ bin/smbgroupedit@EXEEXT@
bin/profiles@EXEEXT@ bin/smbgroupedit@EXEEXT@ bin/ntlm_auth@EXEEXT@ \
TORTURE_PROGS = bin/smbtorture@EXEEXT@ bin/msgtest@EXEEXT@ \
bin/masktest@EXEEXT@ bin/locktest@EXEEXT@ \
@ -186,7 +186,8 @@ LIBSMB_OBJ = libsmb/clientgen.o libsmb/cliconnect.o libsmb/clifile.o \
libsmb/smberr.o libsmb/credentials.o libsmb/pwd_cache.o \
libsmb/clioplock.o libsmb/errormap.o libsmb/clirap2.o \
libsmb/passchange.o libsmb/unexpected.o libsmb/doserr.o \
libsmb/namecache.o $(RPC_PARSE_OBJ1)
libsmb/namecache.o libsmb/ntlmssp.o \
$(RPC_PARSE_OBJ1)
LIBMSRPC_OBJ = rpc_client/cli_lsarpc.o rpc_client/cli_samr.o \
rpc_client/cli_netlogon.o rpc_client/cli_srvsvc.o \
@ -256,7 +257,7 @@ UNIGRP_OBJ = libsmb/netlogon_unigrp.o
AUTH_OBJ = auth/auth.o auth/auth_sam.o auth/auth_server.o auth/auth_domain.o \
auth/auth_rhosts.o auth/auth_unix.o auth/auth_util.o auth/auth_winbind.o \
auth/auth_builtin.o auth/auth_compat.o \
auth/auth_builtin.o auth/auth_compat.o auth/auth_ntlmssp.o \
$(PLAINTEXT_AUTH_OBJ) $(UNIGRP_OBJ)
MANGLE_OBJ = smbd/mangle.o smbd/mangle_hash.o smbd/mangle_map.o smbd/mangle_hash2.o
@ -539,6 +540,8 @@ POPT_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \
TDBBACKUP_OBJ = tdb/tdbbackup.o $(TDBBASE_OBJ)
NTLM_AUTH_OBJ = utils/ntlm_auth.o $(LIBSMB_OBJ) $(POPT_LIB_OBJ)
######################################################################
# now the rules...
######################################################################
@ -869,6 +872,12 @@ bin/wbinfo@EXEEXT@: $(WBINFO_OBJ) $(PARAM_OBJ) $(LIB_OBJ) \
@$(LINK) -o $@ $(WBINFO_OBJ) $(PARAM_OBJ) $(LIB_OBJ) \
$(UBIQX_OBJ) $(SECRETS_OBJ) $(LIBS) @BUILD_POPT@
bin/ntlm_auth@EXEEXT@: $(NTLM_AUTH_OBJ) $(PARAM_OBJ) $(LIB_OBJ) \
$(UBIQX_OBJ) @BUILD_POPT@ bin/.dummy
@echo Linking $@
@$(LINK) -o $@ $(NTLM_AUTH_OBJ) $(PARAM_OBJ) $(LIB_OBJ) \
$(UBIQX_OBJ) $(LIBS) @BUILD_POPT@
bin/pam_smbpass.@SHLIBEXT@: $(PAM_SMBPASS_PICOOBJ)
@echo "Linking shared library $@"
$(SHLD) $(LDSHFLAGS) -o $@ $(PAM_SMBPASS_PICOOBJ) -lpam $(DYNEXP) $(LIBS) -lc

View File

@ -57,7 +57,8 @@ static const uint8 *get_ntlm_challenge(struct auth_context *auth_context)
TALLOC_CTX *mem_ctx;
if (auth_context->challenge.length) {
DEBUG(5, ("get_ntlm_challenge (auth subsystem): returning previous challenge (normal)\n"));
DEBUG(5, ("get_ntlm_challenge (auth subsystem): returning previous challenge by module %s (normal)\n",
auth_context->challenge_set_by));
return auth_context->challenge.data;
}
@ -190,6 +191,12 @@ static NTSTATUS check_ntlm_password(const struct auth_context *auth_context,
DEBUG(3, ("check_ntlm_password: mapped user is: [%s]\\[%s]@[%s]\n",
user_info->domain.str, user_info->internal_username.str, user_info->wksta_name.str));
if (auth_context->challenge.length != 8) {
DEBUG(0, ("check_ntlm_password: Invalid challenge stored for this auth context - cannot continue\n"));
return NT_STATUS_LOGON_FAILURE;
}
if (auth_context->challenge_set_by)
DEBUG(10, ("check_ntlm_password: auth_context challenge created by %s\n",
auth_context->challenge_set_by));
@ -441,6 +448,7 @@ NTSTATUS make_auth_context_fixed(struct auth_context **auth_context, uchar chal[
}
(*auth_context)->challenge = data_blob(chal, 8);
(*auth_context)->challenge_set_by = "fixed";
return nt_status;
}

View File

@ -55,4 +55,8 @@ typedef struct {
#define OID_KERBEROS5_OLD "1 2 840 48018 1 2 2"
#define OID_KERBEROS5 "1 2 840 113554 1 2 2"
#define SPNGEO_NEG_RESULT_ACCEPT 0
#define SPNGEO_NEG_RESULT_INCOMPLETE 1
#define SPNGEO_NEG_RESULT_REJECT 2
#endif /* _ASN_1_H */

View File

@ -149,4 +149,13 @@ struct auth_init_function_entry {
auth_init_function init;
};
typedef struct auth_ntlmssp_state
{
TALLOC_CTX *mem_ctx;
struct auth_context *auth_context;
struct auth_serversupplied_info *server_info;
struct ntlmssp_state *ntlmssp_state;
} AUTH_NTLMSSP_STATE;
#endif /* _SMBAUTH_H_ */

View File

@ -71,9 +71,20 @@ typedef struct ntlmssp_state
{
TALLOC_CTX *mem_ctx;
enum NTLMSSP_ROLE role;
struct auth_context *auth_context;
struct auth_serversupplied_info *server_info;
BOOL unicode;
char *orig_user;
char *orig_domain;
char *user;
char *domain;
char *workstation;
DATA_BLOB lm_resp;
DATA_BLOB nt_resp;
DATA_BLOB chal;
void *auth_context;
const uint8 *(*get_challenge)(struct ntlmssp_state *ntlmssp_state);
NTSTATUS (*check_password)(struct ntlmssp_state *ntlmssp_state);
const char *(*get_global_myname)(void);
const char *(*get_domain)(void);
int server_role;
} NTLMSSP_STATE;

View File

@ -1535,6 +1535,100 @@ void rfc1738_unescape(char *buf)
}
}
static const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/***************************************************************************
decode a base64 string into a DATA_BLOB - simple and slow algorithm
***************************************************************************/
DATA_BLOB base64_decode_data_blob(const char *s)
{
int bit_offset, byte_offset, idx, i, n;
DATA_BLOB decoded = data_blob(s, strlen(s)+1);
unsigned char *d = decoded.data;
char *p;
n=i=0;
while (*s && (p=strchr_m(b64,*s))) {
idx = (int)(p - b64);
byte_offset = (i*6)/8;
bit_offset = (i*6)%8;
d[byte_offset] &= ~((1<<(8-bit_offset))-1);
if (bit_offset < 3) {
d[byte_offset] |= (idx << (2-bit_offset));
n = byte_offset+1;
} else {
d[byte_offset] |= (idx >> (bit_offset-2));
d[byte_offset+1] = 0;
d[byte_offset+1] |= (idx << (8-(bit_offset-2))) & 0xFF;
n = byte_offset+2;
}
s++; i++;
}
/* fix up length */
decoded.length = n;
return decoded;
}
/***************************************************************************
decode a base64 string in-place - wrapper for the above
***************************************************************************/
void base64_decode(char *s)
{
DATA_BLOB decoded = base64_decode_data_blob(s);
memcpy(s, decoded.data, decoded.length);
data_blob_free(&decoded);
/* null terminate */
s[decoded.length] = '\0';
}
/***************************************************************************
encode a base64 string into a malloc()ed string caller to free.
From SQUID: adopted from http://ftp.sunet.se/pub2/gnu/vm/base64-encode.c with adjustments
***************************************************************************/
char * base64_encode_data_blob(DATA_BLOB data)
{
int bits = 0;
int char_count = 0;
size_t out_cnt = 0;
size_t len = data.length;
size_t output_len = data.length * 2;
char *result = malloc(output_len); /* get us plenty of space */
while (len-- && out_cnt < (data.length * 2) - 5) {
int c = (unsigned char) *(data.data++);
bits += c;
char_count++;
if (char_count == 3) {
result[out_cnt++] = b64[bits >> 18];
result[out_cnt++] = b64[(bits >> 12) & 0x3f];
result[out_cnt++] = b64[(bits >> 6) & 0x3f];
result[out_cnt++] = b64[bits & 0x3f];
bits = 0;
char_count = 0;
} else {
bits <<= 8;
}
}
if (char_count != 0) {
bits <<= 16 - (8 * char_count);
result[out_cnt++] = b64[bits >> 18];
result[out_cnt++] = b64[(bits >> 12) & 0x3f];
if (char_count == 1) {
result[out_cnt++] = '=';
result[out_cnt++] = '=';
} else {
result[out_cnt++] = b64[(bits >> 6) & 0x3f];
result[out_cnt++] = '=';
}
}
result[out_cnt] = '\0'; /* terminate */
return result;
}
#ifdef VALGRIND
size_t valgrind_strlen(const char *s)
{

View File

@ -465,7 +465,8 @@ static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, const char *user,
neg_flags = NTLMSSP_NEGOTIATE_UNICODE |
NTLMSSP_NEGOTIATE_128 |
NTLMSSP_NEGOTIATE_NTLM;
NTLMSSP_NEGOTIATE_NTLM |
NTLMSSP_REQUEST_TARGET;
memset(sess_key, 0, 16);
@ -476,8 +477,8 @@ static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, const char *user,
"NTLMSSP",
NTLMSSP_NEGOTIATE,
neg_flags,
workgroup, strlen(workgroup),
cli->calling.name, strlen(cli->calling.name) + 1);
workgroup,
cli->calling.name);
DEBUG(10, ("neg_flags: %0X, workgroup: %s, calling name %s\n",
neg_flags, workgroup, cli->calling.name));
/* and wrap it in a SPNEGO wrapper */

View File

@ -386,51 +386,6 @@ BOOL spnego_parse_challenge(DATA_BLOB blob,
}
/*
generate a spnego NTLMSSP challenge packet given two security blobs
The second challenge is optional
*/
BOOL spnego_gen_challenge(DATA_BLOB *blob,
DATA_BLOB *chal1, DATA_BLOB *chal2)
{
ASN1_DATA data;
ZERO_STRUCT(data);
asn1_push_tag(&data,ASN1_CONTEXT(1));
asn1_push_tag(&data,ASN1_SEQUENCE(0));
asn1_push_tag(&data,ASN1_CONTEXT(0));
asn1_write_enumerated(&data,1);
asn1_pop_tag(&data);
asn1_push_tag(&data,ASN1_CONTEXT(1));
asn1_write_OID(&data, OID_NTLMSSP);
asn1_pop_tag(&data);
asn1_push_tag(&data,ASN1_CONTEXT(2));
asn1_write_OctetString(&data, chal1->data, chal1->length);
asn1_pop_tag(&data);
/* the second challenge is optional (XP doesn't send it) */
if (chal2) {
asn1_push_tag(&data,ASN1_CONTEXT(3));
asn1_write_OctetString(&data, chal2->data, chal2->length);
asn1_pop_tag(&data);
}
asn1_pop_tag(&data);
asn1_pop_tag(&data);
if (data.has_error) {
return False;
}
*blob = data_blob(data.data, data.length);
asn1_free(&data);
return True;
}
/*
generate a SPNEGO NTLMSSP auth packet. This will contain the encrypted passwords
*/
@ -485,18 +440,37 @@ BOOL spnego_parse_auth(DATA_BLOB blob, DATA_BLOB *auth)
/*
generate a minimal SPNEGO NTLMSSP response packet. Doesn't contain much.
*/
DATA_BLOB spnego_gen_auth_response(void)
DATA_BLOB spnego_gen_auth_response(DATA_BLOB *ntlmssp_reply, NTSTATUS nt_status)
{
ASN1_DATA data;
DATA_BLOB ret;
uint8 negResult;
memset(&data, 0, sizeof(data));
if (NT_STATUS_IS_OK(nt_status)) {
negResult = SPNGEO_NEG_RESULT_ACCEPT;
} else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
negResult = SPNGEO_NEG_RESULT_INCOMPLETE;
} else {
negResult = SPNGEO_NEG_RESULT_REJECT;
}
ZERO_STRUCT(data);
asn1_push_tag(&data, ASN1_CONTEXT(1));
asn1_push_tag(&data, ASN1_SEQUENCE(0));
asn1_push_tag(&data, ASN1_CONTEXT(0));
asn1_write_enumerated(&data, 0);
asn1_write_enumerated(&data, negResult);
asn1_pop_tag(&data);
if (negResult == SPNGEO_NEG_RESULT_INCOMPLETE) {
asn1_push_tag(&data,ASN1_CONTEXT(1));
asn1_write_OID(&data, OID_NTLMSSP);
asn1_pop_tag(&data);
asn1_push_tag(&data,ASN1_CONTEXT(2));
asn1_write_OctetString(&data, ntlmssp_reply->data, ntlmssp_reply->length);
asn1_pop_tag(&data);
}
asn1_pop_tag(&data);
asn1_pop_tag(&data);
@ -514,8 +488,9 @@ DATA_BLOB spnego_gen_auth_response(void)
format specifiers are:
U = unicode string (input is unix string)
a = address (1 byte type, 1 byte length, unicode string, all inline)
A = ASCII string (pointer + length) Actually same as B
a = address (input is BOOL unicode, char *unix_string)
(1 byte type, 1 byte length, unicode/ASCII string, all inline)
A = ASCII string (input is unix string)
B = data blob (pointer + length)
b = data blob in header (pointer + length)
D
@ -531,6 +506,7 @@ BOOL msrpc_gen(DATA_BLOB *blob,
uint8 *b;
int head_size=0, data_size=0;
int head_ofs, data_ofs;
BOOL unicode;
/* first scan the format to work out the header and body size */
va_start(ap, format);
@ -541,12 +517,21 @@ BOOL msrpc_gen(DATA_BLOB *blob,
head_size += 8;
data_size += str_charnum(s) * 2;
break;
case 'A':
s = va_arg(ap, char *);
head_size += 8;
data_size += str_ascii_charnum(s);
break;
case 'a':
unicode = va_arg(ap, BOOL);
n = va_arg(ap, int);
s = va_arg(ap, char *);
data_size += (str_charnum(s) * 2) + 4;
if (unicode) {
data_size += (str_charnum(s) * 2) + 4;
} else {
data_size += (str_ascii_charnum(s)) + 4;
}
break;
case 'A':
case 'B':
b = va_arg(ap, uint8 *);
head_size += 8;
@ -586,20 +571,39 @@ BOOL msrpc_gen(DATA_BLOB *blob,
push_string(NULL, blob->data+data_ofs, s, n*2, STR_UNICODE|STR_NOALIGN);
data_ofs += n*2;
break;
case 'A':
s = va_arg(ap, char *);
n = str_ascii_charnum(s);
SSVAL(blob->data, head_ofs, n); head_ofs += 2;
SSVAL(blob->data, head_ofs, n); head_ofs += 2;
SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4;
push_string(NULL, blob->data+data_ofs, s, n, STR_ASCII|STR_NOALIGN);
data_ofs += n;
break;
case 'a':
unicode = va_arg(ap, BOOL);
n = va_arg(ap, int);
SSVAL(blob->data, data_ofs, n); data_ofs += 2;
s = va_arg(ap, char *);
n = str_charnum(s);
SSVAL(blob->data, data_ofs, n*2); data_ofs += 2;
if (0 < n) {
push_string(NULL, blob->data+data_ofs, s, n*2,
STR_UNICODE|STR_NOALIGN);
if (unicode) {
n = str_charnum(s);
SSVAL(blob->data, data_ofs, n*2); data_ofs += 2;
if (0 < n) {
push_string(NULL, blob->data+data_ofs, s, n*2,
STR_UNICODE|STR_NOALIGN);
}
data_ofs += n*2;
} else {
n = str_ascii_charnum(s);
SSVAL(blob->data, data_ofs, n); data_ofs += 2;
if (0 < n) {
push_string(NULL, blob->data+data_ofs, s, n,
STR_ASCII|STR_NOALIGN);
}
data_ofs += n;
}
data_ofs += n*2;
break;
case 'A':
case 'B':
b = va_arg(ap, uint8 *);
n = va_arg(ap, int);
@ -714,7 +718,7 @@ BOOL msrpc_parse(DATA_BLOB *blob,
break;
case 'C':
s = va_arg(ap, char *);
head_ofs += pull_string(NULL, p, blob->data+head_ofs, -1,
head_ofs += pull_string(NULL, p, blob->data+head_ofs, sizeof(p),
blob->length - head_ofs,
STR_ASCII|STR_TERMINATE);
if (strcmp(s, p) != 0) {

View File

@ -272,8 +272,8 @@ reporting %s domain %s 0x%x ntversion=%x lm_nt token=%x lm_20 token=%x\n",
pull_ucs2_fstring(asccomp, unicomp);
DEBUG(3,("process_logon_packet: SAMLOGON user %s\n", ascuser));
fstrcpy(reply_name,"\\\\"); /* Here it wants \\LOGONSERVER. */
fstrcpy(reply_name+2,my_name);
fstrcpy(reply_name, "\\\\"); /* Here it wants \\LOGONSERVER. */
fstrcat(reply_name, my_name);
DEBUG(3,("process_logon_packet: SAMLOGON request from %s(%s) for %s, returning logon svr %s domain %s code %x token=%x\n",
asccomp,inet_ntoa(p->ip), ascuser, reply_name, lp_workgroup(),

View File

@ -264,6 +264,7 @@ static struct dispatch_table dispatch_table[] = {
{ WINBINDD_INFO, winbindd_info, "INFO" },
{ WINBINDD_INTERFACE_VERSION, winbindd_interface_version, "INTERFACE_VERSION" },
{ WINBINDD_DOMAIN_NAME, winbindd_domain_name, "DOMAIN_NAME" },
{ WINBINDD_NETBIOS_NAME, winbindd_netbios_name, "NETBIOS_NAME" },
/* WINS functions */

View File

@ -221,3 +221,15 @@ enum winbindd_result winbindd_domain_name(struct winbindd_cli_state *state)
return WINBINDD_OK;
}
/* What's my name again? */
enum winbindd_result winbindd_netbios_name(struct winbindd_cli_state *state)
{
DEBUG(3, ("[%5d]: request netbios name\n", state->pid));
fstrcpy(state->response.data.netbios_name, global_myname());
return WINBINDD_OK;
}

View File

@ -36,7 +36,7 @@
/* Update this when you change the interface. */
#define WINBIND_INTERFACE_VERSION 6
#define WINBIND_INTERFACE_VERSION 7
/* Socket commands */
@ -102,6 +102,7 @@ enum winbindd_cmd {
/* this is like GETGRENT but gives an empty group list */
WINBINDD_GETGRLST,
WINBINDD_NETBIOS_NAME, /* The netbios name of the server */
/* Placeholder for end of cmd list */
WINBINDD_NUM_CMDS
@ -221,6 +222,7 @@ struct winbindd_response {
fstring samba_version;
} info;
fstring domain_name;
fstring netbios_name;
struct auth_reply {
uint32 nt_status;

View File

@ -23,7 +23,8 @@
#include "includes.h"
uint32 global_client_caps = 0;
static struct auth_context *ntlmssp_auth_context = NULL;
static struct auth_ntlmssp_state *global_ntlmssp_state;
/*
on a logon error possibly map the error to success if "map to guest"
@ -67,6 +68,37 @@ static void add_signature(char *outbuf)
set_message_end(outbuf,p);
}
/****************************************************************************
send a security blob via a session setup reply
****************************************************************************/
static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
DATA_BLOB blob, NTSTATUS nt_status)
{
char *p;
set_message(outbuf,4,0,True);
/* we set NT_STATUS_MORE_PROCESSING_REQUIRED to tell the other end
that we aren't finished yet */
nt_status = nt_status_squash(nt_status);
SIVAL(outbuf, smb_rcls, NT_STATUS_V(nt_status));
SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
SSVAL(outbuf, smb_vwv3, blob.length);
p = smb_buf(outbuf);
/* should we cap this? */
memcpy(p, blob.data, blob.length);
p += blob.length;
p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
p += srvstr_push(outbuf, p, "Samba", -1, STR_TERMINATE);
p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
set_message_end(outbuf,p);
return send_smb(smbd_server_fd(),outbuf);
}
/****************************************************************************
Do a 'guest' logon, getting back the
****************************************************************************/
@ -209,30 +241,54 @@ static int reply_spnego_kerberos(connection_struct *conn,
/****************************************************************************
send a security blob via a session setup reply
****************************************************************************/
static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
DATA_BLOB blob, uint32 errcode)
send a session setup reply, wrapped in SPNEGO.
get vuid and check first.
end the NTLMSSP exchange context if we are OK/complete fail
***************************************************************************/
static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *outbuf,
AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status)
{
char *p;
BOOL ret;
DATA_BLOB response;
struct auth_serversupplied_info *server_info;
server_info = (*auth_ntlmssp_state)->server_info;
set_message(outbuf,4,0,True);
if (!NT_STATUS_IS_OK(nt_status)) {
nt_status = do_map_to_guest(nt_status,
&server_info,
(*auth_ntlmssp_state)->ntlmssp_state->user,
(*auth_ntlmssp_state)->ntlmssp_state->domain);
}
/* we set NT_STATUS_MORE_PROCESSING_REQUIRED to tell the other end
that we aren't finished yet */
if (NT_STATUS_IS_OK(nt_status)) {
int sess_vuid;
sess_vuid = register_vuid(server_info, (*auth_ntlmssp_state)->ntlmssp_state->user /* check this for weird */);
if (sess_vuid == -1) {
nt_status = NT_STATUS_LOGON_FAILURE;
} else {
set_message(outbuf,4,0,True);
SSVAL(outbuf, smb_vwv3, 0);
if ((*auth_ntlmssp_state)->server_info->guest) {
SSVAL(outbuf,smb_vwv2,1);
}
SSVAL(outbuf,smb_uid,sess_vuid);
}
}
SIVAL(outbuf, smb_rcls, errcode);
SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
SSVAL(outbuf, smb_vwv3, blob.length);
p = smb_buf(outbuf);
memcpy(p, blob.data, blob.length);
p += blob.length;
p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
p += srvstr_push(outbuf, p, "Samba", -1, STR_TERMINATE);
p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
set_message_end(outbuf,p);
return send_smb(smbd_server_fd(),outbuf);
response = spnego_gen_auth_response(ntlmssp_blob, nt_status);
ret = reply_sesssetup_blob(conn, outbuf, response, nt_status);
data_blob_free(&response);
if (!ret || !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
auth_ntlmssp_end(&global_ntlmssp_state);
}
return ret;
}
/****************************************************************************
@ -247,12 +303,9 @@ static int reply_spnego_negotiate(connection_struct *conn,
char *OIDs[ASN1_MAX_OIDS];
DATA_BLOB secblob;
int i;
uint32 ntlmssp_command, neg_flags, chal_flags;
DATA_BLOB chal, spnego_chal;
const uint8 *cryptkey;
DATA_BLOB chal;
BOOL got_kerberos = False;
NTSTATUS nt_status;
char *cliname=NULL, *domname=NULL;
/* parse out the OIDs and the first sec blob */
if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
@ -278,95 +331,26 @@ static int reply_spnego_negotiate(connection_struct *conn,
}
#endif
/* parse the NTLMSSP packet */
#if 0
file_save("secblob.dat", secblob.data, secblob.length);
#endif
if (!msrpc_parse(&secblob, "CddAA",
"NTLMSSP",
&ntlmssp_command,
&neg_flags,
&cliname,
&domname)) {
return ERROR_NT(NT_STATUS_LOGON_FAILURE);
}
data_blob_free(&secblob);
if (ntlmssp_command != NTLMSSP_NEGOTIATE) {
return ERROR_NT(NT_STATUS_LOGON_FAILURE);
if (global_ntlmssp_state) {
auth_ntlmssp_end(&global_ntlmssp_state);
}
debug_ntlmssp_flags(neg_flags);
if (ntlmssp_auth_context) {
(ntlmssp_auth_context->free)(&ntlmssp_auth_context);
}
if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&ntlmssp_auth_context))) {
nt_status = auth_ntlmssp_start(&global_ntlmssp_state);
if (!NT_STATUS_IS_OK(nt_status)) {
return ERROR_NT(nt_status);
}
cryptkey = ntlmssp_auth_context->get_ntlm_challenge(ntlmssp_auth_context);
nt_status = auth_ntlmssp_update(global_ntlmssp_state,
secblob, &chal);
/* Give them the challenge. For now, ignore neg_flags and just
return the flags we want. Obviously this is not correct */
chal_flags = NTLMSSP_NEGOTIATE_UNICODE |
NTLMSSP_NEGOTIATE_128 |
NTLMSSP_NEGOTIATE_NTLM |
NTLMSSP_CHAL_TARGET_INFO;
{
DATA_BLOB domain_blob, struct_blob;
fstring dnsname, dnsdomname;
data_blob_free(&secblob);
reply_spnego_ntlmssp(conn, outbuf, &global_ntlmssp_state,
&chal, nt_status);
msrpc_gen(&domain_blob,
"U",
lp_workgroup());
fstrcpy(dnsdomname, (SEC_ADS == lp_security())?lp_realm():"");
strlower(dnsdomname);
fstrcpy(dnsname, global_myname());
fstrcat(dnsname, ".");
fstrcat(dnsname, dnsdomname);
strlower(dnsname);
msrpc_gen(&struct_blob, "aaaaa",
2, lp_workgroup(),
1, global_myname(),
4, dnsdomname,
3, dnsname,
0, "");
msrpc_gen(&chal, "CdUdbddB",
"NTLMSSP",
NTLMSSP_CHALLENGE,
lp_workgroup(),
chal_flags,
cryptkey, 8,
0, 0,
struct_blob.data, struct_blob.length);
data_blob_free(&domain_blob);
data_blob_free(&struct_blob);
}
if (!spnego_gen_challenge(&spnego_chal, &chal, &chal)) {
DEBUG(3,("Failed to generate challenge\n"));
data_blob_free(&chal);
return ERROR_NT(NT_STATUS_LOGON_FAILURE);
}
/* now tell the client to send the auth packet */
reply_sesssetup_blob(conn, outbuf, spnego_chal, NT_STATUS_V(NT_STATUS_MORE_PROCESSING_REQUIRED));
data_blob_free(&chal);
data_blob_free(&spnego_chal);
/* and tell smbd that we have already replied to this packet */
/* already replied */
return -1;
}
@ -378,23 +362,8 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
int length, int bufsize,
DATA_BLOB blob1)
{
DATA_BLOB auth, response;
char *workgroup = NULL, *user = NULL, *machine = NULL;
DATA_BLOB lmhash, nthash, sess_key;
DATA_BLOB plaintext_password = data_blob(NULL, 0);
uint32 ntlmssp_command, neg_flags;
DATA_BLOB auth, auth_reply;
NTSTATUS nt_status;
int sess_vuid;
BOOL as_guest;
uint32 auth_flags = AUTH_FLAG_NONE;
auth_usersupplied_info *user_info = NULL;
auth_serversupplied_info *server_info = NULL;
/* we must have setup the auth context by now */
if (!ntlmssp_auth_context) {
DEBUG(2,("ntlmssp_auth_context is NULL in reply_spnego_auth\n"));
return ERROR_NT(NT_STATUS_LOGON_FAILURE);
}
if (!spnego_parse_auth(blob1, &auth)) {
#if 0
@ -403,157 +372,32 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
return ERROR_NT(NT_STATUS_LOGON_FAILURE);
}
/* now the NTLMSSP encoded auth hashes */
if (!msrpc_parse(&auth, "CdBBUUUBd",
"NTLMSSP",
&ntlmssp_command,
&lmhash,
&nthash,
&workgroup,
&user,
&machine,
&sess_key,
&neg_flags)) {
return ERROR_NT(NT_STATUS_LOGON_FAILURE);
}
nt_status = auth_ntlmssp_update(global_ntlmssp_state,
auth, &auth_reply);
data_blob_free(&auth);
data_blob_free(&sess_key);
DEBUG(3,("Got user=[%s] workgroup=[%s] machine=[%s] len1=%d len2=%d\n",
user, workgroup, machine, lmhash.length, nthash.length));
/* the client has given us its machine name (which we otherwise would not get on port 445).
we need to possibly reload smb.conf if smb.conf includes depend on the machine name */
set_remote_machine_name(machine);
/* setup the string used by %U */
sub_set_smb_name(user);
reload_services(True);
#if 0
file_save("nthash1.dat", nthash.data, nthash.length);
file_save("lmhash1.dat", lmhash.data, lmhash.length);
#endif
if (lmhash.length) {
auth_flags |= AUTH_FLAG_LM_RESP;
}
if (nthash.length == 24) {
auth_flags |= AUTH_FLAG_NTLM_RESP;
} else if (nthash.length > 24) {
auth_flags |= AUTH_FLAG_NTLMv2_RESP;
};
nt_status = make_user_info_map(&user_info, user, workgroup, machine,
lmhash, nthash, plaintext_password,
auth_flags, True);
/* it looks a bit weird, but this function returns int type... */
if (!NT_STATUS_IS_OK(nt_status)) {
return ERROR_NT(NT_STATUS_NO_MEMORY);
}
nt_status = ntlmssp_auth_context->check_ntlm_password(ntlmssp_auth_context, user_info, &server_info);
if (!NT_STATUS_IS_OK(nt_status)) {
nt_status = do_map_to_guest(nt_status, &server_info, user, workgroup);
}
SAFE_FREE(workgroup);
SAFE_FREE(machine);
(ntlmssp_auth_context->free)(&ntlmssp_auth_context);
free_user_info(&user_info);
data_blob_free(&lmhash);
data_blob_free(&nthash);
if (!NT_STATUS_IS_OK(nt_status)) {
SAFE_FREE(user);
return ERROR_NT(nt_status_squash(nt_status));
}
as_guest = server_info->guest;
sess_vuid = register_vuid(server_info, user);
free_server_info(&server_info);
SAFE_FREE(user);
if (sess_vuid == -1) {
return ERROR_NT(NT_STATUS_LOGON_FAILURE);
}
set_message(outbuf,4,0,True);
SSVAL(outbuf, smb_vwv3, 0);
if (as_guest) {
SSVAL(outbuf,smb_vwv2,1);
}
add_signature(outbuf);
SSVAL(outbuf,smb_uid,sess_vuid);
SSVAL(inbuf,smb_uid,sess_vuid);
response = spnego_gen_auth_response();
reply_sesssetup_blob(conn, outbuf, response, 0);
reply_spnego_ntlmssp(conn, outbuf, &global_ntlmssp_state,
&auth_reply, nt_status);
data_blob_free(&auth_reply);
/* and tell smbd that we have already replied to this packet */
return -1;
}
/****************************************************************************
reply to a session setup spnego anonymous packet
****************************************************************************/
static int reply_spnego_anonymous(connection_struct *conn, char *inbuf, char *outbuf,
int length, int bufsize)
{
int sess_vuid;
auth_serversupplied_info *server_info = NULL;
NTSTATUS nt_status;
nt_status = check_guest_password(&server_info);
if (!NT_STATUS_IS_OK(nt_status)) {
return ERROR_NT(nt_status_squash(nt_status));
}
sess_vuid = register_vuid(server_info, lp_guestaccount());
free_server_info(&server_info);
if (sess_vuid == -1) {
return ERROR_NT(NT_STATUS_LOGON_FAILURE);
}
set_message(outbuf,4,0,True);
SSVAL(outbuf, smb_vwv3, 0);
add_signature(outbuf);
SSVAL(outbuf,smb_uid,sess_vuid);
SSVAL(inbuf,smb_uid,sess_vuid);
return chain_reply(inbuf,outbuf,length,bufsize);
}
/****************************************************************************
reply to a session setup command
****************************************************************************/
static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,char *outbuf,
static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
char *outbuf,
int length,int bufsize)
{
uint8 *p;
DATA_BLOB blob1;
int ret;
size_t bufrem;
DEBUG(3,("Doing spnego session setup\n"));
@ -564,12 +408,13 @@ static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,cha
p = (uint8 *)smb_buf(inbuf);
if (SVAL(inbuf, smb_vwv7) == 0) {
/* an anonymous request */
return reply_spnego_anonymous(conn, inbuf, outbuf, length, bufsize);
/* an invalid request */
return ERROR_NT(NT_STATUS_LOGON_FAILURE);
}
bufrem = smb_bufrem(inbuf, p);
/* pull the spnego blob */
blob1 = data_blob(p, SVAL(inbuf, smb_vwv7));
blob1 = data_blob(p, MIN(bufrem, SVAL(inbuf, smb_vwv7)));
#if 0
file_save("negotiate.dat", blob1.data, blob1.length);
@ -786,6 +631,10 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
nt_status = check_guest_password(&server_info);
} else if (doencrypt) {
if (!negprot_global_auth_context) {
DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted session setup without negprot denied!\n"));
return ERROR_NT(NT_STATUS_LOGON_FAILURE);
}
nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
lm_resp, nt_resp);
if (NT_STATUS_IS_OK(nt_status)) {
@ -830,10 +679,8 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
}
/* it's ok - setup a reply */
if (Protocol < PROTOCOL_NT1) {
set_message(outbuf,3,0,True);
} else {
set_message(outbuf,3,0,True);
set_message(outbuf,3,0,True);
if (Protocol >= PROTOCOL_NT1) {
add_signature(outbuf);
/* perhaps grab OS version here?? */
}

View File

@ -291,37 +291,6 @@ static void cgi_web_auth(void)
passwd_free(&pwd);
}
/***************************************************************************
decode a base64 string in-place - simple and slow algorithm
***************************************************************************/
static void base64_decode(char *s)
{
const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int bit_offset, byte_offset, idx, i, n;
unsigned char *d = (unsigned char *)s;
char *p;
n=i=0;
while (*s && (p=strchr_m(b64,*s))) {
idx = (int)(p - b64);
byte_offset = (i*6)/8;
bit_offset = (i*6)%8;
d[byte_offset] &= ~((1<<(8-bit_offset))-1);
if (bit_offset < 3) {
d[byte_offset] |= (idx << (2-bit_offset));
n = byte_offset+1;
} else {
d[byte_offset] |= (idx >> (bit_offset-2));
d[byte_offset+1] = 0;
d[byte_offset+1] |= (idx << (8-(bit_offset-2))) & 0xFF;
n = byte_offset+2;
}
s++; i++;
}
/* null terminate */
d[n] = 0;
}
/***************************************************************************
handle a http authentication line