this is the bug change to using connection_struct* instead of cnum.
[samba.git] / source3 / smbd / ipc.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Inter-process communication and named pipe handling
5    Copyright (C) Andrew Tridgell 1992-1998
6
7    SMB Version handling
8    Copyright (C) John H Terpstra 1995-1998
9    
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23    */
24 /*
25    This file handles the named pipe and mailslot calls
26    in the SMBtrans protocol
27    */
28
29 #include "includes.h"
30 #include "nterr.h"
31
32 #ifdef CHECK_TYPES
33 #undef CHECK_TYPES
34 #endif
35 #define CHECK_TYPES 0
36
37 extern int DEBUGLEVEL;
38 extern int max_send;
39 extern files_struct Files[];
40
41 extern fstring local_machine;
42 extern fstring global_myworkgroup;
43
44 #define NERR_Success 0
45 #define NERR_badpass 86
46 #define NERR_notsupported 50
47
48 #define NERR_BASE (2100)
49 #define NERR_BufTooSmall (NERR_BASE+23)
50 #define NERR_JobNotFound (NERR_BASE+51)
51 #define NERR_DestNotFound (NERR_BASE+52)
52 #define ERROR_INVALID_LEVEL 124
53
54 #define ACCESS_READ 0x01
55 #define ACCESS_WRITE 0x02
56 #define ACCESS_CREATE 0x04
57
58 #define SHPWLEN 8               /* share password length */
59 #define NNLEN 12                /* 8.3 net name length */
60 #define SNLEN 15                /* service name length */
61 #define QNLEN 12                /* queue name maximum length */
62
63 extern int Client;
64 extern int oplock_sock;
65 extern int smb_read_error;
66
67 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
68                             int mdrcnt,int mprcnt,
69                             char **rdata,char **rparam,
70                             int *rdata_len,int *rparam_len);
71 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
72                          int mdrcnt,int mprcnt,
73                          char **rdata,char **rparam,
74                          int *rdata_len,int *rparam_len);
75
76
77 static int CopyExpanded(connection_struct *conn, 
78                         int snum, char** dst, char* src, int* n)
79 {
80         pstring buf;
81         int l;
82
83         if (!src || !dst || !n || !(*dst)) return(0);
84
85         StrnCpy(buf,src,sizeof(buf)/2);
86         string_sub(buf,"%S",lp_servicename(snum));
87         standard_sub(conn,buf);
88         StrnCpy(*dst,buf,*n);
89         l = strlen(*dst) + 1;
90         (*dst) += l;
91         (*n) -= l;
92         return l;
93 }
94
95 static int CopyAndAdvance(char** dst, char* src, int* n)
96 {
97   int l;
98   if (!src || !dst || !n || !(*dst)) return(0);
99   StrnCpy(*dst,src,*n);
100   l = strlen(*dst) + 1;
101   (*dst) += l;
102   (*n) -= l;
103   return l;
104 }
105
106 static int StrlenExpanded(connection_struct *conn, int snum, char* s)
107 {
108         pstring buf;
109         if (!s) return(0);
110         StrnCpy(buf,s,sizeof(buf)/2);
111         string_sub(buf,"%S",lp_servicename(snum));
112         standard_sub(conn,buf);
113         return strlen(buf) + 1;
114 }
115
116 static char* Expand(connection_struct *conn, int snum, char* s)
117 {
118         static pstring buf;
119         if (!s) return(NULL);
120         StrnCpy(buf,s,sizeof(buf)/2);
121         string_sub(buf,"%S",lp_servicename(snum));
122         standard_sub(conn,buf);
123         return &buf[0];
124 }
125
126 /*******************************************************************
127   check a API string for validity when we only need to check the prefix
128   ******************************************************************/
129 static BOOL prefix_ok(char *str,char *prefix)
130 {
131   return(strncmp(str,prefix,strlen(prefix)) == 0);
132 }
133
134 /*******************************************************************
135  copies parameters and data, as needed, into the smb buffer
136
137  *both* the data and params sections should be aligned.  this
138  is fudged in the rpc pipes by 
139  at present, only the data section is.  this may be a possible
140  cause of some of the ipc problems being experienced.  lkcl26dec97
141
142  ******************************************************************/
143 static void copy_trans_params_and_data(char *outbuf, int align,
144                                 struct mem_buf *rparam, struct mem_buf *rdata,
145                                 int param_offset, int data_offset,
146                                 int param_len, int data_len)
147 {
148         char *copy_into = smb_buf(outbuf);
149
150         DEBUG(5,("copy_trans_params_and_data: params[%d..%d] data[%d..%d]\n",
151                         param_offset, param_offset + param_len,
152                         data_offset , data_offset  + data_len));
153
154         if (param_len) mem_buf_copy(copy_into, rparam, param_offset, param_len);
155         copy_into += param_len + align;
156         if (data_len ) mem_buf_copy(copy_into, rdata , data_offset , data_len);
157 }
158
159 /****************************************************************************
160   send a trans reply
161   ****************************************************************************/
162 static void send_trans_reply(char *outbuf,
163                                 struct mem_buf *rdata,
164                                 struct mem_buf *rparam,
165                                 uint16 *setup, int lsetup, int max_data_ret)
166 {
167         int i;
168         int this_ldata,this_lparam;
169         int tot_data=0,tot_param=0;
170         int align;
171
172         int ldata  = rdata  ? mem_buf_len(rdata ) : 0;
173         int lparam = rparam ? mem_buf_len(rparam) : 0;
174
175         BOOL buffer_too_large = max_data_ret ? ldata > max_data_ret : False;
176
177         if (buffer_too_large)
178         {
179                 DEBUG(5,("send_trans_reply: buffer %d too large %d\n", ldata, max_data_ret));
180                 ldata = max_data_ret;
181         }
182
183         this_lparam = MIN(lparam,max_send - (500+lsetup*SIZEOFWORD)); /* hack */
184         this_ldata  = MIN(ldata,max_send - (500+lsetup*SIZEOFWORD+this_lparam));
185
186 #ifdef CONFUSE_NETMONITOR_MSRPC_DECODING
187         /* if you don't want Net Monitor to decode your packets, do this!!! */
188         align = ((this_lparam+1)%4);
189 #else
190         align = (this_lparam%4);
191 #endif
192
193         set_message(outbuf,10+lsetup,align+this_ldata+this_lparam,True);
194
195         if (buffer_too_large)
196         {
197                 /* issue a buffer size warning.  on a DCE/RPC pipe, expect an SMBreadX... */
198                 SIVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
199                 SIVAL(outbuf, smb_rcls, 0x80000000 | NT_STATUS_ACCESS_VIOLATION);
200         }
201
202         copy_trans_params_and_data(outbuf, align,
203                                    rparam     , rdata,
204                                    tot_param  , tot_data,
205                                    this_lparam, this_ldata);
206
207         SSVAL(outbuf,smb_vwv0,lparam);
208         SSVAL(outbuf,smb_vwv1,ldata);
209         SSVAL(outbuf,smb_vwv3,this_lparam);
210         SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf),outbuf));
211         SSVAL(outbuf,smb_vwv5,0);
212         SSVAL(outbuf,smb_vwv6,this_ldata);
213         SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+this_lparam+align,outbuf));
214         SSVAL(outbuf,smb_vwv8,0);
215         SSVAL(outbuf,smb_vwv9,lsetup);
216
217         for (i=0;i<lsetup;i++)
218         {
219                 SSVAL(outbuf,smb_vwv10+i*SIZEOFWORD,setup[i]);
220         }
221
222         show_msg(outbuf);
223         send_smb(Client,outbuf);
224
225         tot_data = this_ldata;
226         tot_param = this_lparam;
227
228         while (tot_data < ldata || tot_param < lparam)
229         {
230                 this_lparam = MIN(lparam-tot_param, max_send - 500); /* hack */
231                 this_ldata  = MIN(ldata -tot_data , max_send - (500+this_lparam));
232
233                 align = (this_lparam%4);
234
235                 set_message(outbuf,10,this_ldata+this_lparam+align,False);
236
237                 copy_trans_params_and_data(outbuf, align,
238                                            rparam     , rdata,
239                                            tot_param  , tot_data,
240                                            this_lparam, this_ldata);
241
242                 SSVAL(outbuf,smb_vwv3,this_lparam);
243                 SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf),outbuf));
244                 SSVAL(outbuf,smb_vwv5,tot_param);
245                 SSVAL(outbuf,smb_vwv6,this_ldata);
246                 SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+this_lparam+align,outbuf));
247                 SSVAL(outbuf,smb_vwv8,tot_data);
248                 SSVAL(outbuf,smb_vwv9,0);
249
250                 show_msg(outbuf);
251                 send_smb(Client,outbuf);
252
253                 tot_data  += this_ldata;
254                 tot_param += this_lparam;
255         }
256 }
257
258 struct pack_desc {
259   char* format;     /* formatstring for structure */
260   char* subformat;  /* subformat for structure */
261   char* base;       /* baseaddress of buffer */
262   int buflen;      /* remaining size for fixed part; on init: length of base */
263   int subcount;     /* count of substructures */
264   char* structbuf;  /* pointer into buffer for remaining fixed part */
265   int stringlen;    /* remaining size for variable part */              
266   char* stringbuf;  /* pointer into buffer for remaining variable part */
267   int neededlen;    /* total needed size */
268   int usedlen;      /* total used size (usedlen <= neededlen and usedlen <= buflen) */
269   char* curpos;     /* current position; pointer into format or subformat */
270   int errcode;
271 };
272
273 static int get_counter(char** p)
274 {
275   int i, n;
276   if (!p || !(*p)) return(1);
277   if (!isdigit(**p)) return 1;
278   for (n = 0;;) {
279     i = **p;
280     if (isdigit(i))
281       n = 10 * n + (i - '0');
282     else
283       return n;
284     (*p)++;
285   }
286 }
287
288 static int getlen(char* p)
289 {
290   int n = 0;
291   if (!p) return(0);
292   while (*p) {
293     switch( *p++ ) {
294     case 'W':                   /* word (2 byte) */
295       n += 2;
296       break;
297     case 'N':                   /* count of substructures (word) at end */
298       n += 2;
299       break;
300     case 'D':                   /* double word (4 byte) */
301     case 'z':                   /* offset to zero terminated string (4 byte) */
302     case 'l':                   /* offset to user data (4 byte) */
303       n += 4;
304       break;
305     case 'b':                   /* offset to data (with counter) (4 byte) */
306       n += 4;
307       get_counter(&p);
308       break;
309     case 'B':                   /* byte (with optional counter) */
310       n += get_counter(&p);
311       break;
312     }
313   }
314   return n;
315 }
316
317 static BOOL init_package(struct pack_desc* p, int count, int subcount)
318 {
319   int n = p->buflen;
320   int i;
321
322   if (!p->format || !p->base) return(False);
323
324   i = count * getlen(p->format);
325   if (p->subformat) i += subcount * getlen(p->subformat);
326   p->structbuf = p->base;
327   p->neededlen = 0;
328   p->usedlen = 0;
329   p->subcount = 0;
330   p->curpos = p->format;
331   if (i > n) {
332     p->neededlen = i;
333     i = n = 0;
334     p->errcode = ERRmoredata;
335   }
336   else
337     p->errcode = NERR_Success;
338   p->buflen = i;
339   n -= i;
340   p->stringbuf = p->base + i;
341   p->stringlen = n;
342   return(p->errcode == NERR_Success);
343 }
344
345 #ifdef HAVE_STDARG_H
346 static int package(struct pack_desc* p, ...)
347 {
348 #else
349 static int package(va_alist)
350 va_dcl
351 {
352   struct pack_desc* p;
353 #endif
354   va_list args;
355   int needed=0, stringneeded;
356   char* str=NULL;
357   int is_string=0, stringused;
358   int32 temp;
359
360 #ifdef HAVE_STDARG_H
361   va_start(args,p);
362 #else
363   va_start(args);
364   p = va_arg(args,struct pack_desc *);
365 #endif
366
367   if (!*p->curpos) {
368     if (!p->subcount)
369       p->curpos = p->format;
370     else {
371       p->curpos = p->subformat;
372       p->subcount--;
373     }
374   }
375 #if CHECK_TYPES
376   str = va_arg(args,char*);
377   if (strncmp(str,p->curpos,strlen(str)) != 0) {
378     DEBUG(2,("type error in package: %s instead of %*s\n",str,
379              strlen(str),p->curpos));
380     va_end(args);
381 #if AJT
382     ajt_panic();
383 #endif  
384     return 0;
385   }
386 #endif
387   stringneeded = -1;
388
389   if (!p->curpos) return(0);
390
391   switch( *p->curpos++ ) {
392   case 'W':                     /* word (2 byte) */
393     needed = 2;
394     temp = va_arg(args,int);
395     if (p->buflen >= needed) SSVAL(p->structbuf,0,temp);
396     break;
397   case 'N':                     /* count of substructures (word) at end */
398     needed = 2;
399     p->subcount = va_arg(args,int);
400     if (p->buflen >= needed) SSVAL(p->structbuf,0,p->subcount);
401     break;
402   case 'D':                     /* double word (4 byte) */
403     needed = 4;
404     temp = va_arg(args,int);
405     if (p->buflen >= needed) SIVAL(p->structbuf,0,temp);
406     break;
407   case 'B':                     /* byte (with optional counter) */
408     needed = get_counter(&p->curpos);
409     {
410       char *s = va_arg(args,char*);
411       if (p->buflen >= needed) StrnCpy(p->structbuf,s?s:"",needed);
412     }
413     break;
414   case 'z':                     /* offset to zero terminated string (4 byte) */
415     str = va_arg(args,char*);
416     stringneeded = (str ? strlen(str)+1 : 0);
417     is_string = 1;
418     break;
419   case 'l':                     /* offset to user data (4 byte) */
420     str = va_arg(args,char*);
421     stringneeded = va_arg(args,int);
422     is_string = 0;
423     break;
424   case 'b':                     /* offset to data (with counter) (4 byte) */
425     str = va_arg(args,char*);
426     stringneeded = get_counter(&p->curpos);
427     is_string = 0;
428     break;
429   }
430   va_end(args);
431   if (stringneeded >= 0) {
432     needed = 4;
433     if (p->buflen >= needed) {
434       stringused = stringneeded;
435       if (stringused > p->stringlen) {
436         stringused = (is_string ? p->stringlen : 0);
437         if (p->errcode == NERR_Success) p->errcode = ERRmoredata;
438       }
439       if (!stringused)
440         SIVAL(p->structbuf,0,0);
441       else {
442         SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
443         memcpy(p->stringbuf,str?str:"",stringused);
444         if (is_string) p->stringbuf[stringused-1] = '\0';
445         p->stringbuf += stringused;
446         p->stringlen -= stringused;
447         p->usedlen += stringused;
448       }
449     }
450     p->neededlen += stringneeded;
451   }
452   p->neededlen += needed;
453   if (p->buflen >= needed) {
454     p->structbuf += needed;
455     p->buflen -= needed;
456     p->usedlen += needed;
457   }
458   else {
459     if (p->errcode == NERR_Success) p->errcode = ERRmoredata;
460   }
461   return 1;
462 }
463
464 #if CHECK_TYPES
465 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
466 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
467 #else
468 #define PACK(desc,t,v) package(desc,v)
469 #define PACKl(desc,t,v,l) package(desc,v,l)
470 #endif
471
472 static void PACKI(struct pack_desc* desc,char *t,int v)
473 {
474   PACK(desc,t,v);
475 }
476
477 static void PACKS(struct pack_desc* desc,char *t,char *v)
478 {
479   PACK(desc,t,v);
480 }
481
482
483 /****************************************************************************
484   get a print queue
485   ****************************************************************************/
486
487 static void PackDriverData(struct pack_desc* desc)
488 {
489   char drivdata[4+4+32];
490   SIVAL(drivdata,0,sizeof drivdata); /* cb */
491   SIVAL(drivdata,4,1000);       /* lVersion */
492   memset(drivdata+8,0,32);      /* szDeviceName */
493   pstrcpy(drivdata+8,"NULL");
494   PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
495 }
496
497 static int check_printq_info(struct pack_desc* desc,
498                              int uLevel, char *id1, char *id2)
499 {
500   desc->subformat = NULL;
501   switch( uLevel ) {
502   case 0:
503     desc->format = "B13";
504     break;
505   case 1:
506     desc->format = "B13BWWWzzzzzWW";
507     break;
508   case 2:
509     desc->format = "B13BWWWzzzzzWN";
510     desc->subformat = "WB21BB16B10zWWzDDz";
511     break;
512   case 3:
513     desc->format = "zWWWWzzzzWWzzl";
514     break;
515   case 4:
516     desc->format = "zWWWWzzzzWNzzl";
517     desc->subformat = "WWzWWDDzz";
518     break;
519   case 5:
520     desc->format = "z";
521     break;
522   case 52:
523     desc->format = "WzzzzzzzzN";
524     desc->subformat = "z";
525     break;
526   default: return False;
527   }
528   if (strcmp(desc->format,id1) != 0) return False;
529   if (desc->subformat && strcmp(desc->subformat,id2) != 0) return False;
530   return True;
531 }
532
533 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
534                                struct pack_desc* desc,
535                                print_queue_struct* queue, int n)
536 {
537   time_t t = queue->time;
538
539   /* the client expects localtime */
540   t -= TimeDiff(t);
541
542   PACKI(desc,"W",printjob_encode(snum, queue->job)); /* uJobId */
543   if (uLevel == 1) {
544     PACKS(desc,"B21",queue->user); /* szUserName */
545     PACKS(desc,"B","");         /* pad */
546     PACKS(desc,"B16","");       /* szNotifyName */
547     PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
548     PACKS(desc,"z","");         /* pszParms */
549     PACKI(desc,"W",n+1);                /* uPosition */
550     PACKI(desc,"W",queue->status); /* fsStatus */
551     PACKS(desc,"z","");         /* pszStatus */
552     PACKI(desc,"D",t); /* ulSubmitted */
553     PACKI(desc,"D",queue->size); /* ulSize */
554     PACKS(desc,"z",queue->file); /* pszComment */
555   }
556   if (uLevel == 2 || uLevel == 3) {
557     PACKI(desc,"W",queue->priority);            /* uPriority */
558     PACKS(desc,"z",queue->user); /* pszUserName */
559     PACKI(desc,"W",n+1);                /* uPosition */
560     PACKI(desc,"W",queue->status); /* fsStatus */
561     PACKI(desc,"D",t); /* ulSubmitted */
562     PACKI(desc,"D",queue->size); /* ulSize */
563     PACKS(desc,"z","Samba");    /* pszComment */
564     PACKS(desc,"z",queue->file); /* pszDocument */
565     if (uLevel == 3) {
566       PACKS(desc,"z","");       /* pszNotifyName */
567       PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
568       PACKS(desc,"z","");       /* pszParms */
569       PACKS(desc,"z","");       /* pszStatus */
570       PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
571       PACKS(desc,"z","lpd");    /* pszQProcName */
572       PACKS(desc,"z","");       /* pszQProcParms */
573       PACKS(desc,"z","NULL"); /* pszDriverName */
574       PackDriverData(desc);     /* pDriverData */
575       PACKS(desc,"z","");       /* pszPrinterName */
576     }
577   }
578 }
579
580 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
581                              struct pack_desc* desc,
582                              int count, print_queue_struct* queue,
583                              print_status_struct* status)
584 {
585   switch (uLevel) {
586     case 1:
587     case 2:
588       PACKS(desc,"B13",SERVICE(snum));
589       break;
590     case 3:
591     case 4:
592     case 5:
593       PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
594       break;
595   }
596
597   if (uLevel == 1 || uLevel == 2) {
598     PACKS(desc,"B","");         /* alignment */
599     PACKI(desc,"W",5);          /* priority */
600     PACKI(desc,"W",0);          /* start time */
601     PACKI(desc,"W",0);          /* until time */
602     PACKS(desc,"z","");         /* pSepFile */
603     PACKS(desc,"z","lpd");      /* pPrProc */
604     PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
605     PACKS(desc,"z","");         /* pParms */
606     if (snum < 0) {
607       PACKS(desc,"z","UNKNOWN PRINTER");
608       PACKI(desc,"W",LPSTAT_ERROR);
609     }
610     else if (!status || !status->message[0]) {
611       PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
612       PACKI(desc,"W",LPSTAT_OK); /* status */
613     } else {
614       PACKS(desc,"z",status->message);
615       PACKI(desc,"W",status->status); /* status */
616     }
617     PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
618   }
619   if (uLevel == 3 || uLevel == 4) {
620     PACKI(desc,"W",5);          /* uPriority */
621     PACKI(desc,"W",0);          /* uStarttime */
622     PACKI(desc,"W",0);          /* uUntiltime */
623     PACKI(desc,"W",5);          /* pad1 */
624     PACKS(desc,"z","");         /* pszSepFile */
625     PACKS(desc,"z","WinPrint"); /* pszPrProc */
626     PACKS(desc,"z","");         /* pszParms */
627     if (!status || !status->message[0]) {
628       PACKS(desc,"z",Expand(conn,snum,lp_comment(snum))); /* pszComment */
629       PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
630     } else {
631       PACKS(desc,"z",status->message); /* pszComment */
632       PACKI(desc,"W",status->status); /* fsStatus */
633     }
634     PACKI(desc,(uLevel == 3 ? "W" : "N"),count);        /* cJobs */
635     PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
636     PACKS(desc,"z",lp_printerdriver(snum));             /* pszDriverName */
637     PackDriverData(desc);       /* pDriverData */
638   }
639   if (uLevel == 2 || uLevel == 4) {
640     int i;
641     for (i=0;i<count;i++)
642       fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
643   }
644
645   if (uLevel==52) {
646     int i,ok=0;
647     pstring tok,driver,datafile,langmon,helpfile,datatype;
648     char *p,*q;
649     FILE *f;
650     pstring fname;
651
652     pstrcpy(fname,lp_driverfile());
653     f=fopen(fname,"r");
654     if (!f) {
655       DEBUG(3,("fill_printq_info: Can't open %s - %s\n",fname,strerror(errno)));
656       desc->errcode=NERR_notsupported;
657       return;
658     }
659
660     p=(char *)malloc(8192*sizeof(char));
661     bzero(p, 8192*sizeof(char));
662     q=p;
663
664     /* lookup the long printer driver name in the file description */
665     while (f && !feof(f) && !ok)
666     {
667       p = q;                    /* reset string pointer */
668       fgets(p,8191,f);
669       p[strlen(p)-1]='\0';
670       if (next_token(&p,tok,":") &&
671         (strlen(lp_printerdriver(snum)) == strlen(tok)) &&
672         (!strncmp(tok,lp_printerdriver(snum),strlen(lp_printerdriver(snum)))))
673         ok=1;
674     }
675     fclose(f);
676
677     /* driver file name */
678     if (ok && !next_token(&p,driver,":")) ok = 0;
679     /* data file name */
680     if (ok && !next_token(&p,datafile,":")) ok = 0;
681       /*
682        * for the next tokens - which may be empty - I have to check for empty
683        * tokens first because the next_token function will skip all empty
684        * token fields 
685        */
686     if (ok) {
687       /* help file */
688       if (*p == ':') {
689           *helpfile = '\0';
690           p++;
691       } else if (!next_token(&p,helpfile,":")) ok = 0;
692     }
693
694     if (ok) {
695       /* language monitor */
696       if (*p == ':') {
697           *langmon = '\0';
698           p++;
699       } else if (!next_token(&p,langmon,":")) ok = 0;
700     }
701
702     /* default data type */
703     if (ok && !next_token(&p,datatype,":")) ok = 0;
704
705     if (ok) {
706       PACKI(desc,"W",0x0400);                    /* don't know */
707       PACKS(desc,"z",lp_printerdriver(snum));    /* long printer name */
708       PACKS(desc,"z",driver);                    /* Driverfile Name */
709       PACKS(desc,"z",datafile);                  /* Datafile name */
710       PACKS(desc,"z",langmon);                   /* language monitor */
711       PACKS(desc,"z",lp_driverlocation(snum));   /* share to retrieve files */
712       PACKS(desc,"z",datatype);                  /* default data type */
713       PACKS(desc,"z",helpfile);                  /* helpfile name */
714       PACKS(desc,"z",driver);                    /* driver name */
715       DEBUG(3,("Driver:%s:\n",driver));
716       DEBUG(3,("Data File:%s:\n",datafile));
717       DEBUG(3,("Language Monitor:%s:\n",langmon));
718       DEBUG(3,("Data Type:%s:\n",datatype));
719       DEBUG(3,("Help File:%s:\n",helpfile));
720       PACKI(desc,"N",count);                     /* number of files to copy */
721       for (i=0;i<count;i++)
722       {
723         /* no need to check return value here - it was already tested in
724          * get_printerdrivernumber
725          */
726         next_token(&p,tok,",");
727         PACKS(desc,"z",tok);                        /* driver files to copy */
728         DEBUG(3,("file:%s:\n",tok));
729       }
730
731       DEBUG(3,("fill_printq_info on <%s> gave %d entries\n",
732             SERVICE(snum),count));
733     } else {
734       DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
735       desc->errcode=NERR_notsupported;
736     }
737     free(q);
738   }
739 }
740
741 /* This function returns the number of files for a given driver */
742 int get_printerdrivernumber(int snum)
743 {
744   int i=0,ok=0;
745   pstring tok;
746   char *p,*q;
747   FILE *f;
748   pstring fname;
749
750   pstrcpy(fname,lp_driverfile());
751
752   DEBUG(4,("In get_printerdrivernumber: %s\n",fname));
753   f=fopen(fname,"r");
754   if (!f) {
755     DEBUG(3,("get_printerdrivernumber: Can't open %s - %s\n",fname,strerror(errno)));
756     return(0);
757   }
758
759   p=(char *)malloc(8192*sizeof(char));
760   q=p; /* need it to free memory because p change ! */
761
762   /* lookup the long printer driver name in the file description */
763   while (!feof(f) && !ok)
764   {
765     p = q;                      /* reset string pointer */
766     fgets(p,8191,f);
767     if (next_token(&p,tok,":") &&
768       (!strncmp(tok,lp_printerdriver(snum),strlen(lp_printerdriver(snum))))) 
769         ok=1;
770   }
771   fclose(f);
772
773   if (ok) {
774     /* skip 5 fields */
775     i = 5;
776     while (*p && i) {
777       if (*p++ == ':') i--;
778     }
779     if (!*p || i)
780       return(0);
781
782     /* count the number of files */
783     while (next_token(&p,tok,","))
784        i++;
785   }
786   free(q);
787
788   return(i);
789 }
790
791 static BOOL api_DosPrintQGetInfo(connection_struct *conn,
792                                  uint16 vuid, char *param,char *data,
793                                  int mdrcnt,int mprcnt,
794                                  char **rdata,char **rparam,
795                                  int *rdata_len,int *rparam_len)
796 {
797   char *str1 = param+2;
798   char *str2 = skip_string(str1,1);
799   char *p = skip_string(str2,1);
800   char *QueueName = p;
801   int uLevel,cbBuf;
802   int count=0;
803   int snum;
804   char* str3;
805   struct pack_desc desc;
806   print_queue_struct *queue=NULL;
807   print_status_struct status;
808   
809   bzero(&status,sizeof(status));
810   bzero(&desc,sizeof(desc));
811  
812   p = skip_string(p,1);
813   uLevel = SVAL(p,0);
814   cbBuf = SVAL(p,2);
815   str3 = p + 4;
816  
817   /* remove any trailing username */
818   if ((p = strchr(QueueName,'%'))) *p = 0;
819  
820   DEBUG(3,("PrintQueue uLevel=%d name=%s\n",uLevel,QueueName));
821  
822   /* check it's a supported varient */
823   if (!prefix_ok(str1,"zWrLh")) return False;
824   if (!check_printq_info(&desc,uLevel,str2,str3)) return False;
825  
826   snum = lp_servicenumber(QueueName);
827   if (snum < 0 && pcap_printername_ok(QueueName,NULL)) {
828     int pnum = lp_servicenumber(PRINTERS_NAME);
829     if (pnum >= 0) {
830       lp_add_printer(QueueName,pnum);
831       snum = lp_servicenumber(QueueName);
832     }
833   }
834   
835   if (snum < 0 || !VALID_SNUM(snum)) return(False);
836
837   if (uLevel==52)
838   {
839     count = get_printerdrivernumber(snum);
840     DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
841   } else {
842     count = get_printqueue(SNUM(conn), conn,&queue,&status);
843   }
844
845   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
846   desc.base = *rdata;
847   desc.buflen = mdrcnt;
848   if (init_package(&desc,1,count)) {
849     desc.subcount = count;
850     fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
851   }
852
853   *rdata_len = desc.usedlen;
854   
855   *rparam_len = 6;
856   *rparam = REALLOC(*rparam,*rparam_len);
857   SSVALS(*rparam,0,desc.errcode);
858   SSVAL(*rparam,2,0);
859   SSVAL(*rparam,4,desc.neededlen);
860   
861   DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
862
863   if (queue) free(queue);
864   
865   return(True);
866 }
867
868
869 /****************************************************************************
870   view list of all print jobs on all queues
871   ****************************************************************************/
872 static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param, char* data,
873                               int mdrcnt, int mprcnt,
874                               char **rdata, char** rparam,
875                               int *rdata_len, int *rparam_len)
876 {
877   char *param_format = param+2;
878   char *output_format1 = skip_string(param_format,1);
879   char *p = skip_string(output_format1,1);
880   int uLevel = SVAL(p,0);
881   char *output_format2 = p + 4;
882   int services = lp_numservices();
883   int i, n;
884   struct pack_desc desc;
885   print_queue_struct **queue = NULL;
886   print_status_struct *status = NULL;
887   int* subcntarr = NULL;
888   int queuecnt, subcnt=0, succnt=0;
889  
890   bzero(&desc,sizeof(desc));
891
892   DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
893  
894   if (!prefix_ok(param_format,"WrLeh")) return False;
895   if (!check_printq_info(&desc,uLevel,output_format1,output_format2))
896     return False;
897   queuecnt = 0;
898   for (i = 0; i < services; i++)
899     if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
900       queuecnt++;
901   if (uLevel > 0) {
902     queue = (print_queue_struct**)malloc(queuecnt*sizeof(print_queue_struct*));
903     memset(queue,0,queuecnt*sizeof(print_queue_struct*));
904     status = (print_status_struct*)malloc(queuecnt*sizeof(print_status_struct));
905     memset(status,0,queuecnt*sizeof(print_status_struct));
906     subcntarr = (int*)malloc(queuecnt*sizeof(int));
907     subcnt = 0;
908     n = 0;
909     for (i = 0; i < services; i++)
910       if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
911         subcntarr[n] = get_printqueue(i, conn,&queue[n],&status[n]);
912         subcnt += subcntarr[n];
913         n++;
914       }
915   }
916   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
917   desc.base = *rdata;
918   desc.buflen = mdrcnt;
919
920   if (init_package(&desc,queuecnt,subcnt)) {
921     n = 0;
922     succnt = 0;
923     for (i = 0; i < services; i++)
924       if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
925         fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
926         n++;
927         if (desc.errcode == NERR_Success) succnt = n;
928       }
929   }
930
931   if (subcntarr) free(subcntarr);
932  
933   *rdata_len = desc.usedlen;
934   *rparam_len = 8;
935   *rparam = REALLOC(*rparam,*rparam_len);
936   SSVALS(*rparam,0,desc.errcode);
937   SSVAL(*rparam,2,0);
938   SSVAL(*rparam,4,succnt);
939   SSVAL(*rparam,6,queuecnt);
940   
941   for (i = 0; i < queuecnt; i++) {
942     if (queue && queue[i]) free(queue[i]);
943   }
944
945   if (queue) free(queue);
946   if (status) free(status);
947   
948   return True;
949 }
950
951 /****************************************************************************
952   get info level for a server list query
953   ****************************************************************************/
954 static BOOL check_server_info(int uLevel, char* id)
955 {
956   switch( uLevel ) {
957   case 0:
958     if (strcmp(id,"B16") != 0) return False;
959     break;
960   case 1:
961     if (strcmp(id,"B16BBDz") != 0) return False;
962     break;
963   default: 
964     return False;
965   }
966   return True;
967 }
968
969 struct srv_info_struct
970 {
971   fstring name;
972   uint32 type;
973   fstring comment;
974   fstring domain;
975   BOOL server_added;
976 };
977
978
979 /*******************************************************************
980   get server info lists from the files saved by nmbd. Return the
981   number of entries
982   ******************************************************************/
983 static int get_server_info(uint32 servertype, 
984                            struct srv_info_struct **servers,
985                            char *domain)
986 {
987   FILE *f;
988   pstring fname;
989   int count=0;
990   int alloced=0;
991   pstring line;
992   BOOL local_list_only;
993
994   pstrcpy(fname,lp_lockdir());
995   trim_string(fname,NULL,"/");
996   pstrcat(fname,"/");
997   pstrcat(fname,SERVER_LIST);
998
999   f = fopen(fname,"r");
1000
1001   if (!f) {
1002     DEBUG(4,("Can't open %s - %s\n",fname,strerror(errno)));
1003     return(0);
1004   }
1005
1006   /* request for everything is code for request all servers */
1007   if (servertype == SV_TYPE_ALL) 
1008         servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1009
1010   local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1011
1012   DEBUG(4,("Servertype search: %8x\n",servertype));
1013
1014   while (!feof(f))
1015   {
1016     fstring stype;
1017     struct srv_info_struct *s;
1018     char *ptr = line;
1019     BOOL ok = True;
1020     *ptr = 0;
1021
1022     fgets(line,sizeof(line)-1,f);
1023     if (!*line) continue;
1024     
1025     if (count == alloced) {
1026       alloced += 10;
1027       (*servers) = (struct srv_info_struct *)
1028         Realloc(*servers,sizeof(**servers)*alloced);
1029       if (!(*servers)) return(0);
1030       bzero((char *)((*servers)+count),sizeof(**servers)*(alloced-count));
1031     }
1032     s = &(*servers)[count];
1033     
1034     if (!next_token(&ptr,s->name   , NULL)) continue;
1035     if (!next_token(&ptr,stype     , NULL)) continue;
1036     if (!next_token(&ptr,s->comment, NULL)) continue;
1037     if (!next_token(&ptr,s->domain , NULL)) {
1038       /* this allows us to cope with an old nmbd */
1039       pstrcpy(s->domain,global_myworkgroup); 
1040     }
1041     
1042     if (sscanf(stype,"%X",&s->type) != 1) { 
1043       DEBUG(4,("r:host file ")); 
1044       ok = False; 
1045     }
1046     
1047         /* Filter the servers/domains we return based on what was asked for. */
1048
1049         /* Check to see if we are being asked for a local list only. */
1050         if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1051           DEBUG(4,("r: local list only"));
1052           ok = False;
1053         }
1054
1055     /* doesn't match up: don't want it */
1056     if (!(servertype & s->type)) { 
1057       DEBUG(4,("r:serv type ")); 
1058       ok = False; 
1059     }
1060     
1061     if ((servertype & SV_TYPE_DOMAIN_ENUM) != 
1062         (s->type & SV_TYPE_DOMAIN_ENUM))
1063       {
1064         DEBUG(4,("s: dom mismatch "));
1065         ok = False;
1066       }
1067     
1068     if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM))
1069       {
1070         ok = False;
1071       }
1072     
1073         /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1074         s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1075
1076     if (ok)
1077       {
1078         DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1079                  s->name, s->type, s->comment, s->domain));
1080         
1081         s->server_added = True;
1082         count++;
1083       }
1084     else
1085       {
1086         DEBUG(4,("%20s %8x %25s %15s\n",
1087                  s->name, s->type, s->comment, s->domain));
1088       }
1089   }
1090   
1091   fclose(f);
1092   return(count);
1093 }
1094
1095
1096 /*******************************************************************
1097   fill in a server info structure
1098   ******************************************************************/
1099 static int fill_srv_info(struct srv_info_struct *service, 
1100                          int uLevel, char **buf, int *buflen, 
1101                          char **stringbuf, int *stringspace, char *baseaddr)
1102 {
1103   int struct_len;
1104   char* p;
1105   char* p2;
1106   int l2;
1107   int len;
1108  
1109   switch (uLevel) {
1110   case 0: struct_len = 16; break;
1111   case 1: struct_len = 26; break;
1112   default: return -1;
1113   }  
1114  
1115   if (!buf)
1116     {
1117       len = 0;
1118       switch (uLevel) 
1119         {
1120         case 1:
1121           len = strlen(service->comment)+1;
1122           break;
1123         }
1124
1125       if (buflen) *buflen = struct_len;
1126       if (stringspace) *stringspace = len;
1127       return struct_len + len;
1128     }
1129   
1130   len = struct_len;
1131   p = *buf;
1132   if (*buflen < struct_len) return -1;
1133   if (stringbuf)
1134     {
1135       p2 = *stringbuf;
1136       l2 = *stringspace;
1137     }
1138   else
1139     {
1140       p2 = p + struct_len;
1141       l2 = *buflen - struct_len;
1142     }
1143   if (!baseaddr) baseaddr = p;
1144   
1145   switch (uLevel)
1146     {
1147     case 0:
1148       StrnCpy(p,service->name,15);
1149       break;
1150
1151     case 1:
1152       StrnCpy(p,service->name,15);
1153       SIVAL(p,18,service->type);
1154       SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1155       len += CopyAndAdvance(&p2,service->comment,&l2);
1156       break;
1157     }
1158
1159   if (stringbuf)
1160     {
1161       *buf = p + struct_len;
1162       *buflen -= struct_len;
1163       *stringbuf = p2;
1164       *stringspace = l2;
1165     }
1166   else
1167     {
1168       *buf = p2;
1169       *buflen -= len;
1170     }
1171   return len;
1172 }
1173
1174
1175 static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1176 {
1177   return(strcmp(s1->name,s2->name));
1178 }
1179
1180 /****************************************************************************
1181   view list of servers available (or possibly domains). The info is
1182   extracted from lists saved by nmbd on the local host
1183   ****************************************************************************/
1184 static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param, char *data,
1185                                int mdrcnt, int mprcnt, char **rdata, 
1186                                char **rparam, int *rdata_len, int *rparam_len)
1187 {
1188   char *str1 = param+2;
1189   char *str2 = skip_string(str1,1);
1190   char *p = skip_string(str2,1);
1191   int uLevel = SVAL(p,0);
1192   int buf_len = SVAL(p,2);
1193   uint32 servertype = IVAL(p,4);
1194   char *p2;
1195   int data_len, fixed_len, string_len;
1196   int f_len = 0, s_len = 0;
1197   struct srv_info_struct *servers=NULL;
1198   int counted=0,total=0;
1199   int i,missed;
1200   fstring domain;
1201   BOOL domain_request;
1202   BOOL local_request;
1203
1204   /* If someone sets all the bits they don't really mean to set
1205      DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1206      known servers. */
1207
1208   if (servertype == SV_TYPE_ALL) 
1209     servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1210
1211   /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1212      any other bit (they may just set this bit on it's own) they 
1213      want all the locally seen servers. However this bit can be 
1214      set on its own so set the requested servers to be 
1215      ALL - DOMAIN_ENUM. */
1216
1217   if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) 
1218     servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1219
1220   domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1221   local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1222
1223   p += 8;
1224
1225   if (!prefix_ok(str1,"WrLehD")) return False;
1226   if (!check_server_info(uLevel,str2)) return False;
1227   
1228   DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1229   DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1230   DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1231
1232   if (strcmp(str1, "WrLehDz") == 0) {
1233     StrnCpy(domain, p, sizeof(fstring)-1);
1234   } else {
1235     StrnCpy(domain, global_myworkgroup, sizeof(fstring)-1);    
1236   }
1237
1238   if (lp_browse_list())
1239     total = get_server_info(servertype,&servers,domain);
1240
1241   data_len = fixed_len = string_len = 0;
1242   missed = 0;
1243
1244   qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1245
1246   {
1247     char *lastname=NULL;
1248
1249     for (i=0;i<total;i++)
1250     {
1251       struct srv_info_struct *s = &servers[i];
1252       if (lastname && strequal(lastname,s->name)) continue;
1253       lastname = s->name;
1254       data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1255       DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1256                s->name, s->type, s->comment, s->domain));
1257       
1258       if (data_len <= buf_len) {
1259           counted++;
1260           fixed_len += f_len;
1261           string_len += s_len;
1262       } else {
1263         missed++;
1264       }
1265     }
1266   }
1267
1268   *rdata_len = fixed_len + string_len;
1269   *rdata = REALLOC(*rdata,*rdata_len);
1270   bzero(*rdata,*rdata_len);
1271   
1272   p2 = (*rdata) + fixed_len;    /* auxilliary data (strings) will go here */
1273   p = *rdata;
1274   f_len = fixed_len;
1275   s_len = string_len;
1276
1277   {
1278     char *lastname=NULL;
1279     int count2 = counted;
1280     for (i = 0; i < total && count2;i++)
1281       {
1282         struct srv_info_struct *s = &servers[i];
1283         if (lastname && strequal(lastname,s->name)) continue;
1284         lastname = s->name;
1285         fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1286         DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1287                  s->name, s->type, s->comment, s->domain));
1288         count2--;
1289       }
1290   }
1291   
1292   *rparam_len = 8;
1293   *rparam = REALLOC(*rparam,*rparam_len);
1294   SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1295   SSVAL(*rparam,2,0);
1296   SSVAL(*rparam,4,counted);
1297   SSVAL(*rparam,6,counted+missed);
1298
1299   if (servers) free(servers);
1300
1301   DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1302            domain,uLevel,counted,counted+missed));
1303
1304   return(True);
1305 }
1306
1307 /****************************************************************************
1308   command 0x34 - suspected of being a "Lookup Names" stub api
1309   ****************************************************************************/
1310 static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid, char *param, char *data,
1311                                int mdrcnt, int mprcnt, char **rdata, 
1312                                char **rparam, int *rdata_len, int *rparam_len)
1313 {
1314   char *str1 = param+2;
1315   char *str2 = skip_string(str1,1);
1316   char *p = skip_string(str2,1);
1317   int uLevel = SVAL(p,0);
1318   int buf_len = SVAL(p,2);
1319   int counted=0;
1320   int missed=0;
1321
1322         DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1323                 str1, str2, p, uLevel, buf_len));
1324
1325   if (!prefix_ok(str1,"zWrLeh")) return False;
1326   
1327   *rdata_len = 0;
1328   *rdata = NULL;
1329   
1330   *rparam_len = 8;
1331   *rparam = REALLOC(*rparam,*rparam_len);
1332
1333   SSVAL(*rparam,0,0x08AC); /* informational warning message */
1334   SSVAL(*rparam,2,0);
1335   SSVAL(*rparam,4,counted);
1336   SSVAL(*rparam,6,counted+missed);
1337
1338   return(True);
1339 }
1340
1341 /****************************************************************************
1342   get info about a share
1343   ****************************************************************************/
1344 static BOOL check_share_info(int uLevel, char* id)
1345 {
1346   switch( uLevel ) {
1347   case 0:
1348     if (strcmp(id,"B13") != 0) return False;
1349     break;
1350   case 1:
1351     if (strcmp(id,"B13BWz") != 0) return False;
1352     break;
1353   case 2:
1354     if (strcmp(id,"B13BWzWWWzB9B") != 0) return False;
1355     break;
1356   case 91:
1357     if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) return False;
1358     break;
1359   default: return False;
1360   }
1361   return True;
1362 }
1363
1364 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1365                            char** buf, int* buflen,
1366                            char** stringbuf, int* stringspace, char* baseaddr)
1367 {
1368   int struct_len;
1369   char* p;
1370   char* p2;
1371   int l2;
1372   int len;
1373  
1374   switch( uLevel ) {
1375   case 0: struct_len = 13; break;
1376   case 1: struct_len = 20; break;
1377   case 2: struct_len = 40; break;
1378   case 91: struct_len = 68; break;
1379   default: return -1;
1380   }
1381   
1382  
1383   if (!buf)
1384     {
1385       len = 0;
1386       if (uLevel > 0) len += StrlenExpanded(conn,snum,lp_comment(snum));
1387       if (uLevel > 1) len += strlen(lp_pathname(snum)) + 1;
1388       if (buflen) *buflen = struct_len;
1389       if (stringspace) *stringspace = len;
1390       return struct_len + len;
1391     }
1392   
1393   len = struct_len;
1394   p = *buf;
1395   if ((*buflen) < struct_len) return -1;
1396   if (stringbuf)
1397     {
1398       p2 = *stringbuf;
1399       l2 = *stringspace;
1400     }
1401   else
1402     {
1403       p2 = p + struct_len;
1404       l2 = (*buflen) - struct_len;
1405     }
1406   if (!baseaddr) baseaddr = p;
1407   
1408   StrnCpy(p,lp_servicename(snum),13);
1409   
1410   if (uLevel > 0)
1411     {
1412       int type;
1413       CVAL(p,13) = 0;
1414       type = STYPE_DISKTREE;
1415       if (lp_print_ok(snum)) type = STYPE_PRINTQ;
1416       if (strequal("IPC$",lp_servicename(snum))) type = STYPE_IPC;
1417       SSVAL(p,14,type);         /* device type */
1418       SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1419       len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1420     }
1421   
1422   if (uLevel > 1)
1423     {
1424       SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1425       SSVALS(p,22,-1);          /* max uses */
1426       SSVAL(p,24,1); /* current uses */
1427       SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1428       len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1429       memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1430     }
1431   
1432   if (uLevel > 2)
1433     {
1434       memset(p+40,0,SHPWLEN+2);
1435       SSVAL(p,50,0);
1436       SIVAL(p,52,0);
1437       SSVAL(p,56,0);
1438       SSVAL(p,58,0);
1439       SIVAL(p,60,0);
1440       SSVAL(p,64,0);
1441       SSVAL(p,66,0);
1442     }
1443        
1444   if (stringbuf)
1445     {
1446       (*buf) = p + struct_len;
1447       (*buflen) -= struct_len;
1448       (*stringbuf) = p2;
1449       (*stringspace) = l2;
1450     }
1451   else
1452     {
1453       (*buf) = p2;
1454       (*buflen) -= len;
1455     }
1456   return len;
1457 }
1458
1459 static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
1460                                  int mdrcnt,int mprcnt,
1461                                  char **rdata,char **rparam,
1462                                  int *rdata_len,int *rparam_len)
1463 {
1464   char *str1 = param+2;
1465   char *str2 = skip_string(str1,1);
1466   char *netname = skip_string(str2,1);
1467   char *p = skip_string(netname,1);
1468   int uLevel = SVAL(p,0);
1469   int snum = find_service(netname);
1470   
1471   if (snum < 0) return False;
1472   
1473   /* check it's a supported varient */
1474   if (!prefix_ok(str1,"zWrLh")) return False;
1475   if (!check_share_info(uLevel,str2)) return False;
1476  
1477   *rdata = REALLOC(*rdata,mdrcnt);
1478   p = *rdata;
1479   *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1480   if (*rdata_len < 0) return False;
1481  
1482   *rparam_len = 6;
1483   *rparam = REALLOC(*rparam,*rparam_len);
1484   SSVAL(*rparam,0,NERR_Success);
1485   SSVAL(*rparam,2,0);           /* converter word */
1486   SSVAL(*rparam,4,*rdata_len);
1487  
1488   return(True);
1489 }
1490
1491 /****************************************************************************
1492   view list of shares available
1493   ****************************************************************************/
1494 static BOOL api_RNetShareEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
1495                               int mdrcnt,int mprcnt,
1496                               char **rdata,char **rparam,
1497                               int *rdata_len,int *rparam_len)
1498 {
1499   char *str1 = param+2;
1500   char *str2 = skip_string(str1,1);
1501   char *p = skip_string(str2,1);
1502   int uLevel = SVAL(p,0);
1503   int buf_len = SVAL(p,2);
1504   char *p2;
1505   int count=lp_numservices();
1506   int total=0,counted=0;
1507   BOOL missed = False;
1508   int i;
1509   int data_len, fixed_len, string_len;
1510   int f_len = 0, s_len = 0;
1511  
1512   if (!prefix_ok(str1,"WrLeh")) return False;
1513   if (!check_share_info(uLevel,str2)) return False;
1514   
1515   data_len = fixed_len = string_len = 0;
1516   for (i=0;i<count;i++)
1517     if (lp_browseable(i) && lp_snum_ok(i))
1518     {
1519       total++;
1520       data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1521       if (data_len <= buf_len)
1522       {
1523         counted++;
1524         fixed_len += f_len;
1525         string_len += s_len;
1526       }
1527       else
1528         missed = True;
1529     }
1530   *rdata_len = fixed_len + string_len;
1531   *rdata = REALLOC(*rdata,*rdata_len);
1532   memset(*rdata,0,*rdata_len);
1533   
1534   p2 = (*rdata) + fixed_len;    /* auxillery data (strings) will go here */
1535   p = *rdata;
1536   f_len = fixed_len;
1537   s_len = string_len;
1538   for (i = 0; i < count;i++)
1539     if (lp_browseable(i) && lp_snum_ok(i))
1540       if (fill_share_info(conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata) < 0)
1541         break;
1542   
1543   *rparam_len = 8;
1544   *rparam = REALLOC(*rparam,*rparam_len);
1545   SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1546   SSVAL(*rparam,2,0);
1547   SSVAL(*rparam,4,counted);
1548   SSVAL(*rparam,6,total);
1549   
1550   DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1551            counted,total,uLevel,
1552            buf_len,*rdata_len,mdrcnt));
1553   return(True);
1554 }
1555
1556
1557
1558 /****************************************************************************
1559   get the time of day info
1560   ****************************************************************************/
1561 static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid, char *param,char *data,
1562                              int mdrcnt,int mprcnt,
1563                              char **rdata,char **rparam,
1564                              int *rdata_len,int *rparam_len)
1565 {
1566   char *p;
1567   *rparam_len = 4;
1568   *rparam = REALLOC(*rparam,*rparam_len);
1569
1570   *rdata_len = 21;
1571   *rdata = REALLOC(*rdata,*rdata_len);
1572
1573   SSVAL(*rparam,0,NERR_Success);
1574   SSVAL(*rparam,2,0);           /* converter word */
1575
1576   p = *rdata;
1577
1578   {
1579     struct tm *t;
1580     time_t unixdate = time(NULL);
1581
1582     put_dos_date3(p,0,unixdate); /* this is the time that is looked at
1583                                     by NT in a "net time" operation,
1584                                     it seems to ignore the one below */
1585
1586     /* the client expects to get localtime, not GMT, in this bit 
1587        (I think, this needs testing) */
1588     t = LocalTime(&unixdate);
1589
1590     SIVAL(p,4,0);               /* msecs ? */
1591     CVAL(p,8) = t->tm_hour;
1592     CVAL(p,9) = t->tm_min;
1593     CVAL(p,10) = t->tm_sec;
1594     CVAL(p,11) = 0;             /* hundredths of seconds */
1595     SSVALS(p,12,TimeDiff(unixdate)/60); /* timezone in minutes from GMT */
1596     SSVAL(p,14,10000);          /* timer interval in 0.0001 of sec */
1597     CVAL(p,16) = t->tm_mday;
1598     CVAL(p,17) = t->tm_mon + 1;
1599     SSVAL(p,18,1900+t->tm_year);
1600     CVAL(p,20) = t->tm_wday;
1601   }
1602
1603
1604   return(True);
1605 }
1606
1607 /****************************************************************************
1608   set the user password
1609   ****************************************************************************/
1610 static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1611                                 int mdrcnt,int mprcnt,
1612                                 char **rdata,char **rparam,
1613                                 int *rdata_len,int *rparam_len)
1614 {
1615   char *p = skip_string(param+2,2);
1616   fstring user;
1617   fstring pass1,pass2;
1618
1619   fstrcpy(user,p);
1620
1621   p = skip_string(p,1);
1622
1623   memcpy(pass1,p,16);
1624   memcpy(pass2,p+16,16);
1625
1626   *rparam_len = 4;
1627   *rparam = REALLOC(*rparam,*rparam_len);
1628
1629   *rdata_len = 0;
1630
1631   SSVAL(*rparam,0,NERR_badpass);
1632   SSVAL(*rparam,2,0);           /* converter word */
1633
1634   DEBUG(3,("Set password for <%s>\n",user));
1635
1636   /*
1637    * Pass the user through the NT -> unix user mapping
1638    * function.
1639    */
1640
1641   (void)map_username(user);
1642
1643   /*
1644    * Do any UNIX username case mangling.
1645    */
1646   (void)Get_Pwnam( user, True);
1647
1648   /*
1649    * Attempt the plaintext password change first.
1650    * Older versions of Windows seem to do this.
1651    */
1652
1653   if (password_ok(user,pass1,strlen(pass1),NULL) &&
1654       chgpasswd(user,pass1,pass2,False))
1655   {
1656     SSVAL(*rparam,0,NERR_Success);
1657   }
1658
1659   /*
1660    * If the plaintext change failed, attempt
1661    * the encrypted. NT will generate this
1662    * after trying the samr method.
1663    */
1664
1665   if(SVAL(*rparam,0) != NERR_Success)
1666   {
1667     struct smb_passwd *sampw = NULL;
1668
1669     if(check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &sampw) && 
1670        change_lanman_password(sampw,(unsigned char *)pass1,(unsigned char *)pass2))
1671     {
1672       SSVAL(*rparam,0,NERR_Success);
1673     }
1674   }
1675
1676   bzero(pass1,sizeof(fstring));
1677   bzero(pass2,sizeof(fstring));  
1678          
1679   return(True);
1680 }
1681
1682 /****************************************************************************
1683   Set the user password (SamOEM version - gets plaintext).
1684 ****************************************************************************/
1685
1686 static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1687                                 int mdrcnt,int mprcnt,
1688                                 char **rdata,char **rparam,
1689                                 int *rdata_len,int *rparam_len)
1690 {
1691   fstring user;
1692   fstring new_passwd;
1693   struct smb_passwd *sampw = NULL;
1694   char *p = param + 2;
1695   int ret = True;
1696
1697   *rparam_len = 2;
1698   *rparam = REALLOC(*rparam,*rparam_len);
1699
1700   *rdata_len = 0;
1701
1702   SSVAL(*rparam,0,NERR_badpass);
1703
1704   /*
1705    * Check the parameter definition is correct.
1706    */
1707   if(!strequal(param + 2, "zsT")) {
1708     DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %sn\n", param + 2));
1709     return False;
1710   }
1711   p = skip_string(p, 1);
1712
1713   if(!strequal(p, "B516B16")) {
1714     DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %sn\n", p));
1715     return False;
1716   }
1717   p = skip_string(p,1);
1718
1719   fstrcpy(user,p);
1720   p = skip_string(p,1);
1721
1722   DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
1723
1724   /*
1725    * Pass the user through the NT -> unix user mapping
1726    * function.
1727    */
1728
1729   (void)map_username(user);
1730
1731   /*
1732    * Do any UNIX username case mangling.
1733    */
1734   (void)Get_Pwnam( user, True);
1735
1736   if(check_oem_password( user, (unsigned char *)data, &sampw, 
1737                          new_passwd, (int)sizeof(new_passwd)) == False) {
1738     return True;
1739   }
1740
1741   /* 
1742    * At this point we have the new case-sensitive plaintext
1743    * password in the fstring new_passwd. If we wanted to synchronise
1744    * with UNIX passwords we would call a UNIX password changing 
1745    * function here. However it would have to be done as root
1746    * as the plaintext of the old users password is not 
1747    * available. JRA.
1748    */
1749
1750   if(lp_unix_password_sync())
1751     ret = chgpasswd(user,"", new_passwd, True);
1752  
1753   if(ret && change_oem_password( sampw, new_passwd, False)) {
1754     SSVAL(*rparam,0,NERR_Success);
1755   }
1756
1757   return(True);
1758 }
1759
1760 /****************************************************************************
1761   delete a print job
1762   Form: <W> <> 
1763   ****************************************************************************/
1764 static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param,char *data,
1765                                 int mdrcnt,int mprcnt,
1766                                 char **rdata,char **rparam,
1767                                 int *rdata_len,int *rparam_len)
1768 {
1769   int function = SVAL(param,0);
1770   char *str1 = param+2;
1771   char *str2 = skip_string(str1,1);
1772   char *p = skip_string(str2,1);
1773   int jobid, snum;
1774   int i, count;
1775
1776   printjob_decode(SVAL(p,0), &snum, &jobid);
1777
1778   /* check it's a supported varient */
1779   if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
1780     return(False);
1781
1782   *rparam_len = 4;
1783   *rparam = REALLOC(*rparam,*rparam_len);
1784
1785   *rdata_len = 0;
1786
1787   SSVAL(*rparam,0,NERR_Success);
1788
1789   if (snum >= 0 && VALID_SNUM(snum))
1790     {
1791       print_queue_struct *queue=NULL;
1792       lpq_reset(snum);
1793       count = get_printqueue(snum,conn,&queue,NULL);
1794   
1795       for (i=0;i<count;i++)
1796         if ((queue[i].job&0xFF) == jobid)
1797           {
1798             switch (function) {
1799             case 81:            /* delete */ 
1800               DEBUG(3,("Deleting queue entry %d\n",queue[i].job));
1801               del_printqueue(conn,snum,queue[i].job);
1802               break;
1803             case 82:            /* pause */
1804             case 83:            /* resume */
1805               DEBUG(3,("%s queue entry %d\n",
1806                        (function==82?"pausing":"resuming"),queue[i].job));
1807               status_printjob(conn,snum,queue[i].job,
1808                               (function==82?LPQ_PAUSED:LPQ_QUEUED));
1809               break;
1810             }
1811             break;
1812           }
1813   
1814       if (i==count)
1815         SSVAL(*rparam,0,NERR_JobNotFound);
1816
1817       if (queue) free(queue);
1818     }
1819
1820   SSVAL(*rparam,2,0);           /* converter word */
1821
1822   return(True);
1823 }
1824
1825 /****************************************************************************
1826   Purge a print queue - or pause or resume it.
1827   ****************************************************************************/
1828 static BOOL api_WPrintQueuePurge(connection_struct *conn,uint16 vuid, char *param,char *data,
1829                                  int mdrcnt,int mprcnt,
1830                                  char **rdata,char **rparam,
1831                                  int *rdata_len,int *rparam_len)
1832 {
1833   int function = SVAL(param,0);
1834   char *str1 = param+2;
1835   char *str2 = skip_string(str1,1);
1836   char *QueueName = skip_string(str2,1);
1837   int snum;
1838
1839   /* check it's a supported varient */
1840   if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
1841     return(False);
1842
1843   *rparam_len = 4;
1844   *rparam = REALLOC(*rparam,*rparam_len);
1845
1846   *rdata_len = 0;
1847
1848   SSVAL(*rparam,0,NERR_Success);
1849   SSVAL(*rparam,2,0);           /* converter word */
1850
1851   snum = lp_servicenumber(QueueName);
1852   if (snum < 0 && pcap_printername_ok(QueueName,NULL)) {
1853     int pnum = lp_servicenumber(PRINTERS_NAME);
1854     if (pnum >= 0) {
1855       lp_add_printer(QueueName,pnum);
1856       snum = lp_servicenumber(QueueName);
1857     }
1858   }
1859
1860   if (snum >= 0 && VALID_SNUM(snum)) {
1861     lpq_reset(snum);
1862     
1863     switch (function) {
1864     case 74: /* Pause queue */
1865     case 75: /* Resume queue */
1866       status_printqueue(conn,snum,(function==74?LPSTAT_STOPPED:LPSTAT_OK));
1867       DEBUG(3,("Print queue %s, queue=%s\n",
1868             (function==74?"pause":"resume"),QueueName));
1869       break;
1870     case 103: /* Purge */
1871       {
1872         print_queue_struct *queue=NULL;
1873         int i, count;
1874         count = get_printqueue(snum,conn,&queue,NULL);
1875         for (i = 0; i < count; i++)
1876           del_printqueue(conn,snum,queue[i].job);
1877  
1878         if (queue) free(queue);
1879         DEBUG(3,("Print queue purge, queue=%s\n",QueueName));
1880         break;
1881       }
1882     }
1883   }
1884
1885   return(True);
1886 }
1887
1888
1889 /****************************************************************************
1890   set the property of a print job (undocumented?)
1891   ? function = 0xb -> set name of print job
1892   ? function = 0x6 -> move print job up/down
1893   Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz> 
1894   or   <WWsTP> <WB21BB16B10zWWzDDz> 
1895 ****************************************************************************/
1896 static int check_printjob_info(struct pack_desc* desc,
1897                                int uLevel, char* id)
1898 {
1899   desc->subformat = NULL;
1900   switch( uLevel ) {
1901   case 0: desc->format = "W"; break;
1902   case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
1903   case 2: desc->format = "WWzWWDDzz"; break;
1904   case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
1905   default: return False;
1906   }
1907   if (strcmp(desc->format,id) != 0) return False;
1908   return True;
1909 }
1910
1911 static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,char *data,
1912                              int mdrcnt,int mprcnt,
1913                              char **rdata,char **rparam,
1914                              int *rdata_len,int *rparam_len)
1915 {
1916   struct pack_desc desc;
1917   char *str1 = param+2;
1918   char *str2 = skip_string(str1,1);
1919   char *p = skip_string(str2,1);
1920   int jobid, snum;
1921   int uLevel = SVAL(p,2);
1922   int function = SVAL(p,4);     /* what is this ?? */
1923   int i;
1924   char *s = data;
1925
1926   printjob_decode(SVAL(p,0), &snum, &jobid);
1927    
1928   *rparam_len = 4;
1929   *rparam = REALLOC(*rparam,*rparam_len);
1930   
1931   *rdata_len = 0;
1932   
1933   /* check it's a supported varient */
1934   if ((strcmp(str1,"WWsTP")) || (!check_printjob_info(&desc,uLevel,str2)))
1935     return(False);
1936    
1937   switch (function) {
1938   case 0x6:     /* change job place in the queue, data gives the new place */
1939     if (snum >= 0 && VALID_SNUM(snum))
1940       {
1941         print_queue_struct *queue=NULL;
1942         int count;
1943   
1944         lpq_reset(snum);
1945         count = get_printqueue(snum,conn,&queue,NULL);
1946         for (i=0;i<count;i++)   /* find job */
1947           if ((queue[i].job&0xFF) == jobid) break;
1948             
1949         if (i==count) {
1950           desc.errcode=NERR_JobNotFound;
1951           if (queue) free(queue);
1952         }
1953         else {
1954           desc.errcode=NERR_Success;
1955           i++;
1956 #if 0   
1957           {
1958             int place= SVAL(data,0);
1959             /* we currently have no way of doing this. Can any unix do it? */
1960             if (i < place)      /* move down */;
1961             else if (i > place )        /* move up */;
1962           }
1963 #endif
1964           desc.errcode=NERR_notsupported; /* not yet supported */
1965           if (queue) free(queue);
1966         }
1967       }
1968     else desc.errcode=NERR_JobNotFound;
1969     break;
1970   case 0xb:   /* change print job name, data gives the name */
1971     /* jobid, snum should be zero */
1972     if (isalpha(*s))
1973       {
1974         pstring name;
1975         int l = 0;
1976         while (l<64 && *s)
1977           {
1978             if (issafe(*s)) name[l++] = *s;
1979             s++;
1980           }      
1981         name[l] = 0;
1982         
1983         DEBUG(3,("Setting print name to %s\n",name));
1984         
1985         become_root(True);
1986
1987         for (i=0;i<MAX_FNUMS;i++)
1988           if (Files[i].open && Files[i].print_file)
1989             {
1990               pstring wd;
1991               connection_struct *fconn = Files[i].conn;
1992               GetWd(wd);
1993               unbecome_user();
1994               
1995               if (!become_user(fconn,vuid) || 
1996                   !become_service(fconn,True))
1997                 break;
1998               
1999               if (sys_rename(Files[i].fsp_name,name) == 0) {
2000                       string_set(&Files[i].fsp_name,name);
2001               }
2002               break;
2003             }
2004
2005          unbecome_root(True);
2006       }
2007     desc.errcode=NERR_Success;
2008   
2009     break;
2010   default:                      /* not implemented */
2011     return False;
2012   }
2013  
2014   SSVALS(*rparam,0,desc.errcode);
2015   SSVAL(*rparam,2,0);           /* converter word */
2016   
2017   return(True);
2018 }
2019
2020
2021 /****************************************************************************
2022   get info about the server
2023   ****************************************************************************/
2024 static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2025                                   int mdrcnt,int mprcnt,
2026                                   char **rdata,char **rparam,
2027                                   int *rdata_len,int *rparam_len)
2028 {
2029   char *str1 = param+2;
2030   char *str2 = skip_string(str1,1);
2031   char *p = skip_string(str2,1);
2032   int uLevel = SVAL(p,0);
2033   char *p2;
2034   int struct_len;
2035
2036   DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2037
2038   /* check it's a supported varient */
2039   if (!prefix_ok(str1,"WrLh")) return False;
2040   switch( uLevel ) {
2041   case 0:
2042     if (strcmp(str2,"B16") != 0) return False;
2043     struct_len = 16;
2044     break;
2045   case 1:
2046     if (strcmp(str2,"B16BBDz") != 0) return False;
2047     struct_len = 26;
2048     break;
2049   case 2:
2050     if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")
2051         != 0) return False;
2052     struct_len = 134;
2053     break;
2054   case 3:
2055     if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz")
2056         != 0) return False;
2057     struct_len = 144;
2058     break;
2059   case 20:
2060     if (strcmp(str2,"DN") != 0) return False;
2061     struct_len = 6;
2062     break;
2063   case 50:
2064     if (strcmp(str2,"B16BBDzWWzzz") != 0) return False;
2065     struct_len = 42;
2066     break;
2067   default: return False;
2068   }
2069
2070   *rdata_len = mdrcnt;
2071   *rdata = REALLOC(*rdata,*rdata_len);
2072
2073   p = *rdata;
2074   p2 = p + struct_len;
2075   if (uLevel != 20) {
2076     StrnCpy(p,local_machine,16);
2077     strupper(p);
2078   }
2079   p += 16;
2080   if (uLevel > 0)
2081     {
2082       struct srv_info_struct *servers=NULL;
2083       int i,count;
2084       pstring comment;
2085       uint32 servertype= lp_default_server_announce();
2086
2087       pstrcpy(comment,lp_serverstring());
2088
2089       if ((count=get_server_info(SV_TYPE_ALL,&servers,global_myworkgroup))>0) {
2090         for (i=0;i<count;i++)
2091           if (strequal(servers[i].name,local_machine))
2092       {
2093             servertype = servers[i].type;
2094             pstrcpy(comment,servers[i].comment);            
2095           }
2096       }
2097       if (servers) free(servers);
2098
2099       SCVAL(p,0,lp_major_announce_version());
2100       SCVAL(p,1,lp_minor_announce_version());
2101       SIVAL(p,2,servertype);
2102
2103       if (mdrcnt == struct_len) {
2104         SIVAL(p,6,0);
2105       } else {
2106         SIVAL(p,6,PTR_DIFF(p2,*rdata));
2107         standard_sub(conn,comment);
2108         StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2109         p2 = skip_string(p2,1);
2110       }
2111     }
2112   if (uLevel > 1)
2113     {
2114       return False;             /* not yet implemented */
2115     }
2116
2117   *rdata_len = PTR_DIFF(p2,*rdata);
2118
2119   *rparam_len = 6;
2120   *rparam = REALLOC(*rparam,*rparam_len);
2121   SSVAL(*rparam,0,NERR_Success);
2122   SSVAL(*rparam,2,0);           /* converter word */
2123   SSVAL(*rparam,4,*rdata_len);
2124
2125   return(True);
2126 }
2127
2128
2129 /****************************************************************************
2130   get info about the server
2131   ****************************************************************************/
2132 static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2133                                 int mdrcnt,int mprcnt,
2134                                 char **rdata,char **rparam,
2135                                 int *rdata_len,int *rparam_len)
2136 {
2137   char *str1 = param+2;
2138   char *str2 = skip_string(str1,1);
2139   char *p = skip_string(str2,1);
2140   char *p2;
2141   extern pstring sesssetup_user;
2142   int level = SVAL(p,0);
2143
2144   DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2145
2146   *rparam_len = 6;
2147   *rparam = REALLOC(*rparam,*rparam_len);
2148
2149   /* check it's a supported varient */
2150   if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz")))
2151     return(False);
2152
2153   *rdata_len = mdrcnt + 1024;
2154   *rdata = REALLOC(*rdata,*rdata_len);
2155
2156   SSVAL(*rparam,0,NERR_Success);
2157   SSVAL(*rparam,2,0);           /* converter word */
2158
2159   p = *rdata;
2160   p2 = p + 22;
2161
2162
2163   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2164   pstrcpy(p2,local_machine);
2165   strupper(p2);
2166   p2 = skip_string(p2,1);
2167   p += 4;
2168
2169   SIVAL(p,0,PTR_DIFF(p2,*rdata));
2170   pstrcpy(p2,sesssetup_user);
2171   p2 = skip_string(p2,1);
2172   p += 4;
2173
2174   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
2175   pstrcpy(p2,global_myworkgroup);
2176   strupper(p2);
2177   p2 = skip_string(p2,1);
2178   p += 4;
2179
2180   SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
2181   SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
2182   p += 2;
2183
2184   SIVAL(p,0,PTR_DIFF(p2,*rdata));
2185   pstrcpy(p2,global_myworkgroup);       /* don't know.  login domain?? */
2186   p2 = skip_string(p2,1);
2187   p += 4;
2188
2189   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
2190   pstrcpy(p2,"");
2191   p2 = skip_string(p2,1);
2192   p += 4;
2193
2194   *rdata_len = PTR_DIFF(p2,*rdata);
2195
2196   SSVAL(*rparam,4,*rdata_len);
2197
2198   return(True);
2199 }
2200
2201 /****************************************************************************
2202   get info about a user
2203
2204     struct user_info_11 {
2205         char                usri11_name[21];  0-20 
2206         char                usri11_pad;       21 
2207         char                *usri11_comment;  22-25 
2208         char            *usri11_usr_comment;  26-29
2209         unsigned short      usri11_priv;      30-31
2210         unsigned long       usri11_auth_flags; 32-35
2211         long                usri11_password_age; 36-39
2212         char                *usri11_homedir; 40-43
2213         char            *usri11_parms; 44-47
2214         long                usri11_last_logon; 48-51
2215         long                usri11_last_logoff; 52-55
2216         unsigned short      usri11_bad_pw_count; 56-57
2217         unsigned short      usri11_num_logons; 58-59
2218         char                *usri11_logon_server; 60-63
2219         unsigned short      usri11_country_code; 64-65
2220         char            *usri11_workstations; 66-69
2221         unsigned long       usri11_max_storage; 70-73
2222         unsigned short      usri11_units_per_week; 74-75
2223         unsigned char       *usri11_logon_hours; 76-79
2224         unsigned short      usri11_code_page; 80-81
2225     };
2226
2227 where:
2228
2229   usri11_name specifies the user name for which information is retireved
2230
2231   usri11_pad aligns the next data structure element to a word boundary
2232
2233   usri11_comment is a null terminated ASCII comment
2234
2235   usri11_user_comment is a null terminated ASCII comment about the user
2236
2237   usri11_priv specifies the level of the privilege assigned to the user.
2238        The possible values are:
2239
2240 Name             Value  Description
2241 USER_PRIV_GUEST  0      Guest privilege
2242 USER_PRIV_USER   1      User privilege
2243 USER_PRV_ADMIN   2      Administrator privilege
2244
2245   usri11_auth_flags specifies the account operator privileges. The
2246        possible values are:
2247
2248 Name            Value   Description
2249 AF_OP_PRINT     0       Print operator
2250
2251
2252 Leach, Naik                                        [Page 28]\r\f
2253
2254
2255 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
2256
2257
2258 AF_OP_COMM      1       Communications operator
2259 AF_OP_SERVER    2       Server operator
2260 AF_OP_ACCOUNTS  3       Accounts operator
2261
2262
2263   usri11_password_age specifies how many seconds have elapsed since the
2264        password was last changed.
2265
2266   usri11_home_dir points to a null terminated ASCII string that contains
2267        the path name of the user's home directory.
2268
2269   usri11_parms points to a null terminated ASCII string that is set
2270        aside for use by applications.
2271
2272   usri11_last_logon specifies the time when the user last logged on.
2273        This value is stored as the number of seconds elapsed since
2274        00:00:00, January 1, 1970.
2275
2276   usri11_last_logoff specifies the time when the user last logged off.
2277        This value is stored as the number of seconds elapsed since
2278        00:00:00, January 1, 1970. A value of 0 means the last logoff
2279        time is unknown.
2280
2281   usri11_bad_pw_count specifies the number of incorrect passwords
2282        entered since the last successful logon.
2283
2284   usri11_log1_num_logons specifies the number of times this user has
2285        logged on. A value of -1 means the number of logons is unknown.
2286
2287   usri11_logon_server points to a null terminated ASCII string that
2288        contains the name of the server to which logon requests are sent.
2289        A null string indicates logon requests should be sent to the
2290        domain controller.
2291
2292   usri11_country_code specifies the country code for the user's language
2293        of choice.
2294
2295   usri11_workstations points to a null terminated ASCII string that
2296        contains the names of workstations the user may log on from.
2297        There may be up to 8 workstations, with the names separated by
2298        commas. A null strings indicates there are no restrictions.
2299
2300   usri11_max_storage specifies the maximum amount of disk space the user
2301        can occupy. A value of 0xffffffff indicates there are no
2302        restrictions.
2303
2304   usri11_units_per_week specifies the equal number of time units into
2305        which a week is divided. This value must be equal to 168.
2306
2307   usri11_logon_hours points to a 21 byte (168 bits) string that
2308        specifies the time during which the user can log on. Each bit
2309        represents one unique hour in a week. The first bit (bit 0, word
2310        0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
2311
2312
2313
2314 Leach, Naik                                        [Page 29]\r\f
2315
2316
2317 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
2318
2319
2320        Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
2321        are no restrictions.
2322
2323   usri11_code_page specifies the code page for the user's language of
2324        choice
2325
2326 All of the pointers in this data structure need to be treated
2327 specially. The  pointer is a 32 bit pointer. The higher 16 bits need
2328 to be ignored. The converter word returned in the parameters section
2329 needs to be subtracted from the lower 16 bits to calculate an offset
2330 into the return buffer where this ASCII string resides.
2331
2332 There is no auxiliary data in the response.
2333
2334   ****************************************************************************/
2335
2336 #define usri11_name           0 
2337 #define usri11_pad            21
2338 #define usri11_comment        22
2339 #define usri11_usr_comment    26
2340 #define usri11_full_name      30
2341 #define usri11_priv           34
2342 #define usri11_auth_flags     36
2343 #define usri11_password_age   40
2344 #define usri11_homedir        44
2345 #define usri11_parms          48
2346 #define usri11_last_logon     52
2347 #define usri11_last_logoff    56
2348 #define usri11_bad_pw_count   60
2349 #define usri11_num_logons     62
2350 #define usri11_logon_server   64
2351 #define usri11_country_code   68
2352 #define usri11_workstations   70
2353 #define usri11_max_storage    74
2354 #define usri11_units_per_week 78
2355 #define usri11_logon_hours    80
2356 #define usri11_code_page      84
2357 #define usri11_end            86
2358
2359 #define USER_PRIV_GUEST 0
2360 #define USER_PRIV_USER 1
2361 #define USER_PRIV_ADMIN 2
2362
2363 #define AF_OP_PRINT     0 
2364 #define AF_OP_COMM      1
2365 #define AF_OP_SERVER    2
2366 #define AF_OP_ACCOUNTS  3
2367
2368
2369 static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2370                                 int mdrcnt,int mprcnt,
2371                                 char **rdata,char **rparam,
2372                                 int *rdata_len,int *rparam_len)
2373 {
2374         char *str1 = param+2;
2375         char *str2 = skip_string(str1,1);
2376         char *UserName = skip_string(str2,1);
2377         char *p = skip_string(UserName,1);
2378         int uLevel = SVAL(p,0);
2379         char *p2;
2380
2381     /* get NIS home of a previously validated user - simeon */
2382     /* With share level security vuid will always be zero.
2383        Don't depend on vuser being non-null !!. JRA */
2384     user_struct *vuser = get_valid_user_struct(vuid);
2385     if(vuser != NULL)
2386       DEBUG(3,("  Username of UID %d is %s\n", vuser->uid, vuser->name));
2387
2388     *rparam_len = 6;
2389     *rparam = REALLOC(*rparam,*rparam_len);
2390
2391     DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
2392   
2393         /* check it's a supported variant */
2394         if (strcmp(str1,"zWrLh") != 0) return False;
2395         switch( uLevel )
2396         {
2397                 case 0: p2 = "B21"; break;
2398                 case 1: p2 = "B21BB16DWzzWz"; break;
2399                 case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
2400                 case 10: p2 = "B21Bzzz"; break;
2401                 case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
2402                 default: return False;
2403         }
2404
2405         if (strcmp(p2,str2) != 0) return False;
2406
2407         *rdata_len = mdrcnt + 1024;
2408         *rdata = REALLOC(*rdata,*rdata_len);
2409
2410         SSVAL(*rparam,0,NERR_Success);
2411         SSVAL(*rparam,2,0);             /* converter word */
2412
2413         p = *rdata;
2414         p2 = p + usri11_end;
2415
2416         memset(p,0,21); 
2417         fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
2418
2419         if (uLevel > 0)
2420         {
2421                 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
2422                 *p2 = 0;
2423         }
2424         if (uLevel >= 10)
2425         {
2426                 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
2427                 pstrcpy(p2,"Comment");
2428                 p2 = skip_string(p2,1);
2429
2430                 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
2431                 pstrcpy(p2,"UserComment");
2432                 p2 = skip_string(p2,1);
2433
2434                 /* EEK! the cifsrap.txt doesn't have this in!!!! */
2435                 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
2436                 pstrcpy(p2,((vuser != NULL) ? vuser->real_name : UserName));
2437                 p2 = skip_string(p2,1);
2438         }
2439
2440         if (uLevel == 11) /* modelled after NTAS 3.51 reply */
2441         {         
2442                 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); 
2443                 SIVAL(p,usri11_auth_flags,AF_OP_PRINT);         /* auth flags */
2444                 SIVALS(p,usri11_password_age,-1);               /* password age */
2445                 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
2446                 pstrcpy(p2, lp_logon_path());
2447                 p2 = skip_string(p2,1);
2448                 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
2449                 pstrcpy(p2,"");
2450                 p2 = skip_string(p2,1);
2451                 SIVAL(p,usri11_last_logon,0);           /* last logon */
2452                 SIVAL(p,usri11_last_logoff,0);          /* last logoff */
2453                 SSVALS(p,usri11_bad_pw_count,-1);       /* bad pw counts */
2454                 SSVALS(p,usri11_num_logons,-1);         /* num logons */
2455                 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
2456                 pstrcpy(p2,"\\\\*");
2457                 p2 = skip_string(p2,1);
2458                 SSVAL(p,usri11_country_code,0);         /* country code */
2459
2460                 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
2461                 pstrcpy(p2,"");
2462                 p2 = skip_string(p2,1);
2463
2464                 SIVALS(p,usri11_max_storage,-1);                /* max storage */
2465                 SSVAL(p,usri11_units_per_week,168);             /* units per week */
2466                 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
2467
2468                 /* a simple way to get logon hours at all times. */
2469                 memset(p2,0xff,21);
2470                 SCVAL(p2,21,0);           /* fix zero termination */
2471                 p2 = skip_string(p2,1);
2472
2473                 SSVAL(p,usri11_code_page,0);            /* code page */
2474         }
2475         if (uLevel == 1 || uLevel == 2)
2476         {
2477                 memset(p+22,' ',16);    /* password */
2478                 SIVALS(p,38,-1);                /* password age */
2479                 SSVAL(p,42,
2480                 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2481                 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
2482                 pstrcpy(p2,lp_logon_path());
2483                 p2 = skip_string(p2,1);
2484                 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
2485                 *p2++ = 0;
2486                 SSVAL(p,52,0);          /* flags */
2487                 SIVAL(p,54,0);          /* script_path */
2488                 if (uLevel == 2)
2489                 {
2490                         SIVAL(p,60,0);          /* auth_flags */
2491                         SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
2492                         pstrcpy(p2,((vuser != NULL) ? vuser->real_name : UserName));
2493                         p2 = skip_string(p2,1);
2494                         SIVAL(p,68,0);          /* urs_comment */
2495                         SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
2496                         pstrcpy(p2,"");
2497                         p2 = skip_string(p2,1);
2498                         SIVAL(p,76,0);          /* workstations */
2499                         SIVAL(p,80,0);          /* last_logon */
2500                         SIVAL(p,84,0);          /* last_logoff */
2501                         SIVALS(p,88,-1);                /* acct_expires */
2502                         SIVALS(p,92,-1);                /* max_storage */
2503                         SSVAL(p,96,168);        /* units_per_week */
2504                         SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
2505                         memset(p2,-1,21);
2506                         p2 += 21;
2507                         SSVALS(p,102,-1);       /* bad_pw_count */
2508                         SSVALS(p,104,-1);       /* num_logons */
2509                         SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
2510                         pstrcpy(p2,"\\\\%L");
2511                         standard_sub_basic(p2);
2512                         p2 = skip_string(p2,1);
2513                         SSVAL(p,110,49);        /* country_code */
2514                         SSVAL(p,112,860);       /* code page */
2515                 }
2516         }
2517
2518         *rdata_len = PTR_DIFF(p2,*rdata);
2519
2520         SSVAL(*rparam,4,*rdata_len);    /* is this right?? */
2521
2522         return(True);
2523 }
2524
2525 /*******************************************************************
2526   get groups that a user is a member of
2527   ******************************************************************/
2528 static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *param,char *data,
2529                                  int mdrcnt,int mprcnt,
2530                                  char **rdata,char **rparam,
2531                                  int *rdata_len,int *rparam_len)
2532 {
2533   char *str1 = param+2;
2534   char *str2 = skip_string(str1,1);
2535   char *UserName = skip_string(str2,1);
2536   char *p = skip_string(UserName,1);
2537   int uLevel = SVAL(p,0);
2538   char *p2;
2539   int count=0;
2540
2541   *rparam_len = 8;
2542   *rparam = REALLOC(*rparam,*rparam_len);
2543
2544   /* check it's a supported varient */
2545   if (strcmp(str1,"zWrLeh") != 0) return False;
2546   switch( uLevel ) {
2547   case 0: p2 = "B21"; break;
2548   default: return False;
2549   }
2550   if (strcmp(p2,str2) != 0) return False;
2551
2552   *rdata_len = mdrcnt + 1024;
2553   *rdata = REALLOC(*rdata,*rdata_len);
2554
2555   SSVAL(*rparam,0,NERR_Success);
2556   SSVAL(*rparam,2,0);           /* converter word */
2557
2558   p = *rdata;
2559
2560   /* XXXX we need a real SAM database some day */
2561   pstrcpy(p,"Users"); p += 21; count++;
2562   pstrcpy(p,"Domain Users"); p += 21; count++;
2563   pstrcpy(p,"Guests"); p += 21; count++;
2564   pstrcpy(p,"Domain Guests"); p += 21; count++;
2565
2566   *rdata_len = PTR_DIFF(p,*rdata);
2567
2568   SSVAL(*rparam,4,count);       /* is this right?? */
2569   SSVAL(*rparam,6,count);       /* is this right?? */
2570
2571   return(True);
2572 }
2573
2574
2575 static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param,char *data,
2576                                 int mdrcnt,int mprcnt,
2577                                 char **rdata,char **rparam,
2578                                 int *rdata_len,int *rparam_len)
2579 {
2580   char *str1 = param+2;
2581   char *str2 = skip_string(str1,1);
2582   char *p = skip_string(str2,1);
2583   int uLevel;
2584   struct pack_desc desc;
2585   char* name;
2586   char* logon_script;
2587
2588   uLevel = SVAL(p,0);
2589   name = p + 2;
2590
2591   bzero(&desc,sizeof(desc));
2592
2593   DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
2594
2595   /* check it's a supported varient */
2596   if (strcmp(str1,"OOWb54WrLh") != 0) return False;
2597   if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) return False;
2598   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2599   desc.base = *rdata;
2600   desc.buflen = mdrcnt;
2601   desc.subformat = NULL;
2602   desc.format = str2;
2603   
2604   if (init_package(&desc,1,0))
2605   {
2606     PACKI(&desc,"W",0);         /* code */
2607     PACKS(&desc,"B21",name);    /* eff. name */
2608     PACKS(&desc,"B","");                /* pad */
2609     PACKI(&desc,"W",
2610           conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2611     PACKI(&desc,"D",0);         /* auth flags XXX */
2612     PACKI(&desc,"W",0);         /* num logons */
2613     PACKI(&desc,"W",0);         /* bad pw count */
2614     PACKI(&desc,"D",0);         /* last logon */
2615     PACKI(&desc,"D",-1);                /* last logoff */
2616     PACKI(&desc,"D",-1);                /* logoff time */
2617     PACKI(&desc,"D",-1);                /* kickoff time */
2618     PACKI(&desc,"D",0);         /* password age */
2619     PACKI(&desc,"D",0);         /* password can change */
2620     PACKI(&desc,"D",-1);                /* password must change */
2621     {
2622       fstring mypath;
2623       fstrcpy(mypath,"\\\\");
2624       fstrcat(mypath,local_machine);
2625       strupper(mypath);
2626       PACKS(&desc,"z",mypath); /* computer */
2627     }
2628     PACKS(&desc,"z",global_myworkgroup);/* domain */
2629
2630 /* JHT - By calling lp_logon_script() and standard_sub() we have */
2631 /* made sure all macros are fully substituted and available */
2632     logon_script = lp_logon_script();
2633     standard_sub( conn, logon_script );
2634     PACKS(&desc,"z", logon_script);             /* script path */
2635 /* End of JHT mods */
2636
2637     PACKI(&desc,"D",0x00000000);                /* reserved */
2638   }
2639
2640   *rdata_len = desc.usedlen;
2641   *rparam_len = 6;
2642   *rparam = REALLOC(*rparam,*rparam_len);
2643   SSVALS(*rparam,0,desc.errcode);
2644   SSVAL(*rparam,2,0);
2645   SSVAL(*rparam,4,desc.neededlen);
2646
2647   DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
2648   return(True);
2649 }
2650
2651
2652 /****************************************************************************
2653   api_WAccessGetUserPerms
2654   ****************************************************************************/
2655 static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid, char *param,char *data,
2656                                     int mdrcnt,int mprcnt,
2657                                     char **rdata,char **rparam,
2658                                     int *rdata_len,int *rparam_len)
2659 {
2660   char *str1 = param+2;
2661   char *str2 = skip_string(str1,1);
2662   char *user = skip_string(str2,1);
2663   char *resource = skip_string(user,1);
2664
2665   DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
2666
2667   /* check it's a supported varient */
2668   if (strcmp(str1,"zzh") != 0) return False;
2669   if (strcmp(str2,"") != 0) return False;
2670
2671   *rparam_len = 6;
2672   *rparam = REALLOC(*rparam,*rparam_len);
2673   SSVALS(*rparam,0,0);          /* errorcode */
2674   SSVAL(*rparam,2,0);           /* converter word */
2675   SSVAL(*rparam,4,0x7f);        /* permission flags */
2676
2677   return(True);
2678 }
2679
2680 /****************************************************************************
2681   api_WPrintJobEnumerate
2682   ****************************************************************************/
2683 static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2684                                  int mdrcnt,int mprcnt,
2685                                  char **rdata,char **rparam,
2686                                  int *rdata_len,int *rparam_len)
2687 {
2688   char *str1 = param+2;
2689   char *str2 = skip_string(str1,1);
2690   char *p = skip_string(str2,1);
2691   int uLevel,cbBuf;
2692   int count;
2693   int i;
2694   int snum;
2695   int job;
2696   struct pack_desc desc;
2697   print_queue_struct *queue=NULL;
2698   print_status_struct status;
2699
2700   uLevel = SVAL(p,2);
2701   cbBuf = SVAL(p,4);
2702
2703   bzero(&desc,sizeof(desc));
2704   bzero(&status,sizeof(status));
2705
2706   DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
2707
2708   /* check it's a supported varient */
2709   if (strcmp(str1,"WWrLh") != 0) return False;
2710   if (!check_printjob_info(&desc,uLevel,str2)) return False;
2711
2712   printjob_decode(SVAL(p,0), &snum, &job);
2713
2714   if (snum < 0 || !VALID_SNUM(snum)) return(False);
2715
2716   count = get_printqueue(snum,conn,&queue,&status);
2717   for (i = 0; i < count; i++) {
2718     if ((queue[i].job & 0xFF) == job) break;
2719   }
2720   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2721   desc.base = *rdata;
2722   desc.buflen = mdrcnt;
2723
2724   if (init_package(&desc,1,0)) {
2725     if (i < count) {
2726       fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2727       *rdata_len = desc.usedlen;
2728     }
2729     else {
2730       desc.errcode = NERR_JobNotFound;
2731       *rdata_len = 0;
2732     }
2733   }
2734
2735   *rparam_len = 6;
2736   *rparam = REALLOC(*rparam,*rparam_len);
2737   SSVALS(*rparam,0,desc.errcode);
2738   SSVAL(*rparam,2,0);
2739   SSVAL(*rparam,4,desc.neededlen);
2740
2741   if (queue) free(queue);
2742
2743   DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
2744   return(True);
2745 }
2746
2747 static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *param,char *data,
2748                                    int mdrcnt,int mprcnt,
2749                                    char **rdata,char **rparam,
2750                                    int *rdata_len,int *rparam_len)
2751 {
2752   char *str1 = param+2;
2753   char *str2 = skip_string(str1,1);
2754   char *p = skip_string(str2,1);
2755   char* name = p;
2756   int uLevel,cbBuf;
2757   int count;
2758   int i, succnt=0;
2759   int snum;
2760   struct pack_desc desc;
2761   print_queue_struct *queue=NULL;
2762   print_status_struct status;
2763
2764   bzero(&desc,sizeof(desc));
2765   bzero(&status,sizeof(status));
2766
2767   p = skip_string(p,1);
2768   uLevel = SVAL(p,0);
2769   cbBuf = SVAL(p,2);
2770
2771   DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
2772
2773   /* check it's a supported varient */
2774   if (strcmp(str1,"zWrLeh") != 0) return False;
2775   if (uLevel > 2) return False; /* defined only for uLevel 0,1,2 */
2776   if (!check_printjob_info(&desc,uLevel,str2)) return False;
2777
2778   snum = lp_servicenumber(name);
2779   if (snum < 0 && pcap_printername_ok(name,NULL)) {
2780     int pnum = lp_servicenumber(PRINTERS_NAME);
2781     if (pnum >= 0) {
2782       lp_add_printer(name,pnum);
2783       snum = lp_servicenumber(name);
2784     }
2785   }
2786
2787   if (snum < 0 || !VALID_SNUM(snum)) return(False);
2788
2789   count = get_printqueue(snum,conn,&queue,&status);
2790   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2791   desc.base = *rdata;
2792   desc.buflen = mdrcnt;
2793
2794   if (init_package(&desc,count,0)) {
2795     succnt = 0;
2796     for (i = 0; i < count; i++) {
2797       fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2798       if (desc.errcode == NERR_Success) succnt = i+1;
2799     }
2800   }
2801
2802   *rdata_len = desc.usedlen;
2803
2804   *rparam_len = 8;
2805   *rparam = REALLOC(*rparam,*rparam_len);
2806   SSVALS(*rparam,0,desc.errcode);
2807   SSVAL(*rparam,2,0);
2808   SSVAL(*rparam,4,succnt);
2809   SSVAL(*rparam,6,count);
2810
2811   if (queue) free(queue);
2812
2813   DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
2814   return(True);
2815 }
2816
2817 static int check_printdest_info(struct pack_desc* desc,
2818                                 int uLevel, char* id)
2819 {
2820   desc->subformat = NULL;
2821   switch( uLevel ) {
2822   case 0: desc->format = "B9"; break;
2823   case 1: desc->format = "B9B21WWzW"; break;
2824   case 2: desc->format = "z"; break;
2825   case 3: desc->format = "zzzWWzzzWW"; break;
2826   default: return False;
2827   }
2828   if (strcmp(desc->format,id) != 0) return False;
2829   return True;
2830 }
2831
2832 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
2833                                 struct pack_desc* desc)
2834 {
2835   char buf[100];
2836   strncpy(buf,SERVICE(snum),sizeof(buf)-1);
2837   buf[sizeof(buf)-1] = 0;
2838   strupper(buf);
2839   if (uLevel <= 1) {
2840     PACKS(desc,"B9",buf);       /* szName */
2841     if (uLevel == 1) {
2842       PACKS(desc,"B21","");     /* szUserName */
2843       PACKI(desc,"W",0);                /* uJobId */
2844       PACKI(desc,"W",0);                /* fsStatus */
2845       PACKS(desc,"z","");       /* pszStatus */
2846       PACKI(desc,"W",0);                /* time */
2847     }
2848   }
2849   if (uLevel == 2 || uLevel == 3) {
2850     PACKS(desc,"z",buf);                /* pszPrinterName */
2851     if (uLevel == 3) {
2852       PACKS(desc,"z","");       /* pszUserName */
2853       PACKS(desc,"z","");       /* pszLogAddr */
2854       PACKI(desc,"W",0);                /* uJobId */
2855       PACKI(desc,"W",0);                /* fsStatus */
2856       PACKS(desc,"z","");       /* pszStatus */
2857       PACKS(desc,"z","");       /* pszComment */
2858       PACKS(desc,"z","NULL"); /* pszDrivers */
2859       PACKI(desc,"W",0);                /* time */
2860       PACKI(desc,"W",0);                /* pad1 */
2861     }
2862   }
2863 }
2864
2865 static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2866                                   int mdrcnt,int mprcnt,
2867                                   char **rdata,char **rparam,
2868                                   int *rdata_len,int *rparam_len)
2869 {
2870   char *str1 = param+2;
2871   char *str2 = skip_string(str1,1);
2872   char *p = skip_string(str2,1);
2873   char* PrinterName = p;
2874   int uLevel,cbBuf;
2875   struct pack_desc desc;
2876   int snum;
2877
2878   bzero(&desc,sizeof(desc));
2879
2880   p = skip_string(p,1);
2881   uLevel = SVAL(p,0);
2882   cbBuf = SVAL(p,2);
2883
2884   DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
2885
2886   /* check it's a supported varient */
2887   if (strcmp(str1,"zWrLh") != 0) return False;
2888   if (!check_printdest_info(&desc,uLevel,str2)) return False;
2889
2890   snum = lp_servicenumber(PrinterName);
2891   if (snum < 0 && pcap_printername_ok(PrinterName,NULL)) {
2892     int pnum = lp_servicenumber(PRINTERS_NAME);
2893     if (pnum >= 0) {
2894       lp_add_printer(PrinterName,pnum);
2895       snum = lp_servicenumber(PrinterName);
2896     }
2897   }
2898
2899   if (snum < 0) {
2900     *rdata_len = 0;
2901     desc.errcode = NERR_DestNotFound;
2902     desc.neededlen = 0;
2903   }
2904   else {
2905     if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2906     desc.base = *rdata;
2907     desc.buflen = mdrcnt;
2908     if (init_package(&desc,1,0)) {
2909       fill_printdest_info(conn,snum,uLevel,&desc);
2910     }
2911     *rdata_len = desc.usedlen;
2912   }
2913
2914   *rparam_len = 6;
2915   *rparam = REALLOC(*rparam,*rparam_len);
2916   SSVALS(*rparam,0,desc.errcode);
2917   SSVAL(*rparam,2,0);
2918   SSVAL(*rparam,4,desc.neededlen);
2919
2920   DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
2921   return(True);
2922 }
2923
2924 static BOOL api_WPrintDestEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
2925                                int mdrcnt,int mprcnt,
2926                                char **rdata,char **rparam,
2927                                int *rdata_len,int *rparam_len)
2928 {
2929   char *str1 = param+2;
2930   char *str2 = skip_string(str1,1);
2931   char *p = skip_string(str2,1);
2932   int uLevel,cbBuf;
2933   int queuecnt;
2934   int i, n, succnt=0;
2935   struct pack_desc desc;
2936   int services = lp_numservices();
2937
2938   bzero(&desc,sizeof(desc));
2939
2940   uLevel = SVAL(p,0);
2941   cbBuf = SVAL(p,2);
2942
2943   DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
2944
2945   /* check it's a supported varient */
2946   if (strcmp(str1,"WrLeh") != 0) return False;
2947   if (!check_printdest_info(&desc,uLevel,str2)) return False;
2948
2949   queuecnt = 0;
2950   for (i = 0; i < services; i++)
2951     if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
2952       queuecnt++;
2953
2954   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2955   desc.base = *rdata;
2956   desc.buflen = mdrcnt;
2957   if (init_package(&desc,queuecnt,0)) {    
2958     succnt = 0;
2959     n = 0;
2960     for (i = 0; i < services; i++) {
2961       if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
2962         fill_printdest_info(conn,i,uLevel,&desc);
2963         n++;
2964         if (desc.errcode == NERR_Success) succnt = n;
2965       }
2966     }
2967   }
2968
2969   *rdata_len = desc.usedlen;
2970
2971   *rparam_len = 8;
2972   *rparam = REALLOC(*rparam,*rparam_len);
2973   SSVALS(*rparam,0,desc.errcode);
2974   SSVAL(*rparam,2,0);
2975   SSVAL(*rparam,4,succnt);
2976   SSVAL(*rparam,6,queuecnt);
2977
2978   DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
2979   return(True);
2980 }
2981
2982 static BOOL api_WPrintDriverEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
2983                                  int mdrcnt,int mprcnt,
2984                                  char **rdata,char **rparam,
2985                                  int *rdata_len,int *rparam_len)
2986 {
2987   char *str1 = param+2;
2988   char *str2 = skip_string(str1,1);
2989   char *p = skip_string(str2,1);
2990   int uLevel,cbBuf;
2991   int succnt;
2992   struct pack_desc desc;
2993
2994   bzero(&desc,sizeof(desc));
2995
2996   uLevel = SVAL(p,0);
2997   cbBuf = SVAL(p,2);
2998
2999   DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
3000
3001   /* check it's a supported varient */
3002   if (strcmp(str1,"WrLeh") != 0) return False;
3003   if (uLevel != 0 || strcmp(str2,"B41") != 0) return False;
3004
3005   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3006   desc.base = *rdata;
3007   desc.buflen = mdrcnt;
3008   if (init_package(&desc,1,0)) {
3009     PACKS(&desc,"B41","NULL");
3010   }
3011
3012   succnt = (desc.errcode == NERR_Success ? 1 : 0);
3013
3014   *rdata_len = desc.usedlen;
3015
3016   *rparam_len = 8;
3017   *rparam = REALLOC(*rparam,*rparam_len);
3018   SSVALS(*rparam,0,desc.errcode);
3019   SSVAL(*rparam,2,0);
3020   SSVAL(*rparam,4,succnt);
3021   SSVAL(*rparam,6,1);
3022
3023   DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
3024   return(True);
3025 }
3026
3027 static BOOL api_WPrintQProcEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3028                                 int mdrcnt,int mprcnt,
3029                                 char **rdata,char **rparam,
3030                                 int *rdata_len,int *rparam_len)
3031 {
3032   char *str1 = param+2;
3033   char *str2 = skip_string(str1,1);
3034   char *p = skip_string(str2,1);
3035   int uLevel,cbBuf;
3036   int succnt;
3037   struct pack_desc desc;
3038
3039   bzero(&desc,sizeof(desc));
3040
3041   uLevel = SVAL(p,0);
3042   cbBuf = SVAL(p,2);
3043
3044   DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
3045
3046   /* check it's a supported varient */
3047   if (strcmp(str1,"WrLeh") != 0) return False;
3048   if (uLevel != 0 || strcmp(str2,"B13") != 0) return False;
3049
3050   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3051   desc.base = *rdata;
3052   desc.buflen = mdrcnt;
3053   desc.format = str2;
3054   if (init_package(&desc,1,0)) {
3055     PACKS(&desc,"B13","lpd");
3056   }
3057
3058   succnt = (desc.errcode == NERR_Success ? 1 : 0);
3059
3060   *rdata_len = desc.usedlen;
3061
3062   *rparam_len = 8;
3063   *rparam = REALLOC(*rparam,*rparam_len);
3064   SSVALS(*rparam,0,desc.errcode);
3065   SSVAL(*rparam,2,0);
3066   SSVAL(*rparam,4,succnt);
3067   SSVAL(*rparam,6,1);
3068
3069   DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
3070   return(True);
3071 }
3072
3073 static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3074                                int mdrcnt,int mprcnt,
3075                                char **rdata,char **rparam,
3076                                int *rdata_len,int *rparam_len)
3077 {
3078   char *str1 = param+2;
3079   char *str2 = skip_string(str1,1);
3080   char *p = skip_string(str2,1);
3081   int uLevel,cbBuf;
3082   int succnt;
3083   struct pack_desc desc;
3084
3085   bzero(&desc,sizeof(desc));
3086
3087   uLevel = SVAL(p,0);
3088   cbBuf = SVAL(p,2);
3089
3090   DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
3091
3092   /* check it's a supported varient */
3093   if (strcmp(str1,"WrLeh") != 0) return False;
3094   if (uLevel != 0 || strcmp(str2,"B9") != 0) return False;
3095
3096   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3097   bzero(&desc,sizeof(desc));
3098   desc.base = *rdata;
3099   desc.buflen = mdrcnt;
3100   desc.format = str2;
3101   if (init_package(&desc,1,0)) {
3102     PACKS(&desc,"B13","lp0");
3103   }
3104
3105   succnt = (desc.errcode == NERR_Success ? 1 : 0);
3106
3107   *rdata_len = desc.usedlen;
3108
3109   *rparam_len = 8;
3110   *rparam = REALLOC(*rparam,*rparam_len);
3111   SSVALS(*rparam,0,desc.errcode);
3112   SSVAL(*rparam,2,0);
3113   SSVAL(*rparam,4,succnt);
3114   SSVAL(*rparam,6,1);
3115
3116   DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
3117   return(True);
3118 }
3119
3120 struct api_cmd
3121 {
3122   char * pipe_clnt_name;
3123   char * pipe_srv_name;
3124   BOOL (*fn) (pipes_struct *, prs_struct *);
3125 };
3126
3127 static struct api_cmd api_fd_commands[] =
3128 {
3129     { "lsarpc",   "lsass",   api_ntlsa_rpc },
3130     { "samr",     "lsass",   api_samr_rpc },
3131     { "srvsvc",   "ntsvcs",  api_srvsvc_rpc },
3132     { "wkssvc",   "ntsvcs",  api_wkssvc_rpc },
3133     { "NETLOGON", "lsass",   api_netlog_rpc },
3134     { "winreg",   "winreg",  api_reg_rpc },
3135     { NULL,       NULL,      NULL }
3136 };
3137
3138 static BOOL api_pipe_bind_req(pipes_struct *p, prs_struct *pd)
3139 {
3140         BOOL ntlmssp_auth = False;
3141         fstring ack_pipe_name;
3142         int i = 0;
3143
3144         DEBUG(5,("api_pipe_bind_req: decode request. %d\n", __LINE__));
3145
3146         for (i = 0; api_fd_commands[i].pipe_clnt_name; i++)
3147         {
3148                 if (strequal(api_fd_commands[i].pipe_clnt_name, p->name) &&
3149                     api_fd_commands[i].fn != NULL)
3150                 {
3151                         DEBUG(3,("api_pipe_bind_req: \\PIPE\\%s -> \\PIPE\\%s\n",
3152                                    api_fd_commands[i].pipe_clnt_name,
3153                                    api_fd_commands[i].pipe_srv_name));
3154                         fstrcpy(p->pipe_srv_name, api_fd_commands[i].pipe_srv_name);
3155                         break;
3156                 }
3157         }
3158
3159         if (api_fd_commands[i].fn == NULL) return False;
3160
3161         /* decode the bind request */
3162         smb_io_rpc_hdr_rb("", &p->hdr_rb, pd, 0);
3163
3164         if (pd->offset == 0) return False;
3165
3166         if (p->hdr.auth_len != 0)
3167         {
3168                 /* decode the authentication verifier */
3169                 smb_io_rpc_auth_ntlmssp_req("", &p->ntlmssp_req, pd, 0);
3170
3171                 if (pd->offset == 0) return False;
3172
3173                 /* ignore the version number for now */
3174                 ntlmssp_auth = strequal(p->ntlmssp_req.ntlmssp_str, "NTLMSSP");
3175         }
3176
3177         /* name has to be \PIPE\xxxxx */
3178         fstrcpy(ack_pipe_name, "\\PIPE\\");
3179         fstrcat(ack_pipe_name, p->pipe_srv_name);
3180
3181         DEBUG(5,("api_pipe_bind_req: make response. %d\n", __LINE__));
3182
3183         prs_init(&(p->rdata), 1024, 4, 0, False);
3184         prs_init(&(p->rhdr ), 0x10, 4, 0, False);
3185         prs_init(&(p->rauth), 1024, 4, 0, False);
3186
3187     /***/
3188         /*** do the bind ack first ***/
3189     /***/
3190
3191         make_rpc_hdr_ba(&p->hdr_ba,
3192                                         p->hdr_rb.bba.max_tsize,
3193                         p->hdr_rb.bba.max_rsize,
3194                         p->hdr_rb.bba.assoc_gid,
3195                                         ack_pipe_name,
3196                                         0x1, 0x0, 0x0,
3197                                         &(p->hdr_rb.transfer));
3198
3199         smb_io_rpc_hdr_ba("", &p->hdr_ba, &p->rdata, 0);
3200         mem_realloc_data(p->rdata.data, p->rdata.offset);
3201
3202     /***/
3203         /*** now the authentication ***/
3204     /***/
3205
3206         if (ntlmssp_auth)
3207         {
3208                 uint8 data[16];
3209                 bzero(data, sizeof(data)); /* first 8 bytes are non-zero */
3210
3211                 make_rpc_auth_ntlmssp_resp(&p->ntlmssp_resp,
3212                                            0x0a, 0x06, 0,
3213                                            "NTLMSSP", 2,
3214                                            0x00000000, 0x0000b2b3, 0x000082b1,
3215                                            data);
3216                 smb_io_rpc_auth_ntlmssp_resp("", &p->ntlmssp_resp, &p->rauth, 0);
3217                 mem_realloc_data(p->rauth.data, p->rauth.offset);
3218         }
3219
3220     /***/
3221         /*** then do the header, now we know the length ***/
3222     /***/
3223
3224         make_rpc_hdr(&p->hdr, RPC_BINDACK, RPC_FLG_FIRST | RPC_FLG_LAST,
3225                                  p->hdr.call_id,
3226                      p->rdata.offset + p->rauth.offset,
3227                      p->rauth.offset);
3228
3229         smb_io_rpc_hdr("", &p->hdr, &p->rhdr, 0);
3230         mem_realloc_data(p->rhdr.data, p->rdata.offset);
3231
3232     /***/
3233         /*** link rpc header, bind acknowledgment and authentication responses ***/
3234     /***/
3235
3236         p->rhdr.data->offset.start = 0;
3237         p->rhdr.data->offset.end   = p->rhdr.offset;
3238         p->rhdr.data->next         = p->rdata.data;
3239
3240         if (ntlmssp_auth)
3241         {
3242                 p->rdata.data->offset.start = p->rhdr.offset;
3243                 p->rdata.data->offset.end   = p->rhdr.offset + p->rdata.offset;
3244                 p->rdata.data->next         = p->rauth.data;
3245
3246                 p->rauth.data->offset.start = p->rhdr.offset + p->rdata.offset;
3247                 p->rauth.data->offset.end   = p->rhdr.offset + p->rauth.offset + p->rdata.offset;
3248                 p->rauth.data->next         = NULL;
3249         }
3250         else
3251         {
3252                 p->rdata.data->offset.start = p->rhdr.offset;
3253                 p->rdata.data->offset.end   = p->rhdr.offset + p->rdata.offset;
3254                 p->rdata.data->next         = NULL;
3255         }
3256
3257         return True;
3258 }
3259
3260 static BOOL api_pipe_request(pipes_struct *p, prs_struct *pd)
3261 {
3262         int i = 0;
3263
3264         for (i = 0; api_fd_commands[i].pipe_clnt_name; i++)
3265         {
3266                 if (strequal(api_fd_commands[i].pipe_clnt_name, p->name) &&
3267                     api_fd_commands[i].fn != NULL)
3268                 {
3269                         DEBUG(3,("Doing \\PIPE\\%s\n", api_fd_commands[i].pipe_clnt_name));
3270                         return api_fd_commands[i].fn(p, pd);
3271                 }
3272         }
3273         return False;
3274 }
3275
3276 static BOOL api_dce_rpc_command(char *outbuf,
3277                                 pipes_struct *p,
3278                                 prs_struct *pd)
3279 {
3280         BOOL reply = False;
3281         if (pd->data == NULL) return False;
3282
3283         /* process the rpc header */
3284         smb_io_rpc_hdr("", &p->hdr, pd, 0);
3285
3286         if (pd->offset == 0) return False;
3287
3288         switch (p->hdr.pkt_type)
3289         {
3290                 case RPC_BIND   :
3291                 {
3292                         reply = api_pipe_bind_req(p, pd);
3293                         break;
3294                 }
3295                 case RPC_REQUEST:
3296                 {
3297                         reply = api_pipe_request (p, pd);
3298                         break;
3299                 }
3300         }
3301
3302         if (reply)
3303         {
3304                 /* now send the reply */
3305                 send_trans_reply(outbuf, p->rhdr.data, NULL, NULL, 0, p->file_offset);
3306
3307                 if (mem_buf_len(p->rhdr.data) <= p->file_offset)
3308                 {
3309                         /* all of data was sent: no need to wait for SMBreadX calls */
3310                         mem_free_data(p->rhdr .data);
3311                         mem_free_data(p->rdata.data);
3312                 }
3313         }
3314
3315         return reply;
3316 }
3317
3318 /****************************************************************************
3319  SetNamedPipeHandleState 
3320 ****************************************************************************/
3321 static BOOL api_SNPHS(char *outbuf, pipes_struct *p, char *param)
3322 {
3323         uint16 id;
3324
3325         if (!param) return False;
3326
3327         id = param[0] + (param[1] << 8);
3328         DEBUG(4,("lsarpc SetNamedPipeHandleState to code %x\n", id));
3329
3330         if (set_rpc_pipe_hnd_state(p, id))
3331         {
3332                 /* now send the reply */
3333                 send_trans_reply(outbuf, NULL, NULL, NULL, 0, p->file_offset);
3334
3335                 return True;
3336         }
3337         return False;
3338 }
3339
3340
3341 /****************************************************************************
3342  when no reply is generated, indicate unsupported.
3343  ****************************************************************************/
3344 static BOOL api_no_reply(char *outbuf, int max_rdata_len)
3345 {
3346         struct mem_buf rparam;
3347
3348         mem_init(&rparam, 0);
3349         mem_alloc_data(&rparam, 4);
3350
3351         rparam.offset.start = 0;
3352         rparam.offset.end   = 4;
3353
3354         /* unsupported */
3355         SSVAL(rparam.data,0,NERR_notsupported);
3356         SSVAL(rparam.data,2,0); /* converter word */
3357
3358         DEBUG(3,("Unsupported API fd command\n"));
3359
3360         /* now send the reply */
3361         send_trans_reply(outbuf, NULL, &rparam, NULL, 0, max_rdata_len);
3362
3363         mem_free_data(&rparam);
3364
3365         return(-1);
3366 }
3367
3368 /****************************************************************************
3369   handle remote api calls delivered to a named pipe already opened.
3370   ****************************************************************************/
3371 static int api_fd_reply(connection_struct *conn,uint16 vuid,char *outbuf,
3372                         uint16 *setup,char *data,char *params,
3373                         int suwcnt,int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
3374 {
3375         BOOL reply    = False;
3376
3377         int pnum;
3378         int subcommand;
3379         pipes_struct *p = NULL;
3380         prs_struct pd;
3381         struct mem_buf data_buf;
3382
3383         DEBUG(5,("api_fd_reply\n"));
3384
3385         /* fake up a data buffer from the api_fd_reply data parameters */
3386         mem_create(&data_buf, data, tdscnt, 0, False);
3387         data_buf.offset.start = 0;
3388         data_buf.offset.end   = tdscnt;
3389
3390         /* fake up a parsing structure */
3391         pd.data = &data_buf;
3392         pd.align = 4;
3393         pd.io = True;
3394         pd.offset = 0;
3395
3396         /* First find out the name of this file. */
3397         if (suwcnt != 2)
3398         {
3399                 DEBUG(0,("Unexpected named pipe transaction.\n"));
3400                 return(-1);
3401         }
3402
3403         /* Get the file handle and hence the file name. */
3404         pnum = setup[1];
3405         subcommand = setup[0];
3406         get_rpc_pipe(pnum, &p);
3407
3408         if (p != NULL)
3409         {
3410                 DEBUG(3,("Got API command 0x%x on pipe \"%s\" (pnum %x)",
3411                                   subcommand, p->name, pnum));
3412
3413                 /* record maximum data length that can be transmitted in an SMBtrans */
3414                 p->file_offset = mdrcnt;
3415
3416                 DEBUG(10,("api_fd_reply: p:%p file_offset: %d\n",
3417                            p, p->file_offset));
3418
3419                 switch (subcommand)
3420                 {
3421                         case 0x26:
3422                         {
3423                                 /* dce/rpc command */
3424                                 reply = api_dce_rpc_command(outbuf, p, &pd);
3425                                 break;
3426                         }
3427                         case 0x01:
3428                         {
3429                                 /* Set Named Pipe Handle state */
3430                                 reply = api_SNPHS(outbuf, p, params);
3431                                 break;
3432                         }
3433                 }
3434         }
3435         else
3436         {
3437                 DEBUG(1,("api_fd_reply: INVALID PIPE HANDLE: %x\n", pnum));
3438         }
3439
3440         if (!reply)
3441         {
3442                 return api_no_reply(outbuf, mdrcnt);
3443         }
3444         return -1;
3445 }
3446
3447 /****************************************************************************
3448   the buffer was too small
3449   ****************************************************************************/
3450 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
3451                          int mdrcnt,int mprcnt,
3452                          char **rdata,char **rparam,
3453                          int *rdata_len,int *rparam_len)
3454 {
3455   *rparam_len = MIN(*rparam_len,mprcnt);
3456   *rparam = REALLOC(*rparam,*rparam_len);
3457
3458   *rdata_len = 0;
3459
3460   SSVAL(*rparam,0,NERR_BufTooSmall);
3461
3462   DEBUG(3,("Supplied buffer too small in API command\n"));
3463
3464   return(True);
3465 }
3466
3467
3468 /****************************************************************************
3469   the request is not supported
3470   ****************************************************************************/
3471 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
3472                             int mdrcnt,int mprcnt,
3473                             char **rdata,char **rparam,
3474                             int *rdata_len,int *rparam_len)
3475 {
3476   *rparam_len = 4;
3477   *rparam = REALLOC(*rparam,*rparam_len);
3478
3479   *rdata_len = 0;
3480
3481   SSVAL(*rparam,0,NERR_notsupported);
3482   SSVAL(*rparam,2,0);           /* converter word */
3483
3484   DEBUG(3,("Unsupported API command\n"));
3485
3486   return(True);
3487 }
3488
3489
3490
3491
3492 struct
3493 {
3494   char *name;
3495   int id;
3496   BOOL (*fn)(connection_struct *,uint16,char *,char *,
3497              int,int,char **,char **,int *,int *);
3498   int flags;
3499 } api_commands[] = {
3500   {"RNetShareEnum",     0,      api_RNetShareEnum,0},
3501   {"RNetShareGetInfo",  1,      api_RNetShareGetInfo,0},
3502   {"RNetServerGetInfo", 13,     api_RNetServerGetInfo,0},
3503   {"RNetGroupGetUsers", 52,     api_RNetGroupGetUsers,0},
3504   {"RNetUserGetInfo",   56,     api_RNetUserGetInfo,0},
3505   {"NetUserGetGroups",  59,     api_NetUserGetGroups,0},
3506   {"NetWkstaGetInfo",   63,     api_NetWkstaGetInfo,0},
3507   {"DosPrintQEnum",     69,     api_DosPrintQEnum,0},
3508   {"DosPrintQGetInfo",  70,     api_DosPrintQGetInfo,0},
3509   {"WPrintQueuePause",  74, api_WPrintQueuePurge,0},
3510   {"WPrintQueueResume", 75, api_WPrintQueuePurge,0},
3511   {"WPrintJobEnumerate",76,     api_WPrintJobEnumerate,0},
3512   {"WPrintJobGetInfo",  77,     api_WPrintJobGetInfo,0},
3513   {"RDosPrintJobDel",   81,     api_RDosPrintJobDel,0},
3514   {"RDosPrintJobPause", 82,     api_RDosPrintJobDel,0},
3515   {"RDosPrintJobResume",83,     api_RDosPrintJobDel,0},
3516   {"WPrintDestEnum",    84,     api_WPrintDestEnum,0},
3517   {"WPrintDestGetInfo", 85,     api_WPrintDestGetInfo,0},
3518   {"NetRemoteTOD",      91,     api_NetRemoteTOD,0},
3519   {"WPrintQueuePurge",  103,    api_WPrintQueuePurge,0},
3520   {"NetServerEnum",     104,    api_RNetServerEnum,0},
3521   {"WAccessGetUserPerms",105,   api_WAccessGetUserPerms,0},
3522   {"SetUserPassword",   115,    api_SetUserPassword,0},
3523   {"WWkstaUserLogon",   132,    api_WWkstaUserLogon,0},
3524   {"PrintJobInfo",      147,    api_PrintJobInfo,0},
3525   {"WPrintDriverEnum",  205,    api_WPrintDriverEnum,0},
3526   {"WPrintQProcEnum",   206,    api_WPrintQProcEnum,0},
3527   {"WPrintPortEnum",    207,    api_WPrintPortEnum,0},
3528   {"SamOEMChangePassword", 214, api_SamOEMChangePassword,0},
3529   {NULL,                -1,     api_Unsupported,0}};
3530
3531
3532 /****************************************************************************
3533   handle remote api calls
3534   ****************************************************************************/
3535 static int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *params,
3536                      int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
3537 {
3538   int api_command = SVAL(params,0);
3539   struct mem_buf rdata_buf;
3540   struct mem_buf rparam_buf;
3541   char *rdata = NULL;
3542   char *rparam = NULL;
3543   int rdata_len = 0;
3544   int rparam_len = 0;
3545   BOOL reply=False;
3546   int i;
3547
3548   DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
3549            api_command,params+2,skip_string(params+2,1),
3550            tdscnt,tpscnt,mdrcnt,mprcnt));
3551
3552   for (i=0;api_commands[i].name;i++)
3553     if (api_commands[i].id == api_command && api_commands[i].fn)
3554       {
3555         DEBUG(3,("Doing %s\n",api_commands[i].name));
3556         break;
3557       }
3558
3559   rdata = (char *)malloc(1024); if (rdata) bzero(rdata,1024);
3560   rparam = (char *)malloc(1024); if (rparam) bzero(rparam,1024);
3561
3562   reply = api_commands[i].fn(conn,vuid,params,data,mdrcnt,mprcnt,
3563                              &rdata,&rparam,&rdata_len,&rparam_len);
3564
3565
3566   if (rdata_len > mdrcnt ||
3567       rparam_len > mprcnt)
3568     {
3569       reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
3570                            &rdata,&rparam,&rdata_len,&rparam_len);
3571     }
3572             
3573
3574   /* if we get False back then it's actually unsupported */
3575   if (!reply)
3576     api_Unsupported(conn,vuid,params,data,mdrcnt,mprcnt,
3577                     &rdata,&rparam,&rdata_len,&rparam_len);
3578
3579       
3580   mem_create(&rdata_buf , rdata , rdata_len , 0, False);
3581   mem_create(&rparam_buf, rparam, rparam_len, 0, False);
3582
3583   rdata_buf.offset.start = 0;
3584   rdata_buf.offset.end   = rdata_len;
3585
3586   rparam_buf.offset.start = 0;
3587   rparam_buf.offset.end   = rparam_len;
3588
3589   /* now send the reply */
3590   send_trans_reply(outbuf, &rdata_buf, &rparam_buf, NULL, 0, 0);
3591
3592   if (rdata ) free(rdata);
3593   if (rparam) free(rparam);
3594   
3595   return(-1);
3596 }
3597
3598 /****************************************************************************
3599   handle named pipe commands
3600   ****************************************************************************/
3601 static int named_pipe(connection_struct *conn,uint16 vuid, char *outbuf,char *name,
3602                       uint16 *setup,char *data,char *params,
3603                       int suwcnt,int tdscnt,int tpscnt,
3604                       int msrcnt,int mdrcnt,int mprcnt)
3605 {
3606         DEBUG(3,("named pipe command on <%s> name\n", name));
3607
3608         if (strequal(name,"LANMAN"))
3609         {
3610                 return api_reply(conn,vuid,outbuf,data,params,tdscnt,tpscnt,mdrcnt,mprcnt);
3611         }
3612
3613         if (strlen(name) < 1)
3614         {
3615                 return api_fd_reply(conn,vuid,outbuf,setup,data,params,suwcnt,tdscnt,tpscnt,mdrcnt,mprcnt);
3616         }
3617
3618         if (setup)
3619         {
3620                 DEBUG(3,("unknown named pipe: setup 0x%X setup1=%d\n", (int)setup[0],(int)setup[1]));
3621         }
3622
3623         return 0;
3624 }
3625
3626
3627 /****************************************************************************
3628   reply to a SMBtrans
3629   ****************************************************************************/
3630 int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int bufsize)
3631 {
3632         fstring name;
3633
3634         char *data=NULL,*params=NULL;
3635         uint16 *setup=NULL;
3636         int outsize = 0;
3637         uint16 vuid = SVAL(inbuf,smb_uid);
3638         int tpscnt = SVAL(inbuf,smb_vwv0);
3639         int tdscnt = SVAL(inbuf,smb_vwv1);
3640         int mprcnt = SVAL(inbuf,smb_vwv2);
3641         int mdrcnt = SVAL(inbuf,smb_vwv3);
3642         int msrcnt = CVAL(inbuf,smb_vwv4);
3643         BOOL close_on_completion = BITSETW(inbuf+smb_vwv5,0);
3644         BOOL one_way = BITSETW(inbuf+smb_vwv5,1);
3645         int pscnt = SVAL(inbuf,smb_vwv9);
3646         int psoff = SVAL(inbuf,smb_vwv10);
3647         int dscnt = SVAL(inbuf,smb_vwv11);
3648         int dsoff = SVAL(inbuf,smb_vwv12);
3649         int suwcnt = CVAL(inbuf,smb_vwv13);
3650
3651         bzero(name, sizeof(name));
3652         fstrcpy(name,smb_buf(inbuf));
3653
3654         if (dscnt > tdscnt || pscnt > tpscnt) {
3655                 exit_server("invalid trans parameters\n");
3656         }
3657   
3658         if (tdscnt)  {
3659                 data = (char *)malloc(tdscnt);
3660                 memcpy(data,smb_base(inbuf)+dsoff,dscnt);
3661         }
3662
3663         if (tpscnt) {
3664                 params = (char *)malloc(tpscnt);
3665                 memcpy(params,smb_base(inbuf)+psoff,pscnt);
3666         }
3667
3668         if (suwcnt) {
3669                 int i;
3670                 setup = (uint16 *)malloc(suwcnt*sizeof(setup[0]));
3671                 for (i=0;i<suwcnt;i++)
3672                         setup[i] = SVAL(inbuf,smb_vwv14+i*SIZEOFWORD);
3673         }
3674
3675
3676         if (pscnt < tpscnt || dscnt < tdscnt) {
3677                 /* We need to send an interim response then receive the rest
3678                    of the parameter/data bytes */
3679                 outsize = set_message(outbuf,0,0,True);
3680                 show_msg(outbuf);
3681                 send_smb(Client,outbuf);
3682         }
3683
3684         /* receive the rest of the trans packet */
3685         while (pscnt < tpscnt || dscnt < tdscnt) {
3686                 BOOL ret;
3687                 int pcnt,poff,dcnt,doff,pdisp,ddisp;
3688       
3689                 ret = receive_next_smb(Client,oplock_sock,inbuf,bufsize,SMB_SECONDARY_WAIT);
3690
3691                 if ((ret && (CVAL(inbuf, smb_com) != SMBtrans)) || !ret) {
3692                         if(ret) {
3693                                 DEBUG(0,("reply_trans: Invalid secondary trans packet\n"));
3694                         } else {
3695                                 DEBUG(0,("reply_trans: %s in getting secondary trans response.\n",
3696                                          (smb_read_error == READ_ERROR) ? "error" : "timeout" ));
3697                         }
3698                         if (params) free(params);
3699                         if (data) free(data);
3700                         if (setup) free(setup);
3701                         return(ERROR(ERRSRV,ERRerror));
3702                 }
3703
3704                 show_msg(inbuf);
3705       
3706                 tpscnt = SVAL(inbuf,smb_vwv0);
3707                 tdscnt = SVAL(inbuf,smb_vwv1);
3708
3709                 pcnt = SVAL(inbuf,smb_vwv2);
3710                 poff = SVAL(inbuf,smb_vwv3);
3711                 pdisp = SVAL(inbuf,smb_vwv4);
3712                 
3713                 dcnt = SVAL(inbuf,smb_vwv5);
3714                 doff = SVAL(inbuf,smb_vwv6);
3715                 ddisp = SVAL(inbuf,smb_vwv7);
3716                 
3717                 pscnt += pcnt;
3718                 dscnt += dcnt;
3719                 
3720                 if (dscnt > tdscnt || pscnt > tpscnt) {
3721                         exit_server("invalid trans parameters\n");
3722                 }
3723                 
3724                 if (pcnt)
3725                         memcpy(params+pdisp,smb_base(inbuf)+poff,pcnt);
3726                 if (dcnt)
3727                         memcpy(data+ddisp,smb_base(inbuf)+doff,dcnt);      
3728         }
3729         
3730         
3731         DEBUG(3,("trans <%s> data=%d params=%d setup=%d\n",
3732                  name,tdscnt,tpscnt,suwcnt));
3733         
3734         if (strncmp(name,"\\PIPE\\",strlen("\\PIPE\\")) == 0) {
3735                 DEBUG(5,("calling named_pipe\n"));
3736                 outsize = named_pipe(conn,vuid,outbuf,name+strlen("\\PIPE\\"),setup,data,params,
3737                                      suwcnt,tdscnt,tpscnt,msrcnt,mdrcnt,mprcnt);
3738         } else {
3739                 DEBUG(3,("invalid pipe name\n"));
3740                 outsize = 0;
3741         }
3742
3743         
3744         if (data) free(data);
3745         if (params) free(params);
3746         if (setup) free(setup);
3747         
3748         if (close_on_completion)
3749                 close_cnum(conn,vuid);
3750
3751         if (one_way)
3752                 return(-1);
3753         
3754         if (outsize == 0)
3755                 return(ERROR(ERRSRV,ERRnosupport));
3756         
3757         return(outsize);
3758 }