Don't check NT permissions when printing from lanman.
[kai/samba.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
1757         jobid = SVAL(p,0);
1758
1759         /* check it's a supported varient */
1760         if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
1761                 return(False);
1762
1763         *rparam_len = 4;
1764         *rparam = REALLOC(*rparam,*rparam_len); 
1765         *rdata_len = 0;
1766
1767         if (!print_job_exists(jobid)) {
1768                 errcode = NERR_JobNotFound;
1769                 goto out;
1770         }
1771
1772         errcode = NERR_notsupported;
1773         
1774         switch (function) {
1775         case 81:                /* delete */ 
1776                 if (print_job_delete(NULL, jobid)) errcode = NERR_Success;
1777                 break;
1778         case 82:                /* pause */
1779                 if (print_job_pause(NULL, jobid)) errcode = NERR_Success;
1780                 break;
1781         case 83:                /* resume */
1782                 if (print_job_resume(NULL, jobid)) errcode = NERR_Success;
1783                 break;
1784         }
1785         
1786  out:
1787         SSVAL(*rparam,0,errcode);       
1788         SSVAL(*rparam,2,0);             /* converter word */
1789
1790         return(True);
1791 }
1792
1793 /****************************************************************************
1794   Purge a print queue - or pause or resume it.
1795   ****************************************************************************/
1796 static BOOL api_WPrintQueuePurge(connection_struct *conn,uint16 vuid, char *param,char *data,
1797                                  int mdrcnt,int mprcnt,
1798                                  char **rdata,char **rparam,
1799                                  int *rdata_len,int *rparam_len)
1800 {
1801         int function = SVAL(param,0);
1802         char *str1 = param+2;
1803         char *str2 = skip_string(str1,1);
1804         char *QueueName = skip_string(str2,1);
1805         int errcode = NERR_notsupported;
1806         int snum;
1807
1808         /* check it's a supported varient */
1809         if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
1810                 return(False);
1811
1812         *rparam_len = 4;
1813         *rparam = REALLOC(*rparam,*rparam_len);
1814         *rdata_len = 0;
1815
1816         snum = print_queue_snum(QueueName);
1817
1818         if (snum == -1) {
1819                 errcode = NERR_JobNotFound;
1820                 goto out;
1821         }
1822
1823         switch (function) {
1824         case 74: /* Pause queue */
1825                 if (print_queue_pause(NULL, snum)) errcode = NERR_Success;
1826                 break;
1827         case 75: /* Resume queue */
1828                 if (print_queue_resume(NULL, snum)) errcode = NERR_Success;
1829                 break;
1830         case 103: /* Purge */
1831                 if (print_queue_purge(NULL, snum)) errcode = NERR_Success;
1832                 break;
1833         }
1834
1835  out:
1836         SSVAL(*rparam,0,errcode);
1837         SSVAL(*rparam,2,0);             /* converter word */
1838
1839         return(True);
1840 }
1841
1842
1843 /****************************************************************************
1844   set the property of a print job (undocumented?)
1845   ? function = 0xb -> set name of print job
1846   ? function = 0x6 -> move print job up/down
1847   Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz> 
1848   or   <WWsTP> <WB21BB16B10zWWzDDz> 
1849 ****************************************************************************/
1850 static int check_printjob_info(struct pack_desc* desc,
1851                                int uLevel, char* id)
1852 {
1853         desc->subformat = NULL;
1854         switch( uLevel ) {
1855         case 0: desc->format = "W"; break;
1856         case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
1857         case 2: desc->format = "WWzWWDDzz"; break;
1858         case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
1859         default: return False;
1860         }
1861         if (strcmp(desc->format,id) != 0) return False;
1862         return True;
1863 }
1864
1865 static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,char *data,
1866                              int mdrcnt,int mprcnt,
1867                              char **rdata,char **rparam,
1868                              int *rdata_len,int *rparam_len)
1869 {
1870         struct pack_desc desc;
1871         char *str1 = param+2;
1872         char *str2 = skip_string(str1,1);
1873         char *p = skip_string(str2,1);
1874         int jobid;
1875         int uLevel = SVAL(p,2);
1876         int function = SVAL(p,4);
1877         int place, errcode;
1878
1879         jobid = SVAL(p,0);
1880         *rparam_len = 4;
1881         *rparam = REALLOC(*rparam,*rparam_len);
1882   
1883         *rdata_len = 0;
1884         
1885         /* check it's a supported varient */
1886         if ((strcmp(str1,"WWsTP")) || 
1887             (!check_printjob_info(&desc,uLevel,str2)))
1888                 return(False);
1889
1890         if (!print_job_exists(jobid)) {
1891                 errcode=NERR_JobNotFound;
1892                 goto out;
1893         }
1894
1895         errcode = NERR_notsupported;
1896
1897         switch (function) {
1898         case 0x6:
1899                 /* change job place in the queue, 
1900                    data gives the new place */
1901                 place = SVAL(data,0);
1902                 if (print_job_set_place(jobid, place)) {
1903                         errcode=NERR_Success;
1904                 }
1905                 break;
1906
1907         case 0xb:   
1908                 /* change print job name, data gives the name */
1909                 if (print_job_set_name(jobid, data)) {
1910                         errcode=NERR_Success;
1911                 }
1912                 break;
1913
1914         default:
1915                 return False;
1916         }
1917
1918  out:
1919         SSVALS(*rparam,0,errcode);
1920         SSVAL(*rparam,2,0);             /* converter word */
1921         
1922         return(True);
1923 }
1924
1925
1926 /****************************************************************************
1927   get info about the server
1928   ****************************************************************************/
1929 static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
1930                                   int mdrcnt,int mprcnt,
1931                                   char **rdata,char **rparam,
1932                                   int *rdata_len,int *rparam_len)
1933 {
1934   char *str1 = param+2;
1935   char *str2 = skip_string(str1,1);
1936   char *p = skip_string(str2,1);
1937   int uLevel = SVAL(p,0);
1938   char *p2;
1939   int struct_len;
1940
1941   DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
1942
1943   /* check it's a supported varient */
1944   if (!prefix_ok(str1,"WrLh")) return False;
1945   switch( uLevel ) {
1946   case 0:
1947     if (strcmp(str2,"B16") != 0) return False;
1948     struct_len = 16;
1949     break;
1950   case 1:
1951     if (strcmp(str2,"B16BBDz") != 0) return False;
1952     struct_len = 26;
1953     break;
1954   case 2:
1955     if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")
1956         != 0) return False;
1957     struct_len = 134;
1958     break;
1959   case 3:
1960     if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz")
1961         != 0) return False;
1962     struct_len = 144;
1963     break;
1964   case 20:
1965     if (strcmp(str2,"DN") != 0) return False;
1966     struct_len = 6;
1967     break;
1968   case 50:
1969     if (strcmp(str2,"B16BBDzWWzzz") != 0) return False;
1970     struct_len = 42;
1971     break;
1972   default: return False;
1973   }
1974
1975   *rdata_len = mdrcnt;
1976   *rdata = REALLOC(*rdata,*rdata_len);
1977
1978   p = *rdata;
1979   p2 = p + struct_len;
1980   if (uLevel != 20) {
1981     StrnCpy(p,local_machine,16);
1982     strupper(p);
1983   }
1984   p += 16;
1985   if (uLevel > 0)
1986     {
1987       struct srv_info_struct *servers=NULL;
1988       int i,count;
1989       pstring comment;
1990       uint32 servertype= lp_default_server_announce();
1991
1992       pstrcpy(comment,string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH));
1993
1994       if ((count=get_server_info(SV_TYPE_ALL,&servers,global_myworkgroup))>0) {
1995         for (i=0;i<count;i++)
1996           if (strequal(servers[i].name,local_machine))
1997       {
1998             servertype = servers[i].type;
1999             pstrcpy(comment,servers[i].comment);            
2000           }
2001       }
2002       if (servers) free(servers);
2003
2004       SCVAL(p,0,lp_major_announce_version());
2005       SCVAL(p,1,lp_minor_announce_version());
2006       SIVAL(p,2,servertype);
2007
2008       if (mdrcnt == struct_len) {
2009         SIVAL(p,6,0);
2010       } else {
2011         SIVAL(p,6,PTR_DIFF(p2,*rdata));
2012         standard_sub_conn(conn,comment);
2013         StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2014         p2 = skip_string(p2,1);
2015       }
2016     }
2017   if (uLevel > 1)
2018     {
2019       return False;             /* not yet implemented */
2020     }
2021
2022   *rdata_len = PTR_DIFF(p2,*rdata);
2023
2024   *rparam_len = 6;
2025   *rparam = REALLOC(*rparam,*rparam_len);
2026   SSVAL(*rparam,0,NERR_Success);
2027   SSVAL(*rparam,2,0);           /* converter word */
2028   SSVAL(*rparam,4,*rdata_len);
2029
2030   return(True);
2031 }
2032
2033
2034 /****************************************************************************
2035   get info about the server
2036   ****************************************************************************/
2037 static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2038                                 int mdrcnt,int mprcnt,
2039                                 char **rdata,char **rparam,
2040                                 int *rdata_len,int *rparam_len)
2041 {
2042   char *str1 = param+2;
2043   char *str2 = skip_string(str1,1);
2044   char *p = skip_string(str2,1);
2045   char *p2;
2046   extern pstring sesssetup_user;
2047   int level = SVAL(p,0);
2048
2049   DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2050
2051   *rparam_len = 6;
2052   *rparam = REALLOC(*rparam,*rparam_len);
2053
2054   /* check it's a supported varient */
2055   if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz")))
2056     return(False);
2057
2058   *rdata_len = mdrcnt + 1024;
2059   *rdata = REALLOC(*rdata,*rdata_len);
2060
2061   SSVAL(*rparam,0,NERR_Success);
2062   SSVAL(*rparam,2,0);           /* converter word */
2063
2064   p = *rdata;
2065   p2 = p + 22;
2066
2067
2068   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2069   pstrcpy(p2,local_machine);
2070   strupper(p2);
2071   p2 = skip_string(p2,1);
2072   p += 4;
2073
2074   SIVAL(p,0,PTR_DIFF(p2,*rdata));
2075   pstrcpy(p2,sesssetup_user);
2076   p2 = skip_string(p2,1);
2077   p += 4;
2078
2079   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
2080   pstrcpy(p2,global_myworkgroup);
2081   strupper(p2);
2082   p2 = skip_string(p2,1);
2083   p += 4;
2084
2085   SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
2086   SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
2087   p += 2;
2088
2089   SIVAL(p,0,PTR_DIFF(p2,*rdata));
2090   pstrcpy(p2,global_myworkgroup);       /* don't know.  login domain?? */
2091   p2 = skip_string(p2,1);
2092   p += 4;
2093
2094   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
2095   pstrcpy(p2,"");
2096   p2 = skip_string(p2,1);
2097   p += 4;
2098
2099   *rdata_len = PTR_DIFF(p2,*rdata);
2100
2101   SSVAL(*rparam,4,*rdata_len);
2102
2103   return(True);
2104 }
2105
2106 /****************************************************************************
2107   get info about a user
2108
2109     struct user_info_11 {
2110         char                usri11_name[21];  0-20 
2111         char                usri11_pad;       21 
2112         char                *usri11_comment;  22-25 
2113         char            *usri11_usr_comment;  26-29
2114         unsigned short      usri11_priv;      30-31
2115         unsigned long       usri11_auth_flags; 32-35
2116         long                usri11_password_age; 36-39
2117         char                *usri11_homedir; 40-43
2118         char            *usri11_parms; 44-47
2119         long                usri11_last_logon; 48-51
2120         long                usri11_last_logoff; 52-55
2121         unsigned short      usri11_bad_pw_count; 56-57
2122         unsigned short      usri11_num_logons; 58-59
2123         char                *usri11_logon_server; 60-63
2124         unsigned short      usri11_country_code; 64-65
2125         char            *usri11_workstations; 66-69
2126         unsigned long       usri11_max_storage; 70-73
2127         unsigned short      usri11_units_per_week; 74-75
2128         unsigned char       *usri11_logon_hours; 76-79
2129         unsigned short      usri11_code_page; 80-81
2130     };
2131
2132 where:
2133
2134   usri11_name specifies the user name for which information is retireved
2135
2136   usri11_pad aligns the next data structure element to a word boundary
2137
2138   usri11_comment is a null terminated ASCII comment
2139
2140   usri11_user_comment is a null terminated ASCII comment about the user
2141
2142   usri11_priv specifies the level of the privilege assigned to the user.
2143        The possible values are:
2144
2145 Name             Value  Description
2146 USER_PRIV_GUEST  0      Guest privilege
2147 USER_PRIV_USER   1      User privilege
2148 USER_PRV_ADMIN   2      Administrator privilege
2149
2150   usri11_auth_flags specifies the account operator privileges. The
2151        possible values are:
2152
2153 Name            Value   Description
2154 AF_OP_PRINT     0       Print operator
2155
2156
2157 Leach, Naik                                        [Page 28]\r\f
2158
2159
2160 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
2161
2162
2163 AF_OP_COMM      1       Communications operator
2164 AF_OP_SERVER    2       Server operator
2165 AF_OP_ACCOUNTS  3       Accounts operator
2166
2167
2168   usri11_password_age specifies how many seconds have elapsed since the
2169        password was last changed.
2170
2171   usri11_home_dir points to a null terminated ASCII string that contains
2172        the path name of the user's home directory.
2173
2174   usri11_parms points to a null terminated ASCII string that is set
2175        aside for use by applications.
2176
2177   usri11_last_logon specifies the time when the user last logged on.
2178        This value is stored as the number of seconds elapsed since
2179        00:00:00, January 1, 1970.
2180
2181   usri11_last_logoff specifies the time when the user last logged off.
2182        This value is stored as the number of seconds elapsed since
2183        00:00:00, January 1, 1970. A value of 0 means the last logoff
2184        time is unknown.
2185
2186   usri11_bad_pw_count specifies the number of incorrect passwords
2187        entered since the last successful logon.
2188
2189   usri11_log1_num_logons specifies the number of times this user has
2190        logged on. A value of -1 means the number of logons is unknown.
2191
2192   usri11_logon_server points to a null terminated ASCII string that
2193        contains the name of the server to which logon requests are sent.
2194        A null string indicates logon requests should be sent to the
2195        domain controller.
2196
2197   usri11_country_code specifies the country code for the user's language
2198        of choice.
2199
2200   usri11_workstations points to a null terminated ASCII string that
2201        contains the names of workstations the user may log on from.
2202        There may be up to 8 workstations, with the names separated by
2203        commas. A null strings indicates there are no restrictions.
2204
2205   usri11_max_storage specifies the maximum amount of disk space the user
2206        can occupy. A value of 0xffffffff indicates there are no
2207        restrictions.
2208
2209   usri11_units_per_week specifies the equal number of time units into
2210        which a week is divided. This value must be equal to 168.
2211
2212   usri11_logon_hours points to a 21 byte (168 bits) string that
2213        specifies the time during which the user can log on. Each bit
2214        represents one unique hour in a week. The first bit (bit 0, word
2215        0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
2216
2217
2218
2219 Leach, Naik                                        [Page 29]\r\f
2220
2221
2222 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
2223
2224
2225        Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
2226        are no restrictions.
2227
2228   usri11_code_page specifies the code page for the user's language of
2229        choice
2230
2231 All of the pointers in this data structure need to be treated
2232 specially. The  pointer is a 32 bit pointer. The higher 16 bits need
2233 to be ignored. The converter word returned in the parameters section
2234 needs to be subtracted from the lower 16 bits to calculate an offset
2235 into the return buffer where this ASCII string resides.
2236
2237 There is no auxiliary data in the response.
2238
2239   ****************************************************************************/
2240
2241 #define usri11_name           0 
2242 #define usri11_pad            21
2243 #define usri11_comment        22
2244 #define usri11_usr_comment    26
2245 #define usri11_full_name      30
2246 #define usri11_priv           34
2247 #define usri11_auth_flags     36
2248 #define usri11_password_age   40
2249 #define usri11_homedir        44
2250 #define usri11_parms          48
2251 #define usri11_last_logon     52
2252 #define usri11_last_logoff    56
2253 #define usri11_bad_pw_count   60
2254 #define usri11_num_logons     62
2255 #define usri11_logon_server   64
2256 #define usri11_country_code   68
2257 #define usri11_workstations   70
2258 #define usri11_max_storage    74
2259 #define usri11_units_per_week 78
2260 #define usri11_logon_hours    80
2261 #define usri11_code_page      84
2262 #define usri11_end            86
2263
2264 #define USER_PRIV_GUEST 0
2265 #define USER_PRIV_USER 1
2266 #define USER_PRIV_ADMIN 2
2267
2268 #define AF_OP_PRINT     0 
2269 #define AF_OP_COMM      1
2270 #define AF_OP_SERVER    2
2271 #define AF_OP_ACCOUNTS  3
2272
2273
2274 static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2275                                 int mdrcnt,int mprcnt,
2276                                 char **rdata,char **rparam,
2277                                 int *rdata_len,int *rparam_len)
2278 {
2279         char *str1 = param+2;
2280         char *str2 = skip_string(str1,1);
2281         char *UserName = skip_string(str2,1);
2282         char *p = skip_string(UserName,1);
2283         int uLevel = SVAL(p,0);
2284         char *p2;
2285
2286     /* get NIS home of a previously validated user - simeon */
2287     /* With share level security vuid will always be zero.
2288        Don't depend on vuser being non-null !!. JRA */
2289     user_struct *vuser = get_valid_user_struct(vuid);
2290     if(vuser != NULL)
2291       DEBUG(3,("  Username of UID %d is %s\n", (int)vuser->uid, 
2292                vuser->user.unix_name));
2293
2294     *rparam_len = 6;
2295     *rparam = REALLOC(*rparam,*rparam_len);
2296
2297     DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
2298   
2299         /* check it's a supported variant */
2300         if (strcmp(str1,"zWrLh") != 0) return False;
2301         switch( uLevel )
2302         {
2303                 case 0: p2 = "B21"; break;
2304                 case 1: p2 = "B21BB16DWzzWz"; break;
2305                 case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
2306                 case 10: p2 = "B21Bzzz"; break;
2307                 case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
2308                 default: return False;
2309         }
2310
2311         if (strcmp(p2,str2) != 0) return False;
2312
2313         *rdata_len = mdrcnt + 1024;
2314         *rdata = REALLOC(*rdata,*rdata_len);
2315
2316         SSVAL(*rparam,0,NERR_Success);
2317         SSVAL(*rparam,2,0);             /* converter word */
2318
2319         p = *rdata;
2320         p2 = p + usri11_end;
2321
2322         memset(p,0,21); 
2323         fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
2324
2325         if (uLevel > 0)
2326         {
2327                 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
2328                 *p2 = 0;
2329         }
2330         if (uLevel >= 10)
2331         {
2332                 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
2333                 pstrcpy(p2,"Comment");
2334                 p2 = skip_string(p2,1);
2335
2336                 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
2337                 pstrcpy(p2,"UserComment");
2338                 p2 = skip_string(p2,1);
2339
2340                 /* EEK! the cifsrap.txt doesn't have this in!!!! */
2341                 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
2342                 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2343                 p2 = skip_string(p2,1);
2344         }
2345
2346         if (uLevel == 11) /* modelled after NTAS 3.51 reply */
2347         {         
2348                 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); 
2349                 SIVAL(p,usri11_auth_flags,AF_OP_PRINT);         /* auth flags */
2350                 SIVALS(p,usri11_password_age,-1);               /* password age */
2351                 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
2352                 pstrcpy(p2, lp_logon_home());
2353                 p2 = skip_string(p2,1);
2354                 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
2355                 pstrcpy(p2,"");
2356                 p2 = skip_string(p2,1);
2357                 SIVAL(p,usri11_last_logon,0);           /* last logon */
2358                 SIVAL(p,usri11_last_logoff,0);          /* last logoff */
2359                 SSVALS(p,usri11_bad_pw_count,-1);       /* bad pw counts */
2360                 SSVALS(p,usri11_num_logons,-1);         /* num logons */
2361                 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
2362                 pstrcpy(p2,"\\\\*");
2363                 p2 = skip_string(p2,1);
2364                 SSVAL(p,usri11_country_code,0);         /* country code */
2365
2366                 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
2367                 pstrcpy(p2,"");
2368                 p2 = skip_string(p2,1);
2369
2370                 SIVALS(p,usri11_max_storage,-1);                /* max storage */
2371                 SSVAL(p,usri11_units_per_week,168);             /* units per week */
2372                 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
2373
2374                 /* a simple way to get logon hours at all times. */
2375                 memset(p2,0xff,21);
2376                 SCVAL(p2,21,0);           /* fix zero termination */
2377                 p2 = skip_string(p2,1);
2378
2379                 SSVAL(p,usri11_code_page,0);            /* code page */
2380         }
2381         if (uLevel == 1 || uLevel == 2)
2382         {
2383                 memset(p+22,' ',16);    /* password */
2384                 SIVALS(p,38,-1);                /* password age */
2385                 SSVAL(p,42,
2386                 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2387                 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
2388                 pstrcpy(p2,lp_logon_home());
2389                 p2 = skip_string(p2,1);
2390                 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
2391                 *p2++ = 0;
2392                 SSVAL(p,52,0);          /* flags */
2393                 SIVAL(p,54,PTR_DIFF(p2,*rdata));                /* script_path */
2394                 pstrcpy(p2,lp_logon_script());
2395                 standard_sub_conn( conn, p2 );             
2396                 p2 = skip_string(p2,1);
2397                 if (uLevel == 2)
2398                 {
2399                         SIVAL(p,60,0);          /* auth_flags */
2400                         SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
2401                         pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2402                         p2 = skip_string(p2,1);
2403                         SIVAL(p,68,0);          /* urs_comment */
2404                         SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
2405                         pstrcpy(p2,"");
2406                         p2 = skip_string(p2,1);
2407                         SIVAL(p,76,0);          /* workstations */
2408                         SIVAL(p,80,0);          /* last_logon */
2409                         SIVAL(p,84,0);          /* last_logoff */
2410                         SIVALS(p,88,-1);                /* acct_expires */
2411                         SIVALS(p,92,-1);                /* max_storage */
2412                         SSVAL(p,96,168);        /* units_per_week */
2413                         SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
2414                         memset(p2,-1,21);
2415                         p2 += 21;
2416                         SSVALS(p,102,-1);       /* bad_pw_count */
2417                         SSVALS(p,104,-1);       /* num_logons */
2418                         SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
2419                         pstrcpy(p2,"\\\\%L");
2420                         standard_sub_conn(conn, p2);
2421                         p2 = skip_string(p2,1);
2422                         SSVAL(p,110,49);        /* country_code */
2423                         SSVAL(p,112,860);       /* code page */
2424                 }
2425         }
2426
2427         *rdata_len = PTR_DIFF(p2,*rdata);
2428
2429         SSVAL(*rparam,4,*rdata_len);    /* is this right?? */
2430
2431         return(True);
2432 }
2433
2434 /*******************************************************************
2435   get groups that a user is a member of
2436   ******************************************************************/
2437 static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *param,char *data,
2438                                  int mdrcnt,int mprcnt,
2439                                  char **rdata,char **rparam,
2440                                  int *rdata_len,int *rparam_len)
2441 {
2442   char *str1 = param+2;
2443   char *str2 = skip_string(str1,1);
2444   char *UserName = skip_string(str2,1);
2445   char *p = skip_string(UserName,1);
2446   int uLevel = SVAL(p,0);
2447   char *p2;
2448   int count=0;
2449
2450   *rparam_len = 8;
2451   *rparam = REALLOC(*rparam,*rparam_len);
2452
2453   /* check it's a supported varient */
2454   if (strcmp(str1,"zWrLeh") != 0) return False;
2455   switch( uLevel ) {
2456   case 0: p2 = "B21"; break;
2457   default: return False;
2458   }
2459   if (strcmp(p2,str2) != 0) return False;
2460
2461   *rdata_len = mdrcnt + 1024;
2462   *rdata = REALLOC(*rdata,*rdata_len);
2463
2464   SSVAL(*rparam,0,NERR_Success);
2465   SSVAL(*rparam,2,0);           /* converter word */
2466
2467   p = *rdata;
2468
2469   /* XXXX we need a real SAM database some day */
2470   pstrcpy(p,"Users"); p += 21; count++;
2471   pstrcpy(p,"Domain Users"); p += 21; count++;
2472   pstrcpy(p,"Guests"); p += 21; count++;
2473   pstrcpy(p,"Domain Guests"); p += 21; count++;
2474
2475   *rdata_len = PTR_DIFF(p,*rdata);
2476
2477   SSVAL(*rparam,4,count);       /* is this right?? */
2478   SSVAL(*rparam,6,count);       /* is this right?? */
2479
2480   return(True);
2481 }
2482
2483
2484 static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param,char *data,
2485                                 int mdrcnt,int mprcnt,
2486                                 char **rdata,char **rparam,
2487                                 int *rdata_len,int *rparam_len)
2488 {
2489   char *str1 = param+2;
2490   char *str2 = skip_string(str1,1);
2491   char *p = skip_string(str2,1);
2492   int uLevel;
2493   struct pack_desc desc;
2494   char* name;
2495
2496   uLevel = SVAL(p,0);
2497   name = p + 2;
2498
2499   memset((char *)&desc,'\0',sizeof(desc));
2500
2501   DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
2502
2503   /* check it's a supported varient */
2504   if (strcmp(str1,"OOWb54WrLh") != 0) return False;
2505   if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) return False;
2506   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2507   desc.base = *rdata;
2508   desc.buflen = mdrcnt;
2509   desc.subformat = NULL;
2510   desc.format = str2;
2511   
2512   if (init_package(&desc,1,0))
2513   {
2514     PACKI(&desc,"W",0);         /* code */
2515     PACKS(&desc,"B21",name);    /* eff. name */
2516     PACKS(&desc,"B","");                /* pad */
2517     PACKI(&desc,"W",
2518           conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2519     PACKI(&desc,"D",0);         /* auth flags XXX */
2520     PACKI(&desc,"W",0);         /* num logons */
2521     PACKI(&desc,"W",0);         /* bad pw count */
2522     PACKI(&desc,"D",0);         /* last logon */
2523     PACKI(&desc,"D",-1);                /* last logoff */
2524     PACKI(&desc,"D",-1);                /* logoff time */
2525     PACKI(&desc,"D",-1);                /* kickoff time */
2526     PACKI(&desc,"D",0);         /* password age */
2527     PACKI(&desc,"D",0);         /* password can change */
2528     PACKI(&desc,"D",-1);                /* password must change */
2529     {
2530       fstring mypath;
2531       fstrcpy(mypath,"\\\\");
2532       fstrcat(mypath,local_machine);
2533       strupper(mypath);
2534       PACKS(&desc,"z",mypath); /* computer */
2535     }
2536     PACKS(&desc,"z",global_myworkgroup);/* domain */
2537
2538 /* JHT - By calling lp_logon_script() and standard_sub() we have */
2539 /* made sure all macros are fully substituted and available */
2540     {
2541       pstring logon_script;
2542       pstrcpy(logon_script,lp_logon_script());
2543       standard_sub_conn( conn, logon_script );
2544       PACKS(&desc,"z", logon_script);           /* script path */
2545     }
2546 /* End of JHT mods */
2547
2548     PACKI(&desc,"D",0x00000000);                /* reserved */
2549   }
2550
2551   *rdata_len = desc.usedlen;
2552   *rparam_len = 6;
2553   *rparam = REALLOC(*rparam,*rparam_len);
2554   SSVALS(*rparam,0,desc.errcode);
2555   SSVAL(*rparam,2,0);
2556   SSVAL(*rparam,4,desc.neededlen);
2557
2558   DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
2559   return(True);
2560 }
2561
2562
2563 /****************************************************************************
2564   api_WAccessGetUserPerms
2565   ****************************************************************************/
2566 static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid, char *param,char *data,
2567                                     int mdrcnt,int mprcnt,
2568                                     char **rdata,char **rparam,
2569                                     int *rdata_len,int *rparam_len)
2570 {
2571   char *str1 = param+2;
2572   char *str2 = skip_string(str1,1);
2573   char *user = skip_string(str2,1);
2574   char *resource = skip_string(user,1);
2575
2576   DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
2577
2578   /* check it's a supported varient */
2579   if (strcmp(str1,"zzh") != 0) return False;
2580   if (strcmp(str2,"") != 0) return False;
2581
2582   *rparam_len = 6;
2583   *rparam = REALLOC(*rparam,*rparam_len);
2584   SSVALS(*rparam,0,0);          /* errorcode */
2585   SSVAL(*rparam,2,0);           /* converter word */
2586   SSVAL(*rparam,4,0x7f);        /* permission flags */
2587
2588   return(True);
2589 }
2590
2591 /****************************************************************************
2592   api_WPrintJobEnumerate
2593   ****************************************************************************/
2594 static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2595                                  int mdrcnt,int mprcnt,
2596                                  char **rdata,char **rparam,
2597                                  int *rdata_len,int *rparam_len)
2598 {
2599   char *str1 = param+2;
2600   char *str2 = skip_string(str1,1);
2601   char *p = skip_string(str2,1);
2602   int uLevel;
2603   int count;
2604   int i;
2605   int snum;
2606   int job;
2607   struct pack_desc desc;
2608   print_queue_struct *queue=NULL;
2609   print_status_struct status;
2610
2611   uLevel = SVAL(p,2);
2612
2613   memset((char *)&desc,'\0',sizeof(desc));
2614   memset((char *)&status,'\0',sizeof(status));
2615
2616   DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
2617
2618   /* check it's a supported varient */
2619   if (strcmp(str1,"WWrLh") != 0) return False;
2620   if (!check_printjob_info(&desc,uLevel,str2)) return False;
2621
2622   job = SVAL(p,0);
2623   snum = print_job_snum(job);
2624
2625   if (snum < 0 || !VALID_SNUM(snum)) return(False);
2626
2627   count = print_queue_status(snum,&queue,&status);
2628   for (i = 0; i < count; i++) {
2629     if (queue[i].job == job) break;
2630   }
2631   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2632   desc.base = *rdata;
2633   desc.buflen = mdrcnt;
2634
2635   if (init_package(&desc,1,0)) {
2636     if (i < count) {
2637       fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2638       *rdata_len = desc.usedlen;
2639     }
2640     else {
2641       desc.errcode = NERR_JobNotFound;
2642       *rdata_len = 0;
2643     }
2644   }
2645
2646   *rparam_len = 6;
2647   *rparam = REALLOC(*rparam,*rparam_len);
2648   SSVALS(*rparam,0,desc.errcode);
2649   SSVAL(*rparam,2,0);
2650   SSVAL(*rparam,4,desc.neededlen);
2651
2652   if (queue) free(queue);
2653
2654   DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
2655   return(True);
2656 }
2657
2658 static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *param,char *data,
2659                                    int mdrcnt,int mprcnt,
2660                                    char **rdata,char **rparam,
2661                                    int *rdata_len,int *rparam_len)
2662 {
2663   char *str1 = param+2;
2664   char *str2 = skip_string(str1,1);
2665   char *p = skip_string(str2,1);
2666   char* name = p;
2667   int uLevel;
2668   int count;
2669   int i, succnt=0;
2670   int snum;
2671   struct pack_desc desc;
2672   print_queue_struct *queue=NULL;
2673   print_status_struct status;
2674
2675   memset((char *)&desc,'\0',sizeof(desc));
2676   memset((char *)&status,'\0',sizeof(status));
2677
2678   p = skip_string(p,1);
2679   uLevel = SVAL(p,0);
2680
2681   DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
2682
2683   /* check it's a supported varient */
2684   if (strcmp(str1,"zWrLeh") != 0) return False;
2685   if (uLevel > 2) return False; /* defined only for uLevel 0,1,2 */
2686   if (!check_printjob_info(&desc,uLevel,str2)) return False;
2687
2688   snum = lp_servicenumber(name);
2689   if (snum < 0 && pcap_printername_ok(name,NULL)) {
2690     int pnum = lp_servicenumber(PRINTERS_NAME);
2691     if (pnum >= 0) {
2692       lp_add_printer(name,pnum);
2693       snum = lp_servicenumber(name);
2694     }
2695   }
2696
2697   if (snum < 0 || !VALID_SNUM(snum)) return(False);
2698
2699   count = print_queue_status(snum,&queue,&status);
2700   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2701   desc.base = *rdata;
2702   desc.buflen = mdrcnt;
2703
2704   if (init_package(&desc,count,0)) {
2705     succnt = 0;
2706     for (i = 0; i < count; i++) {
2707       fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2708       if (desc.errcode == NERR_Success) succnt = i+1;
2709     }
2710   }
2711
2712   *rdata_len = desc.usedlen;
2713
2714   *rparam_len = 8;
2715   *rparam = REALLOC(*rparam,*rparam_len);
2716   SSVALS(*rparam,0,desc.errcode);
2717   SSVAL(*rparam,2,0);
2718   SSVAL(*rparam,4,succnt);
2719   SSVAL(*rparam,6,count);
2720
2721   if (queue) free(queue);
2722
2723   DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
2724   return(True);
2725 }
2726
2727 static int check_printdest_info(struct pack_desc* desc,
2728                                 int uLevel, char* id)
2729 {
2730   desc->subformat = NULL;
2731   switch( uLevel ) {
2732   case 0: desc->format = "B9"; break;
2733   case 1: desc->format = "B9B21WWzW"; break;
2734   case 2: desc->format = "z"; break;
2735   case 3: desc->format = "zzzWWzzzWW"; break;
2736   default: return False;
2737   }
2738   if (strcmp(desc->format,id) != 0) return False;
2739   return True;
2740 }
2741
2742 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
2743                                 struct pack_desc* desc)
2744 {
2745   char buf[100];
2746   strncpy(buf,SERVICE(snum),sizeof(buf)-1);
2747   buf[sizeof(buf)-1] = 0;
2748   strupper(buf);
2749   if (uLevel <= 1) {
2750     PACKS(desc,"B9",buf);       /* szName */
2751     if (uLevel == 1) {
2752       PACKS(desc,"B21","");     /* szUserName */
2753       PACKI(desc,"W",0);                /* uJobId */
2754       PACKI(desc,"W",0);                /* fsStatus */
2755       PACKS(desc,"z","");       /* pszStatus */
2756       PACKI(desc,"W",0);                /* time */
2757     }
2758   }
2759   if (uLevel == 2 || uLevel == 3) {
2760     PACKS(desc,"z",buf);                /* pszPrinterName */
2761     if (uLevel == 3) {
2762       PACKS(desc,"z","");       /* pszUserName */
2763       PACKS(desc,"z","");       /* pszLogAddr */
2764       PACKI(desc,"W",0);                /* uJobId */
2765       PACKI(desc,"W",0);                /* fsStatus */
2766       PACKS(desc,"z","");       /* pszStatus */
2767       PACKS(desc,"z","");       /* pszComment */
2768       PACKS(desc,"z","NULL"); /* pszDrivers */
2769       PACKI(desc,"W",0);                /* time */
2770       PACKI(desc,"W",0);                /* pad1 */
2771     }
2772   }
2773 }
2774
2775 static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2776                                   int mdrcnt,int mprcnt,
2777                                   char **rdata,char **rparam,
2778                                   int *rdata_len,int *rparam_len)
2779 {
2780   char *str1 = param+2;
2781   char *str2 = skip_string(str1,1);
2782   char *p = skip_string(str2,1);
2783   char* PrinterName = p;
2784   int uLevel;
2785   struct pack_desc desc;
2786   int snum;
2787
2788   memset((char *)&desc,'\0',sizeof(desc));
2789
2790   p = skip_string(p,1);
2791   uLevel = SVAL(p,0);
2792
2793   DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
2794
2795   /* check it's a supported varient */
2796   if (strcmp(str1,"zWrLh") != 0) return False;
2797   if (!check_printdest_info(&desc,uLevel,str2)) return False;
2798
2799   snum = lp_servicenumber(PrinterName);
2800   if (snum < 0 && pcap_printername_ok(PrinterName,NULL)) {
2801     int pnum = lp_servicenumber(PRINTERS_NAME);
2802     if (pnum >= 0) {
2803       lp_add_printer(PrinterName,pnum);
2804       snum = lp_servicenumber(PrinterName);
2805     }
2806   }
2807
2808   if (snum < 0) {
2809     *rdata_len = 0;
2810     desc.errcode = NERR_DestNotFound;
2811     desc.neededlen = 0;
2812   }
2813   else {
2814     if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2815     desc.base = *rdata;
2816     desc.buflen = mdrcnt;
2817     if (init_package(&desc,1,0)) {
2818       fill_printdest_info(conn,snum,uLevel,&desc);
2819     }
2820     *rdata_len = desc.usedlen;
2821   }
2822
2823   *rparam_len = 6;
2824   *rparam = REALLOC(*rparam,*rparam_len);
2825   SSVALS(*rparam,0,desc.errcode);
2826   SSVAL(*rparam,2,0);
2827   SSVAL(*rparam,4,desc.neededlen);
2828
2829   DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
2830   return(True);
2831 }
2832
2833 static BOOL api_WPrintDestEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
2834                                int mdrcnt,int mprcnt,
2835                                char **rdata,char **rparam,
2836                                int *rdata_len,int *rparam_len)
2837 {
2838   char *str1 = param+2;
2839   char *str2 = skip_string(str1,1);
2840   char *p = skip_string(str2,1);
2841   int uLevel;
2842   int queuecnt;
2843   int i, n, succnt=0;
2844   struct pack_desc desc;
2845   int services = lp_numservices();
2846
2847   memset((char *)&desc,'\0',sizeof(desc));
2848
2849   uLevel = SVAL(p,0);
2850
2851   DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
2852
2853   /* check it's a supported varient */
2854   if (strcmp(str1,"WrLeh") != 0) return False;
2855   if (!check_printdest_info(&desc,uLevel,str2)) return False;
2856
2857   queuecnt = 0;
2858   for (i = 0; i < services; i++)
2859     if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
2860       queuecnt++;
2861
2862   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2863   desc.base = *rdata;
2864   desc.buflen = mdrcnt;
2865   if (init_package(&desc,queuecnt,0)) {    
2866     succnt = 0;
2867     n = 0;
2868     for (i = 0; i < services; i++) {
2869       if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
2870         fill_printdest_info(conn,i,uLevel,&desc);
2871         n++;
2872         if (desc.errcode == NERR_Success) succnt = n;
2873       }
2874     }
2875   }
2876
2877   *rdata_len = desc.usedlen;
2878
2879   *rparam_len = 8;
2880   *rparam = REALLOC(*rparam,*rparam_len);
2881   SSVALS(*rparam,0,desc.errcode);
2882   SSVAL(*rparam,2,0);
2883   SSVAL(*rparam,4,succnt);
2884   SSVAL(*rparam,6,queuecnt);
2885
2886   DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
2887   return(True);
2888 }
2889
2890 static BOOL api_WPrintDriverEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
2891                                  int mdrcnt,int mprcnt,
2892                                  char **rdata,char **rparam,
2893                                  int *rdata_len,int *rparam_len)
2894 {
2895   char *str1 = param+2;
2896   char *str2 = skip_string(str1,1);
2897   char *p = skip_string(str2,1);
2898   int uLevel;
2899   int succnt;
2900   struct pack_desc desc;
2901
2902   memset((char *)&desc,'\0',sizeof(desc));
2903
2904   uLevel = SVAL(p,0);
2905
2906   DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
2907
2908   /* check it's a supported varient */
2909   if (strcmp(str1,"WrLeh") != 0) return False;
2910   if (uLevel != 0 || strcmp(str2,"B41") != 0) return False;
2911
2912   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2913   desc.base = *rdata;
2914   desc.buflen = mdrcnt;
2915   if (init_package(&desc,1,0)) {
2916     PACKS(&desc,"B41","NULL");
2917   }
2918
2919   succnt = (desc.errcode == NERR_Success ? 1 : 0);
2920
2921   *rdata_len = desc.usedlen;
2922
2923   *rparam_len = 8;
2924   *rparam = REALLOC(*rparam,*rparam_len);
2925   SSVALS(*rparam,0,desc.errcode);
2926   SSVAL(*rparam,2,0);
2927   SSVAL(*rparam,4,succnt);
2928   SSVAL(*rparam,6,1);
2929
2930   DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
2931   return(True);
2932 }
2933
2934 static BOOL api_WPrintQProcEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
2935                                 int mdrcnt,int mprcnt,
2936                                 char **rdata,char **rparam,
2937                                 int *rdata_len,int *rparam_len)
2938 {
2939   char *str1 = param+2;
2940   char *str2 = skip_string(str1,1);
2941   char *p = skip_string(str2,1);
2942   int uLevel;
2943   int succnt;
2944   struct pack_desc desc;
2945
2946   memset((char *)&desc,'\0',sizeof(desc));
2947
2948   uLevel = SVAL(p,0);
2949
2950   DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
2951
2952   /* check it's a supported varient */
2953   if (strcmp(str1,"WrLeh") != 0) return False;
2954   if (uLevel != 0 || strcmp(str2,"B13") != 0) return False;
2955
2956   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2957   desc.base = *rdata;
2958   desc.buflen = mdrcnt;
2959   desc.format = str2;
2960   if (init_package(&desc,1,0)) {
2961     PACKS(&desc,"B13","lpd");
2962   }
2963
2964   succnt = (desc.errcode == NERR_Success ? 1 : 0);
2965
2966   *rdata_len = desc.usedlen;
2967
2968   *rparam_len = 8;
2969   *rparam = REALLOC(*rparam,*rparam_len);
2970   SSVALS(*rparam,0,desc.errcode);
2971   SSVAL(*rparam,2,0);
2972   SSVAL(*rparam,4,succnt);
2973   SSVAL(*rparam,6,1);
2974
2975   DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
2976   return(True);
2977 }
2978
2979 static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
2980                                int mdrcnt,int mprcnt,
2981                                char **rdata,char **rparam,
2982                                int *rdata_len,int *rparam_len)
2983 {
2984   char *str1 = param+2;
2985   char *str2 = skip_string(str1,1);
2986   char *p = skip_string(str2,1);
2987   int uLevel;
2988   int succnt;
2989   struct pack_desc desc;
2990
2991   memset((char *)&desc,'\0',sizeof(desc));
2992
2993   uLevel = SVAL(p,0);
2994
2995   DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
2996
2997   /* check it's a supported varient */
2998   if (strcmp(str1,"WrLeh") != 0) return False;
2999   if (uLevel != 0 || strcmp(str2,"B9") != 0) return False;
3000
3001   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3002   memset((char *)&desc,'\0',sizeof(desc));
3003   desc.base = *rdata;
3004   desc.buflen = mdrcnt;
3005   desc.format = str2;
3006   if (init_package(&desc,1,0)) {
3007     PACKS(&desc,"B13","lp0");
3008   }
3009
3010   succnt = (desc.errcode == NERR_Success ? 1 : 0);
3011
3012   *rdata_len = desc.usedlen;
3013
3014   *rparam_len = 8;
3015   *rparam = REALLOC(*rparam,*rparam_len);
3016   SSVALS(*rparam,0,desc.errcode);
3017   SSVAL(*rparam,2,0);
3018   SSVAL(*rparam,4,succnt);
3019   SSVAL(*rparam,6,1);
3020
3021   DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
3022   return(True);
3023 }
3024
3025 /****************************************************************************
3026  The buffer was too small
3027  ****************************************************************************/
3028
3029 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
3030                          int mdrcnt,int mprcnt,
3031                          char **rdata,char **rparam,
3032                          int *rdata_len,int *rparam_len)
3033 {
3034   *rparam_len = MIN(*rparam_len,mprcnt);
3035   *rparam = REALLOC(*rparam,*rparam_len);
3036
3037   *rdata_len = 0;
3038
3039   SSVAL(*rparam,0,NERR_BufTooSmall);
3040
3041   DEBUG(3,("Supplied buffer too small in API command\n"));
3042
3043   return(True);
3044 }
3045
3046
3047 /****************************************************************************
3048  The request is not supported
3049  ****************************************************************************/
3050
3051 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
3052                             int mdrcnt,int mprcnt,
3053                             char **rdata,char **rparam,
3054                             int *rdata_len,int *rparam_len)
3055 {
3056   *rparam_len = 4;
3057   *rparam = REALLOC(*rparam,*rparam_len);
3058
3059   *rdata_len = 0;
3060
3061   SSVAL(*rparam,0,NERR_notsupported);
3062   SSVAL(*rparam,2,0);           /* converter word */
3063
3064   DEBUG(3,("Unsupported API command\n"));
3065
3066   return(True);
3067 }
3068
3069
3070
3071
3072 struct
3073 {
3074   char *name;
3075   int id;
3076   BOOL (*fn)(connection_struct *,uint16,char *,char *,
3077              int,int,char **,char **,int *,int *);
3078   int flags;
3079 } api_commands[] = {
3080   {"RNetShareEnum",     0,      api_RNetShareEnum,0},
3081   {"RNetShareGetInfo",  1,      api_RNetShareGetInfo,0},
3082   {"RNetServerGetInfo", 13,     api_RNetServerGetInfo,0},
3083   {"RNetGroupGetUsers", 52,     api_RNetGroupGetUsers,0},
3084   {"RNetUserGetInfo",   56,     api_RNetUserGetInfo,0},
3085   {"NetUserGetGroups",  59,     api_NetUserGetGroups,0},
3086   {"NetWkstaGetInfo",   63,     api_NetWkstaGetInfo,0},
3087   {"DosPrintQEnum",     69,     api_DosPrintQEnum,0},
3088   {"DosPrintQGetInfo",  70,     api_DosPrintQGetInfo,0},
3089   {"WPrintQueuePause",  74, api_WPrintQueuePurge,0},
3090   {"WPrintQueueResume", 75, api_WPrintQueuePurge,0},
3091   {"WPrintJobEnumerate",76,     api_WPrintJobEnumerate,0},
3092   {"WPrintJobGetInfo",  77,     api_WPrintJobGetInfo,0},
3093   {"RDosPrintJobDel",   81,     api_RDosPrintJobDel,0},
3094   {"RDosPrintJobPause", 82,     api_RDosPrintJobDel,0},
3095   {"RDosPrintJobResume",83,     api_RDosPrintJobDel,0},
3096   {"WPrintDestEnum",    84,     api_WPrintDestEnum,0},
3097   {"WPrintDestGetInfo", 85,     api_WPrintDestGetInfo,0},
3098   {"NetRemoteTOD",      91,     api_NetRemoteTOD,0},
3099   {"WPrintQueuePurge",  103,    api_WPrintQueuePurge,0},
3100   {"NetServerEnum",     104,    api_RNetServerEnum,0},
3101   {"WAccessGetUserPerms",105,   api_WAccessGetUserPerms,0},
3102   {"SetUserPassword",   115,    api_SetUserPassword,0},
3103   {"WWkstaUserLogon",   132,    api_WWkstaUserLogon,0},
3104   {"PrintJobInfo",      147,    api_PrintJobInfo,0},
3105   {"WPrintDriverEnum",  205,    api_WPrintDriverEnum,0},
3106   {"WPrintQProcEnum",   206,    api_WPrintQProcEnum,0},
3107   {"WPrintPortEnum",    207,    api_WPrintPortEnum,0},
3108   {"SamOEMChangePassword", 214, api_SamOEMChangePassword,0},
3109   {NULL,                -1,     api_Unsupported,0}};
3110
3111
3112 /****************************************************************************
3113  Handle remote api calls
3114  ****************************************************************************/
3115
3116 int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *params,
3117                      int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
3118 {
3119   int api_command;
3120   char *rdata = NULL;
3121   char *rparam = NULL;
3122   int rdata_len = 0;
3123   int rparam_len = 0;
3124   BOOL reply=False;
3125   int i;
3126
3127   if (!params) {
3128           DEBUG(0,("ERROR: NULL params in api_reply()\n"));
3129           return 0;
3130   }
3131
3132   api_command = SVAL(params,0);
3133
3134   DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
3135            api_command,
3136            params+2,
3137            skip_string(params+2,1),
3138            tdscnt,tpscnt,mdrcnt,mprcnt));
3139
3140   for (i=0;api_commands[i].name;i++) {
3141     if (api_commands[i].id == api_command && api_commands[i].fn) {
3142         DEBUG(3,("Doing %s\n",api_commands[i].name));
3143         break;
3144     }
3145   }
3146
3147   rdata = (char *)malloc(1024);
3148   if (rdata)
3149     memset(rdata,'\0',1024);
3150
3151   rparam = (char *)malloc(1024);
3152   if (rparam)
3153     memset(rparam,'\0',1024);
3154
3155   if(!rdata || !rparam) {
3156     DEBUG(0,("api_reply: malloc fail !\n"));
3157     return -1;
3158   }
3159
3160   reply = api_commands[i].fn(conn,vuid,params,data,mdrcnt,mprcnt,
3161                              &rdata,&rparam,&rdata_len,&rparam_len);
3162
3163
3164   if (rdata_len > mdrcnt ||
3165       rparam_len > mprcnt) {
3166       reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
3167                            &rdata,&rparam,&rdata_len,&rparam_len);
3168   }
3169
3170   /* if we get False back then it's actually unsupported */
3171   if (!reply)
3172     api_Unsupported(conn,vuid,params,data,mdrcnt,mprcnt,
3173                     &rdata,&rparam,&rdata_len,&rparam_len);
3174
3175   send_trans_reply(outbuf, rparam, rparam_len, rdata, rdata_len, False);
3176
3177   if (rdata )
3178     free(rdata);
3179   if (rparam)
3180     free(rparam);
3181   
3182   return -1;
3183 }
3184
3185
3186 #undef OLD_NTDOMAIN