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