summaryrefslogtreecommitdiff
path: root/source4/smb_server
diff options
context:
space:
mode:
Diffstat (limited to 'source4/smb_server')
-rw-r--r--source4/smb_server/password.c122
-rw-r--r--source4/smb_server/sesssetup.c143
-rw-r--r--source4/smb_server/smb_server.c2
-rw-r--r--source4/smb_server/smb_server.h9
4 files changed, 157 insertions, 119 deletions
diff --git a/source4/smb_server/password.c b/source4/smb_server/password.c
index 3d7723936d..1132a8ed9a 100644
--- a/source4/smb_server/password.c
+++ b/source4/smb_server/password.c
@@ -2,6 +2,7 @@
Unix SMB/CIFS implementation.
Password and authentication handling
Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -24,39 +25,45 @@
/****************************************************************************
-check if a uid has been validated, and return an pointer to the user_struct
-if it has. NULL if not. vuid is biased by an offset. This allows us to
-tell random client vuid's (normally zero) from valid vuids.
+init the tcon structures
****************************************************************************/
-struct smbsrv_session *smbsrv_session_find(struct smbsrv_connection *smb_conn, uint16_t vuid)
+void smbsrv_vuid_init(struct smbsrv_connection *smb_conn)
{
- struct smbsrv_session *sess;
- int count=0;
+ smb_conn->sessions.idtree_vuid = idr_init(smb_conn);
+}
- if (vuid == UID_FIELD_INVALID)
- return NULL;
- for (sess=smb_conn->sessions.session_list; sess; sess=sess->next,count++) {
- if (vuid == sess->vuid) {
- if (count > 10) {
- DLIST_PROMOTE(smb_conn->sessions.session_list, sess);
- }
- return sess;
- }
+/****************************************************************************
+Find the session structure assoicated with a VUID (not one from an in-progress session setup)
+****************************************************************************/
+struct smbsrv_session *smbsrv_session_find(struct smbsrv_connection *smb_conn, uint16_t vuid)
+{
+ struct smbsrv_session *sess = idr_find(smb_conn->sessions.idtree_vuid, vuid);
+ if (sess && sess->finished_sesssetup) {
+ return sess;
}
-
return NULL;
}
/****************************************************************************
-invalidate a uid
+ Find a VUID assoicated with an in-progress session setup
****************************************************************************/
-void smbsrv_invalidate_vuid(struct smbsrv_connection *smb_conn, uint16_t vuid)
+struct smbsrv_session *smbsrv_session_find_sesssetup(struct smbsrv_connection *smb_conn, uint16_t vuid)
{
- struct smbsrv_session *sess = smbsrv_session_find(smb_conn, vuid);
+ struct smbsrv_session *sess = idr_find(smb_conn->sessions.idtree_vuid, vuid);
+ if (sess && !sess->finished_sesssetup) {
+ return sess;
+ }
+ return NULL;
+}
- if (sess == NULL)
- return;
+/****************************************************************************
+invalidate a session
+****************************************************************************/
+static int smbsrv_session_destructor(void *p)
+{
+ struct smbsrv_session *sess = p;
+ struct smbsrv_connection *smb_conn = sess->smb_conn;
DLIST_REMOVE(smb_conn->sessions.session_list, sess);
@@ -65,20 +72,18 @@ void smbsrv_invalidate_vuid(struct smbsrv_connection *smb_conn, uint16_t vuid)
/* REWRITE: conn_clear_vuid_cache(smb, vuid); */
smb_conn->sessions.num_validated_vuids--;
+
+ idr_remove(smb_conn->sessions.idtree_vuid, sess->vuid);
+ return 0;
}
/****************************************************************************
-invalidate all vuid entries for this process
+invalidate a uid
****************************************************************************/
-void smbsrv_invalidate_all_vuids(struct smbsrv_connection *smb_conn)
+void smbsrv_invalidate_vuid(struct smbsrv_connection *smb_conn, uint16_t vuid)
{
- struct smbsrv_session *sess,*next=NULL;
-
- for (sess=smb_conn->sessions.session_list; sess; sess=next) {
- next = sess->next;
-
- smbsrv_invalidate_vuid(smb_conn, sess->vuid);
- }
+ struct smbsrv_session *sess = smbsrv_session_find(smb_conn, vuid);
+ talloc_free(sess);
}
/**
@@ -93,56 +98,45 @@ void smbsrv_invalidate_all_vuids(struct smbsrv_connection *smb_conn)
*
*/
-uint16_t smbsrv_register_session(struct smbsrv_connection *smb_conn,
- struct auth_session_info *session_info,
- struct gensec_security *gensec_ctx)
+struct smbsrv_session *smbsrv_register_session(struct smbsrv_connection *smb_conn,
+ struct auth_session_info *session_info,
+ struct gensec_security *gensec_ctx)
{
struct smbsrv_session *sess = NULL;
+ int i;
+
+ /* Ensure no vuid gets registered in share level security. */
+ /* TODO: replace lp_security with a flag in smbsrv_connection */
+ if (lp_security() == SEC_SHARE)
+ return UID_FIELD_INVALID;
sess = talloc(smb_conn, struct smbsrv_session);
- if(sess == NULL) {
+ if (sess == NULL) {
DEBUG(0,("talloc(smb_conn->mem_ctx, struct smbsrv_session) failed\n"));
- return UID_FIELD_INVALID;
+ return sess;
}
ZERO_STRUCTP(sess);
- sess->vuid = UID_FIELD_INVALID;
- /* Ensure no vuid gets registered in share level security. */
- /* TODO: replace lp_security with a flag in smbsrv_connection */
- if(lp_security() == SEC_SHARE)
- return sess->vuid;
-
- /* Limit allowed vuids to 16bits - VUID_OFFSET. */
- if (smb_conn->sessions.num_validated_vuids >= 0xFFFF-VUID_OFFSET)
- return sess->vuid;
-
- /* Allocate a free vuid. Yes this is a linear search... :-) */
- while (smbsrv_session_find(smb_conn, smb_conn->sessions.next_vuid) != NULL ) {
- smb_conn->sessions.next_vuid++;
- /* Check for vuid wrap. */
- if (smb_conn->sessions.next_vuid == UID_FIELD_INVALID)
- smb_conn->sessions.next_vuid = VUID_OFFSET;
+ i = idr_get_new_above(smb_conn->sessions.idtree_vuid, sess, VUID_OFFSET, UINT16_MAX);
+ if (i == -1) {
+ DEBUG(1,("ERROR! Out of connection structures\n"));
+ talloc_free(sess);
+ return NULL;
}
+ sess->vuid = i;
- DEBUG(10,("register_vuid: allocated vuid = %u\n",
- (uint_t)smb_conn->sessions.next_vuid));
-
- sess->vuid = smb_conn->sessions.next_vuid;
- smb_conn->sessions.next_vuid++;
smb_conn->sessions.num_validated_vuids++;
/* use this to keep tabs on all our info from the authentication */
- if (session_info) {
- sess->session_info = talloc_reference(sess, session_info);
- }
-
- if (gensec_ctx) {
- sess->gensec_ctx = talloc_reference(sess, gensec_ctx);
- }
+ sess->session_info = talloc_reference(sess, session_info);
+
+ sess->gensec_ctx = talloc_reference(sess, gensec_ctx);
sess->smb_conn = smb_conn;
DLIST_ADD(smb_conn->sessions.session_list, sess);
- return sess->vuid;
+ talloc_set_destructor(sess, smbsrv_session_destructor);
+
+ return sess;
}
diff --git a/source4/smb_server/sesssetup.c b/source4/smb_server/sesssetup.c
index 0f0dcb837e..4e87aa6de6 100644
--- a/source4/smb_server/sesssetup.c
+++ b/source4/smb_server/sesssetup.c
@@ -1,10 +1,10 @@
/*
Unix SMB/CIFS implementation.
handle SMBsessionsetup
- Copyright (C) Andrew Tridgell 1998-2001
- Copyright (C) Andrew Bartlett 2001
- Copyright (C) Jim McDonough 2002
- Copyright (C) Luke Howard 2003
+ Copyright (C) Andrew Tridgell 1998-2001
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2001-2005
+ Copyright (C) Jim McDonough 2002
+ Copyright (C) Luke Howard 2003
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -26,7 +26,7 @@
#include "auth/auth.h"
#include "smb_server/smb_server.h"
#include "smbd/service_stream.h"
-
+#include "libcli/nbt/libnbt.h"
/*
setup the OS, Lanman and domain portions of a session setup reply
@@ -49,9 +49,13 @@ static NTSTATUS sesssetup_old(struct smbsrv_request *req, union smb_sesssetup *s
struct auth_usersupplied_info *user_info = NULL;
struct auth_serversupplied_info *server_info = NULL;
struct auth_session_info *session_info;
+ struct smbsrv_session *smb_sess;
char *remote_machine;
TALLOC_CTX *mem_ctx;
+ sess->old.out.vuid = UID_FIELD_INVALID;
+ sess->old.out.action = 0;
+
mem_ctx = talloc_named(req, 0, "OLD session setup");
NT_STATUS_HAVE_NO_MEMORY(mem_ctx);
@@ -85,18 +89,25 @@ static NTSTATUS sesssetup_old(struct smbsrv_request *req, union smb_sesssetup *s
return auth_nt_status_squash(status);
}
- sess->old.out.action = 0;
- sess->old.out.vuid = smbsrv_register_session(req->smb_conn, session_info, NULL);
- if (sess->old.out.vuid == UID_FIELD_INVALID) {
+ smb_sess = smbsrv_register_session(req->smb_conn, session_info, NULL);
+ if (!smb_sess) {
return NT_STATUS_ACCESS_DENIED;
}
+
+ /* Ensure this is marked as a 'real' vuid, not one
+ * simply valid for the session setup leg */
+ smb_sess->finished_sesssetup = True;
+
+ /* To correctly process any AndX packet (like a tree connect)
+ * we need to fill in the session on the request here */
+ req->session = smb_sess;
+ sess->old.out.vuid = smb_sess->vuid;
+
sesssetup_common_strings(req,
&sess->old.out.os,
&sess->old.out.lanman,
&sess->old.out.domain);
- req->session = smbsrv_session_find(req->smb_conn, sess->old.out.vuid);
-
return NT_STATUS_OK;
}
@@ -107,11 +118,15 @@ static NTSTATUS sesssetup_old(struct smbsrv_request *req, union smb_sesssetup *s
static NTSTATUS sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *sess)
{
NTSTATUS status;
+ struct smbsrv_session *smb_sess;
struct auth_usersupplied_info *user_info = NULL;
struct auth_serversupplied_info *server_info = NULL;
struct auth_session_info *session_info;
TALLOC_CTX *mem_ctx;
+ sess->nt1.out.vuid = UID_FIELD_INVALID;
+ sess->nt1.out.action = 0;
+
mem_ctx = talloc_named(req, 0, "NT1 session setup");
NT_STATUS_HAVE_NO_MEMORY(mem_ctx);
@@ -143,9 +158,15 @@ static NTSTATUS sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *s
status = auth_check_password(auth_context, mem_ctx,
user_info, &server_info);
} else {
- char *remote_machine;
+ const char *remote_machine = NULL;
+
+ if (req->smb_conn->negotiate.called_name) {
+ remote_machine = req->smb_conn->negotiate.called_name->name;
+ }
- remote_machine = socket_get_peer_addr(req->smb_conn->connection->socket, mem_ctx);
+ if (!remote_machine) {
+ remote_machine = socket_get_peer_addr(req->smb_conn->connection->socket, mem_ctx);
+ }
status = make_user_info_for_reply_enc(req->smb_conn,
sess->nt1.in.user, sess->nt1.in.domain,
@@ -174,12 +195,21 @@ static NTSTATUS sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *s
return auth_nt_status_squash(status);
}
- sess->nt1.out.action = 0;
- sess->nt1.out.vuid = smbsrv_register_session(req->smb_conn, session_info, NULL);
+ smb_sess = smbsrv_register_session(req->smb_conn, session_info, NULL);
talloc_free(mem_ctx);
- if (sess->nt1.out.vuid == UID_FIELD_INVALID) {
+ if (!smb_sess) {
return NT_STATUS_ACCESS_DENIED;
}
+
+ /* Ensure this is marked as a 'real' vuid, not one
+ * simply valid for the session setup leg */
+ smb_sess->finished_sesssetup = True;
+
+ /* To correctly process any AndX packet (like a tree connect)
+ * we need to fill in the session on the request here */
+ req->session = smb_sess;
+ sess->nt1.out.vuid = smb_sess->vuid;
+
sesssetup_common_strings(req,
&sess->nt1.out.os,
&sess->nt1.out.lanman,
@@ -190,7 +220,8 @@ static NTSTATUS sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *s
return NT_STATUS_OK;
}
- if (!srv_setup_signing(req->smb_conn, &session_info->session_key, &sess->nt1.in.password2)) {
+
+ if (!srv_setup_signing(req->smb_conn, &session_info->session_key, &sess->nt1.in.password2)) {
/* Already signing, or disabled */
return NT_STATUS_OK;
}
@@ -198,6 +229,9 @@ static NTSTATUS sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *s
/* Force check of the request packet, now we know the session key */
req_signing_check_incoming(req);
+ /* Unfortunetly win2k3 as a client doesn't sign the request
+ * packet here, so we have to force signing to start again */
+
srv_signing_restart(req->smb_conn, &session_info->session_key, &sess->nt1.in.password2);
return NT_STATUS_OK;
@@ -211,26 +245,29 @@ static NTSTATUS sesssetup_spnego(struct smbsrv_request *req, union smb_sesssetup
{
NTSTATUS status = NT_STATUS_ACCESS_DENIED;
struct smbsrv_session *smb_sess;
- struct gensec_security *gensec_ctx = NULL;
+ struct gensec_security *gensec_ctx ;
struct auth_session_info *session_info = NULL;
uint16_t vuid;
+ sess->spnego.out.vuid = UID_FIELD_INVALID;
+ sess->spnego.out.action = 0;
+
+ sesssetup_common_strings(req,
+ &sess->spnego.out.os,
+ &sess->spnego.out.lanman,
+ &sess->spnego.out.workgroup);
+
if (!req->smb_conn->negotiate.done_sesssetup) {
req->smb_conn->negotiate.max_send = sess->nt1.in.bufsize;
req->smb_conn->negotiate.client_caps = sess->nt1.in.capabilities;
}
vuid = SVAL(req->in.hdr,HDR_UID);
- smb_sess = smbsrv_session_find(req->smb_conn, vuid);
- if (smb_sess && !smb_sess->session_info) {
- if (!smb_sess->gensec_ctx) {
- return NT_STATUS_INVALID_HANDLE;
- }
-
- status = gensec_update(smb_sess->gensec_ctx, req, sess->spnego.in.secblob, &sess->spnego.out.secblob);
+ smb_sess = smbsrv_session_find_sesssetup(req->smb_conn, vuid);
+ if (smb_sess) {
+ gensec_ctx = smb_sess->gensec_ctx;
+ status = gensec_update(gensec_ctx, req, sess->spnego.in.secblob, &sess->spnego.out.secblob);
} else {
- smb_sess = NULL;
-
status = gensec_server_start(req->smb_conn, &gensec_ctx);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status)));
@@ -248,55 +285,55 @@ static NTSTATUS sesssetup_spnego(struct smbsrv_request *req, union smb_sesssetup
}
status = gensec_update(gensec_ctx, req, sess->spnego.in.secblob, &sess->spnego.out.secblob);
-
- }
-
- if (!smb_sess) {
- vuid = smbsrv_register_session(req->smb_conn,
- session_info, gensec_ctx);
- if (vuid == UID_FIELD_INVALID) {
- return NT_STATUS_ACCESS_DENIED;
- }
- smb_sess = smbsrv_session_find(req->smb_conn, vuid);
- if (!smb_sess) {
- return NT_STATUS_FOOBAR;
- }
}
if (NT_STATUS_IS_OK(status)) {
DATA_BLOB session_key;
- status = gensec_session_info(smb_sess->gensec_ctx, &smb_sess->session_info);
+ status = gensec_session_info(gensec_ctx, &session_info);
if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(smb_sess);
return status;
}
- status = gensec_session_key(smb_sess->gensec_ctx,
+ status = gensec_session_key(gensec_ctx,
&session_key);
+
if (NT_STATUS_IS_OK(status)
- && smb_sess->session_info->server_info->authenticated
+ && session_info->server_info->authenticated
&& srv_setup_signing(req->smb_conn, &session_key, NULL)) {
/* Force check of the request packet, now we know the session key */
req_signing_check_incoming(req);
srv_signing_restart(req->smb_conn, &session_key, NULL);
-
}
+
+ } else if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
} else {
status = auth_nt_status_squash(status);
- if (smb_sess->gensec_ctx &&
- !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- talloc_free(smb_sess->gensec_ctx);
- smb_sess->gensec_ctx = NULL;
+
+ /* This invalidates the VUID of the failed login */
+ talloc_free(smb_sess);
+ return status;
+ }
+
+ if (!smb_sess) {
+ smb_sess = smbsrv_register_session(req->smb_conn,
+ session_info, gensec_ctx);
+ if (!smb_sess) {
+ return NT_STATUS_ACCESS_DENIED;
}
+ req->session = smb_sess;
+ } else {
+ smb_sess->session_info = talloc_reference(smb_sess, session_info);
}
- sess->spnego.out.action = 0;
- sess->spnego.out.vuid = vuid;
- sesssetup_common_strings(req,
- &sess->spnego.out.os,
- &sess->spnego.out.lanman,
- &sess->spnego.out.workgroup);
+ if (NT_STATUS_IS_OK(status)) {
+ /* Ensure this is marked as a 'real' vuid, not one
+ * simply valid for the session setup leg */
+ smb_sess->finished_sesssetup = True;
+ }
+ sess->spnego.out.vuid = smb_sess->vuid;
return status;
}
diff --git a/source4/smb_server/smb_server.c b/source4/smb_server/smb_server.c
index 11fe965a92..6261621886 100644
--- a/source4/smb_server/smb_server.c
+++ b/source4/smb_server/smb_server.c
@@ -737,7 +737,7 @@ static void smbsrv_accept(struct stream_connection *conn)
smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
- smb_conn->sessions.next_vuid = VUID_OFFSET;
+ smbsrv_vuid_init(smb_conn);
srv_init_signing(smb_conn);
diff --git a/source4/smb_server/smb_server.h b/source4/smb_server/smb_server.h
index 02070f2b13..2f176d9c66 100644
--- a/source4/smb_server/smb_server.h
+++ b/source4/smb_server/smb_server.h
@@ -47,6 +47,10 @@ struct smbsrv_session {
struct gensec_security *gensec_ctx;
struct auth_session_info *session_info;
+
+ /* Distinguish between a VUID allocated for the multi-pass
+ * extended secrity session setup and one that is finished */
+ BOOL finished_sesssetup;
};
/* we need a forward declaration of the ntvfs_ops strucutre to prevent
@@ -216,8 +220,11 @@ struct smbsrv_connection {
struct {
/* this holds info on session vuids that are already validated for this VC */
struct smbsrv_session *session_list;
- uint16_t next_vuid; /* initialise to VUID_OFFSET */
+
int num_validated_vuids;
+
+ /* an id tree used to allocate vuids */
+ struct idr_context *idtree_vuid;
} sessions;
/* the server_context holds a linked list of pending requests,