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