chgpasswd.c: Changed back to getsmb... from getsam...
[kai/samba-autobuild/.git] / source3 / smbd / nttrans.c
1 /*
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    SMB NT transaction handling
5    Copyright (C) Jeremy Allison 1994-1998
6
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.
11
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.
16
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.
20 */
21
22 #include "includes.h"
23
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;
32
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
44 };
45
46 /****************************************************************************
47   reply to an NT create and X call.
48 ****************************************************************************/
49
50 THIS IS JUST CRIBBED FROM REPLY.C AT PRESENT AND IS A WORK
51 IN PROGRESS. JRA.
52
53 int reply_ntcreate_and_X(char *inbuf,char *outbuf,int length,int bufsize)
54 {  
55   pstring fname;
56   int cnum = SVAL(inbuf,smb_tid);
57   int fnum = -1;
58   int smb_mode = SVAL(inbuf,smb_vwv3);
59   int smb_attr = SVAL(inbuf,smb_vwv5);
60   /* Breakout the oplock request bits so we can set the
61      reply bits separately. */
62   BOOL ex_oplock_request = EXTENDED_OPLOCK_REQUEST(inbuf);
63   BOOL core_oplock_request = CORE_OPLOCK_REQUEST(inbuf);
64   BOOL oplock_request = ex_oplock_request | core_oplock_request;
65 #if 0
66   int open_flags = SVAL(inbuf,smb_vwv2);
67   int smb_sattr = SVAL(inbuf,smb_vwv4);
68   uint32 smb_time = make_unix_date3(inbuf+smb_vwv6);
69 #endif 
70   int smb_ofun = SVAL(inbuf,smb_vwv8);
71   int unixmode;
72   int size=0,fmode=0,mtime=0,rmode=0;
73   struct stat sbuf;
74   int smb_action = 0;
75   BOOL bad_path = False;
76   files_struct *fsp;
77     
78   /* If it's an IPC, pass off the pipe handler. */
79   if (IS_IPC(cnum))
80     return reply_open_pipe_and_X(inbuf,outbuf,length,bufsize);
81     
82   /* XXXX we need to handle passed times, sattr and flags */
83     
84   pstrcpy(fname,smb_buf(inbuf));
85   unix_convert(fname,cnum,0,&bad_path);
86     
87   fnum = find_free_file();
88   if (fnum < 0)
89     return(ERROR(ERRSRV,ERRnofids));
90   if (!check_name(fname,cnum))
91   { 
92     if((errno == ENOENT) && bad_path)
93     {
94       unix_ERR_class = ERRDOS;
95       unix_ERR_code = ERRbadpath;
96     }
97     Files[fnum].reserved = False;
98     return(UNIXERROR(ERRDOS,ERRnoaccess));
99   } 
100   
101   unixmode = unix_mode(cnum,smb_attr | aARCH);
102     
103   open_file_shared(fnum,cnum,fname,smb_mode,smb_ofun,unixmode,
104            oplock_request, &rmode,&smb_action);
105
106   fsp = &Files[fnum];
107     
108   if (!fsp->open)
109   { 
110     if((errno == ENOENT) && bad_path)
111     {
112       unix_ERR_class = ERRDOS;
113       unix_ERR_code = ERRbadpath;
114     }
115     Files[fnum].reserved = False;
116     return(UNIXERROR(ERRDOS,ERRnoaccess));
117   } 
118   
119   if (fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
120     close_file(fnum,False);
121     return(ERROR(ERRDOS,ERRnoaccess));
122   } 
123   
124   size = sbuf.st_size;
125   fmode = dos_mode(cnum,fname,&sbuf);
126   mtime = sbuf.st_mtime;
127   if (fmode & aDIR) {
128     close_file(fnum,False);
129     return(ERROR(ERRDOS,ERRnoaccess));
130   } 
131   
132   /* If the caller set the extended oplock request bit
133      and we granted one (by whatever means) - set the
134      correct bit for extended oplock reply.
135    */
136     
137   if (ex_oplock_request && lp_fake_oplocks(SNUM(cnum))) {
138     smb_action |= EXTENDED_OPLOCK_GRANTED;
139   } 
140   
141   if(ex_oplock_request && fsp->granted_oplock) {
142     smb_action |= EXTENDED_OPLOCK_GRANTED;
143   } 
144   
145   /* If the caller set the core oplock request bit
146      and we granted one (by whatever means) - set the
147      correct bit for core oplock reply.
148    */
149     
150   if (core_oplock_request && lp_fake_oplocks(SNUM(cnum))) {
151     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
152   } 
153   
154   if(core_oplock_request && fsp->granted_oplock) {
155     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
156   } 
157   
158   set_message(outbuf,15,0,True);
159   SSVAL(outbuf,smb_vwv2,fnum);
160   SSVAL(outbuf,smb_vwv3,fmode);
161   if(lp_dos_filetime_resolution(SNUM(cnum)) )
162     put_dos_date3(outbuf,smb_vwv4,mtime & ~1);
163   else
164     put_dos_date3(outbuf,smb_vwv4,mtime);
165   SIVAL(outbuf,smb_vwv6,size);
166   SSVAL(outbuf,smb_vwv8,rmode);
167   SSVAL(outbuf,smb_vwv11,smb_action);
168     
169   chain_fnum = fnum;
170     
171   return chain_reply(inbuf,outbuf,length,bufsize);
172 }   
173
174 /****************************************************************************
175   reply to an unsolicited SMBNTtranss - just ignore it!
176 ****************************************************************************/
177
178 int reply_nttranss(char *inbuf,char *outbuf,int length,int bufsize)
179 {
180   DEBUG(4,("Ignoring nttranss of length %d\n",length));
181   return(-1);
182 }
183
184 /****************************************************************************
185   reply to a SMBNTtrans
186 ****************************************************************************/
187
188 int reply_nttrans(char *inbuf,char *outbuf,int length,int bufsize)
189 {
190   int outsize = 0;
191   int cnum = SVAL(inbuf,smb_tid);
192 #if 0
193   uint16 max_setup_count = CVAL(inbuf, smb_nt_MaxSetupCount);
194   uint32 max_parameter_count = IVAL(inbuf, smb_nt_MaxParameterCount);
195   uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount);
196 #endif
197   uint32 total_parameter_count = IVAL(inbuf, smb_nt_TotalParameterCount);
198   uint32 total_data_count = IVAL(inbuf, smb_nt_TotalDataCount);
199   uint32 parameter_count = IVAL(inbuf,smb_nt_ParameterCount);
200   uint32 parameter_offset = IVAL(inbuf,smb_nt_ParameterOffset);
201   uint32 data_count = IVAL(inbuf,smb_nt_DataCount);
202   uint32 data_offset = IVAL(inbuf,smb_nt_DataOffset);
203   uint16 setup_count = SVAL(inbuf,smb_nt_SetupCount);
204   uint16 function_code = SVAL( inbuf, smb_nt_Function);
205   char *params = NULL, *data = NULL, *setup = NULL;
206   uint32 num_params_sofar, num_data_sofar;
207
208   if(global_oplock_break && (function_code == NT_TRANSACT_CREATE)) {
209     /*
210      * Queue this open message as we are the process of an oplock break.
211      */
212
213     DEBUG(2,("%s: reply_nttrans: queueing message NT_TRANSACT_CREATE \
214 due to being in oplock break state.\n", timestring() ));
215
216     push_smb_message( inbuf, length);
217     return -1;
218   }
219
220   outsize = set_message(outbuf,0,0,True);
221
222   /* 
223    * All nttrans messages we handle have smb_wcnt == 19 + setup_count.
224    * Ensure this is so as a sanity check.
225    */
226
227   if(CVAL(inbuf, smb_wcnt) != 19 + setup_count) {
228     DEBUG(2,("Invalid smb_wcnt in trans2 call\n"));
229     return(ERROR(ERRSRV,ERRerror));
230   }
231     
232   /* Allocate the space for the setup, the maximum needed parameters and data */
233
234   if(setup_count > 0)
235     setup = (char *)malloc(setup_count);
236   if (total_parameter_count > 0)
237     params = (char *)malloc(total_parameter_count);
238   if (total_data_count > 0)
239     data = (char *)malloc(total_data_count);
240  
241   if ((total_parameter_count && !params)  || (total_data_count && !data) ||
242       (setup_count && !setup)) {
243     DEBUG(0,("reply_nttrans : Out of memory\n"));
244     return(ERROR(ERRDOS,ERRnomem));
245   }
246
247   /* Copy the param and data bytes sent with this request into
248      the params buffer */
249   num_params_sofar = parameter_count;
250   num_data_sofar = data_count;
251
252   if (parameter_count > total_parameter_count || data_count > total_data_count)
253     exit_server("reply_nttrans: invalid sizes in packet.\n");
254
255   if(setup)
256     memcpy( setup, &inbuf[smb_nt_SetupStart], setup_count);
257   if(params)
258     memcpy( params, smb_base(inbuf) + parameter_offset, parameter_count);
259   if(data)
260     memcpy( data, smb_base(inbuf) + data_offset, data_count);
261
262   if(num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) {
263     /* We need to send an interim response then receive the rest
264        of the parameter/data bytes */
265     outsize = set_message(outbuf,0,0,True);
266     send_smb(Client,outbuf);
267
268     while( num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) {
269       BOOL ret;
270
271       ret = receive_next_smb(Client,oplock_sock,inbuf,bufsize,
272                              SMB_SECONDARY_WAIT);
273
274       if((ret && (CVAL(inbuf, smb_com) != SMBnttranss)) || !ret) {
275         outsize = set_message(outbuf,0,0,True);
276         if(ret)
277           DEBUG(0,("reply_nttrans: Invalid secondary nttrans packet\n"));
278         else
279           DEBUG(0,("reply_nttrans: %s in getting secondary nttrans response.\n",
280                 (smb_read_error == READ_ERROR) ? "error" : "timeout" ));
281         if(params)
282           free(params);
283         if(data)
284           free(data);
285         if(setup)
286           free(setup);
287         return(ERROR(ERRSRV,ERRerror));
288       }
289       
290       /* Revise total_params and total_data in case they have changed downwards */
291       total_parameter_count = SIVAL(inbuf, smb_nts_TotalParameterCount);
292       total_data_count = SIVAL(inbuf, smb_nts_TotalDataCount);
293       num_params_sofar += (parameter_count = SIVAL(inbuf,smb_nts_ParameterCount));
294       num_data_sofar += ( data_count = SIVAL(inbuf, smb_nts_DataCount));
295       if (num_params_sofar > total_parameter_count || num_data_sofar > total_data_count)
296         exit_server("reply_nttrans2: data overflow in secondary nttrans packet\n");
297
298       memcpy( &params[ SIVAL(inbuf, smb_nts_ParameterDisplacement)], 
299               smb_base(inbuf) + SVAL(inbuf, smb_nts_ParameterOffset), parameter_count);
300       memcpy( &data[SVAL(inbuf, smb_nts_DataDisplacement)],
301               smb_base(inbuf)+ SVAL(inbuf, smb_nts_DataOffset), data_count);
302     }
303   }
304
305   if (Protocol >= PROTOCOL_NT1) {
306     uint16 flg2 = SVAL(outbuf,smb_flg2);
307     SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */
308   }
309
310   /* Now we must call the relevant NT_TRANS function */
311   switch(function_code) {
312     case NT_TRANSACT_CREATE:
313       outsize = call_nt_transact_create(inbuf, outbuf, bufsize, cnum, 
314                                         &setup, &params, &data);
315       break;
316     case NT_TRANSACT_IOCTL:
317       outsize = call_nt_transact_ioctl(inbuf, outbuf, bufsize, cnum,
318                                        &setup, &params, &data);
319       break;
320     case NT_TRANSACT_SET_SECURITY_DESC:
321       outsize = call_nt_transact_set_security_desc(inbuf, outbuf, length, bufsize, cnum,
322                                                    &setup, &params, &data);
323       break;
324     case NT_TRANSACT_NOTIFY_CHANGE:
325       outsize = call_nt_transact_notify_change(inbuf, outbuf, length, bufsize, cnum,
326                                                &setup, &params, &data);
327       break;
328     case NT_TRANSACT_RENAME:
329       outsize = call_nt_transact_rename(inbuf, outbuf, length, bufsize, cnum,
330                                         &setup, &params, &data);
331       break;
332     case NT_TRANSACT_QUERY_SECURITY_DESC:
333       outsize = call_nt_transact_query_security_desc(inbuf, outbuf, length, bufsize, cnum,
334                                                      &setup, &params, &data, total_data);
335       break;
336     default:
337       /* Error in request */
338       DEBUG(0,("reply_nttrans: %s Unknown request %d in nttrans call\n",timestring(),
339                  tran_call));
340       if(setup)
341         free(setup);
342       if(params)
343         free(params);
344       if(data)
345         free(data);
346       return (ERROR(ERRSRV,ERRerror));
347   }
348
349   /* As we do not know how many data packets will need to be
350      returned here the various call_nt_transact_xxxx calls
351      must send their own. Thus a call_nt_transact_xxxx routine only
352      returns a value other than -1 when it wants to send
353      an error packet. 
354   */
355
356   if(setup)
357     free(setup);
358   if(params)
359     free(params);
360   if(data)
361     free(data);
362   return outsize; /* If a correct response was needed the call_nt_transact_xxxx 
363                      calls have already sent it. If outsize != -1 then it is
364                      returning an error packet. */
365 }