#include "includes.h"
-extern int DEBUGLEVEL;
extern int Protocol;
extern int max_recv;
extern fstring global_myworkgroup;
extern fstring remote_machine;
+BOOL global_encrypted_passwords_negotiated = False;
+BOOL global_spnego_negotiated = False;
+struct auth_context *negprot_global_auth_context = NULL;
+
+static void get_challange(char buff[8])
+{
+ NTSTATUS nt_status;
+ const uint8 *cryptkey;
+
+ /* We might be called more than once, muliple negprots are premitted */
+ if (negprot_global_auth_context) {
+ DEBUG(3, ("get challange: is this a secondary negprot? negprot_global_auth_context is non-NULL!\n"));
+ (negprot_global_auth_context->free)(&negprot_global_auth_context);
+ }
+
+ DEBUG(10, ("get challange: creating negprot_global_auth_context\n"));
+ if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&negprot_global_auth_context))) {
+ DEBUG(0, ("make_auth_context_subsystem returned %s", get_nt_error_msg(nt_status)));
+ smb_panic("cannot make_negprot_global_auth_context!\n");
+ }
+ DEBUG(10, ("get challange: getting challange\n"));
+ cryptkey = negprot_global_auth_context->get_ntlm_challenge(negprot_global_auth_context);
+ memcpy(buff, cryptkey, 8);
+}
/****************************************************************************
reply for the core protocol
****************************************************************************/
-static int reply_corep(char *outbuf)
+static int reply_corep(char *inbuf, char *outbuf)
{
int outsize = set_message(outbuf,1,0,True);
/****************************************************************************
reply for the coreplus protocol
****************************************************************************/
-static int reply_coreplus(char *outbuf)
+static int reply_coreplus(char *inbuf, char *outbuf)
{
int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
int outsize = set_message(outbuf,13,0,True);
/****************************************************************************
reply for the lanman 1.0 protocol
****************************************************************************/
-static int reply_lanman1(char *outbuf)
+static int reply_lanman1(char *inbuf, char *outbuf)
{
int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
int secword=0;
- BOOL doencrypt = SMBENCRYPT();
time_t t = time(NULL);
+ global_encrypted_passwords_negotiated = lp_encrypted_passwords();
+
if (lp_security()>=SEC_USER) secword |= 1;
- if (doencrypt) secword |= 2;
+ if (global_encrypted_passwords_negotiated) secword |= 2;
- set_message(outbuf,13,doencrypt?8:0,True);
+ set_message(outbuf,13,global_encrypted_passwords_negotiated?8:0,True);
SSVAL(outbuf,smb_vwv1,secword);
/* Create a token value and add it to the outgoing packet. */
- if (doencrypt)
- generate_next_challenge(smb_buf(outbuf));
+ if (global_encrypted_passwords_negotiated) {
+ get_challange(smb_buf(outbuf));
+ }
Protocol = PROTOCOL_LANMAN1;
/****************************************************************************
reply for the lanman 2.0 protocol
****************************************************************************/
-static int reply_lanman2(char *outbuf)
+static int reply_lanman2(char *inbuf, char *outbuf)
{
int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
int secword=0;
- BOOL doencrypt = SMBENCRYPT();
time_t t = time(NULL);
- struct cli_state *cli = NULL;
- char cryptkey[8];
- char crypt_len = 0;
-
- if (lp_security() == SEC_SERVER) {
- cli = server_cryptkey();
- }
-
- if (cli) {
- DEBUG(3,("using password server validation\n"));
- doencrypt = ((cli->sec_mode & 2) != 0);
- }
+ global_encrypted_passwords_negotiated = lp_encrypted_passwords();
+
if (lp_security()>=SEC_USER) secword |= 1;
- if (doencrypt) secword |= 2;
-
- if (doencrypt) {
- crypt_len = 8;
- if (!cli) {
- generate_next_challenge(cryptkey);
- } else {
- memcpy(cryptkey, cli->cryptkey, 8);
- set_challenge(cli->cryptkey);
- }
- }
+ if (global_encrypted_passwords_negotiated) secword |= 2;
- set_message(outbuf,13,crypt_len,True);
+ set_message(outbuf,13,global_encrypted_passwords_negotiated?8:0,True);
SSVAL(outbuf,smb_vwv1,secword);
SIVAL(outbuf,smb_vwv6,sys_getpid());
- if (doencrypt)
- memcpy(smb_buf(outbuf), cryptkey, 8);
+
+ /* Create a token value and add it to the outgoing packet. */
+ if (global_encrypted_passwords_negotiated) {
+ get_challange(smb_buf(outbuf));
+ }
Protocol = PROTOCOL_LANMAN2;
}
-/****************************************************************************
-reply for the nt protocol
-****************************************************************************/
-static int reply_nt1(char *outbuf)
-{
- /* dual names + lock_and_read + nt SMBs + remote API calls */
- int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ|CAP_LEVEL_II_OPLOCKS|
- (lp_nt_smb_support() ? CAP_NT_SMBS | CAP_RPC_REMOTE_APIS : 0) |
- ((lp_large_readwrite() && (SMB_OFF_T_BITS == 64)) ?
- CAP_LARGE_READX | CAP_LARGE_WRITEX | CAP_W2K_SMBS : 0) |
- (SMB_OFF_T_BITS == 64 ? CAP_LARGE_FILES : 0);
-
-
-/*
- other valid capabilities which we may support at some time...
- CAP_LARGE_READX|CAP_STATUS32|CAP_LEVEL_II_OPLOCKS;
- */
-
- int secword=0;
- BOOL doencrypt = SMBENCRYPT();
- time_t t = time(NULL);
- struct cli_state *cli = NULL;
- char cryptkey[8];
- char crypt_len = 0;
- char *p, *q;
-
- if (lp_security() == SEC_SERVER) {
- cli = server_cryptkey();
- }
-
- if (cli) {
- DEBUG(3,("using password server validation\n"));
- doencrypt = ((cli->sec_mode & 2) != 0);
- }
-
- if (doencrypt) {
- crypt_len = 8;
- if (!cli) {
- generate_next_challenge(cryptkey);
- } else {
- memcpy(cryptkey, cli->cryptkey, 8);
- set_challenge(cli->cryptkey);
- }
- }
-
- if (lp_readraw() && lp_writeraw()) {
- capabilities |= CAP_RAW_MODE;
- }
-
- /* allow for disabling unicode */
- if (lp_unicode()) {
- capabilities |= CAP_UNICODE;
- }
-
-#ifdef WITH_MSDFS
- if(lp_host_msdfs())
- capabilities |= CAP_DFS;
+/*
+ generate the spnego negprot reply blob. Return the number of bytes used
+*/
+static int negprot_spnego(char *p)
+{
+ DATA_BLOB blob;
+ extern pstring global_myname;
+ uint8 guid[16];
+ const char *OIDs_krb5[] = {OID_NTLMSSP,
+ OID_KERBEROS5,
+ OID_KERBEROS5_OLD,
+ NULL};
+ const char *OIDs_plain[] = {OID_NTLMSSP, NULL};
+ char *principal;
+ int len;
+
+ global_spnego_negotiated = True;
+
+ memset(guid, 0, 16);
+ safe_strcpy((char *)guid, global_myname, 16);
+ strlower((char *)guid);
+
+#if 0
+ /* strangely enough, NT does not sent the single OID NTLMSSP when
+ not a ADS member, it sends no OIDs at all
+
+ we can't do this until we teach our sesssion setup parser to know
+ about raw NTLMSSP (clients send no ASN.1 wrapping if we do this)
+ */
+ if (lp_security() != SEC_ADS) {
+ memcpy(p, guid, 16);
+ return 16;
+ }
#endif
+ {
+ ADS_STRUCT *ads;
+ ads = ads_init(NULL, NULL, NULL, NULL);
+
+ /* win2000 uses host$@REALM, which we will probably use eventually,
+ but for now this works */
+ asprintf(&principal, "HOST/%s@%s", guid, ads->realm);
+ blob = spnego_gen_negTokenInit(guid,
+ lp_security()==SEC_ADS ? OIDs_krb5 : OIDs_plain,
+ principal);
+ free(principal);
+ ads_destroy(&ads);
+ }
+ memcpy(p, blob.data, blob.length);
+ len = blob.length;
+ data_blob_free(&blob);
+ return len;
+}
- if (lp_security() >= SEC_USER) secword |= 1;
- if (doencrypt) secword |= 2;
-
- set_message(outbuf,17,0,True);
-
- CVAL(outbuf,smb_vwv1) = secword;
- SSVALS(outbuf,smb_vwv16+1,crypt_len);
-
- Protocol = PROTOCOL_NT1;
+
- SSVAL(outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */
- SSVAL(outbuf,smb_vwv2+1,1); /* num vcs */
- SIVAL(outbuf,smb_vwv3+1,0xffff); /* max buffer. LOTS! */
- SIVAL(outbuf,smb_vwv5+1,0x10000); /* raw size. full 64k */
- SIVAL(outbuf,smb_vwv7+1,sys_getpid()); /* session key */
- SIVAL(outbuf,smb_vwv9+1,capabilities); /* capabilities */
- put_long_date(outbuf+smb_vwv11+1,t);
- SSVALS(outbuf,smb_vwv15+1,TimeDiff(t)/60);
+/****************************************************************************
+reply for the nt protocol
+****************************************************************************/
+static int reply_nt1(char *inbuf, char *outbuf)
+{
+ /* dual names + lock_and_read + nt SMBs + remote API calls */
+ int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ|
+ CAP_LEVEL_II_OPLOCKS|CAP_STATUS32;
- p = q = smb_buf(outbuf);
- if (doencrypt) memcpy(p, cryptkey, 8);
- p += 8;
- p += srvstr_push(outbuf, p, global_myworkgroup, -1,
- STR_UNICODE|STR_CONVERT|STR_TERMINATE|STR_NOALIGN);
+ int secword=0;
+ time_t t = time(NULL);
+ char *p, *q;
+ BOOL negotiate_spnego = False;
- SSVAL(outbuf,smb_vwv17, p - q); /* length of challenge+domain strings */
- set_message_end(outbuf, p);
+ global_encrypted_passwords_negotiated = lp_encrypted_passwords();
- return (smb_len(outbuf)+4);
+ /* do spnego in user level security if the client
+ supports it and we can do encrypted passwords */
+
+ if (global_encrypted_passwords_negotiated &&
+ (lp_security() != SEC_SHARE) &&
+ lp_use_spnego() &&
+ (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
+ negotiate_spnego = True;
+ capabilities |= CAP_EXTENDED_SECURITY;
+ }
+
+ capabilities |= CAP_NT_SMBS|CAP_RPC_REMOTE_APIS;
+
+ if (lp_large_readwrite() && (SMB_OFF_T_BITS == 64)) {
+ capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_W2K_SMBS;
+ }
+
+ if (SMB_OFF_T_BITS == 64) {
+ capabilities |= CAP_LARGE_FILES;
+ }
+
+ if (lp_readraw() && lp_writeraw()) {
+ capabilities |= CAP_RAW_MODE;
+ }
+
+ /* allow for disabling unicode */
+ if (lp_unicode()) {
+ capabilities |= CAP_UNICODE;
+ }
+
+ if (lp_host_msdfs())
+ capabilities |= CAP_DFS;
+
+ if (lp_security() >= SEC_USER) secword |= 1;
+ if (global_encrypted_passwords_negotiated) secword |= 2;
+
+ set_message(outbuf,17,0,True);
+
+ CVAL(outbuf,smb_vwv1) = secword;
+
+ Protocol = PROTOCOL_NT1;
+
+ SSVAL(outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */
+ SSVAL(outbuf,smb_vwv2+1,1); /* num vcs */
+ SIVAL(outbuf,smb_vwv3+1,0xffff); /* max buffer. LOTS! */
+ SIVAL(outbuf,smb_vwv5+1,0x10000); /* raw size. full 64k */
+ SIVAL(outbuf,smb_vwv7+1,sys_getpid()); /* session key */
+ SIVAL(outbuf,smb_vwv9+1,capabilities); /* capabilities */
+ put_long_date(outbuf+smb_vwv11+1,t);
+ SSVALS(outbuf,smb_vwv15+1,TimeDiff(t)/60);
+
+ p = q = smb_buf(outbuf);
+ if (!negotiate_spnego) {
+ /* Create a token value and add it to the outgoing packet. */
+ if (global_encrypted_passwords_negotiated) {
+ get_challange(p);
+ }
+ SSVALS(outbuf,smb_vwv16+1,8);
+ p += 8;
+ p += srvstr_push(outbuf, p, global_myworkgroup, -1,
+ STR_UNICODE|STR_TERMINATE|STR_NOALIGN);
+ DEBUG(3,("not using SPNEGO\n"));
+ } else {
+ int len = negprot_spnego(p);
+
+ SSVALS(outbuf,smb_vwv16+1,len);
+ p += len;
+ DEBUG(3,("using SPNEGO\n"));
+ }
+
+ SSVAL(outbuf,smb_vwv17, p - q); /* length of challenge+domain strings */
+ set_message_end(outbuf, p);
+
+ return (smb_len(outbuf)+4);
}
/* these are the protocol lists used for auto architecture detection:
static struct {
char *proto_name;
char *short_name;
- int (*proto_reply_fn)(char *);
+ int (*proto_reply_fn)(char *, char *);
int protocol_level;
} supported_protocols[] = {
{"NT LANMAN 1.0", "NT1", reply_nt1, PROTOCOL_NT1},
/* possibly reload - change of architecture */
reload_services(True);
- /* a special case to stop password server loops */
- if (Index == 1 && strequal(remote_machine,myhostname()) &&
- (lp_security()==SEC_SERVER || lp_security()==SEC_DOMAIN))
- exit_server("Password server loop!");
-
/* Check for protocols, most desirable first */
for (protocol = 0; supported_protocols[protocol].proto_name; protocol++)
{
extern fstring remote_proto;
fstrcpy(remote_proto,supported_protocols[protocol].short_name);
reload_services(True);
- outsize = supported_protocols[protocol].proto_reply_fn(outbuf);
+ outsize = supported_protocols[protocol].proto_reply_fn(inbuf, outbuf);
DEBUG(3,("Selected protocol %s\n",supported_protocols[protocol].proto_name));
}
else {
END_PROFILE(SMBnegprot);
return(outsize);
}
+