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