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