Now conn is part of smb_request, we don't need it as
[nivanova/samba-autobuild/.git] / source3 / smbd / trans2.c
index 0e34284443581ac465108b1733887c5e30ee71f2..c3b5f9fa2f02d50ea13f4a96a7393d56d2ba7721 100644 (file)
@@ -575,7 +575,8 @@ static struct ea_list *ea_list_union(struct ea_list *name_list, struct ea_list *
   HACK ! Always assumes smb_setup field is zero.
 ****************************************************************************/
 
-void send_trans2_replies(struct smb_request *req,
+void send_trans2_replies(connection_struct *conn,
+                       struct smb_request *req,
                         const char *params,
                         int paramsize,
                         const char *pdata,
@@ -737,8 +738,10 @@ void send_trans2_replies(struct smb_request *req,
 
                /* Send the packet */
                show_msg((char *)req->outbuf);
-               if (!send_smb(smbd_server_fd(),(char *)req->outbuf))
-                       exit_server_cleanly("send_trans2_replies: send_smb failed.");
+               if (!srv_send_smb(smbd_server_fd(),
+                               (char *)req->outbuf,
+                               IS_CONN_ENCRYPTED(conn)))
+                       exit_server_cleanly("send_trans2_replies: srv_send_smb failed.");
 
                TALLOC_FREE(req->outbuf);
 
@@ -841,20 +844,6 @@ static void call_trans2open(connection_struct *conn,
                fname, (unsigned int)deny_mode, (unsigned int)open_attr,
                (unsigned int)open_ofun, open_size));
 
-       /* XXXX we need to handle passed times, sattr and flags */
-
-       status = unix_convert(ctx, conn, fname, False, &fname, NULL, &sbuf);
-       if (!NT_STATUS_IS_OK(status)) {
-               reply_nterror(req, status);
-               return;
-       }
-
-       status = check_name(conn, fname);
-       if (!NT_STATUS_IS_OK(status)) {
-               reply_nterror(req, status);
-               return;
-       }
-
        if (open_ofun == 0) {
                reply_nterror(req, NT_STATUS_OBJECT_NAME_COLLISION);
                return;
@@ -899,14 +888,22 @@ static void call_trans2open(connection_struct *conn,
                return;
        }
 
-       status = open_file_ntcreate(conn, req, fname, &sbuf,
-               access_mask,
-               share_mode,
-               create_disposition,
-               create_options,
-               open_attr,
-               oplock_request,
-               &smb_action, &fsp);
+       status = create_file(conn,                      /* conn */
+                            req,                       /* req */
+                            0,                         /* root_dir_fid */
+                            fname,                     /* fname */
+                            access_mask,               /* access_mask */
+                            share_mode,                /* share_access */
+                            create_disposition,        /* create_disposition*/
+                            create_options,            /* create_options */
+                            open_attr,                 /* file_attributes */
+                            oplock_request,            /* oplock_request */
+                            open_size,                 /* allocation_size */
+                            NULL,                      /* sd */
+                            ea_list,                   /* ea_list */
+                            &fsp,                      /* result */
+                            &smb_action,               /* pinfo */
+                            &sbuf);                    /* psbuf */
 
        if (!NT_STATUS_IS_OK(status)) {
                if (open_was_deferred(req->mid)) {
@@ -927,41 +924,6 @@ static void call_trans2open(connection_struct *conn,
                return;
        }
 
-       /* Save the requested allocation size. */
-       /* Allocate space for the file if a size hint is supplied */
-       if ((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) {
-               SMB_BIG_UINT allocation_size = (SMB_BIG_UINT)open_size;
-               if (allocation_size && (allocation_size > (SMB_BIG_UINT)size)) {
-                        fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
-                        if (fsp->is_directory) {
-                                close_file(fsp,ERROR_CLOSE);
-                                /* Can't set allocation size on a directory. */
-                               reply_nterror(req, NT_STATUS_ACCESS_DENIED);
-                               return;
-                        }
-                        if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
-                                close_file(fsp,ERROR_CLOSE);
-                               reply_nterror(req, NT_STATUS_DISK_FULL);
-                               return;
-                        }
-
-                       /* Adjust size here to return the right size in the reply.
-                          Windows does it this way. */
-                       size = fsp->initial_allocation_size;
-                } else {
-                        fsp->initial_allocation_size = smb_roundup(fsp->conn,(SMB_BIG_UINT)size);
-                }
-       }
-
-       if (ea_list && smb_action == FILE_WAS_CREATED) {
-               status = set_ea(conn, fsp, fname, ea_list);
-               if (!NT_STATUS_IS_OK(status)) {
-                       close_file(fsp,ERROR_CLOSE);
-                       reply_nterror(req, status);
-                       return;
-               }
-       }
-
        /* Realloc the size of parameters and data we will return */
        *pparams = (char *)SMB_REALLOC(*pparams, 30);
        if(*pparams == NULL ) {
@@ -997,7 +959,7 @@ static void call_trans2open(connection_struct *conn,
        }
 
        /* Send the required number of replies */
-       send_trans2_replies(req, params, 30, *ppdata, 0, max_data_bytes);
+       send_trans2_replies(conn, req, params, 30, *ppdata, 0, max_data_bytes);
 }
 
 /*********************************************************
@@ -2067,7 +2029,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
        SSVAL(params,6,0); /* Never an EA error */
        SSVAL(params,8,last_entry_off);
 
-       send_trans2_replies(req, params, 10, pdata, PTR_DIFF(p,pdata),
+       send_trans2_replies(conn, req, params, 10, pdata, PTR_DIFF(p,pdata),
                            max_data_bytes);
 
        if ((! *directory) && dptr_path(dptr_num)) {
@@ -2391,7 +2353,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
        SSVAL(params,4,0); /* Never an EA error */
        SSVAL(params,6,last_entry_off);
 
-       send_trans2_replies(req, params, 8, pdata, PTR_DIFF(p,pdata),
+       send_trans2_replies(conn, req, params, 8, pdata, PTR_DIFF(p,pdata),
                            max_data_bytes);
 
        return;
@@ -2430,6 +2392,27 @@ static void call_trans2qfsinfo(connection_struct *conn,
 
        info_level = SVAL(params,0);
 
+       if (IS_IPC(conn)) {
+               if (info_level != SMB_QUERY_CIFS_UNIX_INFO) {
+                       DEBUG(0,("call_trans2qfsinfo: not an allowed "
+                               "info level (0x%x) on IPC$.\n",
+                               (unsigned int)info_level));
+                       reply_nterror(req, NT_STATUS_ACCESS_DENIED);
+                       return;
+               }
+       }
+
+       if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) {
+               if (info_level != SMB_QUERY_CIFS_UNIX_INFO) {
+                       DEBUG(0,("call_trans2qfsinfo: encryption required "
+                               "and info level 0x%x sent.\n",
+                               (unsigned int)info_level));
+                       exit_server_cleanly("encryption required "
+                               "on connection");
+                       return;
+               }
+       }
+
        DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level));
 
        if(SMB_VFS_STAT(conn,".",&st)!=0) {
@@ -2729,22 +2712,45 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                {
                        bool large_write = lp_min_receive_file_size() &&
                                                !srv_is_signing_active();
+                       bool large_read = !srv_is_signing_active();
+                       int encrypt_caps = 0;
 
                        if (!lp_unix_extensions()) {
                                reply_nterror(req, NT_STATUS_INVALID_LEVEL);
                                return;
                        }
+
+                       switch (conn->encrypt_level) {
+                       case 0:
+                               encrypt_caps = 0;
+                               break;
+                       case 1:
+                       case Auto:
+                               encrypt_caps = CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP;
+                               break;
+                       case Required:
+                               encrypt_caps = CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP|
+                                               CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP;
+                               large_write = false;
+                               large_read = false;
+                               break;
+                       }
+
                        data_len = 12;
                        SSVAL(pdata,0,CIFS_UNIX_MAJOR_VERSION);
                        SSVAL(pdata,2,CIFS_UNIX_MINOR_VERSION);
-                       /* We have POSIX ACLs, pathname and locking capability. */
+
+                       /* We have POSIX ACLs, pathname, encryption, 
+                        * large read/write, and locking capability. */
+
                        SBIG_UINT(pdata,4,((SMB_BIG_UINT)(
                                        CIFS_UNIX_POSIX_ACLS_CAP|
                                        CIFS_UNIX_POSIX_PATHNAMES_CAP|
                                        CIFS_UNIX_FCNTL_LOCKS_CAP|
                                        CIFS_UNIX_EXTATTR_CAP|
                                        CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP|
-                                       CIFS_UNIX_LARGE_READ_CAP|
+                                       encrypt_caps|
+                                       (large_read ? CIFS_UNIX_LARGE_READ_CAP : 0) |
                                        (large_write ?
                                        CIFS_UNIX_LARGE_WRITE_CAP : 0))));
                        break;
@@ -2864,8 +2870,8 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                         */
                        for (i = 0, sid_bytes = 0;
                            i < current_user.nt_user_token->num_sids; ++i) {
-                               sid_bytes +=
-                                   sid_size(&current_user.nt_user_token->user_sids[i]);
+                               sid_bytes += ndr_size_dom_sid(
+                                       &current_user.nt_user_token->user_sids[i], 0);
                        }
 
                        /* SID list byte count */
@@ -2885,8 +2891,8 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                        /* SID list */
                        for (i = 0;
                            i < current_user.nt_user_token->num_sids; ++i) {
-                               int sid_len =
-                                   sid_size(&current_user.nt_user_token->user_sids[i]);
+                               int sid_len = ndr_size_dom_sid(
+                                       &current_user.nt_user_token->user_sids[i], 0);
 
                                sid_linearize(pdata + data_len, sid_len,
                                    &current_user.nt_user_token->user_sids[i]);
@@ -2913,7 +2919,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
        }
 
 
-       send_trans2_replies(req, params, 0, pdata, data_len,
+       send_trans2_replies(conn, req, params, 0, pdata, data_len,
                            max_data_bytes);
 
        DEBUG( 4, ( "%s info_level = %d\n",
@@ -2948,6 +2954,28 @@ static void call_trans2setfsinfo(connection_struct *conn,
 
        info_level = SVAL(params,2);
 
+       if (IS_IPC(conn)) {
+               if (info_level != SMB_REQUEST_TRANSPORT_ENCRYPTION &&
+                               info_level != SMB_SET_CIFS_UNIX_INFO) {
+                       DEBUG(0,("call_trans2setfsinfo: not an allowed "
+                               "info level (0x%x) on IPC$.\n",
+                               (unsigned int)info_level));
+                       reply_nterror(req, NT_STATUS_ACCESS_DENIED);
+                       return;
+               }
+       }
+
+       if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) {
+               if (info_level != SMB_REQUEST_TRANSPORT_ENCRYPTION) {
+                       DEBUG(0,("call_trans2setfsinfo: encryption required "
+                               "and info level 0x%x sent.\n",
+                               (unsigned int)info_level));
+                       exit_server_cleanly("encryption required "
+                               "on connection");
+                       return;
+               }
+       }
+
        switch(info_level) {
                case SMB_SET_CIFS_UNIX_INFO:
                        {
@@ -3012,6 +3040,13 @@ cap_low = 0x%x, cap_high = 0x%x\n",
                                        return;
                                }
 
+                               if (lp_smb_encrypt(SNUM(conn)) == false) {
+                                       reply_nterror(
+                                               req,
+                                               NT_STATUS_NOT_SUPPORTED);
+                                       return;
+                               }
+
                                DEBUG( 4,("call_trans2setfsinfo: "
                                        "request transport encrption.\n"));
 
@@ -3027,7 +3062,7 @@ cap_low = 0x%x, cap_high = 0x%x\n",
                                        return;
                                }
 
-                               send_trans2_replies(req,
+                               send_trans2_replies(conn, req,
                                                *pparams,
                                                param_len,
                                                *ppdata,
@@ -3503,7 +3538,7 @@ static void call_trans2qpipeinfo(connection_struct *conn,
                        return;
        }
 
-       send_trans2_replies(req, params, param_size, *ppdata, data_size,
+       send_trans2_replies(conn, req, params, param_size, *ppdata, data_size,
                            max_data_bytes);
 
        return;
@@ -4435,7 +4470,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
                        return;
        }
 
-       send_trans2_replies(req, params, param_size, *ppdata, data_size,
+       send_trans2_replies(conn, req, params, param_size, *ppdata, data_size,
                            max_data_bytes);
 
        return;
@@ -5139,8 +5174,7 @@ static NTSTATUS smb_set_posix_acl(connection_struct *conn,
 ****************************************************************************/
 
 static NTSTATUS smb_set_posix_lock(connection_struct *conn,
-                               const uint8 *inbuf,
-                               int length,
+                               const struct smb_request *req,
                                const char *pdata,
                                int total_data,
                                files_struct *fsp)
@@ -5150,6 +5184,7 @@ static NTSTATUS smb_set_posix_lock(connection_struct *conn,
        uint32 lock_pid;
        bool blocking_lock = False;
        enum brl_type lock_type;
+
        NTSTATUS status = NT_STATUS_OK;
 
        if (fsp == NULL || fsp->fh->fd == -1) {
@@ -5237,7 +5272,7 @@ static NTSTATUS smb_set_posix_lock(connection_struct *conn,
                         * onto the blocking lock queue.
                         */
                        if(push_blocking_lock_request(br_lck,
-                                               (char *)inbuf, length,
+                                               req,
                                                fsp,
                                                -1, /* infinite timeout. */
                                                0,
@@ -6295,7 +6330,7 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
                                DEBUG(3,("call_trans2setfilepathinfo: Cancelling print job (%s)\n", fsp->fsp_name ));
 
                                SSVAL(params,0,0);
-                               send_trans2_replies(req, params, 2,
+                               send_trans2_replies(conn, req, params, 2,
                                                    *ppdata, 0,
                                                    max_data_bytes);
                                return;
@@ -6585,8 +6620,7 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
                                reply_nterror(req, NT_STATUS_INVALID_LEVEL);
                                return;
                        }
-                       status = smb_set_posix_lock(conn, req->inbuf,
-                                                   smb_len(req->inbuf) + 4,
+                       status = smb_set_posix_lock(conn, req,
                                                    pdata, total_data, fsp);
                        break;
                }
@@ -6654,7 +6688,7 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
        }
 
        SSVAL(params,0,0);
-       send_trans2_replies(req, params, 2, *ppdata, data_return_size,
+       send_trans2_replies(conn, req, params, 2, *ppdata, data_return_size,
                            max_data_bytes);
   
        return;
@@ -6746,7 +6780,7 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req,
                return;
        }
 
-       status = create_directory(conn, directory);
+       status = create_directory(conn, req, directory);
 
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);
@@ -6772,7 +6806,7 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req,
 
        SSVAL(params,0,0);
 
-       send_trans2_replies(req, params, 2, *ppdata, 0, max_data_bytes);
+       send_trans2_replies(conn, req, params, 2, *ppdata, 0, max_data_bytes);
   
        return;
 }
@@ -6826,7 +6860,7 @@ static void call_trans2findnotifyfirst(connection_struct *conn,
        if(fnf_handle == 0)
                fnf_handle = 257;
 
-       send_trans2_replies(req, params, 6, *ppdata, 0, max_data_bytes);
+       send_trans2_replies(conn, req, params, 6, *ppdata, 0, max_data_bytes);
   
        return;
 }
@@ -6857,7 +6891,7 @@ static void call_trans2findnotifynext(connection_struct *conn,
        SSVAL(params,0,0); /* No changes */
        SSVAL(params,2,0); /* No EA errors */
 
-       send_trans2_replies(req, params, 4, *ppdata, 0, max_data_bytes);
+       send_trans2_replies(conn, req, params, 4, *ppdata, 0, max_data_bytes);
   
        return;
 }
@@ -6907,7 +6941,7 @@ static void call_trans2getdfsreferral(connection_struct *conn,
 
        SSVAL(req->inbuf, smb_flg2,
              SVAL(req->inbuf,smb_flg2) | FLAGS2_DFS_PATHNAMES);
-       send_trans2_replies(req,0,0,*ppdata,reply_size, max_data_bytes);
+       send_trans2_replies(conn, req,0,0,*ppdata,reply_size, max_data_bytes);
 
        return;
 }
@@ -6954,7 +6988,7 @@ static void call_trans2ioctl(connection_struct *conn,
                srvstr_push(pdata, req->flags2, pdata+18,
                            lp_servicename(SNUM(conn)), 13,
                            STR_ASCII|STR_TERMINATE); /* Service name */
-               send_trans2_replies(req, *pparams, 0, *ppdata, 32,
+               send_trans2_replies(conn, req, *pparams, 0, *ppdata, 32,
                                    max_data_bytes);
                return;
        }
@@ -6967,7 +7001,7 @@ static void call_trans2ioctl(connection_struct *conn,
  Reply to a SMBfindclose (stop trans2 directory search).
 ****************************************************************************/
 
-void reply_findclose(connection_struct *conn, struct smb_request *req)
+void reply_findclose(struct smb_request *req)
 {
        int dptr_num;
 
@@ -6997,7 +7031,7 @@ void reply_findclose(connection_struct *conn, struct smb_request *req)
  Reply to a SMBfindnclose (stop FINDNOTIFYFIRST directory search).
 ****************************************************************************/
 
-void reply_findnclose(connection_struct *conn, struct smb_request *req)
+void reply_findnclose(struct smb_request *req)
 {
        int dptr_num;
 
@@ -7033,6 +7067,17 @@ static void handle_trans2(connection_struct *conn, struct smb_request *req,
                SSVAL(req->inbuf,smb_flg2,req->flags2);
        }
 
+       if (conn->encrypt_level == Required && !req->encrypted) {
+               if (state->call != TRANSACT2_QFSINFO &&
+                               state->call != TRANSACT2_SETFSINFO) {
+                       DEBUG(0,("handle_trans2: encryption required "
+                               "with call 0x%x\n",
+                               (unsigned int)state->call));
+                       reply_nterror(req, NT_STATUS_ACCESS_DENIED);
+                       return;
+               }
+       }
+
        /* Now we must call the relevant TRANS2 function */
        switch(state->call)  {
        case TRANSACT2_OPEN:
@@ -7180,8 +7225,9 @@ static void handle_trans2(connection_struct *conn, struct smb_request *req,
  Reply to a SMBtrans2.
  ****************************************************************************/
 
-void reply_trans2(connection_struct *conn, struct smb_request *req)
+void reply_trans2(struct smb_request *req)
 {
+       connection_struct *conn = req->conn;
        unsigned int dsoff;
        unsigned int dscnt;
        unsigned int psoff;
@@ -7215,12 +7261,20 @@ void reply_trans2(connection_struct *conn, struct smb_request *req)
                return;
        }
 
-       if (IS_IPC(conn) && (tran_call != TRANSACT2_OPEN)
-            && (tran_call != TRANSACT2_GET_DFS_REFERRAL)
-            && (tran_call != TRANSACT2_QFILEINFO)) {
-               reply_doserror(req, ERRSRV, ERRaccess);
-               END_PROFILE(SMBtrans2);
-               return;
+       if (IS_IPC(conn)) {
+               switch (tran_call) {
+               /* List the allowed trans2 calls on IPC$ */
+               case TRANSACT2_OPEN:
+               case TRANSACT2_GET_DFS_REFERRAL:
+               case TRANSACT2_QFILEINFO:
+               case TRANSACT2_QFSINFO:
+               case TRANSACT2_SETFSINFO:
+                       break;
+               default:
+                       reply_doserror(req, ERRSRV, ERRaccess);
+                       END_PROFILE(SMBtrans2);
+                       return;
+               }
        }
 
        if ((state = TALLOC_P(conn->mem_ctx, struct trans_state)) == NULL) {
@@ -7361,8 +7415,9 @@ void reply_trans2(connection_struct *conn, struct smb_request *req)
  Reply to a SMBtranss2
  ****************************************************************************/
 
-void reply_transs2(connection_struct *conn, struct smb_request *req)
+void reply_transs2(struct smb_request *req)
 {
+       connection_struct *conn = req->conn;
        unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp;
        struct trans_state *state;
        int size;