bedf847cc4393db5f025b39acfdd92a15f444d87
[kai/samba.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 char *dom_sid_to_string(DOM_SID *sid)
375 {
376   static pstring sidstr;
377   char subauth[16];
378   int i;
379   uint32 ia = (sid->id_auth[0]) +
380               (sid->id_auth[1] << 8 ) +
381               (sid->id_auth[2] << 16) +
382               (sid->id_auth[3] << 24);
383
384   sprintf(sidstr, "S-%d-%d", sid->sid_no, ia);
385
386   for (i = 0; i < sid->num_auths; i++)
387   {
388     sprintf(subauth, "-%d", sid->sub_auths[i]);
389     strcat(sidstr, subauth);
390   }
391
392   DEBUG(5,("dom_sid_to_string returning %s\n", sidstr));
393   return sidstr;
394 }
395
396 /* BIG NOTE: this function only does SIDS where the identauth is not >= 2^32 */
397 /* identauth >= 2^32 can be detected because it will be specified in hex */
398 static void make_dom_sid(DOM_SID *sid, char *domsid)
399 {
400         int identauth;
401         char *p;
402
403         DEBUG(4,("netlogon domain SID: %s\n", domsid));
404
405         /* assume, but should check, that domsid starts "S-" */
406         p = strtok(domsid+2,"-");
407         sid->sid_no = atoi(p);
408
409         /* identauth in decimal should be <  2^32 */
410         /* identauth in hex     should be >= 2^32 */
411         identauth = atoi(strtok(0,"-"));
412
413         DEBUG(4,("netlogon rev %d\n", sid->sid_no));
414         DEBUG(4,("netlogon %s ia %d\n", p, identauth));
415
416         sid->id_auth[0] = 0;
417         sid->id_auth[1] = 0;
418         sid->id_auth[2] = (identauth & 0xff000000) >> 24;
419         sid->id_auth[3] = (identauth & 0x00ff0000) >> 16;
420         sid->id_auth[4] = (identauth & 0x0000ff00) >> 8;
421         sid->id_auth[5] = (identauth & 0x000000ff);
422
423         sid->num_auths = 0;
424
425         while ((p = strtok(0, "-")) != NULL)
426         {
427                 sid->sub_auths[sid->num_auths++] = atoi(p);
428         }
429 }
430
431 static void create_rpc_reply(RPC_HDR *hdr, uint32 call_id, int data_len)
432 {
433         if (hdr == NULL) return;
434
435         hdr->major        = 5;               /* RPC version 5 */
436         hdr->minor        = 0;               /* minor version 0 */
437         hdr->pkt_type     = 2;               /* RPC response packet */
438         hdr->frag         = 3;               /* first frag + last frag */
439         hdr->pack_type    = 1;               /* packed data representation */
440         hdr->frag_len     = data_len;        /* fragment length, fill in later */
441         hdr->auth_len     = 0;               /* authentication length */
442         hdr->call_id      = call_id;         /* call identifier - match incoming RPC */
443         hdr->alloc_hint   = data_len - 0x18; /* allocation hint (no idea) */
444         hdr->context_id   = 0;               /* presentation context identifier */
445         hdr->cancel_count = 0;               /* cancel count */
446         hdr->reserved     = 0;               /* reserved */
447 }
448
449 static void make_rpc_reply(char *inbuf, char *q, int data_len)
450 {
451         uint32 callid = RIVAL(inbuf, 12);
452         RPC_HDR hdr;
453
454         create_rpc_reply(&hdr, callid, data_len);
455         smb_io_rpc_hdr(False, &hdr, q, q, 4);
456 }
457
458 static int lsa_reply_open_policy(char *q, char *base)
459 {
460         char *start = q;
461         LSA_R_OPEN_POL r_o;
462
463         /* set up the LSA QUERY INFO response */
464         bzero(&(r_o.pol.data), POL_HND_SIZE);
465         r_o.status = 0x0;
466
467         /* store the response in the SMB stream */
468         q = lsa_io_r_open_pol(False, &r_o, q, base, 4);
469
470         /* return length of SMB data stored */
471         return q - start; 
472 }
473
474 static void make_uni_hdr(UNIHDR *hdr, int max_len, int len, uint16 terminate)
475 {
476         hdr->uni_max_len = max_len;
477         hdr->uni_str_len = len;
478         hdr->undoc       = terminate;
479 }
480
481 static void make_uni_hdr2(UNIHDR2 *hdr, int max_len, int len, uint16 terminate)
482 {
483         make_uni_hdr(&(hdr->unihdr), max_len, len, terminate);
484         hdr->undoc_buffer = len > 0 ? 1 : 0;
485 }
486
487 static void make_unistr(UNISTR *str, char *buf)
488 {
489         /* store the string (null-terminated copy) */
490         PutUniCode((char *)(str->buffer), buf);
491 }
492
493 static void make_unistr2(UNISTR2 *str, char *buf, int len, char terminate)
494 {
495         /* set up string lengths. add one if string is not null-terminated */
496         str->uni_max_len = len + (terminate != 0 ? 1 : 0);
497         str->undoc       = 0;
498         str->uni_str_len = len;
499
500         /* store the string (null-terminated copy) */
501         PutUniCode((char *)str->buffer, buf);
502
503         /* overwrite the last character: some strings are terminated with 4 not 0 */
504         str->buffer[len] = (uint16)terminate;
505 }
506
507 static void make_dom_sid2(DOM_SID2 *sid2, char *sid_str)
508 {
509         int len_sid_str = strlen(sid_str);
510
511         sid2->type = 0x5;
512         sid2->undoc = 0;
513         make_uni_hdr2(&(sid2->hdr), len_sid_str, len_sid_str, 0);
514         make_unistr  (&(sid2->str), sid_str);
515 }
516
517 static void make_dom_query(DOM_QUERY *d_q, char *dom_name, char *dom_sid)
518 {
519         int domlen = strlen(dom_name);
520
521         d_q->uni_dom_max_len = domlen * 2;
522         d_q->padding = 0;
523         d_q->uni_dom_str_len = domlen * 2;
524
525         d_q->buffer_dom_name = 0; /* domain buffer pointer */
526         d_q->buffer_dom_sid  = 0; /* domain sid pointer */
527
528         /* NOT null-terminated: 4-terminated instead! */
529         make_unistr2(&(d_q->uni_domain_name), dom_name, domlen, 4);
530
531         make_dom_sid(&(d_q->dom_sid), dom_sid);
532 }
533
534 static int lsa_reply_query_info(LSA_Q_QUERY_INFO *q_q, char *q, char *base,
535                                 char *dom_name, char *dom_sid)
536 {
537         char *start = q;
538         LSA_R_QUERY_INFO r_q;
539
540         /* set up the LSA QUERY INFO response */
541
542         r_q.undoc_buffer = 1; /* not null */
543         r_q.info_class = q_q->info_class;
544
545         make_dom_query(&r_q.dom.id5, dom_name, dom_sid);
546
547         r_q.status = 0x0;
548
549         /* store the response in the SMB stream */
550         q = lsa_io_r_query(False, &r_q, q, base, 4);
551
552         /* return length of SMB data stored */
553         return q - start; 
554 }
555
556 /* pretty much hard-coded choice of "other" sids, unfortunately... */
557 static void make_dom_ref(DOM_R_REF *ref,
558                                 char *dom_name, char *dom_sid,
559                                 char *other_sid1, char *other_sid2, char *other_sid3)
560 {
561         int len_dom_name   = strlen(dom_name);
562         int len_other_sid1 = strlen(other_sid1);
563         int len_other_sid2 = strlen(other_sid2);
564         int len_other_sid3 = strlen(other_sid3);
565
566         ref->undoc_buffer = 1;
567         ref->num_ref_doms_1 = 4;
568         ref->buffer_dom_name = 1;
569         ref->max_entries = 32;
570         ref->num_ref_doms_2 = 4;
571
572         make_uni_hdr2(&(ref->hdr_dom_name  ), len_dom_name  , len_dom_name  , 0);
573         make_uni_hdr2(&(ref->hdr_ref_dom[0]), len_other_sid1, len_other_sid1, 0);
574         make_uni_hdr2(&(ref->hdr_ref_dom[1]), len_other_sid2, len_other_sid2, 0);
575         make_uni_hdr2(&(ref->hdr_ref_dom[2]), len_other_sid3, len_other_sid3, 0);
576
577         if (dom_name != NULL)
578         {
579                 make_unistr(&(ref->uni_dom_name), dom_name);
580         }
581
582         make_dom_sid(&(ref->ref_dom[0]), dom_sid   );
583         make_dom_sid(&(ref->ref_dom[1]), other_sid1);
584         make_dom_sid(&(ref->ref_dom[2]), other_sid2);
585         make_dom_sid(&(ref->ref_dom[3]), other_sid3);
586 }
587
588 static void make_reply_lookup_sids(LSA_R_LOOKUP_SIDS *r_l,
589                                 int num_entries, fstring dom_sids[MAX_LOOKUP_SIDS],
590                                 char *dom_name, char *dom_sid,
591                                 char *other_sid1, char *other_sid2, char *other_sid3)
592 {
593         int i;
594
595         make_dom_ref(&(r_l->dom_ref), dom_name, dom_sid,
596                      other_sid1, other_sid2, other_sid3);
597
598         r_l->num_entries = num_entries;
599         r_l->undoc_buffer = 1;
600         r_l->num_entries2 = num_entries;
601
602         for (i = 0; i < num_entries; i++)
603         {
604                 make_dom_sid2(&(r_l->dom_sid[i]), dom_sids[i]);
605         }
606
607         r_l->num_entries3 = num_entries;
608 }
609
610 static int lsa_reply_lookup_sids(char *q, char *base,
611                                 int num_entries, fstring dom_sids[MAX_LOOKUP_SIDS],
612                                 char *dom_name, char *dom_sid,
613                                 char *other_sid1, char *other_sid2, char *other_sid3)
614 {
615         char *start = q;
616         LSA_R_LOOKUP_SIDS r_l;
617
618         /* set up the LSA Lookup SIDs response */
619         make_reply_lookup_sids(&r_l, num_entries, dom_sids,
620                                 dom_name, dom_sid, other_sid1, other_sid2, other_sid3);
621         r_l.status = 0x0;
622
623         /* store the response in the SMB stream */
624         q = lsa_io_r_lookup_sids(False, &r_l, q, base, 4);
625
626         /* return length of SMB data stored */
627         return q - start; 
628 }
629
630 static void make_lsa_r_req_chal(LSA_R_REQ_CHAL *r_c, char chal[8], int status)
631 {
632         memcpy(r_c->srv_chal.data, chal, sizeof(r_c->srv_chal.data));
633         r_c->status = status;
634 }
635
636 #if 0
637         char chal[8];
638         /* PAXX: set these to random values */
639         for (int i = 0; i < 8; i+++)
640         {
641                 chal[i] = 0xA5;
642         }
643 #endif
644
645 static int lsa_reply_req_chal(LSA_Q_REQ_CHAL *q_c, char *q, char *base,
646                                         char chal[8])
647 {
648         char *start = q;
649         LSA_R_REQ_CHAL r_c;
650
651         /* set up the LSA REQUEST CHALLENGE response */
652
653         make_lsa_r_req_chal(&r_c, chal, 0);
654
655         /* store the response in the SMB stream */
656         q = lsa_io_r_req_chal(False, &r_c, q, base, 4);
657
658         /* return length of SMB data stored */
659         return q - start; 
660 }
661
662 static void make_lsa_chal(DOM_CHAL *cred, char resp_cred[8])
663 {
664         memcpy(cred->data, resp_cred, sizeof(cred->data));
665 }
666
667 static void make_lsa_r_auth_2(LSA_R_AUTH_2 *r_a,
668                               char resp_cred[8], NEG_FLAGS *flgs, int status)
669 {
670         make_lsa_chal(&(r_a->srv_chal), resp_cred);
671         memcpy(&(r_a->srv_flgs), flgs, sizeof(r_a->srv_flgs));
672         r_a->status = status;
673 }
674
675 static int lsa_reply_auth_2(LSA_Q_AUTH_2 *q_a, char *q, char *base,
676                                 char resp_cred[8], int status)
677 {
678         char *start = q;
679         LSA_R_AUTH_2 r_a;
680
681         /* set up the LSA AUTH 2 response */
682
683         make_lsa_r_auth_2(&r_a, resp_cred, &(q_a->clnt_flgs), status);
684
685         /* store the response in the SMB stream */
686         q = lsa_io_r_auth_2(False, &r_a, q, base, 4);
687
688         /* return length of SMB data stored */
689         return q - start; 
690 }
691
692 static void make_lsa_dom_chal(DOM_CRED *cred, char srv_chal[8], UTIME srv_time)
693 {
694         make_lsa_chal(&(cred->challenge), srv_chal);
695         cred->timestamp = srv_time;
696 }
697         
698
699 static void make_lsa_r_srv_pwset(LSA_R_SRV_PWSET *r_a,
700                               char srv_chal[8], UTIME srv_time, int status)
701 {
702         make_lsa_dom_chal(&(r_a->srv_cred), srv_chal, srv_time);
703         r_a->status = status;
704 }
705
706 static int lsa_reply_srv_pwset(LSA_Q_SRV_PWSET *q_s, char *q, char *base,
707                                 char srv_cred[8], UTIME srv_time,
708                                 int status)
709 {
710         char *start = q;
711         LSA_R_SRV_PWSET r_s;
712
713         /* set up the LSA Server Password Set response */
714         make_lsa_r_srv_pwset(&r_s, srv_cred, srv_time, status);
715
716         /* store the response in the SMB stream */
717         q = lsa_io_r_srv_pwset(False, &r_s, q, base, 4);
718
719         /* return length of SMB data stored */
720         return q - start; 
721 }
722
723 static void make_lsa_user_info(LSA_USER_INFO *usr,
724
725         NTTIME *logon_time,
726         NTTIME *logoff_time,
727         NTTIME *kickoff_time,
728         NTTIME *pass_last_set_time,
729         NTTIME *pass_can_change_time,
730         NTTIME *pass_must_change_time,
731
732         char *user_name,
733         char *full_name,
734         char *logon_script,
735         char *profile_path,
736         char *home_dir,
737         char *dir_drive,
738
739         uint16 logon_count,
740         uint16 bad_pw_count,
741
742         uint32 user_id,
743         uint32 group_id,
744         uint32 num_groups,
745         DOM_GID *gids,
746         uint32 user_flgs,
747
748         char sess_key[16],
749
750         char *logon_srv,
751         char *logon_dom,
752
753         char *dom_sid,
754         char *other_sids) /* space-delimited set of SIDs */ 
755 {
756         /* only cope with one "other" sid, right now. */
757         /* need to count the number of space-delimited sids */
758         int i;
759         int num_other_sids = other_sids != NULL ? 1 : 0;
760
761         int len_user_name    = strlen(user_name   );
762         int len_full_name    = strlen(full_name   );
763         int len_logon_script = strlen(logon_script);
764         int len_profile_path = strlen(profile_path);
765         int len_home_dir     = strlen(home_dir    );
766         int len_dir_drive    = strlen(dir_drive   );
767
768         int len_logon_srv    = strlen(logon_srv);
769         int len_logon_dom    = strlen(logon_dom);
770
771         usr->undoc_buffer = 1; /* yes, we're bothering to put USER_INFO data here */
772
773         usr->logon_time            = *logon_time;
774         usr->logoff_time           = *logoff_time;
775         usr->kickoff_time          = *kickoff_time;
776         usr->pass_last_set_time    = *pass_last_set_time;
777         usr->pass_can_change_time  = *pass_can_change_time;
778         usr->pass_must_change_time = *pass_must_change_time;
779
780         make_uni_hdr(&(usr->hdr_user_name   ), len_user_name   , len_user_name   , 4);
781         make_uni_hdr(&(usr->hdr_full_name   ), len_full_name   , len_full_name   , 4);
782         make_uni_hdr(&(usr->hdr_logon_script), len_logon_script, len_logon_script, 4);
783         make_uni_hdr(&(usr->hdr_profile_path), len_profile_path, len_profile_path, 4);
784         make_uni_hdr(&(usr->hdr_home_dir    ), len_home_dir    , len_home_dir    , 4);
785         make_uni_hdr(&(usr->hdr_dir_drive   ), len_dir_drive   , len_dir_drive   , 4);
786
787         usr->logon_count = logon_count;
788         usr->bad_pw_count = bad_pw_count;
789
790         usr->user_id = user_id;
791         usr->group_id = group_id;
792         usr->num_groups = num_groups;
793         usr->buffer_groups = num_groups ? 1 : 0; /* yes, we're bothering to put group info in */
794         usr->user_flgs = user_flgs;
795
796         if (sess_key != NULL)
797         {
798                 memcpy(usr->sess_key, sess_key, sizeof(usr->sess_key));
799         }
800         else
801         {
802                 bzero(usr->sess_key, sizeof(usr->sess_key));
803         }
804
805         make_uni_hdr(&(usr->hdr_logon_srv), len_logon_srv, len_logon_srv, 4);
806         make_uni_hdr(&(usr->hdr_logon_dom), len_logon_dom, len_logon_dom, 4);
807
808         usr->buffer_dom_id = dom_sid ? 1 : 0; /* yes, we're bothering to put a domain SID in */
809
810         bzero(usr->padding, sizeof(usr->padding));
811
812         usr->num_other_sids = num_other_sids;
813         usr->buffer_other_sids = num_other_sids != 0 ? 1 : 0; 
814         
815         make_unistr2(&(usr->uni_user_name   ), user_name   , len_user_name   , 0);
816         make_unistr2(&(usr->uni_full_name   ), full_name   , len_full_name   , 0);
817         make_unistr2(&(usr->uni_logon_script), logon_script, len_logon_script, 0);
818         make_unistr2(&(usr->uni_profile_path), profile_path, len_profile_path, 0);
819         make_unistr2(&(usr->uni_home_dir    ), home_dir    , len_home_dir    , 0);
820         make_unistr2(&(usr->uni_dir_drive   ), dir_drive   , len_dir_drive   , 0);
821
822         usr->num_groups2 = num_groups;
823         for (i = 0; i < num_groups; i++)
824         {
825                 usr->gids[i] = gids[i];
826         }
827
828         make_unistr2(&(usr->uni_logon_srv), logon_srv, len_logon_srv, 0);
829         make_unistr2(&(usr->uni_logon_dom), logon_dom, len_logon_dom, 0);
830
831         make_dom_sid(&(usr->dom_sid), dom_sid);
832         make_dom_sid(&(usr->other_sids[0]), other_sids);
833 }
834
835
836 static int lsa_reply_sam_logon(LSA_Q_SAM_LOGON *q_s, char *q, char *base,
837                                 char srv_cred[8], UTIME srv_time,
838                                 LSA_USER_INFO *user_info)
839 {
840         char *start = q;
841         LSA_R_SAM_LOGON 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         /* store the user information, if there is any. */
848         r_s.user = user_info;
849         r_s.buffer_user = user_info != NULL ? 1 : 0;
850         r_s.status = user_info != NULL ? 0 : (0xC000000|NT_STATUS_NO_SUCH_USER);
851
852         /* store the response in the SMB stream */
853         q = lsa_io_r_sam_logon(False, &r_s, q, base, 4);
854
855         /* return length of SMB data stored */
856         return q - start; 
857 }
858
859
860 static int lsa_reply_sam_logoff(LSA_Q_SAM_LOGOFF *q_s, char *q, char *base,
861                                 char srv_cred[8], UTIME srv_time,
862                                 uint32 status)
863 {
864         char *start = q;
865         LSA_R_SAM_LOGOFF r_s;
866
867         /* XXXX maybe we want to say 'no', reject the client's credentials */
868         r_s.buffer_creds = 1; /* yes, we have valid server credentials */
869         make_lsa_dom_chal(&(r_s.srv_creds), srv_cred, srv_time);
870
871         r_s.status = status;
872
873         /* store the response in the SMB stream */
874         q = lsa_io_r_sam_logoff(False, &r_s, q, base, 4);
875
876         /* return length of SMB data stored */
877         return q - start; 
878 }
879
880
881 static void api_lsa_open_policy( char *param, char *data,
882                              char **rdata, int *rdata_len )
883 {
884         int reply_len;
885
886         /* we might actually want to decode the query, but it's not necessary */
887         /* lsa_io_q_open_policy(...); */
888
889         /* return a 20 byte policy handle */
890         reply_len = lsa_reply_open_policy(*rdata + 0x18, *rdata + 0x18);
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 }
896
897 static void api_lsa_query_info( char *param, char *data,
898                                 char **rdata, int *rdata_len )
899 {
900         int reply_len;
901
902         LSA_Q_QUERY_INFO q_i;
903         pstring dom_name;
904         pstring dom_sid;
905
906         /* grab the info class and policy handle */
907         lsa_io_q_query(True, &q_i, data + 0x18, data + 0x18, 4);
908
909         pstrcpy(dom_name, lp_workgroup());
910         pstrcpy(dom_sid , lp_domainsid());
911
912         /* construct reply.  return status is always 0x0 */
913         reply_len = lsa_reply_query_info(&q_i, *rdata + 0x18, *rdata + 0x18, 
914                                                                          dom_name, dom_sid);
915
916         /* construct header, now that we know the reply length */
917         make_rpc_reply(data, *rdata, reply_len);
918         *rdata_len = reply_len + 0x18;
919 }
920
921 static void api_lsa_lookup_sids( char *param, char *data,
922                                  char **rdata, int *rdata_len )
923 {
924         int reply_len;
925
926         int i;
927         LSA_Q_LOOKUP_SIDS q_l;
928         pstring dom_name;
929         pstring dom_sid;
930         fstring dom_sids[MAX_LOOKUP_SIDS];
931
932         /* grab the info class and policy handle */
933         lsa_io_q_lookup_sids(True, &q_l, data + 0x18, data + 0x18, 4);
934
935         pstrcpy(dom_name, lp_workgroup());
936         pstrcpy(dom_sid , lp_domainsid());
937
938         /* convert received SIDs to strings, so we can do them. */
939         for (i = 0; i < q_l.num_entries; i++)
940         {
941                 fstrcpy(dom_sids[i], dom_sid_to_string(&(q_l.dom_sids[i])));
942         }
943
944         /* construct reply.  return status is always 0x0 */
945         reply_len = lsa_reply_lookup_sids(*rdata + 0x18, *rdata + 0x18,
946                     q_l.num_entries, dom_sids, /* text-converted SIDs */
947                                 dom_name, dom_sid, /* domain name, domain SID */
948                                 "S-1-1", "S-1-3", "S-1-5"); /* the three other SIDs */
949
950         /* construct header, now that we know the reply length */
951         make_rpc_reply(data, *rdata, reply_len);
952         *rdata_len = reply_len + 0x18;
953 }
954
955 /* space in front of this function so that make proto doesn't pick it up */
956  void _dummy_function(void)
957 {
958         UTIME t;
959         lsa_reply_req_chal(NULL, NULL, NULL, NULL);
960         lsa_reply_auth_2(NULL, NULL, NULL, NULL, 0);
961         lsa_reply_srv_pwset(NULL, NULL, NULL, NULL, t, 0);
962         make_lsa_user_info(NULL,
963                                                 NULL, NULL, NULL, NULL, NULL, NULL,
964                                            NULL, NULL, NULL, NULL, NULL, NULL,
965                                                 0, 0,
966                         0, 0, 0, NULL, 0,
967                                                  NULL,
968                                                 NULL, NULL,
969                                                 NULL, NULL);
970         lsa_reply_sam_logon(NULL,NULL,NULL,NULL,t, NULL);
971         lsa_reply_sam_logoff(NULL,NULL,NULL,NULL,t,0);
972         api_lsa_open_policy(NULL,NULL,NULL,NULL);
973         api_lsa_query_info(NULL,NULL,NULL,NULL);
974         api_lsa_lookup_sids(NULL,NULL,NULL,NULL);
975 }