diff options
Diffstat (limited to 'source3/smbd/trans2.c')
-rw-r--r-- | source3/smbd/trans2.c | 294 |
1 files changed, 199 insertions, 95 deletions
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index e37f6ffbfd..c3b5f9fa2f 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -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(¤t_user.nt_user_token->user_sids[i]); + sid_bytes += ndr_size_dom_sid( + ¤t_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(¤t_user.nt_user_token->user_sids[i]); + int sid_len = ndr_size_dom_sid( + ¤t_user.nt_user_token->user_sids[i], 0); sid_linearize(pdata + data_len, sid_len, ¤t_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: { @@ -2998,6 +3026,62 @@ cap_low = 0x%x, cap_high = 0x%x\n", } break; } + + case SMB_REQUEST_TRANSPORT_ENCRYPTION: + { + NTSTATUS status; + size_t param_len = 0; + size_t data_len = total_data; + + if (!lp_unix_extensions()) { + reply_nterror( + req, + NT_STATUS_INVALID_LEVEL); + return; + } + + if (lp_smb_encrypt(SNUM(conn)) == false) { + reply_nterror( + req, + NT_STATUS_NOT_SUPPORTED); + return; + } + + DEBUG( 4,("call_trans2setfsinfo: " + "request transport encrption.\n")); + + status = srv_request_encryption_setup(conn, + (unsigned char **)ppdata, + &data_len, + (unsigned char **)pparams, + ¶m_len); + + if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && + !NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + return; + } + + send_trans2_replies(conn, req, + *pparams, + param_len, + *ppdata, + data_len, + max_data_bytes); + + if (NT_STATUS_IS_OK(status)) { + /* Server-side transport + * encryption is now *on*. */ + status = srv_encryption_start(conn); + if (!NT_STATUS_IS_OK(status)) { + exit_server_cleanly( + "Failure in setting " + "up encrypted transport"); + } + } + return; + } + case SMB_FS_QUOTA_INFORMATION: { files_struct *fsp = NULL; @@ -3454,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; @@ -4386,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; @@ -5090,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) @@ -5101,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) { @@ -5188,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, @@ -6246,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; @@ -6536,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; } @@ -6605,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; @@ -6697,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); @@ -6723,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; } @@ -6777,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; } @@ -6808,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; } @@ -6858,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; } @@ -6905,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; } @@ -6918,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; @@ -6948,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; @@ -6984,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: @@ -7131,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; @@ -7166,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) { @@ -7312,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; |