more merging voodoo
[tprouty/samba.git] / source / 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(),NULL);
503         if (!lines) {
504                 DEBUG(3,("fill_printq_info: Can't open %s - %s\n",
505                          lp_driverfile(),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(), NULL);
672         if (!lines) {
673                 DEBUG(3,("get_printerdrivernumber: Can't open %s - %s\n",
674                          lp_driverfile(),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         /*
780          * This is a *disgusting* hack.
781          * This is *so* bad that even I'm embarrassed (and I
782          * have no shame). Here's the deal :
783          * Until we get the correct SPOOLSS code into smbd
784          * then when we're running with NT SMB support then
785          * NT makes this call with a level of zero, and then
786          * immediately follows it with an open request to
787          * the \\SRVSVC pipe. If we allow that open to
788          * succeed then NT barfs when it cannot open the
789          * \\SPOOLSS pipe immediately after and continually
790          * whines saying "Printer name is invalid" forever
791          * after. If we cause *JUST THIS NEXT OPEN* of \\SRVSVC
792          * to fail, then NT downgrades to using the downlevel code
793          * and everything works as well as before. I hate
794          * myself for adding this code.... JRA.
795          */
796
797         fail_next_srvsvc_open();
798   }
799
800   *rdata_len = desc.usedlen;
801   
802   *rparam_len = 6;
803   *rparam = REALLOC(*rparam,*rparam_len);
804   SSVALS(*rparam,0,desc.errcode);
805   SSVAL(*rparam,2,0);
806   SSVAL(*rparam,4,desc.neededlen);
807   
808   DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
809
810   if (queue) free(queue);
811   
812   return(True);
813 }
814
815
816 /****************************************************************************
817   view list of all print jobs on all queues
818   ****************************************************************************/
819 static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param, char* data,
820                               int mdrcnt, int mprcnt,
821                               char **rdata, char** rparam,
822                               int *rdata_len, int *rparam_len)
823 {
824   char *param_format = param+2;
825   char *output_format1 = skip_string(param_format,1);
826   char *p = skip_string(output_format1,1);
827   int uLevel = SVAL(p,0);
828   char *output_format2 = p + 4;
829   int services = lp_numservices();
830   int i, n;
831   struct pack_desc desc;
832   print_queue_struct **queue = NULL;
833   print_status_struct *status = NULL;
834   int* subcntarr = NULL;
835   int queuecnt, subcnt=0, succnt=0;
836  
837   memset((char *)&desc,'\0',sizeof(desc));
838
839   DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
840  
841   if (!prefix_ok(param_format,"WrLeh")) return False;
842   if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
843     /*
844      * Patch from Scott Moomaw <scott@bridgewater.edu>
845      * to return the 'invalid info level' error if an
846      * unknown level was requested.
847      */
848     *rdata_len = 0;
849     *rparam_len = 6;
850     *rparam = REALLOC(*rparam,*rparam_len);
851     SSVALS(*rparam,0,ERROR_INVALID_LEVEL);
852     SSVAL(*rparam,2,0);
853     SSVAL(*rparam,4,0);
854     return(True);
855   }
856
857   queuecnt = 0;
858   for (i = 0; i < services; i++)
859     if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
860       queuecnt++;
861   if (uLevel > 0) {
862     if((queue = (print_queue_struct**)malloc(queuecnt*sizeof(print_queue_struct*))) == NULL) {
863       DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
864       return False;
865     }
866     memset(queue,0,queuecnt*sizeof(print_queue_struct*));
867     if((status = (print_status_struct*)malloc(queuecnt*sizeof(print_status_struct))) == NULL) {
868       DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
869       return False;
870     }
871     memset(status,0,queuecnt*sizeof(print_status_struct));
872     if((subcntarr = (int*)malloc(queuecnt*sizeof(int))) == NULL) {
873       DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
874       return False;
875     }
876     subcnt = 0;
877     n = 0;
878     for (i = 0; i < services; i++)
879       if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
880         subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
881         subcnt += subcntarr[n];
882         n++;
883       }
884   }
885   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
886   desc.base = *rdata;
887   desc.buflen = mdrcnt;
888
889   if (init_package(&desc,queuecnt,subcnt)) {
890     n = 0;
891     succnt = 0;
892     for (i = 0; i < services; i++)
893       if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
894         fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
895         n++;
896         if (desc.errcode == NERR_Success) succnt = n;
897       }
898   }
899
900   if (subcntarr) free(subcntarr);
901  
902   *rdata_len = desc.usedlen;
903   *rparam_len = 8;
904   *rparam = REALLOC(*rparam,*rparam_len);
905   SSVALS(*rparam,0,desc.errcode);
906   SSVAL(*rparam,2,0);
907   SSVAL(*rparam,4,succnt);
908   SSVAL(*rparam,6,queuecnt);
909   
910   for (i = 0; i < queuecnt; i++) {
911     if (queue && queue[i]) free(queue[i]);
912   }
913
914   if (queue) free(queue);
915   if (status) free(status);
916   
917   return True;
918 }
919
920 /****************************************************************************
921   get info level for a server list query
922   ****************************************************************************/
923 static BOOL check_server_info(int uLevel, char* id)
924 {
925   switch( uLevel ) {
926   case 0:
927     if (strcmp(id,"B16") != 0) return False;
928     break;
929   case 1:
930     if (strcmp(id,"B16BBDz") != 0) return False;
931     break;
932   default: 
933     return False;
934   }
935   return True;
936 }
937
938 struct srv_info_struct
939 {
940   fstring name;
941   uint32 type;
942   fstring comment;
943   fstring domain;
944   BOOL server_added;
945 };
946
947
948 /*******************************************************************
949   get server info lists from the files saved by nmbd. Return the
950   number of entries
951   ******************************************************************/
952 static int get_server_info(uint32 servertype, 
953                            struct srv_info_struct **servers,
954                            char *domain)
955 {
956   int count=0;
957   int alloced=0;
958   char **lines;
959   BOOL local_list_only;
960   int i;
961
962   lines = file_lines_load(lock_path(SERVER_LIST), NULL);
963   if (!lines) {
964     DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
965     return(0);
966   }
967
968   /* request for everything is code for request all servers */
969   if (servertype == SV_TYPE_ALL) 
970         servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
971
972   local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
973
974   DEBUG(4,("Servertype search: %8x\n",servertype));
975
976   for (i=0;lines[i];i++) {
977     fstring stype;
978     struct srv_info_struct *s;
979     char *ptr = lines[i];
980     BOOL ok = True;
981
982     if (!*ptr) continue;
983     
984     if (count == alloced) {
985       alloced += 10;
986       (*servers) = (struct srv_info_struct *)
987         Realloc(*servers,sizeof(**servers)*alloced);
988       if (!(*servers)) return(0);
989       memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
990     }
991     s = &(*servers)[count];
992     
993     if (!next_token(&ptr,s->name   , NULL, sizeof(s->name))) continue;
994     if (!next_token(&ptr,stype     , NULL, sizeof(stype))) continue;
995     if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) continue;
996     if (!next_token(&ptr,s->domain , NULL, sizeof(s->domain))) {
997       /* this allows us to cope with an old nmbd */
998       pstrcpy(s->domain,global_myworkgroup); 
999     }
1000     
1001     if (sscanf(stype,"%X",&s->type) != 1) { 
1002       DEBUG(4,("r:host file ")); 
1003       ok = False; 
1004     }
1005     
1006         /* Filter the servers/domains we return based on what was asked for. */
1007
1008         /* Check to see if we are being asked for a local list only. */
1009         if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1010           DEBUG(4,("r: local list only"));
1011           ok = False;
1012         }
1013
1014     /* doesn't match up: don't want it */
1015     if (!(servertype & s->type)) { 
1016       DEBUG(4,("r:serv type ")); 
1017       ok = False; 
1018     }
1019     
1020     if ((servertype & SV_TYPE_DOMAIN_ENUM) != 
1021         (s->type & SV_TYPE_DOMAIN_ENUM))
1022       {
1023         DEBUG(4,("s: dom mismatch "));
1024         ok = False;
1025       }
1026     
1027     if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM))
1028       {
1029         ok = False;
1030       }
1031     
1032         /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1033         s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1034
1035     if (ok)
1036       {
1037         DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1038                  s->name, s->type, s->comment, s->domain));
1039         
1040         s->server_added = True;
1041         count++;
1042       }
1043     else
1044       {
1045         DEBUG(4,("%20s %8x %25s %15s\n",
1046                  s->name, s->type, s->comment, s->domain));
1047       }
1048   }
1049   
1050   file_lines_free(lines);
1051   return(count);
1052 }
1053
1054
1055 /*******************************************************************
1056   fill in a server info structure
1057   ******************************************************************/
1058 static int fill_srv_info(struct srv_info_struct *service, 
1059                          int uLevel, char **buf, int *buflen, 
1060                          char **stringbuf, int *stringspace, char *baseaddr)
1061 {
1062   int struct_len;
1063   char* p;
1064   char* p2;
1065   int l2;
1066   int len;
1067  
1068   switch (uLevel) {
1069   case 0: struct_len = 16; break;
1070   case 1: struct_len = 26; break;
1071   default: return -1;
1072   }  
1073  
1074   if (!buf)
1075     {
1076       len = 0;
1077       switch (uLevel) 
1078         {
1079         case 1:
1080           len = strlen(service->comment)+1;
1081           break;
1082         }
1083
1084       if (buflen) *buflen = struct_len;
1085       if (stringspace) *stringspace = len;
1086       return struct_len + len;
1087     }
1088   
1089   len = struct_len;
1090   p = *buf;
1091   if (*buflen < struct_len) return -1;
1092   if (stringbuf)
1093     {
1094       p2 = *stringbuf;
1095       l2 = *stringspace;
1096     }
1097   else
1098     {
1099       p2 = p + struct_len;
1100       l2 = *buflen - struct_len;
1101     }
1102   if (!baseaddr) baseaddr = p;
1103   
1104   switch (uLevel)
1105     {
1106     case 0:
1107       StrnCpy(p,service->name,15);
1108       break;
1109
1110     case 1:
1111       StrnCpy(p,service->name,15);
1112       SIVAL(p,18,service->type);
1113       SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1114       len += CopyAndAdvance(&p2,service->comment,&l2);
1115       break;
1116     }
1117
1118   if (stringbuf)
1119     {
1120       *buf = p + struct_len;
1121       *buflen -= struct_len;
1122       *stringbuf = p2;
1123       *stringspace = l2;
1124     }
1125   else
1126     {
1127       *buf = p2;
1128       *buflen -= len;
1129     }
1130   return len;
1131 }
1132
1133
1134 static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1135 {
1136   return(strcmp(s1->name,s2->name));
1137 }
1138
1139 /****************************************************************************
1140   view list of servers available (or possibly domains). The info is
1141   extracted from lists saved by nmbd on the local host
1142   ****************************************************************************/
1143 static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param, char *data,
1144                                int mdrcnt, int mprcnt, char **rdata, 
1145                                char **rparam, int *rdata_len, int *rparam_len)
1146 {
1147   char *str1 = param+2;
1148   char *str2 = skip_string(str1,1);
1149   char *p = skip_string(str2,1);
1150   int uLevel = SVAL(p,0);
1151   int buf_len = SVAL(p,2);
1152   uint32 servertype = IVAL(p,4);
1153   char *p2;
1154   int data_len, fixed_len, string_len;
1155   int f_len = 0, s_len = 0;
1156   struct srv_info_struct *servers=NULL;
1157   int counted=0,total=0;
1158   int i,missed;
1159   fstring domain;
1160   BOOL domain_request;
1161   BOOL local_request;
1162
1163   /* If someone sets all the bits they don't really mean to set
1164      DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1165      known servers. */
1166
1167   if (servertype == SV_TYPE_ALL) 
1168     servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1169
1170   /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1171      any other bit (they may just set this bit on it's own) they 
1172      want all the locally seen servers. However this bit can be 
1173      set on its own so set the requested servers to be 
1174      ALL - DOMAIN_ENUM. */
1175
1176   if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) 
1177     servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1178
1179   domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1180   local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1181
1182   p += 8;
1183
1184   if (!prefix_ok(str1,"WrLehD")) return False;
1185   if (!check_server_info(uLevel,str2)) return False;
1186   
1187   DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1188   DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1189   DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1190
1191   if (strcmp(str1, "WrLehDz") == 0) {
1192     StrnCpy(domain, p, sizeof(fstring)-1);
1193   } else {
1194     StrnCpy(domain, global_myworkgroup, sizeof(fstring)-1);    
1195   }
1196
1197   if (lp_browse_list())
1198     total = get_server_info(servertype,&servers,domain);
1199
1200   data_len = fixed_len = string_len = 0;
1201   missed = 0;
1202
1203   qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1204
1205   {
1206     char *lastname=NULL;
1207
1208     for (i=0;i<total;i++)
1209     {
1210       struct srv_info_struct *s = &servers[i];
1211       if (lastname && strequal(lastname,s->name)) continue;
1212       lastname = s->name;
1213       data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1214       DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1215                s->name, s->type, s->comment, s->domain));
1216       
1217       if (data_len <= buf_len) {
1218           counted++;
1219           fixed_len += f_len;
1220           string_len += s_len;
1221       } else {
1222         missed++;
1223       }
1224     }
1225   }
1226
1227   *rdata_len = fixed_len + string_len;
1228   *rdata = REALLOC(*rdata,*rdata_len);
1229   memset(*rdata,'\0',*rdata_len);
1230   
1231   p2 = (*rdata) + fixed_len;    /* auxilliary data (strings) will go here */
1232   p = *rdata;
1233   f_len = fixed_len;
1234   s_len = string_len;
1235
1236   {
1237     char *lastname=NULL;
1238     int count2 = counted;
1239     for (i = 0; i < total && count2;i++)
1240       {
1241         struct srv_info_struct *s = &servers[i];
1242         if (lastname && strequal(lastname,s->name)) continue;
1243         lastname = s->name;
1244         fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1245         DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1246                  s->name, s->type, s->comment, s->domain));
1247         count2--;
1248       }
1249   }
1250   
1251   *rparam_len = 8;
1252   *rparam = REALLOC(*rparam,*rparam_len);
1253   SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1254   SSVAL(*rparam,2,0);
1255   SSVAL(*rparam,4,counted);
1256   SSVAL(*rparam,6,counted+missed);
1257
1258   if (servers) free(servers);
1259
1260   DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1261            domain,uLevel,counted,counted+missed));
1262
1263   return(True);
1264 }
1265
1266 /****************************************************************************
1267   command 0x34 - suspected of being a "Lookup Names" stub api
1268   ****************************************************************************/
1269 static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid, char *param, char *data,
1270                                int mdrcnt, int mprcnt, char **rdata, 
1271                                char **rparam, int *rdata_len, int *rparam_len)
1272 {
1273   char *str1 = param+2;
1274   char *str2 = skip_string(str1,1);
1275   char *p = skip_string(str2,1);
1276   int uLevel = SVAL(p,0);
1277   int buf_len = SVAL(p,2);
1278   int counted=0;
1279   int missed=0;
1280
1281         DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1282                 str1, str2, p, uLevel, buf_len));
1283
1284   if (!prefix_ok(str1,"zWrLeh")) return False;
1285   
1286   *rdata_len = 0;
1287   
1288   *rparam_len = 8;
1289   *rparam = REALLOC(*rparam,*rparam_len);
1290
1291   SSVAL(*rparam,0,0x08AC); /* informational warning message */
1292   SSVAL(*rparam,2,0);
1293   SSVAL(*rparam,4,counted);
1294   SSVAL(*rparam,6,counted+missed);
1295
1296   return(True);
1297 }
1298
1299 /****************************************************************************
1300   get info about a share
1301   ****************************************************************************/
1302 static BOOL check_share_info(int uLevel, char* id)
1303 {
1304   switch( uLevel ) {
1305   case 0:
1306     if (strcmp(id,"B13") != 0) return False;
1307     break;
1308   case 1:
1309     if (strcmp(id,"B13BWz") != 0) return False;
1310     break;
1311   case 2:
1312     if (strcmp(id,"B13BWzWWWzB9B") != 0) return False;
1313     break;
1314   case 91:
1315     if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) return False;
1316     break;
1317   default: return False;
1318   }
1319   return True;
1320 }
1321
1322 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1323                            char** buf, int* buflen,
1324                            char** stringbuf, int* stringspace, char* baseaddr)
1325 {
1326   int struct_len;
1327   char* p;
1328   char* p2;
1329   int l2;
1330   int len;
1331  
1332   switch( uLevel ) {
1333   case 0: struct_len = 13; break;
1334   case 1: struct_len = 20; break;
1335   case 2: struct_len = 40; break;
1336   case 91: struct_len = 68; break;
1337   default: return -1;
1338   }
1339   
1340  
1341   if (!buf)
1342     {
1343       len = 0;
1344       if (uLevel > 0) len += StrlenExpanded(conn,snum,lp_comment(snum));
1345       if (uLevel > 1) len += strlen(lp_pathname(snum)) + 1;
1346       if (buflen) *buflen = struct_len;
1347       if (stringspace) *stringspace = len;
1348       return struct_len + len;
1349     }
1350   
1351   len = struct_len;
1352   p = *buf;
1353   if ((*buflen) < struct_len) return -1;
1354   if (stringbuf)
1355     {
1356       p2 = *stringbuf;
1357       l2 = *stringspace;
1358     }
1359   else
1360     {
1361       p2 = p + struct_len;
1362       l2 = (*buflen) - struct_len;
1363     }
1364   if (!baseaddr) baseaddr = p;
1365   
1366   StrnCpy(p,lp_servicename(snum),13);
1367   
1368   if (uLevel > 0)
1369     {
1370       int type;
1371       CVAL(p,13) = 0;
1372       type = STYPE_DISKTREE;
1373       if (lp_print_ok(snum)) type = STYPE_PRINTQ;
1374       if (strequal("IPC$",lp_servicename(snum))) type = STYPE_IPC;
1375       SSVAL(p,14,type);         /* device type */
1376       SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1377       len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1378     }
1379   
1380   if (uLevel > 1)
1381     {
1382       SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1383       SSVALS(p,22,-1);          /* max uses */
1384       SSVAL(p,24,1); /* current uses */
1385       SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1386       len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1387       memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1388     }
1389   
1390   if (uLevel > 2)
1391     {
1392       memset(p+40,0,SHPWLEN+2);
1393       SSVAL(p,50,0);
1394       SIVAL(p,52,0);
1395       SSVAL(p,56,0);
1396       SSVAL(p,58,0);
1397       SIVAL(p,60,0);
1398       SSVAL(p,64,0);
1399       SSVAL(p,66,0);
1400     }
1401        
1402   if (stringbuf)
1403     {
1404       (*buf) = p + struct_len;
1405       (*buflen) -= struct_len;
1406       (*stringbuf) = p2;
1407       (*stringspace) = l2;
1408     }
1409   else
1410     {
1411       (*buf) = p2;
1412       (*buflen) -= len;
1413     }
1414   return len;
1415 }
1416
1417 static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
1418                                  int mdrcnt,int mprcnt,
1419                                  char **rdata,char **rparam,
1420                                  int *rdata_len,int *rparam_len)
1421 {
1422   char *str1 = param+2;
1423   char *str2 = skip_string(str1,1);
1424   char *netname = skip_string(str2,1);
1425   char *p = skip_string(netname,1);
1426   int uLevel = SVAL(p,0);
1427   int snum = find_service(netname);
1428   
1429   if (snum < 0) return False;
1430   
1431   /* check it's a supported varient */
1432   if (!prefix_ok(str1,"zWrLh")) return False;
1433   if (!check_share_info(uLevel,str2)) return False;
1434  
1435   *rdata = REALLOC(*rdata,mdrcnt);
1436   p = *rdata;
1437   *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1438   if (*rdata_len < 0) return False;
1439  
1440   *rparam_len = 6;
1441   *rparam = REALLOC(*rparam,*rparam_len);
1442   SSVAL(*rparam,0,NERR_Success);
1443   SSVAL(*rparam,2,0);           /* converter word */
1444   SSVAL(*rparam,4,*rdata_len);
1445  
1446   return(True);
1447 }
1448
1449 /****************************************************************************
1450   view list of shares available
1451   ****************************************************************************/
1452 static BOOL api_RNetShareEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
1453                               int mdrcnt,int mprcnt,
1454                               char **rdata,char **rparam,
1455                               int *rdata_len,int *rparam_len)
1456 {
1457   char *str1 = param+2;
1458   char *str2 = skip_string(str1,1);
1459   char *p = skip_string(str2,1);
1460   int uLevel = SVAL(p,0);
1461   int buf_len = SVAL(p,2);
1462   char *p2;
1463   int count=lp_numservices();
1464   int total=0,counted=0;
1465   BOOL missed = False;
1466   int i;
1467   int data_len, fixed_len, string_len;
1468   int f_len = 0, s_len = 0;
1469  
1470   if (!prefix_ok(str1,"WrLeh")) return False;
1471   if (!check_share_info(uLevel,str2)) return False;
1472   
1473   data_len = fixed_len = string_len = 0;
1474   for (i=0;i<count;i++)
1475     if (lp_browseable(i) && lp_snum_ok(i))
1476     {
1477       total++;
1478       data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1479       if (data_len <= buf_len)
1480       {
1481         counted++;
1482         fixed_len += f_len;
1483         string_len += s_len;
1484       }
1485       else
1486         missed = True;
1487     }
1488   *rdata_len = fixed_len + string_len;
1489   *rdata = REALLOC(*rdata,*rdata_len);
1490   memset(*rdata,0,*rdata_len);
1491   
1492   p2 = (*rdata) + fixed_len;    /* auxillery data (strings) will go here */
1493   p = *rdata;
1494   f_len = fixed_len;
1495   s_len = string_len;
1496   for (i = 0; i < count;i++)
1497     if (lp_browseable(i) && lp_snum_ok(i))
1498       if (fill_share_info(conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata) < 0)
1499         break;
1500   
1501   *rparam_len = 8;
1502   *rparam = REALLOC(*rparam,*rparam_len);
1503   SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1504   SSVAL(*rparam,2,0);
1505   SSVAL(*rparam,4,counted);
1506   SSVAL(*rparam,6,total);
1507   
1508   DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1509            counted,total,uLevel,
1510            buf_len,*rdata_len,mdrcnt));
1511   return(True);
1512 }
1513
1514
1515
1516 /****************************************************************************
1517   get the time of day info
1518   ****************************************************************************/
1519 static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid, char *param,char *data,
1520                              int mdrcnt,int mprcnt,
1521                              char **rdata,char **rparam,
1522                              int *rdata_len,int *rparam_len)
1523 {
1524   char *p;
1525   *rparam_len = 4;
1526   *rparam = REALLOC(*rparam,*rparam_len);
1527
1528   *rdata_len = 21;
1529   *rdata = REALLOC(*rdata,*rdata_len);
1530
1531   SSVAL(*rparam,0,NERR_Success);
1532   SSVAL(*rparam,2,0);           /* converter word */
1533
1534   p = *rdata;
1535
1536   {
1537     struct tm *t;
1538     time_t unixdate = time(NULL);
1539
1540     put_dos_date3(p,0,unixdate); /* this is the time that is looked at
1541                                     by NT in a "net time" operation,
1542                                     it seems to ignore the one below */
1543
1544     /* the client expects to get localtime, not GMT, in this bit 
1545        (I think, this needs testing) */
1546     t = LocalTime(&unixdate);
1547
1548     SIVAL(p,4,0);               /* msecs ? */
1549     CVAL(p,8) = t->tm_hour;
1550     CVAL(p,9) = t->tm_min;
1551     CVAL(p,10) = t->tm_sec;
1552     CVAL(p,11) = 0;             /* hundredths of seconds */
1553     SSVALS(p,12,TimeDiff(unixdate)/60); /* timezone in minutes from GMT */
1554     SSVAL(p,14,10000);          /* timer interval in 0.0001 of sec */
1555     CVAL(p,16) = t->tm_mday;
1556     CVAL(p,17) = t->tm_mon + 1;
1557     SSVAL(p,18,1900+t->tm_year);
1558     CVAL(p,20) = t->tm_wday;
1559   }
1560
1561
1562   return(True);
1563 }
1564
1565 /****************************************************************************
1566  Set the user password.
1567 *****************************************************************************/
1568
1569 static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1570                                 int mdrcnt,int mprcnt,
1571                                 char **rdata,char **rparam,
1572                                 int *rdata_len,int *rparam_len)
1573 {
1574   char *p = skip_string(param+2,2);
1575   fstring user;
1576   fstring pass1,pass2;
1577
1578   fstrcpy(user,p);
1579
1580   p = skip_string(p,1);
1581
1582   memset(pass1,'\0',sizeof(pass1));
1583   memset(pass2,'\0',sizeof(pass2));
1584   memcpy(pass1,p,16);
1585   memcpy(pass2,p+16,16);
1586
1587   *rparam_len = 4;
1588   *rparam = REALLOC(*rparam,*rparam_len);
1589
1590   *rdata_len = 0;
1591
1592   SSVAL(*rparam,0,NERR_badpass);
1593   SSVAL(*rparam,2,0);           /* converter word */
1594
1595   DEBUG(3,("Set password for <%s>\n",user));
1596
1597   /*
1598    * Pass the user through the NT -> unix user mapping
1599    * function.
1600    */
1601
1602   (void)map_username(user);
1603
1604   /*
1605    * Do any UNIX username case mangling.
1606    */
1607   (void)Get_Pwnam( user, True);
1608
1609   /*
1610    * Attempt to verify the old password against smbpasswd entries
1611    * Win98 clients send old and new password in plaintext for this call.
1612    */
1613
1614   {
1615     fstring saved_pass2;
1616     struct smb_passwd *smbpw = NULL;
1617
1618     /*
1619      * Save the new password as change_oem_password overwrites it
1620      * with zeros.
1621      */
1622
1623     fstrcpy(saved_pass2, pass2);
1624
1625     if (check_plaintext_password(user,pass1,strlen(pass1),&smbpw) &&
1626         change_oem_password(smbpw,pass2,False))
1627     {
1628       SSVAL(*rparam,0,NERR_Success);
1629
1630       /*
1631        * If unix password sync was requested, attempt to change
1632        * the /etc/passwd database also. Return failure if this cannot
1633        * be done.
1634        */
1635
1636       if(lp_unix_password_sync() && !chgpasswd(user,pass1,saved_pass2,False))
1637         SSVAL(*rparam,0,NERR_badpass);
1638     }
1639   }
1640
1641   /*
1642    * If the above failed, attempt the plaintext password change.
1643    * This tests against the /etc/passwd database only.
1644    */
1645
1646   if(SVAL(*rparam,0) != NERR_Success)
1647   {
1648     if (password_ok(user, pass1,strlen(pass1),NULL) &&
1649         chgpasswd(user,pass1,pass2,False))
1650     {
1651       SSVAL(*rparam,0,NERR_Success);
1652     }
1653   }
1654
1655   /*
1656    * If the plaintext change failed, attempt
1657    * the old encrypted method. NT will generate this
1658    * after trying the samr method. Note that this
1659    * method is done as a last resort as this
1660    * password change method loses the NT password hash
1661    * and cannot change the UNIX password as no plaintext
1662    * is received.
1663    */
1664
1665   if(SVAL(*rparam,0) != NERR_Success)
1666   {
1667     struct smb_passwd *sampw = NULL;
1668
1669     if(check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &sampw) && 
1670        change_lanman_password(sampw,(unsigned char *)pass1,(unsigned char *)pass2))
1671     {
1672       SSVAL(*rparam,0,NERR_Success);
1673     }
1674   }
1675
1676   memset((char *)pass1,'\0',sizeof(fstring));
1677   memset((char *)pass2,'\0',sizeof(fstring));    
1678          
1679   return(True);
1680 }
1681
1682 /****************************************************************************
1683   Set the user password (SamOEM version - gets plaintext).
1684 ****************************************************************************/
1685
1686 static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1687                                 int mdrcnt,int mprcnt,
1688                                 char **rdata,char **rparam,
1689                                 int *rdata_len,int *rparam_len)
1690 {
1691   fstring user;
1692   char *p = param + 2;
1693   *rparam_len = 2;
1694   *rparam = REALLOC(*rparam,*rparam_len);
1695
1696   *rdata_len = 0;
1697
1698   SSVAL(*rparam,0,NERR_badpass);
1699
1700   /*
1701    * Check the parameter definition is correct.
1702    */
1703   if(!strequal(param + 2, "zsT")) {
1704     DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", param + 2));
1705     return False;
1706   }
1707   p = skip_string(p, 1);
1708
1709   if(!strequal(p, "B516B16")) {
1710     DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
1711     return False;
1712   }
1713   p = skip_string(p,1);
1714
1715   fstrcpy(user,p);
1716   p = skip_string(p,1);
1717
1718   DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
1719
1720   /*
1721    * Pass the user through the NT -> unix user mapping
1722    * function.
1723    */
1724
1725   (void)map_username(user);
1726
1727   /*
1728    * Do any UNIX username case mangling.
1729    */
1730   (void)Get_Pwnam( user, True);
1731
1732   if (pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL))
1733   {
1734     SSVAL(*rparam,0,NERR_Success);
1735   }
1736
1737   return(True);
1738 }
1739
1740 /****************************************************************************
1741   delete a print job
1742   Form: <W> <> 
1743   ****************************************************************************/
1744 static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param,char *data,
1745                                 int mdrcnt,int mprcnt,
1746                                 char **rdata,char **rparam,
1747                                 int *rdata_len,int *rparam_len)
1748 {
1749         int function = SVAL(param,0);
1750         char *str1 = param+2;
1751         char *str2 = skip_string(str1,1);
1752         char *p = skip_string(str2,1);
1753         int jobid, errcode;
1754
1755         jobid = SVAL(p,0);
1756
1757         /* check it's a supported varient */
1758         if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
1759                 return(False);
1760
1761         *rparam_len = 4;
1762         *rparam = REALLOC(*rparam,*rparam_len); 
1763         *rdata_len = 0;
1764
1765         if (!print_job_exists(jobid)) {
1766                 errcode = NERR_JobNotFound;
1767                 goto out;
1768         }
1769
1770         errcode = NERR_notsupported;
1771         
1772         switch (function) {
1773         case 81:                /* delete */ 
1774                 if (print_job_delete(jobid)) errcode = NERR_Success;
1775                 break;
1776         case 82:                /* pause */
1777                 if (print_job_pause(jobid)) errcode = NERR_Success;
1778                 break;
1779         case 83:                /* resume */
1780                 if (print_job_resume(jobid)) errcode = NERR_Success;
1781                 break;
1782         }
1783         
1784  out:
1785         SSVAL(*rparam,0,errcode);       
1786         SSVAL(*rparam,2,0);             /* converter word */
1787
1788         return(True);
1789 }
1790
1791 /****************************************************************************
1792   Purge a print queue - or pause or resume it.
1793   ****************************************************************************/
1794 static BOOL api_WPrintQueuePurge(connection_struct *conn,uint16 vuid, char *param,char *data,
1795                                  int mdrcnt,int mprcnt,
1796                                  char **rdata,char **rparam,
1797                                  int *rdata_len,int *rparam_len)
1798 {
1799         int function = SVAL(param,0);
1800         char *str1 = param+2;
1801         char *str2 = skip_string(str1,1);
1802         char *QueueName = skip_string(str2,1);
1803         int errcode = NERR_notsupported;
1804         int snum;
1805
1806         /* check it's a supported varient */
1807         if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
1808                 return(False);
1809
1810         *rparam_len = 4;
1811         *rparam = REALLOC(*rparam,*rparam_len);
1812         *rdata_len = 0;
1813
1814         snum = print_queue_snum(QueueName);
1815
1816         if (snum == -1) {
1817                 errcode = NERR_JobNotFound;
1818                 goto out;
1819         }
1820
1821         switch (function) {
1822         case 74: /* Pause queue */
1823                 if (print_queue_pause(snum)) errcode = NERR_Success;
1824                 break;
1825         case 75: /* Resume queue */
1826                 if (print_queue_resume(snum)) errcode = NERR_Success;
1827                 break;
1828         case 103: /* Purge */
1829                 if (print_queue_purge(snum)) errcode = NERR_Success;
1830                 break;
1831         }
1832
1833  out:
1834         SSVAL(*rparam,0,errcode);
1835         SSVAL(*rparam,2,0);             /* converter word */
1836
1837         return(True);
1838 }
1839
1840
1841 /****************************************************************************
1842   set the property of a print job (undocumented?)
1843   ? function = 0xb -> set name of print job
1844   ? function = 0x6 -> move print job up/down
1845   Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz> 
1846   or   <WWsTP> <WB21BB16B10zWWzDDz> 
1847 ****************************************************************************/
1848 static int check_printjob_info(struct pack_desc* desc,
1849                                int uLevel, char* id)
1850 {
1851         desc->subformat = NULL;
1852         switch( uLevel ) {
1853         case 0: desc->format = "W"; break;
1854         case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
1855         case 2: desc->format = "WWzWWDDzz"; break;
1856         case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
1857         default: return False;
1858         }
1859         if (strcmp(desc->format,id) != 0) return False;
1860         return True;
1861 }
1862
1863 static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,char *data,
1864                              int mdrcnt,int mprcnt,
1865                              char **rdata,char **rparam,
1866                              int *rdata_len,int *rparam_len)
1867 {
1868         struct pack_desc desc;
1869         char *str1 = param+2;
1870         char *str2 = skip_string(str1,1);
1871         char *p = skip_string(str2,1);
1872         int jobid;
1873         int uLevel = SVAL(p,2);
1874         int function = SVAL(p,4);
1875         int place, errcode;
1876
1877         jobid = SVAL(p,0);
1878         *rparam_len = 4;
1879         *rparam = REALLOC(*rparam,*rparam_len);
1880   
1881         *rdata_len = 0;
1882         
1883         /* check it's a supported varient */
1884         if ((strcmp(str1,"WWsTP")) || 
1885             (!check_printjob_info(&desc,uLevel,str2)))
1886                 return(False);
1887
1888         if (!print_job_exists(jobid)) {
1889                 errcode=NERR_JobNotFound;
1890                 goto out;
1891         }
1892
1893         errcode = NERR_notsupported;
1894
1895         switch (function) {
1896         case 0x6:
1897                 /* change job place in the queue, 
1898                    data gives the new place */
1899                 place = SVAL(data,0);
1900                 if (print_job_set_place(jobid, place)) {
1901                         errcode=NERR_Success;
1902                 }
1903                 break;
1904
1905         case 0xb:   
1906                 /* change print job name, data gives the name */
1907                 if (print_job_set_name(jobid, data)) {
1908                         errcode=NERR_Success;
1909                 }
1910                 break;
1911
1912         default:
1913                 return False;
1914         }
1915
1916  out:
1917         SSVALS(*rparam,0,errcode);
1918         SSVAL(*rparam,2,0);             /* converter word */
1919         
1920         return(True);
1921 }
1922
1923
1924 /****************************************************************************
1925   get info about the server
1926   ****************************************************************************/
1927 static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
1928                                   int mdrcnt,int mprcnt,
1929                                   char **rdata,char **rparam,
1930                                   int *rdata_len,int *rparam_len)
1931 {
1932   char *str1 = param+2;
1933   char *str2 = skip_string(str1,1);
1934   char *p = skip_string(str2,1);
1935   int uLevel = SVAL(p,0);
1936   char *p2;
1937   int struct_len;
1938
1939   DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
1940
1941   /* check it's a supported varient */
1942   if (!prefix_ok(str1,"WrLh")) return False;
1943   switch( uLevel ) {
1944   case 0:
1945     if (strcmp(str2,"B16") != 0) return False;
1946     struct_len = 16;
1947     break;
1948   case 1:
1949     if (strcmp(str2,"B16BBDz") != 0) return False;
1950     struct_len = 26;
1951     break;
1952   case 2:
1953     if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")
1954         != 0) return False;
1955     struct_len = 134;
1956     break;
1957   case 3:
1958     if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz")
1959         != 0) return False;
1960     struct_len = 144;
1961     break;
1962   case 20:
1963     if (strcmp(str2,"DN") != 0) return False;
1964     struct_len = 6;
1965     break;
1966   case 50:
1967     if (strcmp(str2,"B16BBDzWWzzz") != 0) return False;
1968     struct_len = 42;
1969     break;
1970   default: return False;
1971   }
1972
1973   *rdata_len = mdrcnt;
1974   *rdata = REALLOC(*rdata,*rdata_len);
1975
1976   p = *rdata;
1977   p2 = p + struct_len;
1978   if (uLevel != 20) {
1979     StrnCpy(p,local_machine,16);
1980     strupper(p);
1981   }
1982   p += 16;
1983   if (uLevel > 0)
1984     {
1985       struct srv_info_struct *servers=NULL;
1986       int i,count;
1987       pstring comment;
1988       uint32 servertype= lp_default_server_announce();
1989
1990       pstrcpy(comment,string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH));
1991
1992       if ((count=get_server_info(SV_TYPE_ALL,&servers,global_myworkgroup))>0) {
1993         for (i=0;i<count;i++)
1994           if (strequal(servers[i].name,local_machine))
1995       {
1996             servertype = servers[i].type;
1997             pstrcpy(comment,servers[i].comment);            
1998           }
1999       }
2000       if (servers) free(servers);
2001
2002       SCVAL(p,0,lp_major_announce_version());
2003       SCVAL(p,1,lp_minor_announce_version());
2004       SIVAL(p,2,servertype);
2005
2006       if (mdrcnt == struct_len) {
2007         SIVAL(p,6,0);
2008       } else {
2009         SIVAL(p,6,PTR_DIFF(p2,*rdata));
2010         standard_sub_conn(conn,comment);
2011         StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2012         p2 = skip_string(p2,1);
2013       }
2014     }
2015   if (uLevel > 1)
2016     {
2017       return False;             /* not yet implemented */
2018     }
2019
2020   *rdata_len = PTR_DIFF(p2,*rdata);
2021
2022   *rparam_len = 6;
2023   *rparam = REALLOC(*rparam,*rparam_len);
2024   SSVAL(*rparam,0,NERR_Success);
2025   SSVAL(*rparam,2,0);           /* converter word */
2026   SSVAL(*rparam,4,*rdata_len);
2027
2028   return(True);
2029 }
2030
2031
2032 /****************************************************************************
2033   get info about the server
2034   ****************************************************************************/
2035 static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2036                                 int mdrcnt,int mprcnt,
2037                                 char **rdata,char **rparam,
2038                                 int *rdata_len,int *rparam_len)
2039 {
2040   char *str1 = param+2;
2041   char *str2 = skip_string(str1,1);
2042   char *p = skip_string(str2,1);
2043   char *p2;
2044   extern pstring sesssetup_user;
2045   int level = SVAL(p,0);
2046
2047   DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2048
2049   *rparam_len = 6;
2050   *rparam = REALLOC(*rparam,*rparam_len);
2051
2052   /* check it's a supported varient */
2053   if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz")))
2054     return(False);
2055
2056   *rdata_len = mdrcnt + 1024;
2057   *rdata = REALLOC(*rdata,*rdata_len);
2058
2059   SSVAL(*rparam,0,NERR_Success);
2060   SSVAL(*rparam,2,0);           /* converter word */
2061
2062   p = *rdata;
2063   p2 = p + 22;
2064
2065
2066   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2067   pstrcpy(p2,local_machine);
2068   strupper(p2);
2069   p2 = skip_string(p2,1);
2070   p += 4;
2071
2072   SIVAL(p,0,PTR_DIFF(p2,*rdata));
2073   pstrcpy(p2,sesssetup_user);
2074   p2 = skip_string(p2,1);
2075   p += 4;
2076
2077   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
2078   pstrcpy(p2,global_myworkgroup);
2079   strupper(p2);
2080   p2 = skip_string(p2,1);
2081   p += 4;
2082
2083   SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
2084   SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
2085   p += 2;
2086
2087   SIVAL(p,0,PTR_DIFF(p2,*rdata));
2088   pstrcpy(p2,global_myworkgroup);       /* don't know.  login domain?? */
2089   p2 = skip_string(p2,1);
2090   p += 4;
2091
2092   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
2093   pstrcpy(p2,"");
2094   p2 = skip_string(p2,1);
2095   p += 4;
2096
2097   *rdata_len = PTR_DIFF(p2,*rdata);
2098
2099   SSVAL(*rparam,4,*rdata_len);
2100
2101   return(True);
2102 }
2103
2104 /****************************************************************************
2105   get info about a user
2106
2107     struct user_info_11 {
2108         char                usri11_name[21];  0-20 
2109         char                usri11_pad;       21 
2110         char                *usri11_comment;  22-25 
2111         char            *usri11_usr_comment;  26-29
2112         unsigned short      usri11_priv;      30-31
2113         unsigned long       usri11_auth_flags; 32-35
2114         long                usri11_password_age; 36-39
2115         char                *usri11_homedir; 40-43
2116         char            *usri11_parms; 44-47
2117         long                usri11_last_logon; 48-51
2118         long                usri11_last_logoff; 52-55
2119         unsigned short      usri11_bad_pw_count; 56-57
2120         unsigned short      usri11_num_logons; 58-59
2121         char                *usri11_logon_server; 60-63
2122         unsigned short      usri11_country_code; 64-65
2123         char            *usri11_workstations; 66-69
2124         unsigned long       usri11_max_storage; 70-73
2125         unsigned short      usri11_units_per_week; 74-75
2126         unsigned char       *usri11_logon_hours; 76-79
2127         unsigned short      usri11_code_page; 80-81
2128     };
2129
2130 where:
2131
2132   usri11_name specifies the user name for which information is retireved
2133
2134   usri11_pad aligns the next data structure element to a word boundary
2135
2136   usri11_comment is a null terminated ASCII comment
2137
2138   usri11_user_comment is a null terminated ASCII comment about the user
2139
2140   usri11_priv specifies the level of the privilege assigned to the user.
2141        The possible values are:
2142
2143 Name             Value  Description
2144 USER_PRIV_GUEST  0      Guest privilege
2145 USER_PRIV_USER   1      User privilege
2146 USER_PRV_ADMIN   2      Administrator privilege
2147
2148   usri11_auth_flags specifies the account operator privileges. The
2149        possible values are:
2150
2151 Name            Value   Description
2152 AF_OP_PRINT     0       Print operator
2153
2154
2155 Leach, Naik                                        [Page 28]\r\f
2156
2157
2158 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
2159
2160
2161 AF_OP_COMM      1       Communications operator
2162 AF_OP_SERVER    2       Server operator
2163 AF_OP_ACCOUNTS  3       Accounts operator
2164
2165
2166   usri11_password_age specifies how many seconds have elapsed since the
2167        password was last changed.
2168
2169   usri11_home_dir points to a null terminated ASCII string that contains
2170        the path name of the user's home directory.
2171
2172   usri11_parms points to a null terminated ASCII string that is set
2173        aside for use by applications.
2174
2175   usri11_last_logon specifies the time when the user last logged on.
2176        This value is stored as the number of seconds elapsed since
2177        00:00:00, January 1, 1970.
2178
2179   usri11_last_logoff specifies the time when the user last logged off.
2180        This value is stored as the number of seconds elapsed since
2181        00:00:00, January 1, 1970. A value of 0 means the last logoff
2182        time is unknown.
2183
2184   usri11_bad_pw_count specifies the number of incorrect passwords
2185        entered since the last successful logon.
2186
2187   usri11_log1_num_logons specifies the number of times this user has
2188        logged on. A value of -1 means the number of logons is unknown.
2189
2190   usri11_logon_server points to a null terminated ASCII string that
2191        contains the name of the server to which logon requests are sent.
2192        A null string indicates logon requests should be sent to the
2193        domain controller.
2194
2195   usri11_country_code specifies the country code for the user's language
2196        of choice.
2197
2198   usri11_workstations points to a null terminated ASCII string that
2199        contains the names of workstations the user may log on from.
2200        There may be up to 8 workstations, with the names separated by
2201        commas. A null strings indicates there are no restrictions.
2202
2203   usri11_max_storage specifies the maximum amount of disk space the user
2204        can occupy. A value of 0xffffffff indicates there are no
2205        restrictions.
2206
2207   usri11_units_per_week specifies the equal number of time units into
2208        which a week is divided. This value must be equal to 168.
2209
2210   usri11_logon_hours points to a 21 byte (168 bits) string that
2211        specifies the time during which the user can log on. Each bit
2212        represents one unique hour in a week. The first bit (bit 0, word
2213        0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
2214
2215
2216
2217 Leach, Naik                                        [Page 29]\r\f
2218
2219
2220 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
2221
2222
2223        Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
2224        are no restrictions.
2225
2226   usri11_code_page specifies the code page for the user's language of
2227        choice
2228
2229 All of the pointers in this data structure need to be treated
2230 specially. The  pointer is a 32 bit pointer. The higher 16 bits need
2231 to be ignored. The converter word returned in the parameters section
2232 needs to be subtracted from the lower 16 bits to calculate an offset
2233 into the return buffer where this ASCII string resides.
2234
2235 There is no auxiliary data in the response.
2236
2237   ****************************************************************************/
2238
2239 #define usri11_name           0 
2240 #define usri11_pad            21
2241 #define usri11_comment        22
2242 #define usri11_usr_comment    26
2243 #define usri11_full_name      30
2244 #define usri11_priv           34
2245 #define usri11_auth_flags     36
2246 #define usri11_password_age   40
2247 #define usri11_homedir        44
2248 #define usri11_parms          48
2249 #define usri11_last_logon     52
2250 #define usri11_last_logoff    56
2251 #define usri11_bad_pw_count   60
2252 #define usri11_num_logons     62
2253 #define usri11_logon_server   64
2254 #define usri11_country_code   68
2255 #define usri11_workstations   70
2256 #define usri11_max_storage    74
2257 #define usri11_units_per_week 78
2258 #define usri11_logon_hours    80
2259 #define usri11_code_page      84
2260 #define usri11_end            86
2261
2262 #define USER_PRIV_GUEST 0
2263 #define USER_PRIV_USER 1
2264 #define USER_PRIV_ADMIN 2
2265
2266 #define AF_OP_PRINT     0 
2267 #define AF_OP_COMM      1
2268 #define AF_OP_SERVER    2
2269 #define AF_OP_ACCOUNTS  3
2270
2271
2272 static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2273                                 int mdrcnt,int mprcnt,
2274                                 char **rdata,char **rparam,
2275                                 int *rdata_len,int *rparam_len)
2276 {
2277         char *str1 = param+2;
2278         char *str2 = skip_string(str1,1);
2279         char *UserName = skip_string(str2,1);
2280         char *p = skip_string(UserName,1);
2281         int uLevel = SVAL(p,0);
2282         char *p2;
2283
2284     /* get NIS home of a previously validated user - simeon */
2285     /* With share level security vuid will always be zero.
2286        Don't depend on vuser being non-null !!. JRA */
2287     user_struct *vuser = get_valid_user_struct(vuid);
2288     if(vuser != NULL)
2289       DEBUG(3,("  Username of UID %d is %s\n", (int)vuser->uid, 
2290                vuser->user.unix_name));
2291
2292     *rparam_len = 6;
2293     *rparam = REALLOC(*rparam,*rparam_len);
2294
2295     DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
2296   
2297         /* check it's a supported variant */
2298         if (strcmp(str1,"zWrLh") != 0) return False;
2299         switch( uLevel )
2300         {
2301                 case 0: p2 = "B21"; break;
2302                 case 1: p2 = "B21BB16DWzzWz"; break;
2303                 case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
2304                 case 10: p2 = "B21Bzzz"; break;
2305                 case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
2306                 default: return False;
2307         }
2308
2309         if (strcmp(p2,str2) != 0) return False;
2310
2311         *rdata_len = mdrcnt + 1024;
2312         *rdata = REALLOC(*rdata,*rdata_len);
2313
2314         SSVAL(*rparam,0,NERR_Success);
2315         SSVAL(*rparam,2,0);             /* converter word */
2316
2317         p = *rdata;
2318         p2 = p + usri11_end;
2319
2320         memset(p,0,21); 
2321         fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
2322
2323         if (uLevel > 0)
2324         {
2325                 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
2326                 *p2 = 0;
2327         }
2328         if (uLevel >= 10)
2329         {
2330                 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
2331                 pstrcpy(p2,"Comment");
2332                 p2 = skip_string(p2,1);
2333
2334                 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
2335                 pstrcpy(p2,"UserComment");
2336                 p2 = skip_string(p2,1);
2337
2338                 /* EEK! the cifsrap.txt doesn't have this in!!!! */
2339                 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
2340                 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2341                 p2 = skip_string(p2,1);
2342         }
2343
2344         if (uLevel == 11) /* modelled after NTAS 3.51 reply */
2345         {         
2346                 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); 
2347                 SIVAL(p,usri11_auth_flags,AF_OP_PRINT);         /* auth flags */
2348                 SIVALS(p,usri11_password_age,-1);               /* password age */
2349                 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
2350                 pstrcpy(p2, lp_logon_home());
2351                 p2 = skip_string(p2,1);
2352                 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
2353                 pstrcpy(p2,"");
2354                 p2 = skip_string(p2,1);
2355                 SIVAL(p,usri11_last_logon,0);           /* last logon */
2356                 SIVAL(p,usri11_last_logoff,0);          /* last logoff */
2357                 SSVALS(p,usri11_bad_pw_count,-1);       /* bad pw counts */
2358                 SSVALS(p,usri11_num_logons,-1);         /* num logons */
2359                 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
2360                 pstrcpy(p2,"\\\\*");
2361                 p2 = skip_string(p2,1);
2362                 SSVAL(p,usri11_country_code,0);         /* country code */
2363
2364                 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
2365                 pstrcpy(p2,"");
2366                 p2 = skip_string(p2,1);
2367
2368                 SIVALS(p,usri11_max_storage,-1);                /* max storage */
2369                 SSVAL(p,usri11_units_per_week,168);             /* units per week */
2370                 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
2371
2372                 /* a simple way to get logon hours at all times. */
2373                 memset(p2,0xff,21);
2374                 SCVAL(p2,21,0);           /* fix zero termination */
2375                 p2 = skip_string(p2,1);
2376
2377                 SSVAL(p,usri11_code_page,0);            /* code page */
2378         }
2379         if (uLevel == 1 || uLevel == 2)
2380         {
2381                 memset(p+22,' ',16);    /* password */
2382                 SIVALS(p,38,-1);                /* password age */
2383                 SSVAL(p,42,
2384                 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2385                 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
2386                 pstrcpy(p2,lp_logon_home());
2387                 p2 = skip_string(p2,1);
2388                 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
2389                 *p2++ = 0;
2390                 SSVAL(p,52,0);          /* flags */
2391                 SIVAL(p,54,PTR_DIFF(p2,*rdata));                /* script_path */
2392                 pstrcpy(p2,lp_logon_script());
2393                 standard_sub_conn( conn, p2 );             
2394                 p2 = skip_string(p2,1);
2395                 if (uLevel == 2)
2396                 {
2397                         SIVAL(p,60,0);          /* auth_flags */
2398                         SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
2399                         pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2400                         p2 = skip_string(p2,1);
2401                         SIVAL(p,68,0);          /* urs_comment */
2402                         SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
2403                         pstrcpy(p2,"");
2404                         p2 = skip_string(p2,1);
2405                         SIVAL(p,76,0);          /* workstations */
2406                         SIVAL(p,80,0);          /* last_logon */
2407                         SIVAL(p,84,0);          /* last_logoff */
2408                         SIVALS(p,88,-1);                /* acct_expires */
2409                         SIVALS(p,92,-1);                /* max_storage */
2410                         SSVAL(p,96,168);        /* units_per_week */
2411                         SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
2412                         memset(p2,-1,21);
2413                         p2 += 21;
2414                         SSVALS(p,102,-1);       /* bad_pw_count */
2415                         SSVALS(p,104,-1);       /* num_logons */
2416                         SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
2417                         pstrcpy(p2,"\\\\%L");
2418                         standard_sub_conn(conn, p2);
2419                         p2 = skip_string(p2,1);
2420                         SSVAL(p,110,49);        /* country_code */
2421                         SSVAL(p,112,860);       /* code page */
2422                 }
2423         }
2424
2425         *rdata_len = PTR_DIFF(p2,*rdata);
2426
2427         SSVAL(*rparam,4,*rdata_len);    /* is this right?? */
2428
2429         return(True);
2430 }
2431
2432 /*******************************************************************
2433   get groups that a user is a member of
2434   ******************************************************************/
2435 static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *param,char *data,
2436                                  int mdrcnt,int mprcnt,
2437                                  char **rdata,char **rparam,
2438                                  int *rdata_len,int *rparam_len)
2439 {
2440   char *str1 = param+2;
2441   char *str2 = skip_string(str1,1);
2442   char *UserName = skip_string(str2,1);
2443   char *p = skip_string(UserName,1);
2444   int uLevel = SVAL(p,0);
2445   char *p2;
2446   int count=0;
2447
2448   *rparam_len = 8;
2449   *rparam = REALLOC(*rparam,*rparam_len);
2450
2451   /* check it's a supported varient */
2452   if (strcmp(str1,"zWrLeh") != 0) return False;
2453   switch( uLevel ) {
2454   case 0: p2 = "B21"; break;
2455   default: return False;
2456   }
2457   if (strcmp(p2,str2) != 0) return False;
2458
2459   *rdata_len = mdrcnt + 1024;
2460   *rdata = REALLOC(*rdata,*rdata_len);
2461
2462   SSVAL(*rparam,0,NERR_Success);
2463   SSVAL(*rparam,2,0);           /* converter word */
2464
2465   p = *rdata;
2466
2467   /* XXXX we need a real SAM database some day */
2468   pstrcpy(p,"Users"); p += 21; count++;
2469   pstrcpy(p,"Domain Users"); p += 21; count++;
2470   pstrcpy(p,"Guests"); p += 21; count++;
2471   pstrcpy(p,"Domain Guests"); p += 21; count++;
2472
2473   *rdata_len = PTR_DIFF(p,*rdata);
2474
2475   SSVAL(*rparam,4,count);       /* is this right?? */
2476   SSVAL(*rparam,6,count);       /* is this right?? */
2477
2478   return(True);
2479 }
2480
2481
2482 static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param,char *data,
2483                                 int mdrcnt,int mprcnt,
2484                                 char **rdata,char **rparam,
2485                                 int *rdata_len,int *rparam_len)
2486 {
2487   char *str1 = param+2;
2488   char *str2 = skip_string(str1,1);
2489   char *p = skip_string(str2,1);
2490   int uLevel;
2491   struct pack_desc desc;
2492   char* name;
2493
2494   uLevel = SVAL(p,0);
2495   name = p + 2;
2496
2497   memset((char *)&desc,'\0',sizeof(desc));
2498
2499   DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
2500
2501   /* check it's a supported varient */
2502   if (strcmp(str1,"OOWb54WrLh") != 0) return False;
2503   if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) return False;
2504   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2505   desc.base = *rdata;
2506   desc.buflen = mdrcnt;
2507   desc.subformat = NULL;
2508   desc.format = str2;
2509   
2510   if (init_package(&desc,1,0))
2511   {
2512     PACKI(&desc,"W",0);         /* code */
2513     PACKS(&desc,"B21",name);    /* eff. name */
2514     PACKS(&desc,"B","");                /* pad */
2515     PACKI(&desc,"W",
2516           conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2517     PACKI(&desc,"D",0);         /* auth flags XXX */
2518     PACKI(&desc,"W",0);         /* num logons */
2519     PACKI(&desc,"W",0);         /* bad pw count */
2520     PACKI(&desc,"D",0);         /* last logon */
2521     PACKI(&desc,"D",-1);                /* last logoff */
2522     PACKI(&desc,"D",-1);                /* logoff time */
2523     PACKI(&desc,"D",-1);                /* kickoff time */
2524     PACKI(&desc,"D",0);         /* password age */
2525     PACKI(&desc,"D",0);         /* password can change */
2526     PACKI(&desc,"D",-1);                /* password must change */
2527     {
2528       fstring mypath;
2529       fstrcpy(mypath,"\\\\");
2530       fstrcat(mypath,local_machine);
2531       strupper(mypath);
2532       PACKS(&desc,"z",mypath); /* computer */
2533     }
2534     PACKS(&desc,"z",global_myworkgroup);/* domain */
2535
2536 /* JHT - By calling lp_logon_script() and standard_sub() we have */
2537 /* made sure all macros are fully substituted and available */
2538     {
2539       pstring logon_script;
2540       pstrcpy(logon_script,lp_logon_script());
2541       standard_sub_conn( conn, logon_script );
2542       PACKS(&desc,"z", logon_script);           /* script path */
2543     }
2544 /* End of JHT mods */
2545
2546     PACKI(&desc,"D",0x00000000);                /* reserved */
2547   }
2548
2549   *rdata_len = desc.usedlen;
2550   *rparam_len = 6;
2551   *rparam = REALLOC(*rparam,*rparam_len);
2552   SSVALS(*rparam,0,desc.errcode);
2553   SSVAL(*rparam,2,0);
2554   SSVAL(*rparam,4,desc.neededlen);
2555
2556   DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
2557   return(True);
2558 }
2559
2560
2561 /****************************************************************************
2562   api_WAccessGetUserPerms
2563   ****************************************************************************/
2564 static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid, char *param,char *data,
2565                                     int mdrcnt,int mprcnt,
2566                                     char **rdata,char **rparam,
2567                                     int *rdata_len,int *rparam_len)
2568 {
2569   char *str1 = param+2;
2570   char *str2 = skip_string(str1,1);
2571   char *user = skip_string(str2,1);
2572   char *resource = skip_string(user,1);
2573
2574   DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
2575
2576   /* check it's a supported varient */
2577   if (strcmp(str1,"zzh") != 0) return False;
2578   if (strcmp(str2,"") != 0) return False;
2579
2580   *rparam_len = 6;
2581   *rparam = REALLOC(*rparam,*rparam_len);
2582   SSVALS(*rparam,0,0);          /* errorcode */
2583   SSVAL(*rparam,2,0);           /* converter word */
2584   SSVAL(*rparam,4,0x7f);        /* permission flags */
2585
2586   return(True);
2587 }
2588
2589 /****************************************************************************
2590   api_WPrintJobEnumerate
2591   ****************************************************************************/
2592 static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2593                                  int mdrcnt,int mprcnt,
2594                                  char **rdata,char **rparam,
2595                                  int *rdata_len,int *rparam_len)
2596 {
2597   char *str1 = param+2;
2598   char *str2 = skip_string(str1,1);
2599   char *p = skip_string(str2,1);
2600   int uLevel;
2601   int count;
2602   int i;
2603   int snum;
2604   int job;
2605   struct pack_desc desc;
2606   print_queue_struct *queue=NULL;
2607   print_status_struct status;
2608
2609   uLevel = SVAL(p,2);
2610
2611   memset((char *)&desc,'\0',sizeof(desc));
2612   memset((char *)&status,'\0',sizeof(status));
2613
2614   DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
2615
2616   /* check it's a supported varient */
2617   if (strcmp(str1,"WWrLh") != 0) return False;
2618   if (!check_printjob_info(&desc,uLevel,str2)) return False;
2619
2620   job = SVAL(p,0);
2621   snum = print_job_snum(job);
2622
2623   if (snum < 0 || !VALID_SNUM(snum)) return(False);
2624
2625   count = print_queue_status(snum,&queue,&status);
2626   for (i = 0; i < count; i++) {
2627     if (queue[i].job == job) break;
2628   }
2629   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2630   desc.base = *rdata;
2631   desc.buflen = mdrcnt;
2632
2633   if (init_package(&desc,1,0)) {
2634     if (i < count) {
2635       fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2636       *rdata_len = desc.usedlen;
2637     }
2638     else {
2639       desc.errcode = NERR_JobNotFound;
2640       *rdata_len = 0;
2641     }
2642   }
2643
2644   *rparam_len = 6;
2645   *rparam = REALLOC(*rparam,*rparam_len);
2646   SSVALS(*rparam,0,desc.errcode);
2647   SSVAL(*rparam,2,0);
2648   SSVAL(*rparam,4,desc.neededlen);
2649
2650   if (queue) free(queue);
2651
2652   DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
2653   return(True);
2654 }
2655
2656 static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *param,char *data,
2657                                    int mdrcnt,int mprcnt,
2658                                    char **rdata,char **rparam,
2659                                    int *rdata_len,int *rparam_len)
2660 {
2661   char *str1 = param+2;
2662   char *str2 = skip_string(str1,1);
2663   char *p = skip_string(str2,1);
2664   char* name = p;
2665   int uLevel;
2666   int count;
2667   int i, succnt=0;
2668   int snum;
2669   struct pack_desc desc;
2670   print_queue_struct *queue=NULL;
2671   print_status_struct status;
2672
2673   memset((char *)&desc,'\0',sizeof(desc));
2674   memset((char *)&status,'\0',sizeof(status));
2675
2676   p = skip_string(p,1);
2677   uLevel = SVAL(p,0);
2678
2679   DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
2680
2681   /* check it's a supported varient */
2682   if (strcmp(str1,"zWrLeh") != 0) return False;
2683   if (uLevel > 2) return False; /* defined only for uLevel 0,1,2 */
2684   if (!check_printjob_info(&desc,uLevel,str2)) return False;
2685
2686   snum = lp_servicenumber(name);
2687   if (snum < 0 && pcap_printername_ok(name,NULL)) {
2688     int pnum = lp_servicenumber(PRINTERS_NAME);
2689     if (pnum >= 0) {
2690       lp_add_printer(name,pnum);
2691       snum = lp_servicenumber(name);
2692     }
2693   }
2694
2695   if (snum < 0 || !VALID_SNUM(snum)) return(False);
2696
2697   count = print_queue_status(snum,&queue,&status);
2698   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2699   desc.base = *rdata;
2700   desc.buflen = mdrcnt;
2701
2702   if (init_package(&desc,count,0)) {
2703     succnt = 0;
2704     for (i = 0; i < count; i++) {
2705       fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2706       if (desc.errcode == NERR_Success) succnt = i+1;
2707     }
2708   }
2709
2710   *rdata_len = desc.usedlen;
2711
2712   *rparam_len = 8;
2713   *rparam = REALLOC(*rparam,*rparam_len);
2714   SSVALS(*rparam,0,desc.errcode);
2715   SSVAL(*rparam,2,0);
2716   SSVAL(*rparam,4,succnt);
2717   SSVAL(*rparam,6,count);
2718
2719   if (queue) free(queue);
2720
2721   DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
2722   return(True);
2723 }
2724
2725 static int check_printdest_info(struct pack_desc* desc,
2726                                 int uLevel, char* id)
2727 {
2728   desc->subformat = NULL;
2729   switch( uLevel ) {
2730   case 0: desc->format = "B9"; break;
2731   case 1: desc->format = "B9B21WWzW"; break;
2732   case 2: desc->format = "z"; break;
2733   case 3: desc->format = "zzzWWzzzWW"; break;
2734   default: return False;
2735   }
2736   if (strcmp(desc->format,id) != 0) return False;
2737   return True;
2738 }
2739
2740 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
2741                                 struct pack_desc* desc)
2742 {
2743   char buf[100];
2744   strncpy(buf,SERVICE(snum),sizeof(buf)-1);
2745   buf[sizeof(buf)-1] = 0;
2746   strupper(buf);
2747   if (uLevel <= 1) {
2748     PACKS(desc,"B9",buf);       /* szName */
2749     if (uLevel == 1) {
2750       PACKS(desc,"B21","");     /* szUserName */
2751       PACKI(desc,"W",0);                /* uJobId */
2752       PACKI(desc,"W",0);                /* fsStatus */
2753       PACKS(desc,"z","");       /* pszStatus */
2754       PACKI(desc,"W",0);                /* time */
2755     }
2756   }
2757   if (uLevel == 2 || uLevel == 3) {
2758     PACKS(desc,"z",buf);                /* pszPrinterName */
2759     if (uLevel == 3) {
2760       PACKS(desc,"z","");       /* pszUserName */
2761       PACKS(desc,"z","");       /* pszLogAddr */
2762       PACKI(desc,"W",0);                /* uJobId */
2763       PACKI(desc,"W",0);                /* fsStatus */
2764       PACKS(desc,"z","");       /* pszStatus */
2765       PACKS(desc,"z","");       /* pszComment */
2766       PACKS(desc,"z","NULL"); /* pszDrivers */
2767       PACKI(desc,"W",0);                /* time */
2768       PACKI(desc,"W",0);                /* pad1 */
2769     }
2770   }
2771 }
2772
2773 static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2774                                   int mdrcnt,int mprcnt,
2775                                   char **rdata,char **rparam,
2776                                   int *rdata_len,int *rparam_len)
2777 {
2778   char *str1 = param+2;
2779   char *str2 = skip_string(str1,1);
2780   char *p = skip_string(str2,1);
2781   char* PrinterName = p;
2782   int uLevel;
2783   struct pack_desc desc;
2784   int snum;
2785
2786   memset((char *)&desc,'\0',sizeof(desc));
2787
2788   p = skip_string(p,1);
2789   uLevel = SVAL(p,0);
2790
2791   DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
2792
2793   /* check it's a supported varient */
2794   if (strcmp(str1,"zWrLh") != 0) return False;
2795   if (!check_printdest_info(&desc,uLevel,str2)) return False;
2796
2797   snum = lp_servicenumber(PrinterName);
2798   if (snum < 0 && pcap_printername_ok(PrinterName,NULL)) {
2799     int pnum = lp_servicenumber(PRINTERS_NAME);
2800     if (pnum >= 0) {
2801       lp_add_printer(PrinterName,pnum);
2802       snum = lp_servicenumber(PrinterName);
2803     }
2804   }
2805
2806   if (snum < 0) {
2807     *rdata_len = 0;
2808     desc.errcode = NERR_DestNotFound;
2809     desc.neededlen = 0;
2810   }
2811   else {
2812     if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2813     desc.base = *rdata;
2814     desc.buflen = mdrcnt;
2815     if (init_package(&desc,1,0)) {
2816       fill_printdest_info(conn,snum,uLevel,&desc);
2817     }
2818     *rdata_len = desc.usedlen;
2819   }
2820
2821   *rparam_len = 6;
2822   *rparam = REALLOC(*rparam,*rparam_len);
2823   SSVALS(*rparam,0,desc.errcode);
2824   SSVAL(*rparam,2,0);
2825   SSVAL(*rparam,4,desc.neededlen);
2826
2827   DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
2828   return(True);
2829 }
2830
2831 static BOOL api_WPrintDestEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
2832                                int mdrcnt,int mprcnt,
2833                                char **rdata,char **rparam,
2834                                int *rdata_len,int *rparam_len)
2835 {
2836   char *str1 = param+2;
2837   char *str2 = skip_string(str1,1);
2838   char *p = skip_string(str2,1);
2839   int uLevel;
2840   int queuecnt;
2841   int i, n, succnt=0;
2842   struct pack_desc desc;
2843   int services = lp_numservices();
2844
2845   memset((char *)&desc,'\0',sizeof(desc));
2846
2847   uLevel = SVAL(p,0);
2848
2849   DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
2850
2851   /* check it's a supported varient */
2852   if (strcmp(str1,"WrLeh") != 0) return False;
2853   if (!check_printdest_info(&desc,uLevel,str2)) return False;
2854
2855   queuecnt = 0;
2856   for (i = 0; i < services; i++)
2857     if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
2858       queuecnt++;
2859
2860   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2861   desc.base = *rdata;
2862   desc.buflen = mdrcnt;
2863   if (init_package(&desc,queuecnt,0)) {    
2864     succnt = 0;
2865     n = 0;
2866     for (i = 0; i < services; i++) {
2867       if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
2868         fill_printdest_info(conn,i,uLevel,&desc);
2869         n++;
2870         if (desc.errcode == NERR_Success) succnt = n;
2871       }
2872     }
2873   }
2874
2875   *rdata_len = desc.usedlen;
2876
2877   *rparam_len = 8;
2878   *rparam = REALLOC(*rparam,*rparam_len);
2879   SSVALS(*rparam,0,desc.errcode);
2880   SSVAL(*rparam,2,0);
2881   SSVAL(*rparam,4,succnt);
2882   SSVAL(*rparam,6,queuecnt);
2883
2884   DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
2885   return(True);
2886 }
2887
2888 static BOOL api_WPrintDriverEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
2889                                  int mdrcnt,int mprcnt,
2890                                  char **rdata,char **rparam,
2891                                  int *rdata_len,int *rparam_len)
2892 {
2893   char *str1 = param+2;
2894   char *str2 = skip_string(str1,1);
2895   char *p = skip_string(str2,1);
2896   int uLevel;
2897   int succnt;
2898   struct pack_desc desc;
2899
2900   memset((char *)&desc,'\0',sizeof(desc));
2901
2902   uLevel = SVAL(p,0);
2903
2904   DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
2905
2906   /* check it's a supported varient */
2907   if (strcmp(str1,"WrLeh") != 0) return False;
2908   if (uLevel != 0 || strcmp(str2,"B41") != 0) return False;
2909
2910   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2911   desc.base = *rdata;
2912   desc.buflen = mdrcnt;
2913   if (init_package(&desc,1,0)) {
2914     PACKS(&desc,"B41","NULL");
2915   }
2916
2917   succnt = (desc.errcode == NERR_Success ? 1 : 0);
2918
2919   *rdata_len = desc.usedlen;
2920
2921   *rparam_len = 8;
2922   *rparam = REALLOC(*rparam,*rparam_len);
2923   SSVALS(*rparam,0,desc.errcode);
2924   SSVAL(*rparam,2,0);
2925   SSVAL(*rparam,4,succnt);
2926   SSVAL(*rparam,6,1);
2927
2928   DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
2929   return(True);
2930 }
2931
2932 static BOOL api_WPrintQProcEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
2933                                 int mdrcnt,int mprcnt,
2934                                 char **rdata,char **rparam,
2935                                 int *rdata_len,int *rparam_len)
2936 {
2937   char *str1 = param+2;
2938   char *str2 = skip_string(str1,1);
2939   char *p = skip_string(str2,1);
2940   int uLevel;
2941   int succnt;
2942   struct pack_desc desc;
2943
2944   memset((char *)&desc,'\0',sizeof(desc));
2945
2946   uLevel = SVAL(p,0);
2947
2948   DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
2949
2950   /* check it's a supported varient */
2951   if (strcmp(str1,"WrLeh") != 0) return False;
2952   if (uLevel != 0 || strcmp(str2,"B13") != 0) return False;
2953
2954   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2955   desc.base = *rdata;
2956   desc.buflen = mdrcnt;
2957   desc.format = str2;
2958   if (init_package(&desc,1,0)) {
2959     PACKS(&desc,"B13","lpd");
2960   }
2961
2962   succnt = (desc.errcode == NERR_Success ? 1 : 0);
2963
2964   *rdata_len = desc.usedlen;
2965
2966   *rparam_len = 8;
2967   *rparam = REALLOC(*rparam,*rparam_len);
2968   SSVALS(*rparam,0,desc.errcode);
2969   SSVAL(*rparam,2,0);
2970   SSVAL(*rparam,4,succnt);
2971   SSVAL(*rparam,6,1);
2972
2973   DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
2974   return(True);
2975 }
2976
2977 static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
2978                                int mdrcnt,int mprcnt,
2979                                char **rdata,char **rparam,
2980                                int *rdata_len,int *rparam_len)
2981 {
2982   char *str1 = param+2;
2983   char *str2 = skip_string(str1,1);
2984   char *p = skip_string(str2,1);
2985   int uLevel;
2986   int succnt;
2987   struct pack_desc desc;
2988
2989   memset((char *)&desc,'\0',sizeof(desc));
2990
2991   uLevel = SVAL(p,0);
2992
2993   DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
2994
2995   /* check it's a supported varient */
2996   if (strcmp(str1,"WrLeh") != 0) return False;
2997   if (uLevel != 0 || strcmp(str2,"B9") != 0) return False;
2998
2999   if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3000   memset((char *)&desc,'\0',sizeof(desc));
3001   desc.base = *rdata;
3002   desc.buflen = mdrcnt;
3003   desc.format = str2;
3004   if (init_package(&desc,1,0)) {
3005     PACKS(&desc,"B13","lp0");
3006   }
3007
3008   succnt = (desc.errcode == NERR_Success ? 1 : 0);
3009
3010   *rdata_len = desc.usedlen;
3011
3012   *rparam_len = 8;
3013   *rparam = REALLOC(*rparam,*rparam_len);
3014   SSVALS(*rparam,0,desc.errcode);
3015   SSVAL(*rparam,2,0);
3016   SSVAL(*rparam,4,succnt);
3017   SSVAL(*rparam,6,1);
3018
3019   DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
3020   return(True);
3021 }
3022
3023 /****************************************************************************
3024  The buffer was too small
3025  ****************************************************************************/
3026
3027 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
3028                          int mdrcnt,int mprcnt,
3029                          char **rdata,char **rparam,
3030                          int *rdata_len,int *rparam_len)
3031 {
3032   *rparam_len = MIN(*rparam_len,mprcnt);
3033   *rparam = REALLOC(*rparam,*rparam_len);
3034
3035   *rdata_len = 0;
3036
3037   SSVAL(*rparam,0,NERR_BufTooSmall);
3038
3039   DEBUG(3,("Supplied buffer too small in API command\n"));
3040
3041   return(True);
3042 }
3043
3044
3045 /****************************************************************************
3046  The request is not supported
3047  ****************************************************************************/
3048
3049 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
3050                             int mdrcnt,int mprcnt,
3051                             char **rdata,char **rparam,
3052                             int *rdata_len,int *rparam_len)
3053 {
3054   *rparam_len = 4;
3055   *rparam = REALLOC(*rparam,*rparam_len);
3056
3057   *rdata_len = 0;
3058
3059   SSVAL(*rparam,0,NERR_notsupported);
3060   SSVAL(*rparam,2,0);           /* converter word */
3061
3062   DEBUG(3,("Unsupported API command\n"));
3063
3064   return(True);
3065 }
3066
3067
3068
3069
3070 struct
3071 {
3072   char *name;
3073   int id;
3074   BOOL (*fn)(connection_struct *,uint16,char *,char *,
3075              int,int,char **,char **,int *,int *);
3076   int flags;
3077 } api_commands[] = {
3078   {"RNetShareEnum",     0,      api_RNetShareEnum,0},
3079   {"RNetShareGetInfo",  1,      api_RNetShareGetInfo,0},
3080   {"RNetServerGetInfo", 13,     api_RNetServerGetInfo,0},
3081   {"RNetGroupGetUsers", 52,     api_RNetGroupGetUsers,0},
3082   {"RNetUserGetInfo",   56,     api_RNetUserGetInfo,0},
3083   {"NetUserGetGroups",  59,     api_NetUserGetGroups,0},
3084   {"NetWkstaGetInfo",   63,     api_NetWkstaGetInfo,0},
3085   {"DosPrintQEnum",     69,     api_DosPrintQEnum,0},
3086   {"DosPrintQGetInfo",  70,     api_DosPrintQGetInfo,0},
3087   {"WPrintQueuePause",  74, api_WPrintQueuePurge,0},
3088   {"WPrintQueueResume", 75, api_WPrintQueuePurge,0},
3089   {"WPrintJobEnumerate",76,     api_WPrintJobEnumerate,0},
3090   {"WPrintJobGetInfo",  77,     api_WPrintJobGetInfo,0},
3091   {"RDosPrintJobDel",   81,     api_RDosPrintJobDel,0},
3092   {"RDosPrintJobPause", 82,     api_RDosPrintJobDel,0},
3093   {"RDosPrintJobResume",83,     api_RDosPrintJobDel,0},
3094   {"WPrintDestEnum",    84,     api_WPrintDestEnum,0},
3095   {"WPrintDestGetInfo", 85,     api_WPrintDestGetInfo,0},
3096   {"NetRemoteTOD",      91,     api_NetRemoteTOD,0},
3097   {"WPrintQueuePurge",  103,    api_WPrintQueuePurge,0},
3098   {"NetServerEnum",     104,    api_RNetServerEnum,0},
3099   {"WAccessGetUserPerms",105,   api_WAccessGetUserPerms,0},
3100   {"SetUserPassword",   115,    api_SetUserPassword,0},
3101   {"WWkstaUserLogon",   132,    api_WWkstaUserLogon,0},
3102   {"PrintJobInfo",      147,    api_PrintJobInfo,0},
3103   {"WPrintDriverEnum",  205,    api_WPrintDriverEnum,0},
3104   {"WPrintQProcEnum",   206,    api_WPrintQProcEnum,0},
3105   {"WPrintPortEnum",    207,    api_WPrintPortEnum,0},
3106   {"SamOEMChangePassword", 214, api_SamOEMChangePassword,0},
3107   {NULL,                -1,     api_Unsupported,0}};
3108
3109
3110 /****************************************************************************
3111  Handle remote api calls
3112  ****************************************************************************/
3113
3114 int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *params,
3115                      int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
3116 {
3117   int api_command;
3118   char *rdata = NULL;
3119   char *rparam = NULL;
3120   int rdata_len = 0;
3121   int rparam_len = 0;
3122   BOOL reply=False;
3123   int i;
3124
3125   if (!params) {
3126           DEBUG(0,("ERROR: NULL params in api_reply()\n"));
3127           return 0;
3128   }
3129
3130   api_command = SVAL(params,0);
3131
3132   DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
3133            api_command,
3134            params+2,
3135            skip_string(params+2,1),
3136            tdscnt,tpscnt,mdrcnt,mprcnt));
3137
3138   for (i=0;api_commands[i].name;i++) {
3139     if (api_commands[i].id == api_command && api_commands[i].fn) {
3140         DEBUG(3,("Doing %s\n",api_commands[i].name));
3141         break;
3142     }
3143   }
3144
3145   rdata = (char *)malloc(1024);
3146   if (rdata)
3147     memset(rdata,'\0',1024);
3148
3149   rparam = (char *)malloc(1024);
3150   if (rparam)
3151     memset(rparam,'\0',1024);
3152
3153   if(!rdata || !rparam) {
3154     DEBUG(0,("api_reply: malloc fail !\n"));
3155     return -1;
3156   }
3157
3158   reply = api_commands[i].fn(conn,vuid,params,data,mdrcnt,mprcnt,
3159                              &rdata,&rparam,&rdata_len,&rparam_len);
3160
3161
3162   if (rdata_len > mdrcnt ||
3163       rparam_len > mprcnt) {
3164       reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
3165                            &rdata,&rparam,&rdata_len,&rparam_len);
3166   }
3167
3168   /* if we get False back then it's actually unsupported */
3169   if (!reply)
3170     api_Unsupported(conn,vuid,params,data,mdrcnt,mprcnt,
3171                     &rdata,&rparam,&rdata_len,&rparam_len);
3172
3173   send_trans_reply(outbuf, rparam, rparam_len, rdata, rdata_len, False);
3174
3175   if (rdata )
3176     free(rdata);
3177   if (rparam)
3178     free(rparam);
3179   
3180   return -1;
3181 }
3182
3183
3184 #undef OLD_NTDOMAIN