47a4f9a86c57376a64670735cc3c87f2e59856b9
[tprouty/samba.git] / source / lsarpcd / lsarpcd_process.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    process incoming packets - main loop
5    Copyright (C) Andrew Tridgell 1992-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
26 time_t smb_last_time=(time_t)0;
27 static struct pipes_struct static_pipe;
28
29 char *InBuffer = NULL;
30 char *OutBuffer = NULL;
31 char *last_inbuf = NULL;
32
33 /* 
34  * Size of data we can send to client. Set
35  *  by the client for all protocols above CORE.
36  *  Set by us for CORE protocol.
37  */
38 int max_send = BUFFER_SIZE;
39 /*
40  * Size of the data we can receive. Set by us.
41  * Can be modified by the max xmit parameter.
42  */
43 int max_recv = BUFFER_SIZE;
44
45 extern int last_message;
46 extern pstring sesssetup_user;
47 extern char *last_inbuf;
48 extern char *InBuffer;
49 extern char *OutBuffer;
50 extern int smb_read_error;
51 extern BOOL reload_after_sighup;
52 extern int max_send;
53
54
55 /****************************************************************************
56   Do a select on an two fd's - with timeout. 
57
58   If a local udp message has been pushed onto the
59   queue (this can only happen during oplock break
60   processing) return this first.
61
62   If a pending smb message has been pushed onto the
63   queue (this can only happen during oplock break
64   processing) return this next.
65
66   If the first smbfd is ready then read an smb from it.
67   if the second (loopback UDP) fd is ready then read a message
68   from it and setup the buffer header to identify the length
69   and from address.
70   Returns False on timeout or error.
71   Else returns True.
72
73 The timeout is in milli seconds
74 ****************************************************************************/
75
76 static BOOL receive_message_or_smb(char *buffer, int buffer_len, 
77                                    int timeout, BOOL *got_smb)
78 {
79   extern int Client;
80   fd_set fds;
81   int selrtn;
82   struct timeval to;
83   int maxfd;
84
85   smb_read_error = 0;
86
87   *got_smb = False;
88
89   /*
90    * Check to see if we already have a message on the smb queue.
91    * If so - copy and return it.
92    */
93   
94   /*
95    * Setup the select read fd set.
96    */
97
98   FD_ZERO(&fds);
99   FD_SET(Client,&fds);
100   maxfd = 0;
101
102   to.tv_sec = timeout / 1000;
103   to.tv_usec = (timeout % 1000) * 1000;
104
105   selrtn = sys_select(MAX(maxfd,Client)+1,&fds,NULL, timeout>0?&to:NULL);
106
107   /* Check if error */
108   if(selrtn == -1) {
109     /* something is wrong. Maybe the socket is dead? */
110     smb_read_error = READ_ERROR;
111     return False;
112   } 
113     
114   /* Did we timeout ? */
115   if (selrtn == 0) {
116     smb_read_error = READ_TIMEOUT;
117     return False;
118   }
119
120   if (FD_ISSET(Client,&fds))
121   {
122     *got_smb = True;
123     return receive_smb(Client, buffer, 0);
124   }
125         return False;
126 }
127
128 /****************************************************************************
129 Get the next SMB packet, doing the local message processing automatically.
130 ****************************************************************************/
131
132 BOOL receive_next_smb(char *inbuf, int bufsize, int timeout)
133 {
134   BOOL got_smb = False;
135   BOOL ret;
136
137   do
138   {
139     ret = receive_message_or_smb(inbuf,bufsize,timeout,&got_smb);
140
141     if(ret && !got_smb)
142     {
143       continue;
144     }
145
146     if(ret && (CVAL(inbuf,0) == 0x85))
147     {
148       /* Keepalive packet. */
149       got_smb = False;
150     }
151
152   }
153   while(ret && !got_smb);
154
155   return ret;
156 }
157
158
159 /*
160 These flags determine some of the permissions required to do an operation 
161
162 Note that I don't set NEED_WRITE on some write operations because they
163 are used by some brain-dead clients when printing, and I don't want to
164 force write permissions on print services.
165 */
166 #define AS_USER (1<<0)
167 #define NEED_WRITE (1<<1)
168 #define TIME_INIT (1<<2)
169 #define CAN_IPC (1<<3)
170 #define AS_GUEST (1<<5)
171 #define QUEUE_IN_OPLOCK (1<<6)
172
173 /* 
174    define a list of possible SMB messages and their corresponding
175    functions. Any message that has a NULL function is unimplemented -
176    please feel free to contribute implementations!
177 */
178
179 /****************************************************************************
180 do a switch on the message type, and return the response size
181 ****************************************************************************/
182 static int do_message(char *inbuf,char *outbuf,int size,int bufsize)
183 {
184   static int pid= -1;
185
186         pipes_struct *p = &static_pipe;
187         prs_struct pd;
188         int outsize = -1;
189
190         /* make a static data parsing structure from the api_fd_reply data */
191         prs_init(&pd, 0, 4, 0, True);
192         mem_create(pd.data, smb_base(inbuf), 0, smb_len(inbuf), 0, False);
193
194   if (pid == -1)
195     pid = getpid();
196
197         /* dce/rpc command */
198         if (rpc_command(p, &pd))
199         {
200                 char *copy_into = smb_base(outbuf);
201                 outsize = mem_buf_len(p->rhdr.data);
202                 if (!mem_buf_copy(copy_into, p->rhdr.data, 0, outsize))
203                 {
204                         return -1;
205                 }
206         }
207         mem_free_data(pd.data);
208
209         mem_free_data(p->rhdr .data);
210         mem_free_data(p->rfault .data);
211         mem_free_data(p->rdata  .data);
212         mem_free_data(p->rdata_i.data);         
213         mem_free_data(p->rauth  .data);
214         mem_free_data(p->rverf  .data);
215         mem_free_data(p->rntlm  .data);         
216
217         return outsize;
218 }
219
220
221 /****************************************************************************
222   construct a reply to the incoming packet
223 ****************************************************************************/
224 static int construct_reply(char *inbuf,char *outbuf,int size,int bufsize)
225 {
226   int outsize = 0;
227   smb_last_time = time(NULL);
228
229   outsize = do_message(inbuf,outbuf,size,bufsize) + 4;
230
231   if(outsize > 4)
232     _smb_setlen(outbuf,outsize - 4);
233   return(outsize);
234 }
235
236
237 /****************************************************************************
238   process an smb from the client - split out from the process() code so
239   it can be used by the oplock break code.
240 ****************************************************************************/
241 void process_smb(char *inbuf, char *outbuf)
242 {
243   extern int Client;
244   static int trans_num;
245   int32 len = smb_len(inbuf);
246   int nread = len + 4;
247
248   if (trans_num == 0) {
249           /* on the first packet, check the global hosts allow/ hosts
250              deny parameters before doing any parsing of the packet
251              passed to us by the client.  This prevents attacks on our
252              parsing code from hosts not in the hosts allow list */
253           if (!check_access(Client, lp_hostsallow(-1), lp_hostsdeny(-1))) {
254                   /* send a negative session response "not listining on calling
255                    name" */
256                   DEBUG( 1, ( "Connection denied from %s\n",
257                               client_addr(Client) ) );
258                   exit_server("connection denied");
259           }
260   }
261
262   DEBUG( 6, ( "got message of len 0x%x\n", len ) );
263   DEBUG( 3, ( "Transaction %d of length %d\n", trans_num, nread ) );
264
265         dump_data(10, inbuf, len);
266
267 #ifdef WITH_VTP
268   if(trans_num == 1 && VT_Check(inbuf)) 
269   {
270     VT_Process();
271     return;
272   }
273 #endif
274
275   nread = construct_reply(inbuf,outbuf,nread,max_send);
276       
277   if(nread > 0) 
278   {
279       dump_data(10, outbuf, nread);
280         
281     if (nread != smb_len(outbuf) + 4) 
282     {
283       DEBUG(0,("ERROR: Invalid message response size! %d %d\n",
284                  nread, smb_len(outbuf)));
285     }
286     else
287       send_smb(Client,outbuf);
288   }
289   trans_num++;
290 }
291
292
293 BOOL get_user_creds(struct user_creds *usr)
294 {
295         pstring buf;
296         int rl;
297         uint32 len;
298         BOOL new_con = False;
299         extern int Client;
300         uint32 status;
301
302         CREDS_CMD cmd;
303         prs_struct ps;
304
305         ZERO_STRUCTP(usr);
306         ZERO_STRUCT(cmd);
307         cmd.cred = usr;
308
309         DEBUG(10,("get_user_creds: first request\n"));
310
311         rl = read(Client, &buf, sizeof(len));
312
313         if (rl != sizeof(len))
314         {
315                 DEBUG(0,("Unable to read length\n"));
316                 dump_data(0, buf, sizeof(len));
317                 return False;
318         }
319
320         len = IVAL(buf, 0);
321
322         if (len > sizeof(buf))
323         {
324                 DEBUG(0,("length %d too long\n", len));
325                 return False;
326         }
327
328         rl = read(Client, buf, len);
329
330         if (rl < 0)
331         {
332                 DEBUG(0,("Unable to read from connection\n"));
333                 return False;
334         }
335         
336 #ifdef DEBUG_PASSWORD
337         dump_data(100, buf, rl);
338 #endif
339
340         /* make a static data parsing structure from the api_fd_reply data */
341         prs_init(&ps, 0, 4, 0, True);
342         mem_create(ps.data, buf, 0, len, 0, False);
343
344         if (!creds_io_cmd("creds", &cmd, &ps, 0))
345         {
346                 DEBUG(0,("Unable to parse credentials\n"));
347                 mem_free_data(ps.data);
348                 return False;
349         }
350
351         mem_free_data(ps.data);
352
353         if (ps.offset != rl)
354         {
355                 DEBUG(0,("Buffer size %d %d!\n", ps.offset, rl));
356                 return False;
357         }
358
359         switch (cmd.command)
360         {
361                 case AGENT_CMD_CON:
362                 case AGENT_CMD_CON_ANON:
363                 {
364                         new_con = True;
365                         break;
366                 }
367                 case AGENT_CMD_CON_REUSE:
368                 {
369                         new_con = True;
370                         break;
371                 }
372                 default:
373                 {
374                         DEBUG(0,("unknown command %d\n", cmd.command));
375                         return False;
376                 }
377         }
378
379         status = new_con ? 0x0 : 0x1;
380
381         if (write(Client, &status, sizeof(status)) !=
382             sizeof(status))
383         {
384                 return False;
385         }
386
387         return new_con;
388 }
389
390 /****************************************************************************
391   process commands from the client
392 ****************************************************************************/
393 void lsarpcd_process(void)
394 {
395         struct user_creds usr;
396
397         ZERO_STRUCT(static_pipe);
398
399         fstrcpy(static_pipe.name, "lsarpc");
400         
401         if (!get_user_creds(&usr))
402         {
403                 DEBUG(0,("authentication failed\n"));
404                 free_user_creds(&usr);
405                 return;
406         }
407
408         free_user_creds(&usr);
409
410   InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
411   OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
412   if ((InBuffer == NULL) || (OutBuffer == NULL)) 
413     return;
414
415   InBuffer += SMB_ALIGNMENT;
416   OutBuffer += SMB_ALIGNMENT;
417
418   max_recv = MIN(lp_maxxmit(),BUFFER_SIZE);
419
420   /* re-initialise the timezone */
421   TimeInit();
422
423   while (True)
424   {
425     int counter;
426     int service_load_counter = 0;
427     BOOL got_smb = False;
428
429     errno = 0;      
430
431     for (counter=SMBD_SELECT_LOOP; 
432           !receive_message_or_smb(InBuffer,BUFFER_SIZE,
433                                   SMBD_SELECT_LOOP*1000,&got_smb); 
434           counter += SMBD_SELECT_LOOP)
435     {
436       time_t t;
437
438       if (counter > 365 * 3600) /* big number of seconds. */
439       {
440         counter = 0;
441         service_load_counter = 0;
442       }
443
444       if (smb_read_error == READ_EOF) 
445       {
446         DEBUG(3,("end of file from client\n"));
447         return;
448       }
449
450       if (smb_read_error == READ_ERROR) 
451       {
452         DEBUG(3,("receive_smb error (%s) exiting\n",
453                   strerror(errno)));
454         return;
455       }
456
457       t = time(NULL);
458
459       /* become root again if waiting */
460       unbecome_user();
461
462       /* check for smb.conf reload */
463       if (counter >= service_load_counter + SMBD_RELOAD_CHECK)
464       {
465         service_load_counter = counter;
466
467         /* reload services, if files have changed. */
468         reload_services(True);
469       }
470
471       /*
472        * If reload_after_sighup == True then we got a SIGHUP
473        * and are being asked to reload. Fix from <branko.cibej@hermes.si>
474        */
475
476       if (reload_after_sighup)
477       {
478         DEBUG(0,("Reloading services after SIGHUP\n"));
479         reload_services(False);
480         reload_after_sighup = False;
481         /*
482          * Use this as an excuse to print some stats.
483          */
484       }
485
486       /* automatic timeout if all connections are closed */      
487       if (counter >= IDLE_CLOSED_TIMEOUT) 
488       {
489         DEBUG( 2, ( "Closing idle connection\n" ) );
490         return;
491       }
492
493     }
494
495     if(got_smb)
496       process_smb(InBuffer, OutBuffer);
497   }
498 }