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