2 Unix SMB/Netbios implementation.
4 SMB NT transaction handling
5 Copyright (C) Jeremy Allison 1994-1998
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 extern int DEBUGLEVEL
;
26 extern connection_struct Connections
[];
27 extern files_struct Files
[];
29 extern int oplock_sock
;
30 extern int smb_read_error
;
31 extern int global_oplock_break
;
33 static char *known_nt_pipes
[] = {
46 /****************************************************************************
47 reply to an NT create and X call.
48 ****************************************************************************/
50 THIS IS JUST CRIBBED FROM REPLY
.C AT PRESENT AND IS A WORK
53 int reply_ntcreate_and_X(char *inbuf
,char *outbuf
,int length
,int bufsize
)
56 int cnum
= SVAL(inbuf
,smb_tid
);
58 uint32 flags
= SIVAL(inbuf
,smb_ntcreate_Flags
);
59 uint32 desired_access
= SIVAL(inbuf
,smb_ntcreate_DesiredAccess
);
60 uint32 file_attributes
= SIVAL(inbuf
,smb_ntcreate_FileAttributes
);
61 uint32 share_access
= SIVAL(inbuf
,smb_ntcreate_ShareAccess
);
62 uint32 create_disposition
= SIVAL(inbuf
,smb_ntcreate_CreateDisposition
);
66 int smb_attr
= SVAL(inbuf
,smb_vwv5
);
67 /* Breakout the oplock request bits so we can set the
68 reply bits separately. */
69 BOOL ex_oplock_request
= flags
&
70 BOOL core_oplock_request
= CORE_OPLOCK_REQUEST(inbuf
);
71 BOOL oplock_request
= ex_oplock_request
| core_oplock_request
;
73 int size
=0,fmode
=0,mtime
=0,rmode
=0;
76 BOOL bad_path
= False
;
79 /* If it's an IPC, pass off the pipe handler. */
81 return nt_open_pipe_and_X(inbuf
,outbuf
,length
,bufsize
);
83 /* If it's a request for a directory open, fail it. */
84 if(flags
& OPEN_DIRECTORY
)
85 return(ERROR(ERRSRV
,ERRfilespecs
));
88 * We need to construct the open_and_X ofun value from the
89 * NT values, as that's what our code is structured to accept.
92 switch( create_disposition
) {
94 /* create if not exist, fail if exist */
98 /* create if not exist, trunc if exist */
102 /* fail if not exist, open if exists */
106 /* create if not exist, open if exists */
109 case TRUNCATE_EXISTING
:
110 /* fail if not exist, truncate if exists */
114 DEBUG(0,("reply_ntcreate_and_X: Incorrect value for create_disposition = %d\n",
115 create_disposition
));
116 return(ERROR(ERRDOS
,ERRbadaccess
));
120 * Now contruct the smb_open_mode value from the desired access
121 * and the share access.
124 switch( desired_access
& (FILE_READ_DATA
|FILE_WRITE_DATA
) ) {
128 case FILE_WRITE_DATA
:
131 case FILE_READ_DATA
|FILE_WRITE_DATA
:
135 DEBUG(0,("reply_ntcreate_and_X: Incorrect value for desired_access = %x\n",
137 return(ERROR(ERRDOS
,ERRbadaccess
));
140 /* Add in the requested share mode - ignore FILE_SHARE_DELETE for now. */
141 switch( share_access
& (FILE_SHARE_READ
|FILE_SHARE_WRITE
)) {
142 case FILE_SHARE_READ
:
143 smb_open_mode
|= (DENY_WRITE
<<4);
145 case FILE_SHARE_WRITE
:
146 smb_open_mode
|= (DENY_READ
<<4);
148 case (FILE_SHARE_READ
|FILE_SHARE_WRITE
):
149 smb_open_mode
|= (DENY_NONE
<<4);
151 case FILE_SHARE_NONE
:
152 smb_open_mode
|= (DENY_ALL
<<4);
157 * Handle a O_SYNC request.
159 if(file_attributes
& FILE_FLAG_WRITE_THROUGH
)
160 smb_open_mode
|= (1<<14);
162 pstrcpy(fname
,smb_buf(inbuf
));
163 unix_convert(fname
,cnum
,0,&bad_path
);
165 fnum
= find_free_file();
167 return(ERROR(ERRSRV
,ERRnofids
));
168 if (!check_name(fname
,cnum
))
170 if((errno
== ENOENT
) && bad_path
)
172 unix_ERR_class
= ERRDOS
;
173 unix_ERR_code
= ERRbadpath
;
175 Files
[fnum
].reserved
= False
;
176 return(UNIXERROR(ERRDOS
,ERRnoaccess
));
179 unixmode
= unix_mode(cnum
,smb_attr
| aARCH
);
181 open_file_shared(fnum
,cnum
,fname
,smb_open_mode
,smb_ofun
,unixmode
,
182 oplock_request
, &rmode
,&smb_action
);
188 if((errno
== ENOENT
) && bad_path
)
190 unix_ERR_class
= ERRDOS
;
191 unix_ERR_code
= ERRbadpath
;
193 Files
[fnum
].reserved
= False
;
194 return(UNIXERROR(ERRDOS
,ERRnoaccess
));
197 if (fstat(fsp
->fd_ptr
->fd
,&sbuf
) != 0) {
198 close_file(fnum
,False
);
199 return(ERROR(ERRDOS
,ERRnoaccess
));
203 fmode
= dos_mode(cnum
,fname
,&sbuf
);
204 mtime
= sbuf
.st_mtime
;
206 close_file(fnum
,False
);
207 return(ERROR(ERRDOS
,ERRnoaccess
));
210 /* If the caller set the extended oplock request bit
211 and we granted one (by whatever means) - set the
212 correct bit for extended oplock reply.
215 if (ex_oplock_request
&& lp_fake_oplocks(SNUM(cnum
))) {
216 smb_action
|= EXTENDED_OPLOCK_GRANTED
;
219 if(ex_oplock_request
&& fsp
->granted_oplock
) {
220 smb_action
|= EXTENDED_OPLOCK_GRANTED
;
223 /* If the caller set the core oplock request bit
224 and we granted one (by whatever means) - set the
225 correct bit for core oplock reply.
228 if (core_oplock_request
&& lp_fake_oplocks(SNUM(cnum
))) {
229 CVAL(outbuf
,smb_flg
) |= CORE_OPLOCK_GRANTED
;
232 if(core_oplock_request
&& fsp
->granted_oplock
) {
233 CVAL(outbuf
,smb_flg
) |= CORE_OPLOCK_GRANTED
;
236 set_message(outbuf
,15,0,True
);
237 SSVAL(outbuf
,smb_vwv2
,fnum
);
238 SSVAL(outbuf
,smb_vwv3
,fmode
);
239 if(lp_dos_filetime_resolution(SNUM(cnum
)) )
240 put_dos_date3(outbuf
,smb_vwv4
,mtime
& ~1);
242 put_dos_date3(outbuf
,smb_vwv4
,mtime
);
243 SIVAL(outbuf
,smb_vwv6
,size
);
244 SSVAL(outbuf
,smb_vwv8
,rmode
);
245 SSVAL(outbuf
,smb_vwv11
,smb_action
);
249 return chain_reply(inbuf
,outbuf
,length
,bufsize
);
252 /****************************************************************************
253 reply to an unsolicited SMBNTtranss - just ignore it!
254 ****************************************************************************/
256 int reply_nttranss(char *inbuf
,char *outbuf
,int length
,int bufsize
)
258 DEBUG(4,("Ignoring nttranss of length %d\n",length
));
262 /****************************************************************************
263 reply to a SMBNTtrans
264 ****************************************************************************/
266 int reply_nttrans(char *inbuf
,char *outbuf
,int length
,int bufsize
)
269 int cnum
= SVAL(inbuf
,smb_tid
);
271 uint16 max_setup_count
= CVAL(inbuf
, smb_nt_MaxSetupCount
);
272 uint32 max_parameter_count
= IVAL(inbuf
, smb_nt_MaxParameterCount
);
273 uint32 max_data_count
= IVAL(inbuf
,smb_nt_MaxDataCount
);
275 uint32 total_parameter_count
= IVAL(inbuf
, smb_nt_TotalParameterCount
);
276 uint32 total_data_count
= IVAL(inbuf
, smb_nt_TotalDataCount
);
277 uint32 parameter_count
= IVAL(inbuf
,smb_nt_ParameterCount
);
278 uint32 parameter_offset
= IVAL(inbuf
,smb_nt_ParameterOffset
);
279 uint32 data_count
= IVAL(inbuf
,smb_nt_DataCount
);
280 uint32 data_offset
= IVAL(inbuf
,smb_nt_DataOffset
);
281 uint16 setup_count
= SVAL(inbuf
,smb_nt_SetupCount
);
282 uint16 function_code
= SVAL( inbuf
, smb_nt_Function
);
283 char *params
= NULL
, *data
= NULL
, *setup
= NULL
;
284 uint32 num_params_sofar
, num_data_sofar
;
286 if(global_oplock_break
&& (function_code
== NT_TRANSACT_CREATE
)) {
288 * Queue this open message as we are the process of an oplock break.
291 DEBUG(2,("%s: reply_nttrans: queueing message NT_TRANSACT_CREATE \
292 due to being in oplock break state.\n", timestring() ));
294 push_smb_message( inbuf
, length
);
298 outsize
= set_message(outbuf
,0,0,True
);
301 * All nttrans messages we handle have smb_wcnt == 19 + setup_count.
302 * Ensure this is so as a sanity check.
305 if(CVAL(inbuf
, smb_wcnt
) != 19 + setup_count
) {
306 DEBUG(2,("Invalid smb_wcnt in trans2 call\n"));
307 return(ERROR(ERRSRV
,ERRerror
));
310 /* Allocate the space for the setup, the maximum needed parameters and data */
313 setup
= (char *)malloc(setup_count
);
314 if (total_parameter_count
> 0)
315 params
= (char *)malloc(total_parameter_count
);
316 if (total_data_count
> 0)
317 data
= (char *)malloc(total_data_count
);
319 if ((total_parameter_count
&& !params
) || (total_data_count
&& !data
) ||
320 (setup_count
&& !setup
)) {
321 DEBUG(0,("reply_nttrans : Out of memory\n"));
322 return(ERROR(ERRDOS
,ERRnomem
));
325 /* Copy the param and data bytes sent with this request into
327 num_params_sofar
= parameter_count
;
328 num_data_sofar
= data_count
;
330 if (parameter_count
> total_parameter_count
|| data_count
> total_data_count
)
331 exit_server("reply_nttrans: invalid sizes in packet.\n");
334 memcpy( setup
, &inbuf
[smb_nt_SetupStart
], setup_count
);
336 memcpy( params
, smb_base(inbuf
) + parameter_offset
, parameter_count
);
338 memcpy( data
, smb_base(inbuf
) + data_offset
, data_count
);
340 if(num_data_sofar
< total_data_count
|| num_params_sofar
< total_parameter_count
) {
341 /* We need to send an interim response then receive the rest
342 of the parameter/data bytes */
343 outsize
= set_message(outbuf
,0,0,True
);
344 send_smb(Client
,outbuf
);
346 while( num_data_sofar
< total_data_count
|| num_params_sofar
< total_parameter_count
) {
349 ret
= receive_next_smb(Client
,oplock_sock
,inbuf
,bufsize
,
352 if((ret
&& (CVAL(inbuf
, smb_com
) != SMBnttranss
)) || !ret
) {
353 outsize
= set_message(outbuf
,0,0,True
);
355 DEBUG(0,("reply_nttrans: Invalid secondary nttrans packet\n"));
357 DEBUG(0,("reply_nttrans: %s in getting secondary nttrans response.\n",
358 (smb_read_error
== READ_ERROR
) ? "error" : "timeout" ));
365 return(ERROR(ERRSRV
,ERRerror
));
368 /* Revise total_params and total_data in case they have changed downwards */
369 total_parameter_count
= SIVAL(inbuf
, smb_nts_TotalParameterCount
);
370 total_data_count
= SIVAL(inbuf
, smb_nts_TotalDataCount
);
371 num_params_sofar
+= (parameter_count
= SIVAL(inbuf
,smb_nts_ParameterCount
));
372 num_data_sofar
+= ( data_count
= SIVAL(inbuf
, smb_nts_DataCount
));
373 if (num_params_sofar
> total_parameter_count
|| num_data_sofar
> total_data_count
)
374 exit_server("reply_nttrans2: data overflow in secondary nttrans packet\n");
376 memcpy( ¶ms
[ SIVAL(inbuf
, smb_nts_ParameterDisplacement
)],
377 smb_base(inbuf
) + SVAL(inbuf
, smb_nts_ParameterOffset
), parameter_count
);
378 memcpy( &data
[SVAL(inbuf
, smb_nts_DataDisplacement
)],
379 smb_base(inbuf
)+ SVAL(inbuf
, smb_nts_DataOffset
), data_count
);
383 if (Protocol
>= PROTOCOL_NT1
) {
384 uint16 flg2
= SVAL(outbuf
,smb_flg2
);
385 SSVAL(outbuf
,smb_flg2
,flg2
| 0x40); /* IS_LONG_NAME */
388 /* Now we must call the relevant NT_TRANS function */
389 switch(function_code
) {
390 case NT_TRANSACT_CREATE
:
391 outsize
= call_nt_transact_create(inbuf
, outbuf
, bufsize
, cnum
,
392 &setup
, ¶ms
, &data
);
394 case NT_TRANSACT_IOCTL
:
395 outsize
= call_nt_transact_ioctl(inbuf
, outbuf
, bufsize
, cnum
,
396 &setup
, ¶ms
, &data
);
398 case NT_TRANSACT_SET_SECURITY_DESC
:
399 outsize
= call_nt_transact_set_security_desc(inbuf
, outbuf
, length
, bufsize
, cnum
,
400 &setup
, ¶ms
, &data
);
402 case NT_TRANSACT_NOTIFY_CHANGE
:
403 outsize
= call_nt_transact_notify_change(inbuf
, outbuf
, length
, bufsize
, cnum
,
404 &setup
, ¶ms
, &data
);
406 case NT_TRANSACT_RENAME
:
407 outsize
= call_nt_transact_rename(inbuf
, outbuf
, length
, bufsize
, cnum
,
408 &setup
, ¶ms
, &data
);
410 case NT_TRANSACT_QUERY_SECURITY_DESC
:
411 outsize
= call_nt_transact_query_security_desc(inbuf
, outbuf
, length
, bufsize
, cnum
,
412 &setup
, ¶ms
, &data
, total_data
);
415 /* Error in request */
416 DEBUG(0,("reply_nttrans: %s Unknown request %d in nttrans call\n",timestring(),
424 return (ERROR(ERRSRV
,ERRerror
));
427 /* As we do not know how many data packets will need to be
428 returned here the various call_nt_transact_xxxx calls
429 must send their own. Thus a call_nt_transact_xxxx routine only
430 returns a value other than -1 when it wants to send
440 return outsize
; /* If a correct response was needed the call_nt_transact_xxxx
441 calls have already sent it. If outsize != -1 then it is
442 returning an error packet. */