nttrans.c: More code towards NT protocol.
[Samba/gebeck_regimport.git] / source / smbd / nttrans.c
blob9d6f0d402185c524ea39d509c550be43b4fb2759
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
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.
22 #include "includes.h"
24 extern int DEBUGLEVEL;
25 extern int Protocol;
26 extern connection_struct Connections[];
27 extern files_struct Files[];
28 extern int Client;
29 extern int oplock_sock;
30 extern int smb_read_error;
31 extern int global_oplock_break;
33 static char *known_nt_pipes[] = {
34 "\\LANMAN",
35 "\\srvsvc",
36 "\\samr",
37 "\\wkssvc",
38 "\\NETLOGON",
39 "\\ntlsa",
40 "\\ntsvcs",
41 "\\lsass",
42 "\\lsarpc",
43 NULL
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
51 IN PROGRESS. JRA.
53 int reply_ntcreate_and_X(char *inbuf,char *outbuf,int length,int bufsize)
55 pstring fname;
56 int cnum = SVAL(inbuf,smb_tid);
57 int fnum = -1;
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);
64 int smb_ofun;
65 int smb_open_mode;
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;
72 int unixmode;
73 int size=0,fmode=0,mtime=0,rmode=0;
74 struct stat sbuf;
75 int smb_action = 0;
76 BOOL bad_path = False;
77 files_struct *fsp;
79 /* If it's an IPC, pass off the pipe handler. */
80 if (IS_IPC(cnum))
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));
87 /*
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.
90 */
92 switch( create_disposition ) {
93 case CREATE_NEW:
94 /* create if not exist, fail if exist */
95 smb_ofun = 0x10;
96 break;
97 case CREATE_ALWAYS:
98 /* create if not exist, trunc if exist */
99 smb_ofun = 0x12;
100 break;
101 case OPEN_EXISTING:
102 /* fail if not exist, open if exists */
103 smb_ofun = 0x1;
104 break;
105 case OPEN_ALWAYS:
106 /* create if not exist, open if exists */
107 smb_ofun = 0x11;
108 break;
109 case TRUNCATE_EXISTING:
110 /* fail if not exist, truncate if exists */
111 smb_ofun = 0x2;
112 break;
113 default:
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) ) {
125 case FILE_READ_DATA:
126 smb_open_mode = 0;
127 break;
128 case FILE_WRITE_DATA:
129 smb_open_mode = 1;
130 break;
131 case FILE_READ_DATA|FILE_WRITE_DATA:
132 smb_open_mode = 2;
133 break;
134 default:
135 DEBUG(0,("reply_ntcreate_and_X: Incorrect value for desired_access = %x\n",
136 desired_access));
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);
144 break;
145 case FILE_SHARE_WRITE:
146 smb_open_mode |= (DENY_READ<<4);
147 break;
148 case (FILE_SHARE_READ|FILE_SHARE_WRITE):
149 smb_open_mode |= (DENY_NONE<<4);
150 break;
151 case FILE_SHARE_NONE:
152 smb_open_mode |= (DENY_ALL<<4);
153 break;
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();
166 if (fnum < 0)
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);
184 fsp = &Files[fnum];
186 if (!fsp->open)
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));
202 size = sbuf.st_size;
203 fmode = dos_mode(cnum,fname,&sbuf);
204 mtime = sbuf.st_mtime;
205 if (fmode & aDIR) {
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);
241 else
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);
247 chain_fnum = fnum;
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));
259 return(-1);
262 /****************************************************************************
263 reply to a SMBNTtrans
264 ****************************************************************************/
266 int reply_nttrans(char *inbuf,char *outbuf,int length,int bufsize)
268 int outsize = 0;
269 int cnum = SVAL(inbuf,smb_tid);
270 #if 0
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);
274 #endif
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);
295 return -1;
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 */
312 if(setup_count > 0)
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
326 the params buffer */
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");
333 if(setup)
334 memcpy( setup, &inbuf[smb_nt_SetupStart], setup_count);
335 if(params)
336 memcpy( params, smb_base(inbuf) + parameter_offset, parameter_count);
337 if(data)
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) {
347 BOOL ret;
349 ret = receive_next_smb(Client,oplock_sock,inbuf,bufsize,
350 SMB_SECONDARY_WAIT);
352 if((ret && (CVAL(inbuf, smb_com) != SMBnttranss)) || !ret) {
353 outsize = set_message(outbuf,0,0,True);
354 if(ret)
355 DEBUG(0,("reply_nttrans: Invalid secondary nttrans packet\n"));
356 else
357 DEBUG(0,("reply_nttrans: %s in getting secondary nttrans response.\n",
358 (smb_read_error == READ_ERROR) ? "error" : "timeout" ));
359 if(params)
360 free(params);
361 if(data)
362 free(data);
363 if(setup)
364 free(setup);
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( &params[ 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, &params, &data);
393 break;
394 case NT_TRANSACT_IOCTL:
395 outsize = call_nt_transact_ioctl(inbuf, outbuf, bufsize, cnum,
396 &setup, &params, &data);
397 break;
398 case NT_TRANSACT_SET_SECURITY_DESC:
399 outsize = call_nt_transact_set_security_desc(inbuf, outbuf, length, bufsize, cnum,
400 &setup, &params, &data);
401 break;
402 case NT_TRANSACT_NOTIFY_CHANGE:
403 outsize = call_nt_transact_notify_change(inbuf, outbuf, length, bufsize, cnum,
404 &setup, &params, &data);
405 break;
406 case NT_TRANSACT_RENAME:
407 outsize = call_nt_transact_rename(inbuf, outbuf, length, bufsize, cnum,
408 &setup, &params, &data);
409 break;
410 case NT_TRANSACT_QUERY_SECURITY_DESC:
411 outsize = call_nt_transact_query_security_desc(inbuf, outbuf, length, bufsize, cnum,
412 &setup, &params, &data, total_data);
413 break;
414 default:
415 /* Error in request */
416 DEBUG(0,("reply_nttrans: %s Unknown request %d in nttrans call\n",timestring(),
417 tran_call));
418 if(setup)
419 free(setup);
420 if(params)
421 free(params);
422 if(data)
423 free(data);
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
431 an error packet.
434 if(setup)
435 free(setup);
436 if(params)
437 free(params);
438 if(data)
439 free(data);
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. */