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