loadparm.c proto.h:
[nivanova/samba-autobuild/.git] / source3 / smbd / pipes.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Pipe SMB reply routines
5    Copyright (C) Andrew Tridgell 1992-1997,
6                  Paul Ashton  1997,
7                  Luke Kenneth Casson Leighton 1996-1997.
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23 /*
24    This file handles reply_ calls on named pipes that the server
25    makes to handle specific protocols
26 */
27
28
29 #include "includes.h"
30 #include "trans2.h"
31 #include "nterr.h"
32
33 #define PIPE            "\\PIPE\\"
34 #define PIPELEN         strlen(PIPE)
35
36 #define REALLOC(ptr,size) Realloc(ptr,MAX((size),4*1024))
37
38 /* look in server.c for some explanation of these variables */
39 extern int Protocol;
40 extern int DEBUGLEVEL;
41 extern int chain_fnum;
42 extern char magic_char;
43 extern connection_struct Connections[];
44 extern files_struct Files[];
45 extern BOOL case_sensitive;
46 extern pstring sesssetup_user;
47 extern int Client;
48 extern fstring myworkgroup;
49
50 /* this macro should always be used to extract an fnum (smb_fid) from
51 a packet to ensure chaining works correctly */
52 #define GETFNUM(buf,where) (chain_fnum!= -1?chain_fnum:SVAL(buf,where))
53
54 char * known_pipes [] =
55 {
56   "lsarpc",
57 #if 0
58   "NETLOGON",
59 #endif
60   NULL
61 };
62
63 /****************************************************************************
64   reply to an open and X on a named pipe
65
66   In fact what we do is to open a regular file with the same name in
67   /tmp. This can then be closed as normal. Reading and writing won't
68   make much sense, but will do *something*. The real reason for this
69   support is to be able to do transactions on them (well, on lsarpc
70   for domain login purposes...).
71
72   This code is basically stolen from reply_open_and_X with some
73   wrinkles to handle pipes.
74 ****************************************************************************/
75 int reply_open_pipe_and_X(char *inbuf,char *outbuf,int length,int bufsize)
76 {
77   pstring fname;
78   int cnum = SVAL(inbuf,smb_tid);
79   int fnum = -1;
80   int smb_mode = SVAL(inbuf,smb_vwv3);
81   int smb_attr = SVAL(inbuf,smb_vwv5);
82 #if 0
83   int open_flags = SVAL(inbuf,smb_vwv2);
84   int smb_sattr = SVAL(inbuf,smb_vwv4); 
85   uint32 smb_time = make_unix_date3(inbuf+smb_vwv6);
86 #endif
87   int smb_ofun = SVAL(inbuf,smb_vwv8);
88   int unixmode;
89   int size=0,fmode=0,mtime=0,rmode=0;
90   struct stat sbuf;
91   int smb_action = 0;
92   int i;
93   BOOL bad_path = False;
94
95   /* XXXX we need to handle passed times, sattr and flags */
96   pstrcpy(fname,smb_buf(inbuf));
97
98   /* If the name doesn't start \PIPE\ then this is directed */
99   /* at a mailslot or something we really, really don't understand, */
100   /* not just something we really don't understand. */
101   if ( strncmp(fname,PIPE,PIPELEN) != 0 )
102     return(ERROR(ERRSRV,ERRaccess));
103
104   DEBUG(4,("Opening pipe %s.\n", fname));
105
106   /* Strip \PIPE\ off the name. */
107   pstrcpy(fname,smb_buf(inbuf) + PIPELEN);
108
109   /* See if it is one we want to handle. */
110   for( i = 0; known_pipes[i] ; i++ )
111     if( strcmp(fname,known_pipes[i]) == 0 )
112       break;
113
114   if ( known_pipes[i] == NULL )
115     return(ERROR(ERRSRV,ERRaccess));
116
117   /* Known pipes arrive with DIR attribs. Remove it so a regular file */
118   /* can be opened and add it in after the open. */
119   DEBUG(3,("Known pipe %s opening.\n",fname));
120   smb_attr &= ~aDIR;
121   Connections[cnum].read_only = 0;
122   smb_ofun |= 0x10;             /* Add Create it not exists flag */
123
124   unix_convert(fname,cnum,0,&bad_path);
125     
126   fnum = find_free_file();
127   if (fnum < 0)
128     return(ERROR(ERRSRV,ERRnofids));
129
130   if (!check_name(fname,cnum))
131     return(UNIXERROR(ERRDOS,ERRnoaccess));
132
133   unixmode = unix_mode(cnum,smb_attr);
134       
135   open_file_shared(fnum,cnum,fname,smb_mode,smb_ofun,unixmode,
136                    0, &rmode,&smb_action);
137       
138   if (!Files[fnum].open)
139   {
140     /* Change the error code if bad_path was set. */
141     if((errno == ENOENT) && bad_path)
142     {
143       unix_ERR_class = ERRDOS;
144       unix_ERR_code = ERRbadpath;
145     }
146     return(UNIXERROR(ERRDOS,ERRnoaccess));
147   }
148
149   if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) {
150     close_file(fnum);
151     return(ERROR(ERRDOS,ERRnoaccess));
152   }
153
154   size = sbuf.st_size;
155   fmode = dos_mode(cnum,fname,&sbuf);
156   mtime = sbuf.st_mtime;
157   if (fmode & aDIR) {
158     close_file(fnum);
159     return(ERROR(ERRDOS,ERRnoaccess));
160   }
161
162   /* Prepare the reply */
163   set_message(outbuf,15,0,True);
164
165   /* Put things back the way they were. */
166   Connections[cnum].read_only = 1;
167
168   /* Mark the opened file as an existing named pipe in message mode. */
169   SSVAL(outbuf,smb_vwv9,2);
170   SSVAL(outbuf,smb_vwv10,0xc700);
171   if (rmode == 2)
172   {
173     DEBUG(4,("Resetting open result to open from create.\n"));
174     rmode = 1;
175   }
176
177   SSVAL(outbuf,smb_vwv2,fnum);
178   SSVAL(outbuf,smb_vwv3,fmode);
179   put_dos_date3(outbuf,smb_vwv4,mtime);
180   SIVAL(outbuf,smb_vwv6,size);
181   SSVAL(outbuf,smb_vwv8,rmode);
182   SSVAL(outbuf,smb_vwv11,smb_action);
183
184   chain_fnum = fnum;
185
186   DEBUG(4,("Opened pipe %s with handle %d, saved name %s.\n",
187            fname, fnum, Files[fnum].name));
188   
189   return chain_reply(inbuf,outbuf,length,bufsize);
190 }
191
192
193 /****************************************************************************
194  api_LsarpcSNPHS
195
196  SetNamedPipeHandleState on \PIPE\lsarpc. We can't really do much here,
197  so just blithely return True. This is really only for NT domain stuff,
198  we we're only handling that - don't assume Samba now does complete
199  named pipe handling.
200 ****************************************************************************/
201 BOOL api_LsarpcSNPHS(int cnum,int uid, char *param,char *data,
202                      int mdrcnt,int mprcnt,
203                      char **rdata,char **rparam,
204                      int *rdata_len,int *rparam_len)
205 {
206   uint16 id;
207
208   id = param[0] + (param[1] << 8);
209   DEBUG(4,("lsarpc SetNamedPipeHandleState to code %x\n",id));
210   return(True);
211 }
212
213
214 /****************************************************************************
215  api_LsarpcTNP
216
217  TransactNamedPipe on \PIPE\lsarpc.
218 ****************************************************************************/
219 static void LsarpcTNP1(char *data,char **rdata, int *rdata_len)
220 {
221   uint32 dword1, dword2;
222   char pname[] = "\\PIPE\\lsass";
223
224   /* All kinds of mysterious numbers here */
225   *rdata_len = 68;
226   *rdata = REALLOC(*rdata,*rdata_len);
227
228   dword1 = IVAL(data,0xC);
229   dword2 = IVAL(data,0x10);
230
231   SIVAL(*rdata,0,0xc0005);
232   SIVAL(*rdata,4,0x10);
233   SIVAL(*rdata,8,0x44);
234   SIVAL(*rdata,0xC,dword1);
235   
236   SIVAL(*rdata,0x10,dword2);
237   SIVAL(*rdata,0x14,0x15);
238   SSVAL(*rdata,0x18,sizeof(pname));
239   strcpy(*rdata + 0x1a,pname);
240   SIVAL(*rdata,0x28,1);
241   memcpy(*rdata + 0x30, data + 0x34, 0x14);
242 }
243
244 static void LsarpcTNP2(char *data,char **rdata, int *rdata_len)
245 {
246   uint32 dword1;
247
248   /* All kinds of mysterious numbers here */
249   *rdata_len = 48;
250   *rdata = REALLOC(*rdata,*rdata_len);
251
252   dword1 = IVAL(data,0xC);
253
254   SIVAL(*rdata,0,0x03020005);
255   SIVAL(*rdata,4,0x10);
256   SIVAL(*rdata,8,0x30);
257   SIVAL(*rdata,0xC,dword1);
258   SIVAL(*rdata,0x10,0x18);
259   SIVAL(*rdata,0x1c,0x44332211);
260   SIVAL(*rdata,0x20,0x88776655);
261   SIVAL(*rdata,0x24,0xCCBBAA99);
262   SIVAL(*rdata,0x28,0x11FFEEDD);
263 }
264
265 static void LsarpcTNP3(char *data,char **rdata, int *rdata_len)
266 {
267   uint32 dword1;
268   uint16 word1;
269   char * workgroup = myworkgroup;
270   int wglen = strlen(workgroup);
271   int i;
272
273   /* All kinds of mysterious numbers here */
274   *rdata_len = 90 + 2 * wglen;
275   *rdata = REALLOC(*rdata,*rdata_len);
276
277   dword1 = IVAL(data,0xC);
278   word1 = SVAL(data,0x2C);
279
280   SIVAL(*rdata,0,0x03020005);
281   SIVAL(*rdata,4,0x10);
282   SIVAL(*rdata,8,0x60);
283   SIVAL(*rdata,0xC,dword1);
284   SIVAL(*rdata,0x10,0x48);
285   SSVAL(*rdata,0x18,0x5988);    /* This changes */
286   SSVAL(*rdata,0x1A,0x15);
287   SSVAL(*rdata,0x1C,word1);
288   SSVAL(*rdata,0x20,6);
289   SSVAL(*rdata,0x22,8);
290   SSVAL(*rdata,0x24,0x8E8);     /* So does this */
291   SSVAL(*rdata,0x26,0x15);
292   SSVAL(*rdata,0x28,0x4D48);    /* And this */
293   SSVAL(*rdata,0x2A,0x15);
294   SIVAL(*rdata,0x2C,4);
295   SIVAL(*rdata,0x34,wglen);
296   for ( i = 0 ; i < wglen ; i++ )
297     (*rdata)[0x38 + i * 2] = workgroup[i];
298    
299   /* Now fill in the rest */
300   i = 0x38 + wglen * 2;
301   SSVAL(*rdata,i,0x648);
302   SIVAL(*rdata,i+2,4);
303   SIVAL(*rdata,i+6,0x401);
304   SSVAL(*rdata,i+0xC,0x500);
305   SIVAL(*rdata,i+0xE,0x15);
306   SIVAL(*rdata,i+0x12,0x2372FE1);
307   SIVAL(*rdata,i+0x16,0x7E831BEF);
308   SIVAL(*rdata,i+0x1A,0x4B454B2);
309 }
310
311 static void LsarpcTNP4(char *data,char **rdata, int *rdata_len)
312 {
313   uint32 dword1;
314
315   /* All kinds of mysterious numbers here */
316   *rdata_len = 48;
317   *rdata = REALLOC(*rdata,*rdata_len);
318
319   dword1 = IVAL(data,0xC);
320
321   SIVAL(*rdata,0,0x03020005);
322   SIVAL(*rdata,4,0x10);
323   SIVAL(*rdata,8,0x30);
324   SIVAL(*rdata,0xC,dword1);
325   SIVAL(*rdata,0x10,0x18);
326 }
327
328
329 BOOL api_LsarpcTNP(int cnum,int uid, char *param,char *data,
330                      int mdrcnt,int mprcnt,
331                      char **rdata,char **rparam,
332                      int *rdata_len,int *rparam_len)
333 {
334   uint32 id,id2;
335
336   id = IVAL(data,0);
337
338   DEBUG(4,("lsarpc TransactNamedPipe id %lx\n",id));
339   switch (id)
340   {
341     case 0xb0005:
342       LsarpcTNP1(data,rdata,rdata_len);
343       break;
344
345     case 0x03000005:
346       id2 = IVAL(data,8);
347       DEBUG(4,("\t- Suboperation %lx\n",id2));
348       switch (id2 & 0xF)
349       {
350         case 8:
351           LsarpcTNP2(data,rdata,rdata_len);
352           break;
353
354         case 0xC:
355           LsarpcTNP4(data,rdata,rdata_len);
356           break;
357
358         case 0xE:
359           LsarpcTNP3(data,rdata,rdata_len);
360           break;
361       }
362       break;
363   }
364   return(True);
365 }
366
367 /*
368    PAXX: Someone fix above.
369    The above API is indexing RPC calls based on RPC flags and 
370    fragment length. I've decided to do it based on operation number :-)
371 */
372
373 /* BIG NOTE: this function only does SIDS where the identauth is not >= 2^32 */
374 /* identauth >= 2^32 can be detected because it will be specified in hex */
375 static void make_dom_sid(DOM_SID *sid, char *domsid)
376 {
377         int identauth;
378         char *p;
379
380         DEBUG(4,("netlogon domain SID: %s\n", domsid));
381
382         /* assume, but should check, that domsid starts "S-" */
383         p = strtok(domsid+2,"-");
384         sid->sid_no = atoi(p);
385
386         /* identauth in decimal should be <  2^32 */
387         /* identauth in hex     should be >= 2^32 */
388         identauth = atoi(strtok(0,"-"));
389
390         DEBUG(4,("netlogon rev %d\n", sid->sid_no));
391         DEBUG(4,("netlogon %s ia %d\n", p, identauth));
392
393         sid->id_auth[0] = 0;
394         sid->id_auth[1] = 0;
395         sid->id_auth[2] = (identauth & 0xff000000) >> 24;
396         sid->id_auth[3] = (identauth & 0x00ff0000) >> 16;
397         sid->id_auth[4] = (identauth & 0x0000ff00) >> 8;
398         sid->id_auth[5] = (identauth & 0x000000ff);
399
400         sid->num_auths = 0;
401
402         while ((p = strtok(0, "-")) != NULL)
403         {
404                 sid->sub_auths[sid->num_auths++] = atoi(p);
405         }
406 }
407
408 static void create_rpc_reply(RPC_HDR *hdr, uint32 call_id, int data_len)
409 {
410         if (hdr == NULL) return;
411
412         hdr->major        = 5;               /* RPC version 5 */
413         hdr->minor        = 0;               /* minor version 0 */
414         hdr->pkt_type     = 2;               /* RPC response packet */
415         hdr->frag         = 3;               /* first frag + last frag */
416         hdr->pack_type    = 1;               /* packed data representation */
417         hdr->frag_len     = data_len;        /* fragment length, fill in later */
418         hdr->auth_len     = 0;               /* authentication length */
419         hdr->call_id      = call_id;         /* call identifier - match incoming RPC */
420         hdr->alloc_hint   = data_len - 0x18; /* allocation hint (no idea) */
421         hdr->context_id   = 0;               /* presentation context identifier */
422         hdr->cancel_count = 0;               /* cancel count */
423         hdr->reserved     = 0;               /* reserved */
424 }
425
426 static void make_rpc_reply(char *inbuf, char *q, int data_len)
427 {
428         uint32 callid = RIVAL(inbuf, 12);
429         RPC_HDR hdr;
430
431         create_rpc_reply(&hdr, callid, data_len);
432         smb_io_rpc_hdr(False, &hdr, q, q, 4);
433 }
434
435 static int lsa_reply_open_policy(char *q, char *base)
436 {
437         char *start = q;
438         LSA_R_OPEN_POL r_o;
439
440         /* set up the LSA QUERY INFO response */
441         bzero(&(r_o.pol.data), POL_HND_SIZE);
442         r_o.status = 0x0;
443
444         /* store the response in the SMB stream */
445         q = lsa_io_r_open_pol(False, &r_o, q, base, 4);
446
447         /* return length of SMB data stored */
448         return q - start; 
449 }
450
451 static void make_uni_hdr(UNIHDR *hdr, int max_len, int len, uint16 terminate)
452 {
453         hdr->uni_max_len = max_len;
454         hdr->uni_str_len = len;
455         hdr->undoc       = terminate;
456 }
457
458 static void make_uni_hdr2(UNIHDR2 *hdr, int max_len, int len, uint16 terminate)
459 {
460         make_uni_hdr(&(hdr->unihdr), max_len, len, terminate);
461         hdr->undoc_buffer = len > 0 ? 1 : 0;
462 }
463
464 static void make_unistr(UNISTR *str, char *buf)
465 {
466         /* store the string (null-terminated copy) */
467         PutUniCode((char *)(str->buffer), buf);
468 }
469
470 static void make_unistr2(UNISTR2 *str, char *buf, int len, char terminate)
471 {
472         /* set up string lengths. add one if string is not null-terminated */
473         str->uni_max_len = len + (terminate != 0 ? 1 : 0);
474         str->undoc       = 0;
475         str->uni_str_len = len;
476
477         /* store the string (null-terminated copy) */
478         PutUniCode((char *)str->buffer, buf);
479
480         /* overwrite the last character: some strings are terminated with 4 not 0 */
481         str->buffer[len] = (uint16)terminate;
482 }
483
484 static void make_dom_sid2(DOM_SID2 *sid2, char *sid_str)
485 {
486         int len_sid_str = strlen(sid_str);
487
488         sid2->type = 0x5;
489         sid2->undoc = 0;
490         make_uni_hdr2(&(sid2->hdr), len_sid_str, len_sid_str, 0);
491         make_unistr  (&(sid2->str), sid_str);
492 }
493
494 static void make_dom_query(DOM_QUERY *d_q, char *dom_name, char *dom_sid)
495 {
496         int domlen = strlen(dom_name);
497
498         d_q->uni_dom_max_len = domlen * 2;
499         d_q->padding = 0;
500         d_q->uni_dom_str_len = domlen * 2;
501
502         d_q->buffer_dom_name = 0; /* domain buffer pointer */
503         d_q->buffer_dom_sid  = 0; /* domain sid pointer */
504
505         /* NOT null-terminated: 4-terminated instead! */
506         make_unistr2(&(d_q->uni_domain_name), dom_name, domlen, 4);
507
508         make_dom_sid(&(d_q->dom_sid), dom_sid);
509 }
510
511 static int lsa_reply_query_info(LSA_Q_QUERY_INFO *q_q, char *q, char *base,
512                                 char *dom_name, char *dom_sid)
513 {
514         char *start = q;
515         LSA_R_QUERY_INFO r_q;
516
517         /* set up the LSA QUERY INFO response */
518
519         r_q.undoc_buffer = 1; /* not null */
520         r_q.info_class = q_q->info_class;
521
522         make_dom_query(&r_q.dom.id5, dom_name, dom_sid);
523
524         r_q.status = 0x0;
525
526         /* store the response in the SMB stream */
527         q = lsa_io_r_query(False, &r_q, q, base, 4);
528
529         /* return length of SMB data stored */
530         return q - start; 
531 }
532
533 /* pretty much hard-coded choice of "other" sids, unfortunately... */
534 static void make_dom_ref(DOM_R_REF *ref,
535                                 char *dom_name, char *dom_sid,
536                                 char *other_sid1, char *other_sid2, char *other_sid3)
537 {
538         int len_dom_name   = strlen(dom_name);
539         int len_other_sid1 = strlen(other_sid1);
540         int len_other_sid2 = strlen(other_sid2);
541         int len_other_sid3 = strlen(other_sid3);
542
543         ref->undoc_buffer = 1;
544         ref->num_ref_doms_1 = 4;
545         ref->buffer_dom_name = 1;
546         ref->max_entries = 32;
547         ref->num_ref_doms_2 = 4;
548
549         make_uni_hdr2(&(ref->hdr_dom_name  ), len_dom_name  , len_dom_name  , 0);
550         make_uni_hdr2(&(ref->hdr_ref_dom[0]), len_other_sid1, len_other_sid1, 0);
551         make_uni_hdr2(&(ref->hdr_ref_dom[1]), len_other_sid2, len_other_sid2, 0);
552         make_uni_hdr2(&(ref->hdr_ref_dom[2]), len_other_sid3, len_other_sid3, 0);
553
554         if (dom_name != NULL)
555         {
556                 make_unistr(&(ref->uni_dom_name), dom_name);
557         }
558
559         make_dom_sid(&(ref->ref_dom[0]), dom_sid   );
560         make_dom_sid(&(ref->ref_dom[1]), other_sid1);
561         make_dom_sid(&(ref->ref_dom[2]), other_sid2);
562         make_dom_sid(&(ref->ref_dom[3]), other_sid3);
563 }
564
565 static void make_reply_lookup_sids(LSA_R_LOOKUP_SIDS *r_l,
566                                 int num_entries, char *dom_sids[MAX_LOOKUP_SIDS],
567                                 char *dom_name, char *dom_sid,
568                                 char *other_sid1, char *other_sid2, char *other_sid3)
569 {
570         int i;
571
572         make_dom_ref(&(r_l->dom_ref), dom_name, dom_sid,
573                      other_sid1, other_sid2, other_sid3);
574
575         r_l->num_entries = num_entries;
576         r_l->undoc_buffer = 1;
577         r_l->num_entries2 = num_entries;
578
579         for (i = 0; i < num_entries; i++)
580         {
581                 make_dom_sid2(&(r_l->dom_sid[i]), dom_sids[i]);
582         }
583
584         r_l->num_entries3 = num_entries;
585 }
586
587 static int lsa_reply_lookup_sids(LSA_Q_LOOKUP_SIDS *q_l, char *q, char *base,
588                                 char *dom_name, char *dom_sid,
589                                 char *other_sid1, char *other_sid2, char *other_sid3)
590 {
591         char *start = q;
592         LSA_R_LOOKUP_SIDS r_l;
593
594         /* set up the LSA Lookup SIDs response */
595         make_reply_lookup_sids(&r_l, 0, NULL, /* q_l->num_entries, q_l->dom_sids, */
596                                 dom_name, dom_sid, other_sid1, other_sid2, other_sid3);
597         r_l.status = 0x0;
598
599         /* store the response in the SMB stream */
600         q = lsa_io_r_lookup_sids(False, &r_l, q, base, 4);
601
602         /* return length of SMB data stored */
603         return q - start; 
604 }
605
606 static void make_lsa_r_req_chal(LSA_R_REQ_CHAL *r_c, char chal[8], int status)
607 {
608         memcpy(r_c->srv_chal.data, chal, sizeof(r_c->srv_chal.data));
609         r_c->status = status;
610 }
611
612 #if 0
613         char chal[8];
614         /* PAXX: set these to random values */
615         for (int i = 0; i < 8; i+++)
616         {
617                 chal[i] = 0xA5;
618         }
619 #endif
620
621 static int lsa_reply_req_chal(LSA_Q_REQ_CHAL *q_c, char *q, char *base,
622                                         char chal[8])
623 {
624         char *start = q;
625         LSA_R_REQ_CHAL r_c;
626
627         /* set up the LSA REQUEST CHALLENGE response */
628
629         make_lsa_r_req_chal(&r_c, chal, 0);
630
631         /* store the response in the SMB stream */
632         q = lsa_io_r_req_chal(False, &r_c, q, base, 4);
633
634         /* return length of SMB data stored */
635         return q - start; 
636 }
637
638 static void make_lsa_chal(DOM_CHAL *cred, char resp_cred[8])
639 {
640         memcpy(cred->data, resp_cred, sizeof(cred->data));
641 }
642
643 static void make_lsa_r_auth_2(LSA_R_AUTH_2 *r_a,
644                               char resp_cred[8], NEG_FLAGS *flgs, int status)
645 {
646         make_lsa_chal(&(r_a->srv_chal), resp_cred);
647         memcpy(&(r_a->srv_flgs), flgs, sizeof(r_a->srv_flgs));
648         r_a->status = status;
649 }
650
651 static int lsa_reply_auth_2(LSA_Q_AUTH_2 *q_a, char *q, char *base,
652                                 char resp_cred[8], int status)
653 {
654         char *start = q;
655         LSA_R_AUTH_2 r_a;
656
657         /* set up the LSA AUTH 2 response */
658
659         make_lsa_r_auth_2(&r_a, resp_cred, &(q_a->clnt_flgs), status);
660
661         /* store the response in the SMB stream */
662         q = lsa_io_r_auth_2(False, &r_a, q, base, 4);
663
664         /* return length of SMB data stored */
665         return q - start; 
666 }
667
668 static void make_lsa_dom_chal(DOM_CRED *cred, char srv_chal[8], UTIME srv_time)
669 {
670         make_lsa_chal(&(cred->challenge), srv_chal);
671         cred->timestamp = srv_time;
672 }
673         
674
675 static void make_lsa_r_srv_pwset(LSA_R_SRV_PWSET *r_a,
676                               char srv_chal[8], UTIME srv_time, int status)
677 {
678         make_lsa_dom_chal(&(r_a->srv_cred), srv_chal, srv_time);
679         r_a->status = status;
680 }
681
682 static int lsa_reply_srv_pwset(LSA_Q_SRV_PWSET *q_s, char *q, char *base,
683                                 char srv_cred[8], UTIME srv_time,
684                                 int status)
685 {
686         char *start = q;
687         LSA_R_SRV_PWSET r_s;
688
689         /* set up the LSA Server Password Set response */
690         make_lsa_r_srv_pwset(&r_s, srv_cred, srv_time, status);
691
692         /* store the response in the SMB stream */
693         q = lsa_io_r_srv_pwset(False, &r_s, q, base, 4);
694
695         /* return length of SMB data stored */
696         return q - start; 
697 }
698
699 static void make_lsa_user_info(LSA_USER_INFO *usr,
700
701         NTTIME *logon_time,
702         NTTIME *logoff_time,
703         NTTIME *kickoff_time,
704         NTTIME *pass_last_set_time,
705         NTTIME *pass_can_change_time,
706         NTTIME *pass_must_change_time,
707
708         char *user_name,
709         char *full_name,
710         char *logon_script,
711         char *profile_path,
712         char *home_dir,
713         char *dir_drive,
714
715         uint16 logon_count,
716         uint16 bad_pw_count,
717
718         uint32 user_id,
719         uint32 group_id,
720         uint32 num_groups,
721         DOM_GID *gids,
722         uint32 user_flgs,
723
724         char sess_key[16],
725
726         char *logon_srv,
727         char *logon_dom,
728
729         char *dom_sid,
730         char *other_sids) /* space-delimited set of SIDs */ 
731 {
732         /* only cope with one "other" sid, right now. */
733         /* need to count the number of space-delimited sids */
734         int i;
735         int num_other_sids = other_sids != NULL ? 1 : 0;
736
737         int len_user_name    = strlen(user_name   );
738         int len_full_name    = strlen(full_name   );
739         int len_logon_script = strlen(logon_script);
740         int len_profile_path = strlen(profile_path);
741         int len_home_dir     = strlen(home_dir    );
742         int len_dir_drive    = strlen(dir_drive   );
743
744         int len_logon_srv    = strlen(logon_srv);
745         int len_logon_dom    = strlen(logon_dom);
746
747         usr->undoc_buffer = 1; /* yes, we're bothering to put USER_INFO data here */
748
749         usr->logon_time            = *logon_time;
750         usr->logoff_time           = *logoff_time;
751         usr->kickoff_time          = *kickoff_time;
752         usr->pass_last_set_time    = *pass_last_set_time;
753         usr->pass_can_change_time  = *pass_can_change_time;
754         usr->pass_must_change_time = *pass_must_change_time;
755
756         make_uni_hdr(&(usr->hdr_user_name   ), len_user_name   , len_user_name   , 4);
757         make_uni_hdr(&(usr->hdr_full_name   ), len_full_name   , len_full_name   , 4);
758         make_uni_hdr(&(usr->hdr_logon_script), len_logon_script, len_logon_script, 4);
759         make_uni_hdr(&(usr->hdr_profile_path), len_profile_path, len_profile_path, 4);
760         make_uni_hdr(&(usr->hdr_home_dir    ), len_home_dir    , len_home_dir    , 4);
761         make_uni_hdr(&(usr->hdr_dir_drive   ), len_dir_drive   , len_dir_drive   , 4);
762
763         usr->logon_count = logon_count;
764         usr->bad_pw_count = bad_pw_count;
765
766         usr->user_id = user_id;
767         usr->group_id = group_id;
768         usr->num_groups = num_groups;
769         usr->buffer_groups = num_groups ? 1 : 0; /* yes, we're bothering to put group info in */
770         usr->user_flgs = user_flgs;
771
772         if (sess_key != NULL)
773         {
774                 memcpy(usr->sess_key, sess_key, sizeof(usr->sess_key));
775         }
776         else
777         {
778                 bzero(usr->sess_key, sizeof(usr->sess_key));
779         }
780
781         make_uni_hdr(&(usr->hdr_logon_srv), len_logon_srv, len_logon_srv, 4);
782         make_uni_hdr(&(usr->hdr_logon_dom), len_logon_dom, len_logon_dom, 4);
783
784         usr->buffer_dom_id = dom_sid ? 1 : 0; /* yes, we're bothering to put a domain SID in */
785
786         bzero(usr->padding, sizeof(usr->padding));
787
788         usr->num_other_sids = num_other_sids;
789         usr->buffer_other_sids = num_other_sids != 0 ? 1 : 0; 
790         
791         make_unistr2(&(usr->uni_user_name   ), user_name   , len_user_name   , 0);
792         make_unistr2(&(usr->uni_full_name   ), full_name   , len_full_name   , 0);
793         make_unistr2(&(usr->uni_logon_script), logon_script, len_logon_script, 0);
794         make_unistr2(&(usr->uni_profile_path), profile_path, len_profile_path, 0);
795         make_unistr2(&(usr->uni_home_dir    ), home_dir    , len_home_dir    , 0);
796         make_unistr2(&(usr->uni_dir_drive   ), dir_drive   , len_dir_drive   , 0);
797
798         usr->num_groups2 = num_groups;
799         for (i = 0; i < num_groups; i++)
800         {
801                 usr->gids[i] = gids[i];
802         }
803
804         make_unistr2(&(usr->uni_logon_srv), logon_srv, len_logon_srv, 0);
805         make_unistr2(&(usr->uni_logon_dom), logon_dom, len_logon_dom, 0);
806
807         make_dom_sid(&(usr->dom_sid), dom_sid);
808         make_dom_sid(&(usr->other_sids[0]), other_sids);
809 }
810
811
812 static int lsa_reply_sam_logon(LSA_Q_SAM_LOGON *q_s, char *q, char *base,
813                                 char srv_cred[8], UTIME srv_time,
814                                 LSA_USER_INFO *user_info)
815 {
816         char *start = q;
817         LSA_R_SAM_LOGON r_s;
818
819         /* XXXX maybe we want to say 'no', reject the client's credentials */
820         r_s.buffer_creds = 1; /* yes, we have valid server credentials */
821         make_lsa_dom_chal(&(r_s.srv_creds), srv_cred, srv_time);
822
823         /* store the user information, if there is any. */
824         r_s.user = user_info;
825         r_s.buffer_user = user_info != NULL ? 1 : 0;
826         r_s.status = user_info != NULL ? 0 : (0xC000000|NT_STATUS_NO_SUCH_USER);
827
828         /* store the response in the SMB stream */
829         q = lsa_io_r_sam_logon(False, &r_s, q, base, 4);
830
831         /* return length of SMB data stored */
832         return q - start; 
833 }
834
835
836 static int lsa_reply_sam_logoff(LSA_Q_SAM_LOGOFF *q_s, char *q, char *base,
837                                 char srv_cred[8], UTIME srv_time,
838                                 uint32 status)
839 {
840         char *start = q;
841         LSA_R_SAM_LOGOFF r_s;
842
843         /* XXXX maybe we want to say 'no', reject the client's credentials */
844         r_s.buffer_creds = 1; /* yes, we have valid server credentials */
845         make_lsa_dom_chal(&(r_s.srv_creds), srv_cred, srv_time);
846
847         r_s.status = status;
848
849         /* store the response in the SMB stream */
850         q = lsa_io_r_sam_logoff(False, &r_s, q, base, 4);
851
852         /* return length of SMB data stored */
853         return q - start; 
854 }
855
856
857 static void api_lsa_open_policy( char *param, char *data,
858                              char **rdata, int *rdata_len )
859 {
860         int reply_len;
861
862         /* we might actually want to decode the query, but it's not necessary */
863         /* lsa_io_q_open_policy(...); */
864
865         /* return a 20 byte policy handle */
866         reply_len = lsa_reply_open_policy(*rdata + 0x18, *rdata + 0x18);
867
868         /* construct header, now that we know the reply length */
869         make_rpc_reply(data, *rdata, reply_len);
870         *rdata_len = reply_len + 0x18;
871 }
872
873 static void api_lsa_query_info( char *param, char *data,
874                                 char **rdata, int *rdata_len )
875 {
876         int reply_len;
877
878         LSA_Q_QUERY_INFO q_i;
879         pstring dom_name;
880         pstring dom_sid;
881
882         /* grab the info class and policy handle */
883         lsa_io_q_query(True, &q_i, data + 0x18, data + 0x18, 4);
884
885         pstrcpy(dom_name, lp_workgroup());
886         pstrcpy(dom_sid , lp_domainsid());
887
888         /* construct reply.  return status is always 0x0 */
889         reply_len = lsa_reply_query_info(&q_i, *rdata + 0x18, *rdata + 0x18, 
890                                                                          dom_name, dom_sid);
891
892         /* construct header, now that we know the reply length */
893         make_rpc_reply(data, *rdata, reply_len);
894         *rdata_len = reply_len + 0x18;
895 }