*/
#include "includes.h"
+#include "smbd/globals.h"
-extern struct auth_context *negprot_global_auth_context;
-extern bool global_encrypted_passwords_negotiated;
-extern bool global_spnego_negotiated;
extern enum protocol_types Protocol;
-extern int max_send;
-uint32 global_client_caps = 0;
+/* For split krb5 SPNEGO blobs. */
+struct pending_auth_data {
+ struct pending_auth_data *prev, *next;
+ uint16 vuid; /* Tag for this entry. */
+ uint16 smbpid; /* Alternate tag for this entry. */
+ size_t needed_len;
+ DATA_BLOB partial_data;
+};
/*
on a logon error possibly map the error to success if "map to guest"
(lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
DEBUG(3,("No such user %s [%s] - using guest account\n",
user, domain));
- status = make_server_info_guest(server_info);
+ status = make_server_info_guest(NULL, server_info);
}
}
if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
DEBUG(3,("Registered username %s for guest access\n",
user));
- status = make_server_info_guest(server_info);
+ status = make_server_info_guest(NULL, server_info);
}
}
if (tmp == -1) return -1;
result += tmp;
- if (asprintf(&lanman, "Samba %s", SAMBA_VERSION_STRING) != -1) {
+ if (asprintf(&lanman, "Samba %s", samba_version_string()) != -1) {
tmp = message_push_string(outbuf, lanman, STR_TERMINATE);
SAFE_FREE(lanman);
}
return result;
}
-/****************************************************************************
- Start the signing engine if needed. Don't fail signing here.
-****************************************************************************/
-
-static void sessionsetup_start_signing_engine(
- const auth_serversupplied_info *server_info,
- const uint8 *inbuf)
-{
- if (!server_info->guest && !srv_signing_started()) {
- /* We need to start the signing engine
- * here but a W2K client sends the old
- * "BSRSPYL " signature instead of the
- * correct one. Subsequent packets will
- * be correct.
- */
- srv_check_sign_mac((char *)inbuf, False);
- }
-}
-
/****************************************************************************
Send a security blob via a session setup reply.
****************************************************************************/
-static void reply_sesssetup_blob(connection_struct *conn,
- struct smb_request *req,
+static void reply_sesssetup_blob(struct smb_request *req,
DATA_BLOB blob,
NTSTATUS nt_status)
{
if (!NT_STATUS_IS_OK(nt_status) &&
!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
reply_nterror(req, nt_status_squash(nt_status));
- } else {
- nt_status = nt_status_squash(nt_status);
- SIVAL(req->outbuf, smb_rcls, NT_STATUS_V(nt_status));
- SSVAL(req->outbuf, smb_vwv0, 0xFF); /* no chaining possible */
- SSVAL(req->outbuf, smb_vwv3, blob.length);
-
- if ((message_push_blob(&req->outbuf, blob) == -1)
- || (push_signature(&req->outbuf) == -1)) {
- reply_nterror(req, NT_STATUS_NO_MEMORY);
- }
+ return;
}
- show_msg((char *)req->outbuf);
- srv_send_smb(smbd_server_fd(),(char *)req->outbuf,req->encrypted);
- TALLOC_FREE(req->outbuf);
+ nt_status = nt_status_squash(nt_status);
+ SIVAL(req->outbuf, smb_rcls, NT_STATUS_V(nt_status));
+ SSVAL(req->outbuf, smb_vwv0, 0xFF); /* no chaining possible */
+ SSVAL(req->outbuf, smb_vwv3, blob.length);
+
+ if ((message_push_blob(&req->outbuf, blob) == -1)
+ || (push_signature(&req->outbuf) == -1)) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ }
}
/****************************************************************************
Reply to a session setup spnego negotiate packet for kerberos.
****************************************************************************/
-static void reply_spnego_kerberos(connection_struct *conn,
- struct smb_request *req,
+static void reply_spnego_kerberos(struct smb_request *req,
DATA_BLOB *secblob,
+ const char *mechOID,
uint16 vuid,
bool *p_invalidate_vuid)
{
fstring user;
int sess_vuid = req->vuid;
NTSTATUS ret = NT_STATUS_OK;
- PAC_DATA *pac_data;
+ struct PAC_DATA *pac_data = NULL;
DATA_BLOB ap_rep, ap_rep_wrapped, response;
auth_serversupplied_info *server_info = NULL;
DATA_BLOB session_key = data_blob_null;
fstring real_username;
bool map_domainuser_to_guest = False;
bool username_was_mapped;
- PAC_LOGON_INFO *logon_info = NULL;
+ struct PAC_LOGON_INFO *logon_info = NULL;
+ struct smbd_server_connection *sconn = smbd_server_conn;
ZERO_STRUCT(ticket);
- ZERO_STRUCT(pac_data);
ZERO_STRUCT(ap_rep);
ZERO_STRUCT(ap_rep_wrapped);
ZERO_STRUCT(response);
DEBUG(3,("Doesn't look like a valid principal\n"));
data_blob_free(&ap_rep);
data_blob_free(&session_key);
- SAFE_FREE(client);
talloc_destroy(mem_ctx);
reply_nterror(req,nt_status_squash(NT_STATUS_LOGON_FAILURE));
return;
if (!lp_allow_trusted_domains()) {
data_blob_free(&ap_rep);
data_blob_free(&session_key);
- SAFE_FREE(client);
talloc_destroy(mem_ctx);
reply_nterror(req, nt_status_squash(
NT_STATUS_LOGON_FAILURE));
domain = p+1;
- if (logon_info && logon_info->info3.hdr_logon_dom.uni_str_len) {
- unistr2_to_ascii(netbios_domain_name,
- &logon_info->info3.uni_logon_dom,
- sizeof(netbios_domain_name));
+ if (logon_info && logon_info->info3.base.domain.string) {
+ fstrcpy(netbios_domain_name,
+ logon_info->info3.base.domain.string);
domain = netbios_domain_name;
DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain));
name. And even w2k3 does use ntlmssp if you for example
connect to an ip address. */
- struct winbindd_request wb_request;
- struct winbindd_response wb_response;
- NSS_STATUS wb_result;
-
- ZERO_STRUCT(wb_request);
- ZERO_STRUCT(wb_response);
+ wbcErr wbc_status;
+ struct wbcDomainInfo *info = NULL;
DEBUG(10, ("Mapping [%s] to short name\n", domain));
- fstrcpy(wb_request.domain_name, domain);
+ wbc_status = wbcDomainInfo(domain, &info);
- wb_result = winbindd_request_response(WINBINDD_DOMAIN_INFO,
- &wb_request, &wb_response);
-
- if (wb_result == NSS_STATUS_SUCCESS) {
+ if (WBC_ERROR_IS_OK(wbc_status)) {
fstrcpy(netbios_domain_name,
- wb_response.data.domain_info.name);
- domain = netbios_domain_name;
+ info->short_name);
+ wbcFreeMemory(info);
+ domain = netbios_domain_name;
DEBUG(10, ("Mapped to [%s] (using Winbind)\n", domain));
} else {
- DEBUG(3, ("Could not find short name -- winbind "
- "not running?\n"));
+ DEBUG(3, ("Could not find short name: %s\n",
+ wbcErrorString(wbc_status)));
}
}
/* lookup the passwd struct, create a new user if necessary */
- username_was_mapped = map_username( user );
+ username_was_mapped = map_username(sconn, user);
pw = smb_getpwnam( mem_ctx, user, real_username, True );
if (pw) {
/* if a real user check pam account restrictions */
/* only really perfomed if "obey pam restriction" is true */
- /* do this before an eventual mappign to guest occurs */
+ /* do this before an eventual mapping to guest occurs */
ret = smb_pam_accountcheck(pw->pw_name);
if ( !NT_STATUS_IS_OK(ret)) {
DEBUG(1,("PAM account restriction "
if ( !pw ) {
DEBUG(1,("Username %s is invalid on this system\n",
user));
- SAFE_FREE(client);
data_blob_free(&ap_rep);
data_blob_free(&session_key);
TALLOC_FREE(mem_ctx);
reload_services(True);
if ( map_domainuser_to_guest ) {
- make_server_info_guest(&server_info);
+ make_server_info_guest(NULL, &server_info);
} else if (logon_info) {
/* pass the unmapped username here since map_username()
will be called again from inside make_server_info_info3() */
if ( !NT_STATUS_IS_OK(ret) ) {
DEBUG(1,("make_server_info_info3 failed: %s!\n",
nt_errstr(ret)));
- SAFE_FREE(client);
data_blob_free(&ap_rep);
data_blob_free(&session_key);
TALLOC_FREE(mem_ctx);
if ( !NT_STATUS_IS_OK(ret) ) {
DEBUG(1,("make_server_info_pw failed: %s!\n",
nt_errstr(ret)));
- SAFE_FREE(client);
data_blob_free(&ap_rep);
data_blob_free(&session_key);
TALLOC_FREE(mem_ctx);
}
}
- server_info->was_mapped |= username_was_mapped;
+ server_info->nss_token |= username_was_mapped;
/* we need to build the token for the user. make_server_info_guest()
already does this */
if ( !server_info->ptok ) {
ret = create_local_token( server_info );
if ( !NT_STATUS_IS_OK(ret) ) {
- SAFE_FREE(client);
+ DEBUG(10,("failed to create local token: %s\n",
+ nt_errstr(ret)));
data_blob_free(&ap_rep);
data_blob_free(&session_key);
TALLOC_FREE( mem_ctx );
}
}
+ if (!is_partial_auth_vuid(sconn, sess_vuid)) {
+ sess_vuid = register_initial_vuid(sconn);
+ }
+
+ data_blob_free(&server_info->user_session_key);
+ server_info->user_session_key = session_key;
+ session_key = data_blob_null;
+
/* register_existing_vuid keeps the server info */
/* register_existing_vuid takes ownership of session_key on success,
* no need to free after this on success. A better interface would copy
* it.... */
- if (!is_partial_auth_vuid(sess_vuid)) {
- sess_vuid = register_initial_vuid();
- }
- sess_vuid = register_existing_vuid(sess_vuid,
+ sess_vuid = register_existing_vuid(sconn,
+ sess_vuid,
server_info,
- session_key,
nullblob,
client);
- SAFE_FREE(client);
-
reply_outbuf(req, 4, 0);
SSVAL(req->outbuf,smb_uid,sess_vuid);
if (sess_vuid == UID_FIELD_INVALID ) {
ret = NT_STATUS_LOGON_FAILURE;
- data_blob_free(&session_key);
} else {
/* current_user_info is changed on new vuid */
reload_services( True );
SSVAL(req->outbuf, smb_uid, sess_vuid);
- sessionsetup_start_signing_engine(server_info, req->inbuf);
/* Successful logon. Keep this vuid. */
*p_invalidate_vuid = False;
}
ap_rep_wrapped = data_blob_null;
}
response = spnego_gen_auth_response(&ap_rep_wrapped, ret,
- OID_KERBEROS5_OLD);
- reply_sesssetup_blob(conn, req, response, ret);
+ mechOID);
+ reply_sesssetup_blob(req, response, ret);
data_blob_free(&ap_rep);
data_blob_free(&ap_rep_wrapped);
leg of the NTLM auth steps.
***************************************************************************/
-static void reply_spnego_ntlmssp(connection_struct *conn,
- struct smb_request *req,
+static void reply_spnego_ntlmssp(struct smb_request *req,
uint16 vuid,
AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
+ const char *OID,
bool wrap)
{
DATA_BLOB response;
struct auth_serversupplied_info *server_info = NULL;
+ struct smbd_server_connection *sconn = smbd_server_conn;
if (NT_STATUS_IS_OK(nt_status)) {
server_info = (*auth_ntlmssp_state)->server_info;
if (NT_STATUS_IS_OK(nt_status)) {
DATA_BLOB nullblob = data_blob_null;
- DATA_BLOB session_key =
- data_blob(
- (*auth_ntlmssp_state)->ntlmssp_state->session_key.data,
- (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
- if (!is_partial_auth_vuid(vuid)) {
- data_blob_free(&session_key);
+ if (!is_partial_auth_vuid(sconn, vuid)) {
nt_status = NT_STATUS_LOGON_FAILURE;
goto out;
}
+
+ data_blob_free(&server_info->user_session_key);
+ server_info->user_session_key =
+ data_blob_talloc(
+ server_info,
+ (*auth_ntlmssp_state)->ntlmssp_state->session_key.data,
+ (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
+
/* register_existing_vuid keeps the server info */
- if (register_existing_vuid(vuid,
- server_info,
- session_key, nullblob,
+ if (register_existing_vuid(sconn, vuid,
+ server_info, nullblob,
(*auth_ntlmssp_state)->ntlmssp_state->user) !=
vuid) {
- data_blob_free(&session_key);
nt_status = NT_STATUS_LOGON_FAILURE;
goto out;
}
if (server_info->guest) {
SSVAL(req->outbuf,smb_vwv2,1);
}
-
- sessionsetup_start_signing_engine(server_info,
- (uint8 *)req->inbuf);
}
out:
if (wrap) {
response = spnego_gen_auth_response(ntlmssp_blob,
- nt_status, OID_NTLMSSP);
+ nt_status, OID);
} else {
response = *ntlmssp_blob;
}
- reply_sesssetup_blob(conn, req, response, nt_status);
+ reply_sesssetup_blob(req, response, nt_status);
if (wrap) {
data_blob_free(&response);
}
auth_ntlmssp_end(auth_ntlmssp_state);
if (!NT_STATUS_IS_OK(nt_status)) {
/* Kill the intermediate vuid */
- invalidate_vuid(vuid);
+ invalidate_vuid(sconn, vuid);
}
}
}
Is this a krb5 mechanism ?
****************************************************************************/
-NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in, DATA_BLOB *pblob_out,
- bool *p_is_krb5)
+NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in,
+ DATA_BLOB *pblob_out,
+ char **kerb_mechOID)
{
char *OIDs[ASN1_MAX_OIDS];
int i;
+ NTSTATUS ret = NT_STATUS_OK;
- *p_is_krb5 = False;
+ *kerb_mechOID = NULL;
/* parse out the OIDs and the first sec blob */
if (!parse_negTokenTarg(blob_in, OIDs, pblob_out)) {
#ifdef HAVE_KRB5
if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
- *p_is_krb5 = True;
+ *kerb_mechOID = SMB_STRDUP(OIDs[0]);
+ if (*kerb_mechOID == NULL) {
+ ret = NT_STATUS_NO_MEMORY;
+ }
}
#endif
for (i=0;OIDs[i];i++) {
DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i]));
- free(OIDs[i]);
+ talloc_free(OIDs[i]);
}
- return NT_STATUS_OK;
+ return ret;
+}
+
+/****************************************************************************
+ Fall back from krb5 to NTLMSSP.
+****************************************************************************/
+
+static void reply_spnego_downgrade_to_ntlmssp(struct smb_request *req,
+ uint16 vuid)
+{
+ DATA_BLOB response;
+
+ reply_outbuf(req, 4, 0);
+ SSVAL(req->outbuf,smb_uid,vuid);
+
+ DEBUG(3,("reply_spnego_downgrade_to_ntlmssp: Got krb5 ticket in SPNEGO "
+ "but set to downgrade to NTLMSSP\n"));
+
+ response = spnego_gen_auth_response(NULL,
+ NT_STATUS_MORE_PROCESSING_REQUIRED,
+ OID_NTLMSSP);
+ reply_sesssetup_blob(req, response, NT_STATUS_MORE_PROCESSING_REQUIRED);
+ data_blob_free(&response);
}
/****************************************************************************
Reply to a session setup spnego negotiate packet.
****************************************************************************/
-static void reply_spnego_negotiate(connection_struct *conn,
- struct smb_request *req,
+static void reply_spnego_negotiate(struct smb_request *req,
uint16 vuid,
DATA_BLOB blob1,
AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
{
DATA_BLOB secblob;
DATA_BLOB chal;
- bool got_kerberos_mechanism = False;
+ char *kerb_mech = NULL;
NTSTATUS status;
+ struct smbd_server_connection *sconn = smbd_server_conn;
- status = parse_spnego_mechanisms(blob1, &secblob,
- &got_kerberos_mechanism);
+ status = parse_spnego_mechanisms(blob1, &secblob, &kerb_mech);
if (!NT_STATUS_IS_OK(status)) {
/* Kill the intermediate vuid */
- invalidate_vuid(vuid);
+ invalidate_vuid(sconn, vuid);
reply_nterror(req, nt_status_squash(status));
return;
}
(unsigned long)secblob.length));
#ifdef HAVE_KRB5
- if ( got_kerberos_mechanism && ((lp_security()==SEC_ADS) ||
- lp_use_kerberos_keytab()) ) {
+ if (kerb_mech && ((lp_security()==SEC_ADS) ||
+ USE_KERBEROS_KEYTAB) ) {
bool destroy_vuid = True;
- reply_spnego_kerberos(conn, req, &secblob, vuid,
- &destroy_vuid);
+ reply_spnego_kerberos(req, &secblob, kerb_mech,
+ vuid, &destroy_vuid);
data_blob_free(&secblob);
if (destroy_vuid) {
/* Kill the intermediate vuid */
- invalidate_vuid(vuid);
+ invalidate_vuid(sconn, vuid);
}
+ SAFE_FREE(kerb_mech);
return;
}
#endif
auth_ntlmssp_end(auth_ntlmssp_state);
}
+ if (kerb_mech) {
+ data_blob_free(&secblob);
+ /* The mechtoken is a krb5 ticket, but
+ * we need to fall back to NTLM. */
+ reply_spnego_downgrade_to_ntlmssp(req, vuid);
+ SAFE_FREE(kerb_mech);
+ return;
+ }
+
status = auth_ntlmssp_start(auth_ntlmssp_state);
if (!NT_STATUS_IS_OK(status)) {
/* Kill the intermediate vuid */
- invalidate_vuid(vuid);
+ invalidate_vuid(sconn, vuid);
reply_nterror(req, nt_status_squash(status));
return;
}
data_blob_free(&secblob);
- reply_spnego_ntlmssp(conn, req, vuid, auth_ntlmssp_state,
- &chal, status, True);
+ reply_spnego_ntlmssp(req, vuid, auth_ntlmssp_state,
+ &chal, status, OID_NTLMSSP, true);
data_blob_free(&chal);
Reply to a session setup spnego auth packet.
****************************************************************************/
-static void reply_spnego_auth(connection_struct *conn,
- struct smb_request *req,
+static void reply_spnego_auth(struct smb_request *req,
uint16 vuid,
DATA_BLOB blob1,
AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
DATA_BLOB auth = data_blob_null;
DATA_BLOB auth_reply = data_blob_null;
DATA_BLOB secblob = data_blob_null;
- NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
+ NTSTATUS status = NT_STATUS_LOGON_FAILURE;
+ struct smbd_server_connection *sconn = smbd_server_conn;
if (!spnego_parse_auth(blob1, &auth)) {
#if 0
file_save("auth.dat", blob1.data, blob1.length);
#endif
/* Kill the intermediate vuid */
- invalidate_vuid(vuid);
+ invalidate_vuid(sconn, vuid);
reply_nterror(req, nt_status_squash(
- NT_STATUS_INVALID_PARAMETER));
+ NT_STATUS_LOGON_FAILURE));
return;
}
if (auth.data[0] == ASN1_APPLICATION(0)) {
/* Might be a second negTokenTarg packet */
+ char *kerb_mech = NULL;
+
+ status = parse_spnego_mechanisms(auth, &secblob, &kerb_mech);
- bool got_krb5_mechanism = False;
- status = parse_spnego_mechanisms(auth, &secblob,
- &got_krb5_mechanism);
- if (NT_STATUS_IS_OK(status)) {
- DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n",
- (unsigned long)secblob.length));
+ if (!NT_STATUS_IS_OK(status)) {
+ /* Kill the intermediate vuid */
+ invalidate_vuid(sconn, vuid);
+ reply_nterror(req, nt_status_squash(status));
+ return;
+ }
+
+ DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n",
+ (unsigned long)secblob.length));
#ifdef HAVE_KRB5
- if ( got_krb5_mechanism && ((lp_security()==SEC_ADS) ||
- lp_use_kerberos_keytab()) ) {
- bool destroy_vuid = True;
- reply_spnego_kerberos(conn, req, &secblob,
- vuid, &destroy_vuid);
- data_blob_free(&secblob);
- data_blob_free(&auth);
- if (destroy_vuid) {
- /* Kill the intermediate vuid */
- invalidate_vuid(vuid);
- }
- return;
+ if (kerb_mech && ((lp_security()==SEC_ADS) ||
+ USE_KERBEROS_KEYTAB)) {
+ bool destroy_vuid = True;
+ reply_spnego_kerberos(req, &secblob, kerb_mech,
+ vuid, &destroy_vuid);
+ data_blob_free(&secblob);
+ data_blob_free(&auth);
+ if (destroy_vuid) {
+ /* Kill the intermediate vuid */
+ invalidate_vuid(sconn, vuid);
}
+ SAFE_FREE(kerb_mech);
+ return;
+ }
#endif
+ /* Can't blunder into NTLMSSP auth if we have
+ * a krb5 ticket. */
+
+ if (kerb_mech) {
+ /* Kill the intermediate vuid */
+ invalidate_vuid(sconn, vuid);
+ DEBUG(3,("reply_spnego_auth: network "
+ "misconfiguration, client sent us a "
+ "krb5 ticket and kerberos security "
+ "not enabled\n"));
+ reply_nterror(req, nt_status_squash(
+ NT_STATUS_LOGON_FAILURE));
+ SAFE_FREE(kerb_mech);
}
}
data_blob_free(&secblob);
if (!*auth_ntlmssp_state) {
- /* Kill the intermediate vuid */
- invalidate_vuid(vuid);
-
- /* auth before negotiatiate? */
- reply_nterror(req, nt_status_squash(
- NT_STATUS_INVALID_PARAMETER));
- return;
+ status = auth_ntlmssp_start(auth_ntlmssp_state);
+ if (!NT_STATUS_IS_OK(status)) {
+ /* Kill the intermediate vuid */
+ invalidate_vuid(sconn, vuid);
+ reply_nterror(req, nt_status_squash(status));
+ return;
+ }
}
status = auth_ntlmssp_update(*auth_ntlmssp_state,
data_blob_free(&auth);
- reply_spnego_ntlmssp(conn, req, vuid,
+ /* Don't send the mechid as we've already sent this (RFC4178). */
+
+ reply_spnego_ntlmssp(req, vuid,
auth_ntlmssp_state,
- &auth_reply, status, True);
+ &auth_reply, status, NULL, true);
data_blob_free(&auth_reply);
return;
}
-/****************************************************************************
- List to store partial SPNEGO auth fragments.
-****************************************************************************/
-
-static struct pending_auth_data *pd_list;
-
/****************************************************************************
Delete an entry on the list.
****************************************************************************/
-static void delete_partial_auth(struct pending_auth_data *pad)
+static void delete_partial_auth(struct smbd_server_connection *sconn,
+ struct pending_auth_data *pad)
{
if (!pad) {
return;
}
- DLIST_REMOVE(pd_list, pad);
+ DLIST_REMOVE(sconn->smb1.pd_list, pad);
data_blob_free(&pad->partial_data);
SAFE_FREE(pad);
}
Search for a partial SPNEGO auth fragment matching an smbpid.
****************************************************************************/
-static struct pending_auth_data *get_pending_auth_data(uint16 smbpid)
+static struct pending_auth_data *get_pending_auth_data(
+ struct smbd_server_connection *sconn,
+ uint16_t smbpid)
{
struct pending_auth_data *pad;
-
- for (pad = pd_list; pad; pad = pad->next) {
+/*
+ * NOTE: using the smbpid here is completely wrong...
+ * see [MS-SMB]
+ * 3.3.5.3 Receiving an SMB_COM_SESSION_SETUP_ANDX Request
+ */
+ for (pad = sconn->smb1.pd_list; pad; pad = pad->next) {
if (pad->smbpid == smbpid) {
break;
}
the blob to be more than 64k.
****************************************************************************/
-static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid,
- DATA_BLOB *pblob)
+static NTSTATUS check_spnego_blob_complete(struct smbd_server_connection *sconn,
+ uint16 smbpid, uint16 vuid,
+ DATA_BLOB *pblob)
{
struct pending_auth_data *pad = NULL;
- ASN1_DATA data;
+ ASN1_DATA *data;
size_t needed_len = 0;
- pad = get_pending_auth_data(smbpid);
+ pad = get_pending_auth_data(sconn, smbpid);
/* Ensure we have some data. */
if (pblob->length == 0) {
/* Caller can cope. */
DEBUG(2,("check_spnego_blob_complete: zero blob length !\n"));
- delete_partial_auth(pad);
+ delete_partial_auth(sconn, pad);
return NT_STATUS_OK;
}
(unsigned int)pad->partial_data.length,
(unsigned int)copy_len ));
- delete_partial_auth(pad);
+ delete_partial_auth(sconn, pad);
return NT_STATUS_INVALID_PARAMETER;
}
data_blob_free(pblob);
*pblob = pad->partial_data;
ZERO_STRUCT(pad->partial_data);
- delete_partial_auth(pad);
+ delete_partial_auth(sconn, pad);
return NT_STATUS_OK;
}
* the data given in this blob is enough.
*/
- asn1_load(&data, *pblob);
- asn1_start_tag(&data, pblob->data[0]);
- if (data.has_error || data.nesting == NULL) {
- asn1_free(&data);
+ data = asn1_init(NULL);
+ if (data == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ asn1_load(data, *pblob);
+ asn1_start_tag(data, pblob->data[0]);
+ if (data->has_error || data->nesting == NULL) {
+ asn1_free(data);
/* Let caller catch. */
return NT_STATUS_OK;
}
/* Integer wrap paranoia.... */
- if (data.nesting->taglen + data.nesting->start < data.nesting->taglen ||
- data.nesting->taglen + data.nesting->start < data.nesting->start) {
+ if (data->nesting->taglen + data->nesting->start < data->nesting->taglen ||
+ data->nesting->taglen + data->nesting->start < data->nesting->start) {
DEBUG(2,("check_spnego_blob_complete: integer wrap "
"data.nesting->taglen = %u, "
"data.nesting->start = %u\n",
- (unsigned int)data.nesting->taglen,
- (unsigned int)data.nesting->start ));
+ (unsigned int)data->nesting->taglen,
+ (unsigned int)data->nesting->start ));
- asn1_free(&data);
+ asn1_free(data);
return NT_STATUS_INVALID_PARAMETER;
}
/* Total length of the needed asn1 is the tag length
* plus the current offset. */
- needed_len = data.nesting->taglen + data.nesting->start;
- asn1_free(&data);
+ needed_len = data->nesting->taglen + data->nesting->start;
+ asn1_free(data);
DEBUG(10,("check_spnego_blob_complete: needed_len = %u, "
"pblob->length = %u\n",
}
pad->smbpid = smbpid;
pad->vuid = vuid;
- DLIST_ADD(pd_list, pad);
+ DLIST_ADD(sconn->smb1.pd_list, pad);
return NT_STATUS_MORE_PROCESSING_REQUIRED;
}
conn POINTER CAN BE NULL HERE !
****************************************************************************/
-static void reply_sesssetup_and_X_spnego(connection_struct *conn,
- struct smb_request *req)
+static void reply_sesssetup_and_X_spnego(struct smb_request *req)
{
- uint8 *p;
+ const uint8 *p;
DATA_BLOB blob1;
size_t bufrem;
- fstring native_os, native_lanman, primary_domain;
+ char *tmp;
+ const char *native_os;
+ const char *native_lanman;
+ const char *primary_domain;
const char *p2;
- uint16 data_blob_len = SVAL(req->inbuf, smb_vwv7);
+ uint16 data_blob_len = SVAL(req->vwv+7, 0);
enum remote_arch_types ra_type = get_remote_arch();
- int vuid = SVAL(req->inbuf,smb_uid);
+ int vuid = req->vuid;
user_struct *vuser = NULL;
NTSTATUS status = NT_STATUS_OK;
uint16 smbpid = req->smbpid;
- uint16 smb_flag2 = req->flags2;
+ struct smbd_server_connection *sconn = smbd_server_conn;
DEBUG(3,("Doing spnego session setup\n"));
if (global_client_caps == 0) {
- global_client_caps = IVAL(req->inbuf,smb_vwv10);
+ global_client_caps = IVAL(req->vwv+10, 0);
if (!(global_client_caps & CAP_STATUS32)) {
remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
}
- p = (uint8 *)smb_buf(req->inbuf);
+ p = req->buf;
if (data_blob_len == 0) {
/* an invalid request */
return;
}
- bufrem = smb_bufrem(req->inbuf, p);
+ bufrem = smbreq_bufrem(req, p);
/* pull the spnego blob */
blob1 = data_blob(p, MIN(bufrem, data_blob_len));
file_save("negotiate.dat", blob1.data, blob1.length);
#endif
- p2 = (char *)req->inbuf + smb_vwv13 + data_blob_len;
- p2 += srvstr_pull_buf(req->inbuf, smb_flag2, native_os, p2,
- sizeof(native_os), STR_TERMINATE);
- p2 += srvstr_pull_buf(req->inbuf, smb_flag2, native_lanman, p2,
- sizeof(native_lanman), STR_TERMINATE);
- p2 += srvstr_pull_buf(req->inbuf, smb_flag2, primary_domain, p2,
- sizeof(primary_domain), STR_TERMINATE);
+ p2 = (char *)req->buf + data_blob_len;
+
+ p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
+ STR_TERMINATE);
+ native_os = tmp ? tmp : "";
+
+ p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
+ STR_TERMINATE);
+ native_lanman = tmp ? tmp : "";
+
+ p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
+ STR_TERMINATE);
+ primary_domain = tmp ? tmp : "";
+
DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
native_os, native_lanman, primary_domain));
}
/* Did we get a valid vuid ? */
- if (!is_partial_auth_vuid(vuid)) {
+ if (!is_partial_auth_vuid(sconn, vuid)) {
/* No, then try and see if this is an intermediate sessionsetup
* for a large SPNEGO packet. */
- struct pending_auth_data *pad = get_pending_auth_data(smbpid);
+ struct pending_auth_data *pad;
+ pad = get_pending_auth_data(sconn, smbpid);
if (pad) {
DEBUG(10,("reply_sesssetup_and_X_spnego: found "
"pending vuid %u\n",
}
/* Do we have a valid vuid now ? */
- if (!is_partial_auth_vuid(vuid)) {
+ if (!is_partial_auth_vuid(sconn, vuid)) {
/* No, start a new authentication setup. */
- vuid = register_initial_vuid();
+ vuid = register_initial_vuid(sconn);
if (vuid == UID_FIELD_INVALID) {
data_blob_free(&blob1);
reply_nterror(req, nt_status_squash(
}
}
- vuser = get_partial_auth_user_struct(vuid);
+ vuser = get_partial_auth_user_struct(sconn, vuid);
/* This MUST be valid. */
if (!vuser) {
smb_panic("reply_sesssetup_and_X_spnego: invalid vuid.");
* field is 4k. Bug #4400. JRA.
*/
- status = check_spnego_blob_complete(smbpid, vuid, &blob1);
+ status = check_spnego_blob_complete(sconn, smbpid, vuid, &blob1);
if (!NT_STATUS_IS_OK(status)) {
if (!NT_STATUS_EQUAL(status,
NT_STATUS_MORE_PROCESSING_REQUIRED)) {
/* Real error - kill the intermediate vuid */
- invalidate_vuid(vuid);
+ invalidate_vuid(sconn, vuid);
}
data_blob_free(&blob1);
reply_nterror(req, nt_status_squash(status));
/* its a negTokenTarg packet */
- reply_spnego_negotiate(conn, req, vuid, blob1,
+ reply_spnego_negotiate(req, vuid, blob1,
&vuser->auth_ntlmssp_state);
data_blob_free(&blob1);
return;
/* its a auth packet */
- reply_spnego_auth(conn, req, vuid, blob1,
+ reply_spnego_auth(req, vuid, blob1,
&vuser->auth_ntlmssp_state);
data_blob_free(&blob1);
return;
status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
if (!NT_STATUS_IS_OK(status)) {
/* Kill the intermediate vuid */
- invalidate_vuid(vuid);
+ invalidate_vuid(sconn, vuid);
data_blob_free(&blob1);
reply_nterror(req, nt_status_squash(status));
return;
data_blob_free(&blob1);
- reply_spnego_ntlmssp(conn, req, vuid,
+ reply_spnego_ntlmssp(req, vuid,
&vuser->auth_ntlmssp_state,
- &chal, status, False);
+ &chal, status, OID_NTLMSSP, false);
data_blob_free(&chal);
return;
}
return 0;
}
+ DEBUG(0,("shutdown_other_smbds: shutting down pid %u "
+ "(IP %s)\n", (unsigned int)procid_to_pid(&crec->pid), ip));
+
messaging_send(smbd_messaging_context(), crec->pid, MSG_SHUTDOWN,
&data_blob_null);
return 0;
Reply to a session setup command.
****************************************************************************/
-void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req)
+void reply_sesssetup_and_X(struct smb_request *req)
{
int sess_vuid;
int smb_bufsize;
DATA_BLOB lm_resp;
DATA_BLOB nt_resp;
DATA_BLOB plaintext_password;
- fstring user;
+ char *tmp;
+ const char *user;
fstring sub_user; /* Sainitised username for substituion */
- fstring domain;
- fstring native_os;
- fstring native_lanman;
- fstring primary_domain;
- static bool done_sesssetup = False;
+ const char *domain;
+ const char *native_os;
+ const char *native_lanman;
+ const char *primary_domain;
auth_usersupplied_info *user_info = NULL;
auth_serversupplied_info *server_info = NULL;
uint16 smb_flag2 = req->flags2;
NTSTATUS nt_status;
+ struct smbd_server_connection *sconn = smbd_server_conn;
- bool doencrypt = global_encrypted_passwords_negotiated;
-
- DATA_BLOB session_key;
+ bool doencrypt = sconn->smb1.negprot.encrypted_passwords;
START_PROFILE(SMBsesssetupX);
if (req->wct == 12 &&
(req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
- if (!global_spnego_negotiated) {
+ if (!sconn->smb1.negprot.spnego) {
DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
"at SPNEGO session setup when it was not "
"negotiated.\n"));
return;
}
- if (SVAL(req->inbuf,smb_vwv4) == 0) {
+ if (SVAL(req->vwv+4, 0) == 0) {
setup_new_vc_session();
}
- reply_sesssetup_and_X_spnego(conn, req);
+ reply_sesssetup_and_X_spnego(req);
END_PROFILE(SMBsesssetupX);
return;
}
- smb_bufsize = SVAL(req->inbuf,smb_vwv2);
+ smb_bufsize = SVAL(req->vwv+2, 0);
if (Protocol < PROTOCOL_NT1) {
- uint16 passlen1 = SVAL(req->inbuf,smb_vwv7);
+ uint16 passlen1 = SVAL(req->vwv+7, 0);
/* Never do NT status codes with protocols before NT1 as we
* don't get client caps. */
remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
- if ((passlen1 > MAX_PASS_LEN)
- || (passlen1 > smb_bufrem(req->inbuf,
- smb_buf(req->inbuf)))) {
+ if ((passlen1 > MAX_PASS_LEN) || (passlen1 > req->buflen)) {
reply_nterror(req, nt_status_squash(
NT_STATUS_INVALID_PARAMETER));
END_PROFILE(SMBsesssetupX);
}
if (doencrypt) {
- lm_resp = data_blob(smb_buf(req->inbuf), passlen1);
+ lm_resp = data_blob(req->buf, passlen1);
} else {
- plaintext_password = data_blob(smb_buf(req->inbuf),
- passlen1+1);
+ plaintext_password = data_blob(req->buf, passlen1+1);
/* Ensure null termination */
plaintext_password.data[passlen1] = 0;
}
- srvstr_pull_buf(req->inbuf, req->flags2, user,
- smb_buf(req->inbuf)+passlen1, sizeof(user),
- STR_TERMINATE);
- *domain = 0;
+ srvstr_pull_req_talloc(talloc_tos(), req, &tmp,
+ req->buf + passlen1, STR_TERMINATE);
+ user = tmp ? tmp : "";
+
+ domain = "";
} else {
- uint16 passlen1 = SVAL(req->inbuf,smb_vwv7);
- uint16 passlen2 = SVAL(req->inbuf,smb_vwv8);
+ uint16 passlen1 = SVAL(req->vwv+7, 0);
+ uint16 passlen2 = SVAL(req->vwv+8, 0);
enum remote_arch_types ra_type = get_remote_arch();
- char *p = smb_buf(req->inbuf);
- char *save_p = smb_buf(req->inbuf);
+ const uint8_t *p = req->buf;
+ const uint8_t *save_p = req->buf;
uint16 byte_count;
if(global_client_caps == 0) {
- global_client_caps = IVAL(req->inbuf,smb_vwv11);
+ global_client_caps = IVAL(req->vwv+11, 0);
if (!(global_client_caps & CAP_STATUS32)) {
remove_from_common_flags2(
/* check for nasty tricks */
if (passlen1 > MAX_PASS_LEN
- || passlen1 > smb_bufrem(req->inbuf, p)) {
+ || passlen1 > smbreq_bufrem(req, p)) {
reply_nterror(req, nt_status_squash(
NT_STATUS_INVALID_PARAMETER));
END_PROFILE(SMBsesssetupX);
}
if (passlen2 > MAX_PASS_LEN
- || passlen2 > smb_bufrem(req->inbuf, p+passlen1)) {
+ || passlen2 > smbreq_bufrem(req, p+passlen1)) {
reply_nterror(req, nt_status_squash(
NT_STATUS_INVALID_PARAMETER));
END_PROFILE(SMBsesssetupX);
if (doencrypt) {
lm_resp = data_blob(p, passlen1);
nt_resp = data_blob(p+passlen1, passlen2);
- } else {
+ } else if (lp_security() != SEC_SHARE) {
+ /*
+ * In share level we should ignore any passwords, so
+ * only read them if we're not.
+ */
char *pass = NULL;
bool unic= smb_flag2 & FLAGS2_UNICODE_STRINGS;
req->inbuf,
req->flags2,
&pass,
- smb_buf(req->inbuf),
+ req->buf,
passlen1,
STR_TERMINATE|STR_ASCII);
} else {
req->inbuf,
req->flags2,
&pass,
- smb_buf(req->inbuf),
+ req->buf,
unic ? passlen2 : passlen1,
STR_TERMINATE);
}
}
p += passlen1 + passlen2;
- p += srvstr_pull_buf(req->inbuf, req->flags2, user, p,
- sizeof(user), STR_TERMINATE);
- p += srvstr_pull_buf(req->inbuf, req->flags2, domain, p,
- sizeof(domain), STR_TERMINATE);
- p += srvstr_pull_buf(req->inbuf, req->flags2, native_os,
- p, sizeof(native_os), STR_TERMINATE);
- p += srvstr_pull_buf(req->inbuf, req->flags2,
- native_lanman, p, sizeof(native_lanman),
- STR_TERMINATE);
+
+ p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
+ STR_TERMINATE);
+ user = tmp ? tmp : "";
+
+ p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
+ STR_TERMINATE);
+ domain = tmp ? tmp : "";
+
+ p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
+ STR_TERMINATE);
+ native_os = tmp ? tmp : "";
+
+ p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
+ STR_TERMINATE);
+ native_lanman = tmp ? tmp : "";
/* not documented or decoded by Ethereal but there is one more
* string in the extra bytes which is the same as the
* Windows 9x does not include a string here at all so we have
* to check if we have any extra bytes left */
- byte_count = SVAL(req->inbuf, smb_vwv13);
+ byte_count = SVAL(req->vwv+13, 0);
if ( PTR_DIFF(p, save_p) < byte_count) {
- p += srvstr_pull_buf(req->inbuf, req->flags2,
- primary_domain, p,
- sizeof(primary_domain),
- STR_TERMINATE);
+ p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
+ STR_TERMINATE);
+ primary_domain = tmp ? tmp : "";
} else {
- fstrcpy( primary_domain, "null" );
+ primary_domain = talloc_strdup(talloc_tos(), "null");
}
DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] "
}
- if (SVAL(req->inbuf,smb_vwv4) == 0) {
+ if (SVAL(req->vwv+4, 0) == 0) {
setup_new_vc_session();
}
domain, user, get_remote_machine_name()));
if (*user) {
- if (global_spnego_negotiated) {
+ if (sconn->smb1.negprot.spnego) {
/* This has to be here, because this is a perfectly
* valid behaviour for guest logons :-( */
reload_services(True);
if (lp_security() == SEC_SHARE) {
- /* in share level we should ignore any passwords */
+ /* In share level we should ignore any passwords */
data_blob_free(&lm_resp);
data_blob_free(&nt_resp);
data_blob_clear_free(&plaintext_password);
- map_username(sub_user);
- add_session_user(sub_user);
- add_session_workgroup(domain);
+ map_username(sconn, sub_user);
+ add_session_user(sconn, sub_user);
+ add_session_workgroup(sconn, domain);
/* Then force it to null for the benfit of the code below */
- *user = 0;
+ user = "";
}
if (!*user) {
nt_status = check_guest_password(&server_info);
} else if (doencrypt) {
- if (!negprot_global_auth_context) {
+ struct auth_context *negprot_auth_context = NULL;
+ negprot_auth_context = sconn->smb1.negprot.auth_context;
+ if (!negprot_auth_context) {
DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted "
"session setup without negprot denied!\n"));
reply_nterror(req, nt_status_squash(
domain,
lm_resp, nt_resp);
if (NT_STATUS_IS_OK(nt_status)) {
- nt_status = negprot_global_auth_context->check_ntlm_password(
- negprot_global_auth_context,
+ nt_status = negprot_auth_context->check_ntlm_password(
+ negprot_auth_context,
user_info,
&server_info);
}
} else {
struct auth_context *plaintext_auth_context = NULL;
- const uint8 *chal;
nt_status = make_auth_context_subsystem(
&plaintext_auth_context);
if (NT_STATUS_IS_OK(nt_status)) {
- chal = plaintext_auth_context->get_ntlm_challenge(
- plaintext_auth_context);
+ uint8_t chal[8];
+
+ plaintext_auth_context->get_ntlm_challenge(
+ plaintext_auth_context, chal);
if (!make_user_info_for_reply(&user_info,
user, domain, chal,
return;
}
- nt_status = create_local_token(server_info);
- if (!NT_STATUS_IS_OK(nt_status)) {
- DEBUG(10, ("create_local_token failed: %s\n",
- nt_errstr(nt_status)));
- data_blob_free(&nt_resp);
- data_blob_free(&lm_resp);
- data_blob_clear_free(&plaintext_password);
- reply_nterror(req, nt_status_squash(nt_status));
- END_PROFILE(SMBsesssetupX);
- return;
- }
+ if (!server_info->ptok) {
+ nt_status = create_local_token(server_info);
- if (server_info->user_session_key.data) {
- session_key = data_blob(server_info->user_session_key.data,
- server_info->user_session_key.length);
- } else {
- session_key = data_blob_null;
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(10, ("create_local_token failed: %s\n",
+ nt_errstr(nt_status)));
+ data_blob_free(&nt_resp);
+ data_blob_free(&lm_resp);
+ data_blob_clear_free(&plaintext_password);
+ reply_nterror(req, nt_status_squash(nt_status));
+ END_PROFILE(SMBsesssetupX);
+ return;
+ }
}
data_blob_clear_free(&plaintext_password);
if (lp_security() == SEC_SHARE) {
sess_vuid = UID_FIELD_INVALID;
- data_blob_free(&session_key);
TALLOC_FREE(server_info);
} else {
/* Ignore the initial vuid. */
- sess_vuid = register_initial_vuid();
+ sess_vuid = register_initial_vuid(sconn);
if (sess_vuid == UID_FIELD_INVALID) {
data_blob_free(&nt_resp);
data_blob_free(&lm_resp);
- data_blob_free(&session_key);
reply_nterror(req, nt_status_squash(
NT_STATUS_LOGON_FAILURE));
END_PROFILE(SMBsesssetupX);
return;
}
/* register_existing_vuid keeps the server info */
- sess_vuid = register_existing_vuid(sess_vuid,
+ sess_vuid = register_existing_vuid(sconn, sess_vuid,
server_info,
- session_key,
nt_resp.data ? nt_resp : lm_resp,
sub_user);
if (sess_vuid == UID_FIELD_INVALID) {
data_blob_free(&nt_resp);
data_blob_free(&lm_resp);
- data_blob_free(&session_key);
reply_nterror(req, nt_status_squash(
NT_STATUS_LOGON_FAILURE));
END_PROFILE(SMBsesssetupX);
/* current_user_info is changed on new vuid */
reload_services( True );
-
- sessionsetup_start_signing_engine(server_info, req->inbuf);
}
data_blob_free(&nt_resp);
SSVAL(req->outbuf,smb_uid,sess_vuid);
SSVAL(req->inbuf,smb_uid,sess_vuid);
+ req->vuid = sess_vuid;
- if (!done_sesssetup)
- max_send = MIN(max_send,smb_bufsize);
-
- done_sesssetup = True;
+ if (!sconn->smb1.sessions.done_sesssetup) {
+ sconn->smb1.sessions.max_send =
+ MIN(sconn->smb1.sessions.max_send,smb_bufsize);
+ }
+ sconn->smb1.sessions.done_sesssetup = true;
END_PROFILE(SMBsesssetupX);
chain_reply(req);