s3:smbd: add a optional_support helper variable to reply_tcon_and_X()
[kai/samba.git] / source3 / smbd / reply.c
index 50c974f22b8e9b140921a5dead78113fa764cd1e..a89338082f60f995d74ad2f43c02e52b0e816813 100644 (file)
@@ -41,6 +41,7 @@
 #include "auth.h"
 #include "smbprofile.h"
 #include "../lib/tsocket/tsocket.h"
+#include "lib/tevent_wait.h"
 
 /****************************************************************************
  Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
@@ -735,7 +736,7 @@ void reply_tcon_and_X(struct smb_request *req)
        tcon_flags = SVAL(req->vwv+2, 0);
 
        /* we might have to close an old one */
-       if ((tcon_flags & 0x1) && conn) {
+       if ((tcon_flags & TCONX_FLAG_DISCONNECT_TID) && conn) {
                struct smbXsrv_tcon *tcon;
                NTSTATUS status;
 
@@ -838,7 +839,8 @@ void reply_tcon_and_X(struct smb_request *req)
                }
        } else {
                /* NT sets the fstype of IPC$ to the null string */
-               const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
+               const char *fstype = IS_IPC(conn) ? "" : lp_fstype(ctx, SNUM(conn));
+               uint16_t optional_support = 0;
 
                if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
                        /* Return permissions. */
@@ -871,15 +873,17 @@ void reply_tcon_and_X(struct smb_request *req)
 
                /* what does setting this bit do? It is set by NT4 and
                   may affect the ability to autorun mounted cdroms */
-               SSVAL(req->outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS|
-                     (lp_csc_policy(SNUM(conn)) << 2));
+               optional_support |= SMB_SUPPORT_SEARCH_BITS;
+               optional_support |=
+                       (lp_csc_policy(SNUM(conn)) << SMB_CSC_POLICY_SHIFT);
 
                if (lp_msdfs_root(SNUM(conn)) && lp_host_msdfs()) {
                        DEBUG(2,("Serving %s as a Dfs root\n",
-                                lp_servicename(SNUM(conn)) ));
-                       SSVAL(req->outbuf, smb_vwv2,
-                             SMB_SHARE_IN_DFS | SVAL(req->outbuf, smb_vwv2));
+                                lp_servicename(ctx, SNUM(conn)) ));
+                       optional_support |= SMB_SHARE_IN_DFS;
                }
+
+               SSVAL(req->outbuf, smb_vwv2, optional_support);
        }
 
        SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
@@ -973,7 +977,9 @@ void reply_ioctl(struct smb_request *req)
                                    STR_TERMINATE|STR_ASCII);
                        if (conn) {
                                srvstr_push((char *)req->outbuf, req->flags2,
-                                           p+18, lp_servicename(SNUM(conn)),
+                                           p+18,
+                                           lp_servicename(talloc_tos(),
+                                                          SNUM(conn)),
                                            13, STR_TERMINATE|STR_ASCII);
                        } else {
                                memset(p+18, 0, 13);
@@ -1542,7 +1548,7 @@ void reply_search(struct smb_request *req)
        if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
                char buf[DIR_STRUCT_SIZE];
                memcpy(buf,status,21);
-               if (!make_dir_struct(ctx,buf,"???????????",volume_label(SNUM(conn)),
+               if (!make_dir_struct(ctx,buf,"???????????",volume_label(ctx, SNUM(conn)),
                                0,FILE_ATTRIBUTE_VOLUME,0,!allow_long_path_components)) {
                        reply_nterror(req, NT_STATUS_NO_MEMORY);
                        goto out;
@@ -1568,8 +1574,8 @@ void reply_search(struct smb_request *req)
                         /DIR_STRUCT_SIZE));
 
                DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
-                       directory,lp_dontdescend(SNUM(conn))));
-               if (in_list(directory, lp_dontdescend(SNUM(conn)),True)) {
+                        directory,lp_dontdescend(ctx, SNUM(conn))));
+               if (in_list(directory, lp_dontdescend(ctx, SNUM(conn)),True)) {
                        check_descend = True;
                }
 
@@ -2096,6 +2102,8 @@ void reply_ulogoffX(struct smb_request *req)
 {
        struct smbd_server_connection *sconn = req->sconn;
        struct user_struct *vuser;
+       struct smbXsrv_session *session = NULL;
+       NTSTATUS status;
 
        START_PROFILE(SMBulogoffX);
 
@@ -2111,13 +2119,27 @@ void reply_ulogoffX(struct smb_request *req)
                return;
        }
 
-       /* in user level security we are supposed to close any files
-               open by this user */
-       if (vuser != NULL) {
-               file_close_user(sconn, req->vuid);
+       session = vuser->session;
+       vuser = NULL;
+
+       /*
+        * TODO: cancel all outstanding requests on the session
+        */
+       status = smbXsrv_session_logoff(session);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("reply_ulogoff: "
+                         "smbXsrv_session_logoff() failed: %s\n",
+                         nt_errstr(status)));
+               /*
+                * If we hit this case, there is something completely
+                * wrong, so we better disconnect the transport connection.
+                */
+               END_PROFILE(SMBulogoffX);
+               exit_server(__location__ ": smbXsrv_session_logoff failed");
+               return;
        }
 
-       invalidate_vuid(sconn, req->vuid);
+       TALLOC_FREE(session);
 
        reply_outbuf(req, 2, 0);
        SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
@@ -4794,9 +4816,12 @@ void reply_exit(struct smb_request *req)
        return;
 }
 
-/****************************************************************************
- Reply to a close - has to deal with closing a directory opened by NT SMB's.
-****************************************************************************/
+struct reply_close_state {
+       files_struct *fsp;
+       struct smb_request *smbreq;
+};
+
+static void do_smb1_close(struct tevent_req *req);
 
 void reply_close(struct smb_request *req)
 {
@@ -4823,21 +4848,13 @@ void reply_close(struct smb_request *req)
                return;
        }
 
-       if(fsp->is_directory) {
-               /*
-                * Special case - close NT SMB directory handle.
-                */
-               DEBUG(3,("close directory %s\n", fsp_fnum_dbg(fsp)));
-               status = close_file(req, fsp, NORMAL_CLOSE);
-       } else {
-               time_t t;
-               /*
-                * Close ordinary file.
-                */
+       DEBUG(3, ("Close %s fd=%d %s (numopen=%d)\n",
+                 fsp->is_directory ? "directory" : "file",
+                 fsp->fh->fd, fsp_fnum_dbg(fsp),
+                 conn->num_files_open));
 
-               DEBUG(3,("close fd=%d %s (numopen=%d)\n",
-                        fsp->fh->fd, fsp_fnum_dbg(fsp),
-                        conn->num_files_open));
+       if (!fsp->is_directory) {
+               time_t t;
 
                /*
                 * Take care of any time sent in the close.
@@ -4845,16 +4862,49 @@ void reply_close(struct smb_request *req)
 
                t = srv_make_unix_date3(req->vwv+1);
                set_close_write_time(fsp, convert_time_t_to_timespec(t));
+       }
+
+       if (fsp->num_aio_requests != 0) {
+
+               struct reply_close_state *state;
+
+               DEBUG(10, ("closing with aio %u requests pending\n",
+                          fsp->num_aio_requests));
 
                /*
-                * close_file() returns the unix errno if an error
-                * was detected on close - normally this is due to
-                * a disk full error. If not then it was probably an I/O error.
+                * We depend on the aio_extra destructor to take care of this
+                * close request once fsp->num_aio_request drops to 0.
                 */
 
-               status = close_file(req, fsp, NORMAL_CLOSE);
-       }  
+               fsp->deferred_close = tevent_wait_send(
+                       fsp, fsp->conn->sconn->ev_ctx);
+               if (fsp->deferred_close == NULL) {
+                       status = NT_STATUS_NO_MEMORY;
+                       goto done;
+               }
+
+               state = talloc(fsp, struct reply_close_state);
+               if (state == NULL) {
+                       TALLOC_FREE(fsp->deferred_close);
+                       status = NT_STATUS_NO_MEMORY;
+                       goto done;
+               }
+               state->fsp = fsp;
+               state->smbreq = talloc_move(fsp, &req);
+               tevent_req_set_callback(fsp->deferred_close, do_smb1_close,
+                                       state);
+               END_PROFILE(SMBclose);
+               return;
+       }
 
+       /*
+        * close_file() returns the unix errno if an error was detected on
+        * close - normally this is due to a disk full error. If not then it
+        * was probably an I/O error.
+        */
+
+       status = close_file(req, fsp, NORMAL_CLOSE);
+done:
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);
                END_PROFILE(SMBclose);
@@ -4866,6 +4916,49 @@ void reply_close(struct smb_request *req)
        return;
 }
 
+static void do_smb1_close(struct tevent_req *req)
+{
+       struct reply_close_state *state = tevent_req_callback_data(
+               req, struct reply_close_state);
+       struct smb_request *smbreq;
+       NTSTATUS status;
+       int ret;
+
+       ret = tevent_wait_recv(req);
+       TALLOC_FREE(req);
+       if (ret != 0) {
+               DEBUG(10, ("tevent_wait_recv returned %s\n",
+                          strerror(ret)));
+               /*
+                * Continue anyway, this should never happen
+                */
+       }
+
+       /*
+        * fsp->smb2_close_request right now is a talloc grandchild of
+        * fsp. When we close_file(fsp), it would go with it. No chance to
+        * reply...
+        */
+       smbreq = talloc_move(talloc_tos(), &state->smbreq);
+
+       status = close_file(smbreq, state->fsp, NORMAL_CLOSE);
+       if (NT_STATUS_IS_OK(status)) {
+               reply_outbuf(smbreq, 0, 0);
+       } else {
+               reply_nterror(smbreq, status);
+       }
+       if (!srv_send_smb(smbreq->sconn,
+                       (char *)smbreq->outbuf,
+                       true,
+                       smbreq->seqnum+1,
+                       IS_CONN_ENCRYPTED(smbreq->conn)||smbreq->encrypted,
+                       NULL)) {
+               exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
+                                   "failed.");
+       }
+       TALLOC_FREE(smbreq);
+}
+
 /****************************************************************************
  Reply to a writeclose (Core+ protocol).
 ****************************************************************************/
@@ -5333,7 +5426,7 @@ void reply_printqueue(struct smb_request *req)
                TALLOC_CTX *mem_ctx = talloc_tos();
                NTSTATUS status;
                WERROR werr;
-               const char *sharename = lp_servicename(SNUM(conn));
+               const char *sharename = lp_servicename(mem_ctx, SNUM(conn));
                struct rpc_pipe_client *cli = NULL;
                struct dcerpc_binding_handle *b = NULL;
                struct policy_handle handle;