delineation between smb and msrpc more marked. smbd now constructs
[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_to_smb(p, smb_base(inbuf), smb_len(inbuf)))
199         {
200                 char *copy_into = smb_base(outbuf);
201                 outsize = mem_buf_len(p->rsmb_pdu.data);
202                 if (!mem_buf_copy(copy_into, p->rsmb_pdu.data, 0, outsize))
203                 {
204                         return -1;
205                 }
206                 mem_free_data(p->rsmb_pdu.data);
207         }
208
209         return outsize;
210 }
211
212
213 /****************************************************************************
214   construct a reply to the incoming packet
215 ****************************************************************************/
216 static int construct_reply(char *inbuf,char *outbuf,int size,int bufsize)
217 {
218   int outsize = 0;
219   smb_last_time = time(NULL);
220
221   outsize = do_message(inbuf,outbuf,size,bufsize) + 4;
222
223   if(outsize > 4)
224     _smb_setlen(outbuf,outsize - 4);
225   return(outsize);
226 }
227
228
229 /****************************************************************************
230   process an smb from the client - split out from the process() code so
231   it can be used by the oplock break code.
232 ****************************************************************************/
233 void process_smb(char *inbuf, char *outbuf)
234 {
235   extern int Client;
236   static int trans_num;
237   int32 len = smb_len(inbuf);
238   int nread = len + 4;
239
240   if (trans_num == 0) {
241           /* on the first packet, check the global hosts allow/ hosts
242              deny parameters before doing any parsing of the packet
243              passed to us by the client.  This prevents attacks on our
244              parsing code from hosts not in the hosts allow list */
245           if (!check_access(Client, lp_hostsallow(-1), lp_hostsdeny(-1))) {
246                   /* send a negative session response "not listining on calling
247                    name" */
248                   DEBUG( 1, ( "Connection denied from %s\n",
249                               client_addr(Client) ) );
250                   exit_server("connection denied");
251           }
252   }
253
254   DEBUG( 6, ( "got message of len 0x%x\n", len ) );
255   DEBUG( 3, ( "Transaction %d of length %d\n", trans_num, nread ) );
256
257         dump_data(10, inbuf, len);
258
259 #ifdef WITH_VTP
260   if(trans_num == 1 && VT_Check(inbuf)) 
261   {
262     VT_Process();
263     return;
264   }
265 #endif
266
267   nread = construct_reply(inbuf,outbuf,nread,max_send);
268       
269   if(nread > 0) 
270   {
271       dump_data(10, outbuf, nread);
272         
273     if (nread != smb_len(outbuf) + 4) 
274     {
275       DEBUG(0,("ERROR: Invalid message response size! %d %d\n",
276                  nread, smb_len(outbuf)));
277     }
278     else
279       send_smb(Client,outbuf);
280   }
281   trans_num++;
282 }
283
284
285 BOOL get_user_creds(struct user_creds *usr)
286 {
287         pstring buf;
288         int rl;
289         uint32 len;
290         BOOL new_con = False;
291         extern int Client;
292         uint32 status;
293
294         CREDS_CMD cmd;
295         prs_struct ps;
296
297         ZERO_STRUCTP(usr);
298         ZERO_STRUCT(cmd);
299         cmd.cred = usr;
300
301         DEBUG(10,("get_user_creds: first request\n"));
302
303         rl = read(Client, &buf, sizeof(len));
304
305         if (rl != sizeof(len))
306         {
307                 DEBUG(0,("Unable to read length\n"));
308                 dump_data(0, buf, sizeof(len));
309                 return False;
310         }
311
312         len = IVAL(buf, 0);
313
314         if (len > sizeof(buf))
315         {
316                 DEBUG(0,("length %d too long\n", len));
317                 return False;
318         }
319
320         rl = read(Client, buf, len);
321
322         if (rl < 0)
323         {
324                 DEBUG(0,("Unable to read from connection\n"));
325                 return False;
326         }
327         
328 #ifdef DEBUG_PASSWORD
329         dump_data(100, buf, rl);
330 #endif
331
332         /* make a static data parsing structure from the api_fd_reply data */
333         prs_init(&ps, 0, 4, 0, True);
334         mem_create(ps.data, buf, 0, len, 0, False);
335
336         if (!creds_io_cmd("creds", &cmd, &ps, 0))
337         {
338                 DEBUG(0,("Unable to parse credentials\n"));
339                 mem_free_data(ps.data);
340                 return False;
341         }
342
343         mem_free_data(ps.data);
344
345         if (ps.offset != rl)
346         {
347                 DEBUG(0,("Buffer size %d %d!\n", ps.offset, rl));
348                 return False;
349         }
350
351         switch (cmd.command)
352         {
353                 case AGENT_CMD_CON:
354                 case AGENT_CMD_CON_ANON:
355                 {
356                         new_con = True;
357                         break;
358                 }
359                 case AGENT_CMD_CON_REUSE:
360                 {
361                         new_con = True;
362                         break;
363                 }
364                 default:
365                 {
366                         DEBUG(0,("unknown command %d\n", cmd.command));
367                         return False;
368                 }
369         }
370
371         status = new_con ? 0x0 : 0x1;
372
373         if (write(Client, &status, sizeof(status)) !=
374             sizeof(status))
375         {
376                 return False;
377         }
378
379         return new_con;
380 }
381
382 /****************************************************************************
383   process commands from the client
384 ****************************************************************************/
385 void lsarpcd_process(void)
386 {
387         struct user_creds usr;
388         gid_t *groups = NULL;
389
390         ZERO_STRUCT(static_pipe);
391
392         fstrcpy(static_pipe.name, "lsarpc");
393         
394         if (!get_user_creds(&usr))
395         {
396                 DEBUG(0,("authentication failed\n"));
397                 free_user_creds(&usr);
398                 return;
399         }
400
401         if (usr.uxs.num_grps != 0)
402         {
403                 int i;
404                 groups = malloc(usr.uxs.num_grps * sizeof(groups[0]));
405                 if (groups == NULL)
406                 {
407                         return;
408                 }
409                 for (i = 0; i < usr.uxs.num_grps; i++)
410                 {
411                         groups[i] = (gid_t)usr.uxs.grps[i];
412                 }
413         }
414                 
415         static_pipe.vuid = create_vuid(usr.uxs.uid, usr.uxs.gid,
416                                        usr.uxs.num_grps, groups,
417                                        usr.uxc.user_name,
418                                        usr.uxc.requested_name,
419                                        usr.uxc.real_name,
420                                        usr.uxc.guest,
421                                        usr.ntc.pwd.sess_key);
422
423         if (static_pipe.vuid == UID_FIELD_INVALID)
424         {
425                 return;
426         }
427
428         free_user_creds(&usr);
429
430         become_vuser(static_pipe.vuid);
431
432         static_pipe.l = malloc(sizeof(*static_pipe.l));
433         if (static_pipe.l == NULL)
434         {
435                 return;
436         }
437
438         ZERO_STRUCTP(static_pipe.l);
439
440   InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
441   OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
442   if ((InBuffer == NULL) || (OutBuffer == NULL)) 
443     return;
444
445   InBuffer += SMB_ALIGNMENT;
446   OutBuffer += SMB_ALIGNMENT;
447
448   max_recv = MIN(lp_maxxmit(),BUFFER_SIZE);
449
450   /* re-initialise the timezone */
451   TimeInit();
452
453   while (True)
454   {
455     int counter;
456     int service_load_counter = 0;
457     BOOL got_smb = False;
458
459     errno = 0;      
460
461     for (counter=SMBD_SELECT_LOOP; 
462           !receive_message_or_smb(InBuffer,BUFFER_SIZE,
463                                   SMBD_SELECT_LOOP*1000,&got_smb); 
464           counter += SMBD_SELECT_LOOP)
465     {
466       time_t t;
467
468       if (counter > 365 * 3600) /* big number of seconds. */
469       {
470         counter = 0;
471         service_load_counter = 0;
472       }
473
474       if (smb_read_error == READ_EOF) 
475       {
476         DEBUG(3,("end of file from client\n"));
477         return;
478       }
479
480       if (smb_read_error == READ_ERROR) 
481       {
482         DEBUG(3,("receive_smb error (%s) exiting\n",
483                   strerror(errno)));
484         return;
485       }
486
487       t = time(NULL);
488
489       /* become root again if waiting */
490       unbecome_vuser();
491
492       /* check for smb.conf reload */
493       if (counter >= service_load_counter + SMBD_RELOAD_CHECK)
494       {
495         service_load_counter = counter;
496
497         /* reload services, if files have changed. */
498         reload_services(True);
499       }
500
501       /*
502        * If reload_after_sighup == True then we got a SIGHUP
503        * and are being asked to reload. Fix from <branko.cibej@hermes.si>
504        */
505
506       if (reload_after_sighup)
507       {
508         DEBUG(0,("Reloading services after SIGHUP\n"));
509         reload_services(False);
510         reload_after_sighup = False;
511         /*
512          * Use this as an excuse to print some stats.
513          */
514       }
515
516       /* automatic timeout if all connections are closed */      
517       if (counter >= IDLE_CLOSED_TIMEOUT) 
518       {
519         DEBUG( 2, ( "Closing idle connection\n" ) );
520         return;
521       }
522
523     }
524
525     if(got_smb)
526       process_smb(InBuffer, OutBuffer);
527   }
528 }