ca6cc57cc3e9ff1ac171761f4c2f07de6d7b36f9
[metze/samba/wip.git] / source3 / 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, 0);
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
1054         local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1055
1056         DEBUG(4,("Servertype search: %8x\n",servertype));
1057
1058         for (i=0;lines[i];i++) {
1059                 fstring stype;
1060                 struct srv_info_struct *s;
1061                 const char *ptr = lines[i];
1062                 BOOL ok = True;
1063
1064                 if (!*ptr) {
1065                         continue;
1066                 }
1067     
1068                 if (count == alloced) {
1069                         struct srv_info_struct *ts;
1070       
1071                         alloced += 10;
1072                         ts = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1073                         if (!ts) {
1074                                 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1075                                 return 0;
1076                         } else {
1077                                 *servers = ts;
1078                         }
1079                         memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1080                 }
1081                 s = &(*servers)[count];
1082     
1083                 if (!next_token(&ptr,s->name, NULL, sizeof(s->name))) {
1084                         continue;
1085                 }
1086                 if (!next_token(&ptr,stype, NULL, sizeof(stype))) {
1087                         continue;
1088                 }
1089                 if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) {
1090                         continue;
1091                 }
1092                 if (!next_token(&ptr,s->domain, NULL, sizeof(s->domain))) {
1093                         /* this allows us to cope with an old nmbd */
1094                         fstrcpy(s->domain,lp_workgroup()); 
1095                 }
1096     
1097                 if (sscanf(stype,"%X",&s->type) != 1) { 
1098                         DEBUG(4,("r:host file ")); 
1099                         ok = False; 
1100                 }
1101     
1102                 /* Filter the servers/domains we return based on what was asked for. */
1103
1104                 /* Check to see if we are being asked for a local list only. */
1105                 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1106                         DEBUG(4,("r: local list only"));
1107                         ok = False;
1108                 }
1109
1110                 /* doesn't match up: don't want it */
1111                 if (!(servertype & s->type)) { 
1112                         DEBUG(4,("r:serv type ")); 
1113                         ok = False; 
1114                 }
1115     
1116                 if ((servertype & SV_TYPE_DOMAIN_ENUM) != 
1117                                 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1118                         DEBUG(4,("s: dom mismatch "));
1119                         ok = False;
1120                 }
1121     
1122                 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1123                         ok = False;
1124                 }
1125     
1126                 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1127                 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1128
1129                 if (ok) {
1130                         DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1131                                 s->name, s->type, s->comment, s->domain));
1132                         s->server_added = True;
1133                         count++;
1134                 } else {
1135                         DEBUG(4,("%20s %8x %25s %15s\n",
1136                                 s->name, s->type, s->comment, s->domain));
1137                 }
1138         }
1139   
1140         file_lines_free(lines);
1141         return count;
1142 }
1143
1144 /*******************************************************************
1145  Fill in a server info structure.
1146 ******************************************************************/
1147
1148 static int fill_srv_info(struct srv_info_struct *service, 
1149                          int uLevel, char **buf, int *buflen, 
1150                          char **stringbuf, int *stringspace, char *baseaddr)
1151 {
1152         int struct_len;
1153         char* p;
1154         char* p2;
1155         int l2;
1156         int len;
1157  
1158         switch (uLevel) {
1159                 case 0:
1160                         struct_len = 16;
1161                         break;
1162                 case 1:
1163                         struct_len = 26;
1164                         break;
1165                 default:
1166                         return -1;
1167         }
1168  
1169         if (!buf) {
1170                 len = 0;
1171                 switch (uLevel) {
1172                         case 1:
1173                                 len = strlen(service->comment)+1;
1174                                 break;
1175                 }
1176
1177                 if (buflen) {
1178                         *buflen = struct_len;
1179                 }
1180                 if (stringspace) {
1181                         *stringspace = len;
1182                 }
1183                 return struct_len + len;
1184         }
1185   
1186         len = struct_len;
1187         p = *buf;
1188         if (*buflen < struct_len) {
1189                 return -1;
1190         }
1191         if (stringbuf) {
1192                 p2 = *stringbuf;
1193                 l2 = *stringspace;
1194         } else {
1195                 p2 = p + struct_len;
1196                 l2 = *buflen - struct_len;
1197         }
1198         if (!baseaddr) {
1199                 baseaddr = p;
1200         }
1201   
1202         switch (uLevel) {
1203                 case 0:
1204                         push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1205                         break;
1206
1207                 case 1:
1208                         push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1209                         SIVAL(p,18,service->type);
1210                         SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1211                         len += CopyAndAdvance(&p2,service->comment,&l2);
1212                         break;
1213         }
1214
1215         if (stringbuf) {
1216                 *buf = p + struct_len;
1217                 *buflen -= struct_len;
1218                 *stringbuf = p2;
1219                 *stringspace = l2;
1220         } else {
1221                 *buf = p2;
1222                 *buflen -= len;
1223         }
1224         return len;
1225 }
1226
1227
1228 static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1229 {
1230         return(strcmp(s1->name,s2->name));
1231 }
1232
1233 /****************************************************************************
1234  View list of servers available (or possibly domains). The info is
1235  extracted from lists saved by nmbd on the local host.
1236 ****************************************************************************/
1237
1238 static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param, char *data,
1239                                int mdrcnt, int mprcnt, char **rdata, 
1240                                char **rparam, int *rdata_len, int *rparam_len)
1241 {
1242         char *str1 = param+2;
1243         char *str2 = skip_string(str1,1);
1244         char *p = skip_string(str2,1);
1245         int uLevel = SVAL(p,0);
1246         int buf_len = SVAL(p,2);
1247         uint32 servertype = IVAL(p,4);
1248         char *p2;
1249         int data_len, fixed_len, string_len;
1250         int f_len = 0, s_len = 0;
1251         struct srv_info_struct *servers=NULL;
1252         int counted=0,total=0;
1253         int i,missed;
1254         fstring domain;
1255         BOOL domain_request;
1256         BOOL local_request;
1257
1258         /* If someone sets all the bits they don't really mean to set
1259            DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1260            known servers. */
1261
1262         if (servertype == SV_TYPE_ALL) {
1263                 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1264         }
1265
1266         /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1267            any other bit (they may just set this bit on it's own) they 
1268            want all the locally seen servers. However this bit can be 
1269            set on its own so set the requested servers to be 
1270            ALL - DOMAIN_ENUM. */
1271
1272         if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1273                 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1274         }
1275
1276         domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1277         local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1278
1279         p += 8;
1280
1281         if (!prefix_ok(str1,"WrLehD")) {
1282                 return False;
1283         }
1284         if (!check_server_info(uLevel,str2)) {
1285                 return False;
1286         }
1287   
1288         DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1289         DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1290         DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1291
1292         if (strcmp(str1, "WrLehDz") == 0) {
1293                 pull_ascii_fstring(domain, p);
1294         } else {
1295                 fstrcpy(domain, lp_workgroup());
1296         }
1297
1298         if (lp_browse_list()) {
1299                 total = get_server_info(servertype,&servers,domain);
1300         }
1301
1302         data_len = fixed_len = string_len = 0;
1303         missed = 0;
1304
1305         if (total > 0) {
1306                 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1307         }
1308
1309         {
1310                 char *lastname=NULL;
1311
1312                 for (i=0;i<total;i++) {
1313                         struct srv_info_struct *s = &servers[i];
1314
1315                         if (lastname && strequal(lastname,s->name)) {
1316                                 continue;
1317                         }
1318                         lastname = s->name;
1319                         data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1320                         DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1321                                 s->name, s->type, s->comment, s->domain));
1322       
1323                         if (data_len <= buf_len) {
1324                                 counted++;
1325                                 fixed_len += f_len;
1326                                 string_len += s_len;
1327                         } else {
1328                                 missed++;
1329                         }
1330                 }
1331         }
1332
1333         *rdata_len = fixed_len + string_len;
1334         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1335         memset(*rdata,'\0',*rdata_len);
1336   
1337         p2 = (*rdata) + fixed_len;      /* auxilliary data (strings) will go here */
1338         p = *rdata;
1339         f_len = fixed_len;
1340         s_len = string_len;
1341
1342         {
1343                 char *lastname=NULL;
1344                 int count2 = counted;
1345
1346                 for (i = 0; i < total && count2;i++) {
1347                         struct srv_info_struct *s = &servers[i];
1348
1349                         if (lastname && strequal(lastname,s->name)) {
1350                                 continue;
1351                         }
1352                         lastname = s->name;
1353                         fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1354                         DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1355                                 s->name, s->type, s->comment, s->domain));
1356                         count2--;
1357                 }
1358         }
1359   
1360         *rparam_len = 8;
1361         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1362         SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1363         SSVAL(*rparam,2,0);
1364         SSVAL(*rparam,4,counted);
1365         SSVAL(*rparam,6,counted+missed);
1366
1367         SAFE_FREE(servers);
1368
1369         DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1370                 domain,uLevel,counted,counted+missed));
1371
1372         return True;
1373 }
1374
1375 /****************************************************************************
1376   command 0x34 - suspected of being a "Lookup Names" stub api
1377   ****************************************************************************/
1378
1379 static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid, char *param, char *data,
1380                                int mdrcnt, int mprcnt, char **rdata, 
1381                                char **rparam, int *rdata_len, int *rparam_len)
1382 {
1383         char *str1 = param+2;
1384         char *str2 = skip_string(str1,1);
1385         char *p = skip_string(str2,1);
1386         int uLevel = SVAL(p,0);
1387         int buf_len = SVAL(p,2);
1388         int counted=0;
1389         int missed=0;
1390
1391         DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1392                 str1, str2, p, uLevel, buf_len));
1393
1394         if (!prefix_ok(str1,"zWrLeh")) {
1395                 return False;
1396         }
1397   
1398         *rdata_len = 0;
1399   
1400         *rparam_len = 8;
1401         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1402
1403         SSVAL(*rparam,0,0x08AC); /* informational warning message */
1404         SSVAL(*rparam,2,0);
1405         SSVAL(*rparam,4,counted);
1406         SSVAL(*rparam,6,counted+missed);
1407
1408         return True;
1409 }
1410
1411 /****************************************************************************
1412   get info about a share
1413   ****************************************************************************/
1414
1415 static BOOL check_share_info(int uLevel, char* id)
1416 {
1417         switch( uLevel ) {
1418                 case 0:
1419                         if (strcmp(id,"B13") != 0) {
1420                                 return False;
1421                         }
1422                         break;
1423                 case 1:
1424                         if (strcmp(id,"B13BWz") != 0) {
1425                                 return False;
1426                         }
1427                         break;
1428                 case 2:
1429                         if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1430                                 return False;
1431                         }
1432                         break;
1433                 case 91:
1434                         if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1435                                 return False;
1436                         }
1437                         break;
1438                 default:
1439                         return False;
1440         }
1441         return True;
1442 }
1443
1444 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1445                            char** buf, int* buflen,
1446                            char** stringbuf, int* stringspace, char* baseaddr)
1447 {
1448         int struct_len;
1449         char* p;
1450         char* p2;
1451         int l2;
1452         int len;
1453  
1454         switch( uLevel ) {
1455                 case 0:
1456                         struct_len = 13;
1457                         break;
1458                 case 1:
1459                         struct_len = 20;
1460                         break;
1461                 case 2:
1462                         struct_len = 40;
1463                         break;
1464                 case 91:
1465                         struct_len = 68;
1466                         break;
1467                 default:
1468                         return -1;
1469         }
1470   
1471  
1472         if (!buf) {
1473                 len = 0;
1474
1475                 if (uLevel > 0) {
1476                         len += StrlenExpanded(conn,snum,lp_comment(snum));
1477                 }
1478                 if (uLevel > 1) {
1479                         len += strlen(lp_pathname(snum)) + 1;
1480                 }
1481                 if (buflen) {
1482                         *buflen = struct_len;
1483                 }
1484                 if (stringspace) {
1485                         *stringspace = len;
1486                 }
1487                 return struct_len + len;
1488         }
1489   
1490         len = struct_len;
1491         p = *buf;
1492         if ((*buflen) < struct_len) {
1493                 return -1;
1494         }
1495
1496         if (stringbuf) {
1497                 p2 = *stringbuf;
1498                 l2 = *stringspace;
1499         } else {
1500                 p2 = p + struct_len;
1501                 l2 = (*buflen) - struct_len;
1502         }
1503
1504         if (!baseaddr) {
1505                 baseaddr = p;
1506         }
1507   
1508         push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1509   
1510         if (uLevel > 0) {
1511                 int type;
1512
1513                 SCVAL(p,13,0);
1514                 type = STYPE_DISKTREE;
1515                 if (lp_print_ok(snum)) {
1516                         type = STYPE_PRINTQ;
1517                 }
1518                 if (strequal("IPC",lp_fstype(snum))) {
1519                         type = STYPE_IPC;
1520                 }
1521                 SSVAL(p,14,type);               /* device type */
1522                 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1523                 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1524         }
1525   
1526         if (uLevel > 1) {
1527                 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1528                 SSVALS(p,22,-1);                /* max uses */
1529                 SSVAL(p,24,1); /* current uses */
1530                 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1531                 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1532                 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1533         }
1534   
1535         if (uLevel > 2) {
1536                 memset(p+40,0,SHPWLEN+2);
1537                 SSVAL(p,50,0);
1538                 SIVAL(p,52,0);
1539                 SSVAL(p,56,0);
1540                 SSVAL(p,58,0);
1541                 SIVAL(p,60,0);
1542                 SSVAL(p,64,0);
1543                 SSVAL(p,66,0);
1544         }
1545        
1546         if (stringbuf) {
1547                 (*buf) = p + struct_len;
1548                 (*buflen) -= struct_len;
1549                 (*stringbuf) = p2;
1550                 (*stringspace) = l2;
1551         } else {
1552                 (*buf) = p2;
1553                 (*buflen) -= len;
1554         }
1555
1556         return len;
1557 }
1558
1559 static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
1560                                  int mdrcnt,int mprcnt,
1561                                  char **rdata,char **rparam,
1562                                  int *rdata_len,int *rparam_len)
1563 {
1564         char *str1 = param+2;
1565         char *str2 = skip_string(str1,1);
1566         char *netname = skip_string(str2,1);
1567         char *p = skip_string(netname,1);
1568         int uLevel = SVAL(p,0);
1569         int snum = find_service(netname);
1570   
1571         if (snum < 0) {
1572                 return False;
1573         }
1574   
1575         /* check it's a supported varient */
1576         if (!prefix_ok(str1,"zWrLh")) {
1577                 return False;
1578         }
1579         if (!check_share_info(uLevel,str2)) {
1580                 return False;
1581         }
1582  
1583         *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
1584         p = *rdata;
1585         *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1586         if (*rdata_len < 0) {
1587                 return False;
1588         }
1589  
1590         *rparam_len = 6;
1591         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1592         SSVAL(*rparam,0,NERR_Success);
1593         SSVAL(*rparam,2,0);             /* converter word */
1594         SSVAL(*rparam,4,*rdata_len);
1595  
1596         return True;
1597 }
1598
1599 /****************************************************************************
1600   View the list of available shares.
1601
1602   This function is the server side of the NetShareEnum() RAP call.
1603   It fills the return buffer with share names and share comments.
1604   Note that the return buffer normally (in all known cases) allows only
1605   twelve byte strings for share names (plus one for a nul terminator).
1606   Share names longer than 12 bytes must be skipped.
1607  ****************************************************************************/
1608
1609 static BOOL api_RNetShareEnum( connection_struct *conn,
1610                                uint16             vuid,
1611                                char              *param,
1612                                char              *data,
1613                                int                mdrcnt,
1614                                int                mprcnt,
1615                                char             **rdata,
1616                                char             **rparam,
1617                                int               *rdata_len,
1618                                int               *rparam_len )
1619 {
1620         char *str1 = param+2;
1621         char *str2 = skip_string(str1,1);
1622         char *p = skip_string(str2,1);
1623         int uLevel = SVAL(p,0);
1624         int buf_len = SVAL(p,2);
1625         char *p2;
1626         int count = 0;
1627         int total=0,counted=0;
1628         BOOL missed = False;
1629         int i;
1630         int data_len, fixed_len, string_len;
1631         int f_len = 0, s_len = 0;
1632  
1633         if (!prefix_ok(str1,"WrLeh")) {
1634                 return False;
1635         }
1636         if (!check_share_info(uLevel,str2)) {
1637                 return False;
1638         }
1639   
1640         /* Ensure all the usershares are loaded. */
1641         become_root();
1642         count = load_usershare_shares();
1643         unbecome_root();
1644
1645         data_len = fixed_len = string_len = 0;
1646         for (i=0;i<count;i++) {
1647                 fstring servicename_dos;
1648                 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1649                         continue;
1650                 }
1651                 push_ascii_fstring(servicename_dos, lp_servicename(i));
1652                 /* Maximum name length = 13. */
1653                 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
1654                         total++;
1655                         data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1656                         if (data_len <= buf_len) {
1657                                 counted++;
1658                                 fixed_len += f_len;
1659                                 string_len += s_len;
1660                         } else {
1661                                 missed = True;
1662                         }
1663                 }
1664         }
1665
1666         *rdata_len = fixed_len + string_len;
1667         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1668         memset(*rdata,0,*rdata_len);
1669   
1670         p2 = (*rdata) + fixed_len;      /* auxiliary data (strings) will go here */
1671         p = *rdata;
1672         f_len = fixed_len;
1673         s_len = string_len;
1674
1675         for( i = 0; i < count; i++ ) {
1676                 fstring servicename_dos;
1677                 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1678                         continue;
1679                 }
1680
1681                 push_ascii_fstring(servicename_dos, lp_servicename(i));
1682                 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
1683                         if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
1684                                 break;
1685                         }
1686                 }
1687         }
1688   
1689         *rparam_len = 8;
1690         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1691         SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1692         SSVAL(*rparam,2,0);
1693         SSVAL(*rparam,4,counted);
1694         SSVAL(*rparam,6,total);
1695   
1696         DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1697                 counted,total,uLevel,
1698                 buf_len,*rdata_len,mdrcnt));
1699
1700         return True;
1701 }
1702
1703 /****************************************************************************
1704   Add a share
1705   ****************************************************************************/
1706
1707 static BOOL api_RNetShareAdd(connection_struct *conn,uint16 vuid, char *param,char *data,
1708                                  int mdrcnt,int mprcnt,
1709                                  char **rdata,char **rparam,
1710                                  int *rdata_len,int *rparam_len)
1711 {
1712         char *str1 = param+2;
1713         char *str2 = skip_string(str1,1);
1714         char *p = skip_string(str2,1);
1715         int uLevel = SVAL(p,0);
1716         fstring sharename;
1717         fstring comment;
1718         pstring pathname;
1719         char *command, *cmdname;
1720         unsigned int offset;
1721         int snum;
1722         int res = ERRunsup;
1723   
1724         /* check it's a supported varient */
1725         if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
1726                 return False;
1727         }
1728         if (!check_share_info(uLevel,str2)) {
1729                 return False;
1730         }
1731         if (uLevel != 2) {
1732                 return False;
1733         }
1734
1735         pull_ascii_fstring(sharename,data);
1736         snum = find_service(sharename);
1737         if (snum >= 0) { /* already exists */
1738                 res = ERRfilexists;
1739                 goto error_exit;
1740         }
1741
1742         /* only support disk share adds */
1743         if (SVAL(data,14)!=STYPE_DISKTREE) {
1744                 return False;
1745         }
1746
1747         offset = IVAL(data, 16);
1748         if (offset >= mdrcnt) {
1749                 res = ERRinvalidparam;
1750                 goto error_exit;
1751         }
1752
1753         pull_ascii_fstring(comment, offset? (data+offset) : "");
1754
1755         offset = IVAL(data, 26);
1756
1757         if (offset >= mdrcnt) {
1758                 res = ERRinvalidparam;
1759                 goto error_exit;
1760         }
1761
1762         pull_ascii_pstring(pathname, offset? (data+offset) : "");
1763
1764         string_replace(sharename, '"', ' ');
1765         string_replace(pathname, '"', ' ');
1766         string_replace(comment, '"', ' ');
1767
1768         cmdname = lp_add_share_cmd();
1769
1770         if (!cmdname || *cmdname == '\0') {
1771                 return False;
1772         }
1773
1774         asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
1775                 lp_add_share_cmd(), dyn_CONFIGFILE, sharename, pathname, comment);
1776
1777         if (command) {
1778                 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
1779
1780                 if ((res = smbrun(command, NULL)) != 0) {
1781                         DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n", command, res ));
1782                         SAFE_FREE(command);
1783                         res = ERRnoaccess;
1784                         goto error_exit;
1785                 } else {
1786                         SAFE_FREE(command);
1787                         message_send_all(conn_tdb_ctx(), MSG_SMB_CONF_UPDATED, NULL, 0, False, NULL);
1788                 }
1789         } else {
1790                 return False;
1791         }
1792
1793         *rparam_len = 6;
1794         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1795         SSVAL(*rparam,0,NERR_Success);
1796         SSVAL(*rparam,2,0);             /* converter word */
1797         SSVAL(*rparam,4,*rdata_len);
1798         *rdata_len = 0;
1799   
1800         return True;
1801
1802   error_exit:
1803
1804         *rparam_len = 4;
1805         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1806         *rdata_len = 0;
1807         SSVAL(*rparam,0,res);
1808         SSVAL(*rparam,2,0);
1809         return True;
1810 }
1811
1812 /****************************************************************************
1813   view list of groups available
1814   ****************************************************************************/
1815
1816 static BOOL api_RNetGroupEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
1817                               int mdrcnt,int mprcnt,
1818                               char **rdata,char **rparam,
1819                               int *rdata_len,int *rparam_len)
1820 {
1821         int i;
1822         int errflags=0;
1823         int resume_context, cli_buf_size;
1824         char *str1 = param+2;
1825         char *str2 = skip_string(str1,1);
1826         char *p = skip_string(str2,1);
1827
1828         struct pdb_search *search;
1829         struct samr_displayentry *entries;
1830
1831         int num_entries;
1832  
1833         if (strcmp(str1,"WrLeh") != 0) {
1834                 return False;
1835         }
1836
1837         /* parameters  
1838          * W-> resume context (number of users to skip)
1839          * r -> return parameter pointer to receive buffer 
1840          * L -> length of receive buffer
1841          * e -> return parameter number of entries
1842          * h -> return parameter total number of users
1843          */
1844
1845         if (strcmp("B21",str2) != 0) {
1846                 return False;
1847         }
1848
1849         /* get list of domain groups SID_DOMAIN_GRP=2 */
1850         become_root();
1851         search = pdb_search_groups();
1852         unbecome_root();
1853
1854         if (search == NULL) {
1855                 DEBUG(3,("api_RNetGroupEnum:failed to get group list"));
1856                 return False;
1857         }
1858
1859         resume_context = SVAL(p,0); 
1860         cli_buf_size=SVAL(p+2,0);
1861         DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
1862                   "%d\n", resume_context, cli_buf_size));
1863
1864         become_root();
1865         num_entries = pdb_search_entries(search, resume_context, 0xffffffff,
1866                                          &entries);
1867         unbecome_root();
1868
1869         *rdata_len = cli_buf_size;
1870         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1871
1872         p = *rdata;
1873
1874         for(i=0; i<num_entries; i++) {
1875                 fstring name;
1876                 fstrcpy(name, entries[i].account_name);
1877                 if( ((PTR_DIFF(p,*rdata)+21) <= *rdata_len) ) {
1878                         /* truncate the name at 21 chars. */
1879                         memcpy(p, name, 21); 
1880                         DEBUG(10,("adding entry %d group %s\n", i, p));
1881                         p += 21;
1882                         p += 5; /* Both NT4 and W2k3SP1 do padding here.
1883                                    No idea why... */
1884                 } else {
1885                         /* set overflow error */
1886                         DEBUG(3,("overflow on entry %d group %s\n", i, name));
1887                         errflags=234;
1888                         break;
1889                 }
1890         }
1891
1892         pdb_search_destroy(search);
1893
1894         *rdata_len = PTR_DIFF(p,*rdata);
1895
1896         *rparam_len = 8;
1897         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1898
1899         SSVAL(*rparam, 0, errflags);
1900         SSVAL(*rparam, 2, 0);           /* converter word */
1901         SSVAL(*rparam, 4, i);   /* is this right?? */
1902         SSVAL(*rparam, 6, resume_context+num_entries);  /* is this right?? */
1903
1904         return(True);
1905 }
1906
1907 /*******************************************************************
1908  Get groups that a user is a member of.
1909 ******************************************************************/
1910
1911 static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *param,char *data,
1912                               int mdrcnt,int mprcnt,
1913                               char **rdata,char **rparam,
1914                               int *rdata_len,int *rparam_len)
1915 {
1916         char *str1 = param+2;
1917         char *str2 = skip_string(str1,1);
1918         char *UserName = skip_string(str2,1);
1919         char *p = skip_string(UserName,1);
1920         int uLevel = SVAL(p,0);
1921         const char *level_string;
1922         int count=0;
1923         struct samu *sampw = NULL;
1924         BOOL ret = False;
1925         DOM_SID *sids;
1926         gid_t *gids;
1927         size_t num_groups;
1928         size_t i;
1929         NTSTATUS result;
1930         DOM_SID user_sid;
1931         enum SID_NAME_USE type;
1932         TALLOC_CTX *mem_ctx;
1933
1934         *rparam_len = 8;
1935         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1936   
1937         /* check it's a supported varient */
1938         
1939         if ( strcmp(str1,"zWrLeh") != 0 )
1940                 return False;
1941                 
1942         switch( uLevel ) {
1943                 case 0:
1944                         level_string = "B21";
1945                         break;
1946                 default:
1947                         return False;
1948         }
1949
1950         if (strcmp(level_string,str2) != 0)
1951                 return False;
1952
1953         *rdata_len = mdrcnt + 1024;
1954         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1955
1956         SSVAL(*rparam,0,NERR_Success);
1957         SSVAL(*rparam,2,0);             /* converter word */
1958
1959         p = *rdata;
1960
1961         mem_ctx = talloc_new(NULL);
1962         if (mem_ctx == NULL) {
1963                 DEBUG(0, ("talloc_new failed\n"));
1964                 return False;
1965         }
1966
1967         /* Lookup the user information; This should only be one of 
1968            our accounts (not remote domains) */
1969
1970         become_root();                                  /* ROOT BLOCK */
1971
1972         if (!lookup_name(mem_ctx, UserName, LOOKUP_NAME_ALL,
1973                          NULL, NULL, &user_sid, &type)) {
1974                 DEBUG(10, ("lookup_name(%s) failed\n", UserName));
1975                 goto done;
1976         }
1977
1978         if (type != SID_NAME_USER) {
1979                 DEBUG(10, ("%s is a %s, not a user\n", UserName,
1980                            sid_type_lookup(type)));
1981                 goto done;
1982         }
1983
1984         if ( !(sampw = samu_new(mem_ctx)) ) {
1985                 DEBUG(0, ("samu_new() failed!\n"));
1986                 goto done;
1987         }
1988
1989         if ( !pdb_getsampwsid(sampw, &user_sid) ) {
1990                 DEBUG(10, ("pdb_getsampwsid(%s) failed for user %s\n",
1991                            sid_string_static(&user_sid), UserName));
1992                 goto done;
1993         }
1994
1995         gids = NULL;
1996         sids = NULL;
1997         num_groups = 0;
1998
1999         result = pdb_enum_group_memberships(mem_ctx, sampw,
2000                                             &sids, &gids, &num_groups);
2001
2002         if (!NT_STATUS_IS_OK(result)) {
2003                 DEBUG(10, ("pdb_enum_group_memberships failed for %s\n",
2004                            UserName));
2005                 goto done;
2006         }
2007
2008         for (i=0; i<num_groups; i++) {
2009
2010                 const char *grp_name;
2011         
2012                 if ( lookup_sid(mem_ctx, &sids[i], NULL, &grp_name, NULL) ) {
2013                         pstrcpy(p, grp_name);
2014                         p += 21; 
2015                         count++;
2016                 }
2017         }
2018
2019         *rdata_len = PTR_DIFF(p,*rdata);
2020
2021         SSVAL(*rparam,4,count); /* is this right?? */
2022         SSVAL(*rparam,6,count); /* is this right?? */
2023
2024         ret = True;
2025
2026 done:
2027         unbecome_root();                                /* END ROOT BLOCK */
2028
2029         TALLOC_FREE(mem_ctx);
2030
2031         return ret;
2032 }
2033
2034 /*******************************************************************
2035  Get all users.
2036 ******************************************************************/
2037
2038 static BOOL api_RNetUserEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
2039                                  int mdrcnt,int mprcnt,
2040                                  char **rdata,char **rparam,
2041                                  int *rdata_len,int *rparam_len)
2042 {
2043         int count_sent=0;
2044         int num_users=0;
2045         int errflags=0;
2046         int i, resume_context, cli_buf_size;
2047         struct pdb_search *search;
2048         struct samr_displayentry *users;
2049
2050         char *str1 = param+2;
2051         char *str2 = skip_string(str1,1);
2052         char *p = skip_string(str2,1);
2053
2054         if (strcmp(str1,"WrLeh") != 0)
2055                 return False;
2056         /* parameters
2057           * W-> resume context (number of users to skip)
2058           * r -> return parameter pointer to receive buffer
2059           * L -> length of receive buffer
2060           * e -> return parameter number of entries
2061           * h -> return parameter total number of users
2062           */
2063   
2064         resume_context = SVAL(p,0);
2065         cli_buf_size=SVAL(p+2,0);
2066         DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2067                         resume_context, cli_buf_size));
2068
2069         *rparam_len = 8;
2070         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2071
2072         /* check it's a supported varient */
2073         if (strcmp("B21",str2) != 0)
2074                 return False;
2075
2076         *rdata_len = cli_buf_size;
2077         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2078
2079         p = *rdata;
2080
2081         become_root();
2082         search = pdb_search_users(ACB_NORMAL);
2083         unbecome_root();
2084         if (search == NULL) {
2085                 DEBUG(0, ("api_RNetUserEnum:unable to open sam database.\n"));
2086                 return False;
2087         }
2088
2089         become_root();
2090         num_users = pdb_search_entries(search, resume_context, 0xffffffff,
2091                                        &users);
2092         unbecome_root();
2093
2094         errflags=NERR_Success;
2095
2096         for (i=0; i<num_users; i++) {
2097                 const char *name = users[i].account_name;
2098                 
2099                 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)&&(strlen(name)<=21)) {
2100                         pstrcpy(p,name); 
2101                         DEBUG(10,("api_RNetUserEnum:adding entry %d username "
2102                                   "%s\n",count_sent,p));
2103                         p += 21; 
2104                         count_sent++; 
2105                 } else {
2106                         /* set overflow error */
2107                         DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2108                                   "username %s\n",count_sent,name));
2109                         errflags=234;
2110                         break;
2111                 }
2112         }
2113
2114         pdb_search_destroy(search);
2115
2116         *rdata_len = PTR_DIFF(p,*rdata);
2117
2118         SSVAL(*rparam,0,errflags);
2119         SSVAL(*rparam,2,0);           /* converter word */
2120         SSVAL(*rparam,4,count_sent);  /* is this right?? */
2121         SSVAL(*rparam,6,num_users); /* is this right?? */
2122
2123         return True;
2124 }
2125
2126 /****************************************************************************
2127  Get the time of day info.
2128 ****************************************************************************/
2129
2130 static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid, char *param,char *data,
2131                              int mdrcnt,int mprcnt,
2132                              char **rdata,char **rparam,
2133                              int *rdata_len,int *rparam_len)
2134 {
2135         struct tm *t;
2136         time_t unixdate = time(NULL);
2137         char *p;
2138
2139         *rparam_len = 4;
2140         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2141
2142         *rdata_len = 21;
2143         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2144
2145         SSVAL(*rparam,0,NERR_Success);
2146         SSVAL(*rparam,2,0);             /* converter word */
2147
2148         p = *rdata;
2149
2150         srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2151                                             by NT in a "net time" operation,
2152                                             it seems to ignore the one below */
2153
2154         /* the client expects to get localtime, not GMT, in this bit 
2155                 (I think, this needs testing) */
2156         t = localtime(&unixdate);
2157
2158         SIVAL(p,4,0);           /* msecs ? */
2159         SCVAL(p,8,t->tm_hour);
2160         SCVAL(p,9,t->tm_min);
2161         SCVAL(p,10,t->tm_sec);
2162         SCVAL(p,11,0);          /* hundredths of seconds */
2163         SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2164         SSVAL(p,14,10000);              /* timer interval in 0.0001 of sec */
2165         SCVAL(p,16,t->tm_mday);
2166         SCVAL(p,17,t->tm_mon + 1);
2167         SSVAL(p,18,1900+t->tm_year);
2168         SCVAL(p,20,t->tm_wday);
2169
2170         return True;
2171 }
2172
2173 /****************************************************************************
2174  Set the user password.
2175 *****************************************************************************/
2176
2177 static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param,char *data,
2178                                 int mdrcnt,int mprcnt,
2179                                 char **rdata,char **rparam,
2180                                 int *rdata_len,int *rparam_len)
2181 {
2182         char *p = skip_string(param+2,2);
2183         fstring user;
2184         fstring pass1,pass2;
2185
2186         pull_ascii_fstring(user,p);
2187
2188         p = skip_string(p,1);
2189
2190         memset(pass1,'\0',sizeof(pass1));
2191         memset(pass2,'\0',sizeof(pass2));
2192         memcpy(pass1,p,16);
2193         memcpy(pass2,p+16,16);
2194
2195         *rparam_len = 4;
2196         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2197
2198         *rdata_len = 0;
2199
2200         SSVAL(*rparam,0,NERR_badpass);
2201         SSVAL(*rparam,2,0);             /* converter word */
2202
2203         DEBUG(3,("Set password for <%s>\n",user));
2204
2205         /*
2206          * Attempt to verify the old password against smbpasswd entries
2207          * Win98 clients send old and new password in plaintext for this call.
2208          */
2209
2210         {
2211                 auth_serversupplied_info *server_info = NULL;
2212                 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2213
2214                 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2215
2216                         become_root();
2217                         if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2218                                 SSVAL(*rparam,0,NERR_Success);
2219                         }
2220                         unbecome_root();
2221
2222                         TALLOC_FREE(server_info);
2223                 }
2224                 data_blob_clear_free(&password);
2225         }
2226
2227         /*
2228          * If the plaintext change failed, attempt
2229          * the old encrypted method. NT will generate this
2230          * after trying the samr method. Note that this
2231          * method is done as a last resort as this
2232          * password change method loses the NT password hash
2233          * and cannot change the UNIX password as no plaintext
2234          * is received.
2235          */
2236
2237         if(SVAL(*rparam,0) != NERR_Success) {
2238                 struct samu *hnd = NULL;
2239
2240                 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2241                         become_root();
2242                         if (change_lanman_password(hnd,(uchar *)pass2)) {
2243                                 SSVAL(*rparam,0,NERR_Success);
2244                         }
2245                         unbecome_root();
2246                         TALLOC_FREE(hnd);
2247                 }
2248         }
2249
2250         memset((char *)pass1,'\0',sizeof(fstring));
2251         memset((char *)pass2,'\0',sizeof(fstring));      
2252          
2253         return(True);
2254 }
2255
2256 /****************************************************************************
2257   Set the user password (SamOEM version - gets plaintext).
2258 ****************************************************************************/
2259
2260 static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char *param,char *data,
2261                                 int mdrcnt,int mprcnt,
2262                                 char **rdata,char **rparam,
2263                                 int *rdata_len,int *rparam_len)
2264 {
2265         fstring user;
2266         char *p = param + 2;
2267         *rparam_len = 2;
2268         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2269
2270         *rdata_len = 0;
2271
2272         SSVAL(*rparam,0,NERR_badpass);
2273
2274         /*
2275          * Check the parameter definition is correct.
2276          */
2277
2278         if(!strequal(param + 2, "zsT")) {
2279                 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", param + 2));
2280                 return False;
2281         }
2282         p = skip_string(p, 1);
2283
2284         if(!strequal(p, "B516B16")) {
2285                 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2286                 return False;
2287         }
2288         p = skip_string(p,1);
2289         p += pull_ascii_fstring(user,p);
2290
2291         DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2292
2293         /*
2294          * Pass the user through the NT -> unix user mapping
2295          * function.
2296          */
2297
2298         (void)map_username(user);
2299
2300         if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2301                 SSVAL(*rparam,0,NERR_Success);
2302         }
2303
2304         return(True);
2305 }
2306
2307 /****************************************************************************
2308   delete a print job
2309   Form: <W> <> 
2310   ****************************************************************************/
2311
2312 static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param,char *data,
2313                                 int mdrcnt,int mprcnt,
2314                                 char **rdata,char **rparam,
2315                                 int *rdata_len,int *rparam_len)
2316 {
2317         int function = SVAL(param,0);
2318         char *str1 = param+2;
2319         char *str2 = skip_string(str1,1);
2320         char *p = skip_string(str2,1);
2321         uint32 jobid;
2322         int snum;
2323         fstring sharename;
2324         int errcode;
2325         WERROR werr = WERR_OK;
2326
2327         if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2328                 return False;
2329
2330         /* check it's a supported varient */
2331         if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2332                 return(False);
2333
2334         *rparam_len = 4;
2335         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);       
2336         *rdata_len = 0;
2337
2338         if (!print_job_exists(sharename, jobid)) {
2339                 errcode = NERR_JobNotFound;
2340                 goto out;
2341         }
2342
2343         snum = lp_servicenumber( sharename);
2344         if (snum == -1) {
2345                 errcode = NERR_DestNotFound;
2346                 goto out;
2347         }
2348
2349         errcode = NERR_notsupported;
2350         
2351         switch (function) {
2352         case 81:                /* delete */ 
2353                 if (print_job_delete(&current_user, snum, jobid, &werr)) 
2354                         errcode = NERR_Success;
2355                 break;
2356         case 82:                /* pause */
2357                 if (print_job_pause(&current_user, snum, jobid, &werr)) 
2358                         errcode = NERR_Success;
2359                 break;
2360         case 83:                /* resume */
2361                 if (print_job_resume(&current_user, snum, jobid, &werr)) 
2362                         errcode = NERR_Success;
2363                 break;
2364         }
2365
2366         if (!W_ERROR_IS_OK(werr))
2367                 errcode = W_ERROR_V(werr);
2368         
2369  out:
2370         SSVAL(*rparam,0,errcode);       
2371         SSVAL(*rparam,2,0);             /* converter word */
2372
2373         return(True);
2374 }
2375
2376 /****************************************************************************
2377   Purge a print queue - or pause or resume it.
2378   ****************************************************************************/
2379
2380 static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid, char *param,char *data,
2381                                  int mdrcnt,int mprcnt,
2382                                  char **rdata,char **rparam,
2383                                  int *rdata_len,int *rparam_len)
2384 {
2385         int function = SVAL(param,0);
2386         char *str1 = param+2;
2387         char *str2 = skip_string(str1,1);
2388         char *QueueName = skip_string(str2,1);
2389         int errcode = NERR_notsupported;
2390         int snum;
2391         WERROR werr = WERR_OK;
2392
2393         /* check it's a supported varient */
2394         if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
2395                 return(False);
2396
2397         *rparam_len = 4;
2398         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2399         *rdata_len = 0;
2400
2401         snum = print_queue_snum(QueueName);
2402
2403         if (snum == -1) {
2404                 errcode = NERR_JobNotFound;
2405                 goto out;
2406         }
2407
2408         switch (function) {
2409         case 74: /* Pause queue */
2410                 if (print_queue_pause(&current_user, snum, &werr)) errcode = NERR_Success;
2411                 break;
2412         case 75: /* Resume queue */
2413                 if (print_queue_resume(&current_user, snum, &werr)) errcode = NERR_Success;
2414                 break;
2415         case 103: /* Purge */
2416                 if (print_queue_purge(&current_user, snum, &werr)) errcode = NERR_Success;
2417                 break;
2418         }
2419
2420         if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr);
2421
2422  out:
2423         SSVAL(*rparam,0,errcode);
2424         SSVAL(*rparam,2,0);             /* converter word */
2425
2426         return(True);
2427 }
2428
2429 /****************************************************************************
2430   set the property of a print job (undocumented?)
2431   ? function = 0xb -> set name of print job
2432   ? function = 0x6 -> move print job up/down
2433   Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz> 
2434   or   <WWsTP> <WB21BB16B10zWWzDDz> 
2435 ****************************************************************************/
2436
2437 static int check_printjob_info(struct pack_desc* desc,
2438                                int uLevel, char* id)
2439 {
2440         desc->subformat = NULL;
2441         switch( uLevel ) {
2442         case 0: desc->format = "W"; break;
2443         case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2444         case 2: desc->format = "WWzWWDDzz"; break;
2445         case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2446         case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2447         default: return False;
2448         }
2449         if (strcmp(desc->format,id) != 0) return False;
2450         return True;
2451 }
2452
2453 static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,char *data,
2454                              int mdrcnt,int mprcnt,
2455                              char **rdata,char **rparam,
2456                              int *rdata_len,int *rparam_len)
2457 {
2458         struct pack_desc desc;
2459         char *str1 = param+2;
2460         char *str2 = skip_string(str1,1);
2461         char *p = skip_string(str2,1);
2462         uint32 jobid;
2463         int snum;
2464         fstring sharename;
2465         int uLevel = SVAL(p,2);
2466         int function = SVAL(p,4);
2467         int place, errcode;
2468
2469         if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2470                 return False;
2471         *rparam_len = 4;
2472         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2473
2474         if ( (snum = lp_servicenumber(sharename)) == -1 ) {
2475                 DEBUG(0,("api_PrintJobInfo: unable to get service number from sharename [%s]\n",
2476                         sharename));
2477                 return False;
2478         }
2479   
2480         *rdata_len = 0;
2481         
2482         /* check it's a supported varient */
2483         if ((strcmp(str1,"WWsTP")) || 
2484             (!check_printjob_info(&desc,uLevel,str2)))
2485                 return(False);
2486
2487         if (!print_job_exists(sharename, jobid)) {
2488                 errcode=NERR_JobNotFound;
2489                 goto out;
2490         }
2491
2492         errcode = NERR_notsupported;
2493
2494         switch (function) {
2495         case 0x6:
2496                 /* change job place in the queue, 
2497                    data gives the new place */
2498                 place = SVAL(data,0);
2499                 if (print_job_set_place(snum, jobid, place)) {
2500                         errcode=NERR_Success;
2501                 }
2502                 break;
2503
2504         case 0xb:   
2505                 /* change print job name, data gives the name */
2506                 if (print_job_set_name(snum, jobid, data)) {
2507                         errcode=NERR_Success;
2508                 }
2509                 break;
2510
2511         default:
2512                 return False;
2513         }
2514
2515  out:
2516         SSVALS(*rparam,0,errcode);
2517         SSVAL(*rparam,2,0);             /* converter word */
2518         
2519         return(True);
2520 }
2521
2522
2523 /****************************************************************************
2524  Get info about the server.
2525 ****************************************************************************/
2526
2527 static BOOL api_RNetServerGetInfo(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         int uLevel = SVAL(p,0);
2536         char *p2;
2537         int struct_len;
2538
2539         DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2540
2541         /* check it's a supported varient */
2542         if (!prefix_ok(str1,"WrLh")) {
2543                 return False;
2544         }
2545
2546         switch( uLevel ) {
2547                 case 0:
2548                         if (strcmp(str2,"B16") != 0) {
2549                                 return False;
2550                         }
2551                         struct_len = 16;
2552                         break;
2553                 case 1:
2554                         if (strcmp(str2,"B16BBDz") != 0) {
2555                                 return False;
2556                         }
2557                         struct_len = 26;
2558                         break;
2559                 case 2:
2560                         if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
2561                                 return False;
2562                         }
2563                         struct_len = 134;
2564                         break;
2565                 case 3:
2566                         if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
2567                                 return False;
2568                         }
2569                         struct_len = 144;
2570                         break;
2571                 case 20:
2572                         if (strcmp(str2,"DN") != 0) {
2573                                 return False;
2574                         }
2575                         struct_len = 6;
2576                         break;
2577                 case 50:
2578                         if (strcmp(str2,"B16BBDzWWzzz") != 0) {
2579                                 return False;
2580                         }
2581                         struct_len = 42;
2582                         break;
2583                 default:
2584                         return False;
2585         }
2586
2587         *rdata_len = mdrcnt;
2588         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2589
2590         p = *rdata;
2591         p2 = p + struct_len;
2592         if (uLevel != 20) {
2593                 srvstr_push(NULL, p,get_local_machine_name(),16, 
2594                         STR_ASCII|STR_UPPER|STR_TERMINATE);
2595         }
2596         p += 16;
2597         if (uLevel > 0) {
2598                 struct srv_info_struct *servers=NULL;
2599                 int i,count;
2600                 pstring comment;
2601                 uint32 servertype= lp_default_server_announce();
2602
2603                 push_ascii(comment,lp_serverstring(), MAX_SERVER_STRING_LENGTH,STR_TERMINATE);
2604
2605                 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
2606                         for (i=0;i<count;i++) {
2607                                 if (strequal(servers[i].name,get_local_machine_name())) {
2608                                         servertype = servers[i].type;
2609                                         push_ascii(comment,servers[i].comment,sizeof(pstring),STR_TERMINATE);
2610                                 }
2611                         }
2612                 }
2613
2614                 SAFE_FREE(servers);
2615
2616                 SCVAL(p,0,lp_major_announce_version());
2617                 SCVAL(p,1,lp_minor_announce_version());
2618                 SIVAL(p,2,servertype);
2619
2620                 if (mdrcnt == struct_len) {
2621                         SIVAL(p,6,0);
2622                 } else {
2623                         SIVAL(p,6,PTR_DIFF(p2,*rdata));
2624                         standard_sub_conn(conn,comment,sizeof(comment));
2625                         StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2626                         p2 = skip_string(p2,1);
2627                 }
2628         }
2629
2630         if (uLevel > 1) {
2631                 return False;           /* not yet implemented */
2632         }
2633
2634         *rdata_len = PTR_DIFF(p2,*rdata);
2635
2636         *rparam_len = 6;
2637         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2638         SSVAL(*rparam,0,NERR_Success);
2639         SSVAL(*rparam,2,0);             /* converter word */
2640         SSVAL(*rparam,4,*rdata_len);
2641
2642         return True;
2643 }
2644
2645 /****************************************************************************
2646  Get info about the server.
2647 ****************************************************************************/
2648
2649 static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2650                                 int mdrcnt,int mprcnt,
2651                                 char **rdata,char **rparam,
2652                                 int *rdata_len,int *rparam_len)
2653 {
2654         char *str1 = param+2;
2655         char *str2 = skip_string(str1,1);
2656         char *p = skip_string(str2,1);
2657         char *p2;
2658         int level = SVAL(p,0);
2659
2660         DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2661
2662         *rparam_len = 6;
2663         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2664
2665         /* check it's a supported varient */
2666         if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
2667                 return False;
2668         }
2669
2670         *rdata_len = mdrcnt + 1024;
2671         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2672
2673         SSVAL(*rparam,0,NERR_Success);
2674         SSVAL(*rparam,2,0);             /* converter word */
2675
2676         p = *rdata;
2677         p2 = p + 22;
2678
2679         SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2680         pstrcpy(p2,get_local_machine_name());
2681         strupper_m(p2);
2682         p2 = skip_string(p2,1);
2683         p += 4;
2684
2685         SIVAL(p,0,PTR_DIFF(p2,*rdata));
2686         pstrcpy(p2,current_user_info.smb_name);
2687         p2 = skip_string(p2,1);
2688         p += 4;
2689
2690         SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
2691         pstrcpy(p2,lp_workgroup());
2692         strupper_m(p2);
2693         p2 = skip_string(p2,1);
2694         p += 4;
2695
2696         SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
2697         SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
2698         p += 2;
2699
2700         SIVAL(p,0,PTR_DIFF(p2,*rdata));
2701         pstrcpy(p2,lp_workgroup());     /* don't know.  login domain?? */
2702         p2 = skip_string(p2,1);
2703         p += 4;
2704
2705         SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
2706         pstrcpy(p2,"");
2707         p2 = skip_string(p2,1);
2708         p += 4;
2709
2710         *rdata_len = PTR_DIFF(p2,*rdata);
2711
2712         SSVAL(*rparam,4,*rdata_len);
2713
2714         return True;
2715 }
2716
2717 /****************************************************************************
2718   get info about a user
2719
2720     struct user_info_11 {
2721         char                usri11_name[21];  0-20 
2722         char                usri11_pad;       21 
2723         char                *usri11_comment;  22-25 
2724         char            *usri11_usr_comment;  26-29
2725         unsigned short      usri11_priv;      30-31
2726         unsigned long       usri11_auth_flags; 32-35
2727         long                usri11_password_age; 36-39
2728         char                *usri11_homedir; 40-43
2729         char            *usri11_parms; 44-47
2730         long                usri11_last_logon; 48-51
2731         long                usri11_last_logoff; 52-55
2732         unsigned short      usri11_bad_pw_count; 56-57
2733         unsigned short      usri11_num_logons; 58-59
2734         char                *usri11_logon_server; 60-63
2735         unsigned short      usri11_country_code; 64-65
2736         char            *usri11_workstations; 66-69
2737         unsigned long       usri11_max_storage; 70-73
2738         unsigned short      usri11_units_per_week; 74-75
2739         unsigned char       *usri11_logon_hours; 76-79
2740         unsigned short      usri11_code_page; 80-81
2741     };
2742
2743 where:
2744
2745   usri11_name specifies the user name for which information is retireved
2746
2747   usri11_pad aligns the next data structure element to a word boundary
2748
2749   usri11_comment is a null terminated ASCII comment
2750
2751   usri11_user_comment is a null terminated ASCII comment about the user
2752
2753   usri11_priv specifies the level of the privilege assigned to the user.
2754        The possible values are:
2755
2756 Name             Value  Description
2757 USER_PRIV_GUEST  0      Guest privilege
2758 USER_PRIV_USER   1      User privilege
2759 USER_PRV_ADMIN   2      Administrator privilege
2760
2761   usri11_auth_flags specifies the account operator privileges. The
2762        possible values are:
2763
2764 Name            Value   Description
2765 AF_OP_PRINT     0       Print operator
2766
2767
2768 Leach, Naik                                        [Page 28]
2769 \f
2770
2771
2772 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
2773
2774
2775 AF_OP_COMM      1       Communications operator
2776 AF_OP_SERVER    2       Server operator
2777 AF_OP_ACCOUNTS  3       Accounts operator
2778
2779
2780   usri11_password_age specifies how many seconds have elapsed since the
2781        password was last changed.
2782
2783   usri11_home_dir points to a null terminated ASCII string that contains
2784        the path name of the user's home directory.
2785
2786   usri11_parms points to a null terminated ASCII string that is set
2787        aside for use by applications.
2788
2789   usri11_last_logon specifies the time when the user last logged on.
2790        This value is stored as the number of seconds elapsed since
2791        00:00:00, January 1, 1970.
2792
2793   usri11_last_logoff specifies the time when the user last logged off.
2794        This value is stored as the number of seconds elapsed since
2795        00:00:00, January 1, 1970. A value of 0 means the last logoff
2796        time is unknown.
2797
2798   usri11_bad_pw_count specifies the number of incorrect passwords
2799        entered since the last successful logon.
2800
2801   usri11_log1_num_logons specifies the number of times this user has
2802        logged on. A value of -1 means the number of logons is unknown.
2803
2804   usri11_logon_server points to a null terminated ASCII string that
2805        contains the name of the server to which logon requests are sent.
2806        A null string indicates logon requests should be sent to the
2807        domain controller.
2808
2809   usri11_country_code specifies the country code for the user's language
2810        of choice.
2811
2812   usri11_workstations points to a null terminated ASCII string that
2813        contains the names of workstations the user may log on from.
2814        There may be up to 8 workstations, with the names separated by
2815        commas. A null strings indicates there are no restrictions.
2816
2817   usri11_max_storage specifies the maximum amount of disk space the user
2818        can occupy. A value of 0xffffffff indicates there are no
2819        restrictions.
2820
2821   usri11_units_per_week specifies the equal number of time units into
2822        which a week is divided. This value must be equal to 168.
2823
2824   usri11_logon_hours points to a 21 byte (168 bits) string that
2825        specifies the time during which the user can log on. Each bit
2826        represents one unique hour in a week. The first bit (bit 0, word
2827        0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
2828
2829
2830
2831 Leach, Naik                                        [Page 29]
2832 \f
2833
2834
2835 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
2836
2837
2838        Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
2839        are no restrictions.
2840
2841   usri11_code_page specifies the code page for the user's language of
2842        choice
2843
2844 All of the pointers in this data structure need to be treated
2845 specially. The  pointer is a 32 bit pointer. The higher 16 bits need
2846 to be ignored. The converter word returned in the parameters section
2847 needs to be subtracted from the lower 16 bits to calculate an offset
2848 into the return buffer where this ASCII string resides.
2849
2850 There is no auxiliary data in the response.
2851
2852   ****************************************************************************/
2853
2854 #define usri11_name           0 
2855 #define usri11_pad            21
2856 #define usri11_comment        22
2857 #define usri11_usr_comment    26
2858 #define usri11_full_name      30
2859 #define usri11_priv           34
2860 #define usri11_auth_flags     36
2861 #define usri11_password_age   40
2862 #define usri11_homedir        44
2863 #define usri11_parms          48
2864 #define usri11_last_logon     52
2865 #define usri11_last_logoff    56
2866 #define usri11_bad_pw_count   60
2867 #define usri11_num_logons     62
2868 #define usri11_logon_server   64
2869 #define usri11_country_code   68
2870 #define usri11_workstations   70
2871 #define usri11_max_storage    74
2872 #define usri11_units_per_week 78
2873 #define usri11_logon_hours    80
2874 #define usri11_code_page      84
2875 #define usri11_end            86
2876
2877 #define USER_PRIV_GUEST 0
2878 #define USER_PRIV_USER 1
2879 #define USER_PRIV_ADMIN 2
2880
2881 #define AF_OP_PRINT     0 
2882 #define AF_OP_COMM      1
2883 #define AF_OP_SERVER    2
2884 #define AF_OP_ACCOUNTS  3
2885
2886
2887 static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2888                                 int mdrcnt,int mprcnt,
2889                                 char **rdata,char **rparam,
2890                                 int *rdata_len,int *rparam_len)
2891 {
2892         char *str1 = param+2;
2893         char *str2 = skip_string(str1,1);
2894         char *UserName = skip_string(str2,1);
2895         char *p = skip_string(UserName,1);
2896         int uLevel = SVAL(p,0);
2897         char *p2;
2898         const char *level_string;
2899
2900         /* get NIS home of a previously validated user - simeon */
2901         /* With share level security vuid will always be zero.
2902            Don't depend on vuser being non-null !!. JRA */
2903         user_struct *vuser = get_valid_user_struct(vuid);
2904         if(vuser != NULL) {
2905                 DEBUG(3,("  Username of UID %d is %s\n", (int)vuser->uid, 
2906                         vuser->user.unix_name));
2907         }
2908
2909         *rparam_len = 6;
2910         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2911
2912         DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
2913   
2914         /* check it's a supported variant */
2915         if (strcmp(str1,"zWrLh") != 0) {
2916                 return False;
2917         }
2918         switch( uLevel ) {
2919                 case 0: level_string = "B21"; break;
2920                 case 1: level_string = "B21BB16DWzzWz"; break;
2921                 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
2922                 case 10: level_string = "B21Bzzz"; break;
2923                 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
2924                 default: return False;
2925         }
2926
2927         if (strcmp(level_string,str2) != 0) {
2928                 return False;
2929         }
2930
2931         *rdata_len = mdrcnt + 1024;
2932         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2933
2934         SSVAL(*rparam,0,NERR_Success);
2935         SSVAL(*rparam,2,0);             /* converter word */
2936
2937         p = *rdata;
2938         p2 = p + usri11_end;
2939
2940         memset(p,0,21); 
2941         fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
2942
2943         if (uLevel > 0) {
2944                 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
2945                 *p2 = 0;
2946         }
2947
2948         if (uLevel >= 10) {
2949                 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
2950                 pstrcpy(p2,"Comment");
2951                 p2 = skip_string(p2,1);
2952
2953                 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
2954                 pstrcpy(p2,"UserComment");
2955                 p2 = skip_string(p2,1);
2956
2957                 /* EEK! the cifsrap.txt doesn't have this in!!!! */
2958                 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
2959                 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2960                 p2 = skip_string(p2,1);
2961         }
2962
2963         if (uLevel == 11) {
2964                 /* modelled after NTAS 3.51 reply */
2965                 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); 
2966                 SIVAL(p,usri11_auth_flags,AF_OP_PRINT);         /* auth flags */
2967                 SIVALS(p,usri11_password_age,-1);               /* password age */
2968                 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
2969                 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
2970                 p2 = skip_string(p2,1);
2971                 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
2972                 pstrcpy(p2,"");
2973                 p2 = skip_string(p2,1);
2974                 SIVAL(p,usri11_last_logon,0);           /* last logon */
2975                 SIVAL(p,usri11_last_logoff,0);          /* last logoff */
2976                 SSVALS(p,usri11_bad_pw_count,-1);       /* bad pw counts */
2977                 SSVALS(p,usri11_num_logons,-1);         /* num logons */
2978                 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
2979                 pstrcpy(p2,"\\\\*");
2980                 p2 = skip_string(p2,1);
2981                 SSVAL(p,usri11_country_code,0);         /* country code */
2982
2983                 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
2984                 pstrcpy(p2,"");
2985                 p2 = skip_string(p2,1);
2986
2987                 SIVALS(p,usri11_max_storage,-1);                /* max storage */
2988                 SSVAL(p,usri11_units_per_week,168);             /* units per week */
2989                 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
2990
2991                 /* a simple way to get logon hours at all times. */
2992                 memset(p2,0xff,21);
2993                 SCVAL(p2,21,0);           /* fix zero termination */
2994                 p2 = skip_string(p2,1);
2995
2996                 SSVAL(p,usri11_code_page,0);            /* code page */
2997         }
2998
2999         if (uLevel == 1 || uLevel == 2) {
3000                 memset(p+22,' ',16);    /* password */
3001                 SIVALS(p,38,-1);                /* password age */
3002                 SSVAL(p,42,
3003                 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3004                 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
3005                 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
3006                 p2 = skip_string(p2,1);
3007                 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
3008                 *p2++ = 0;
3009                 SSVAL(p,52,0);          /* flags */
3010                 SIVAL(p,54,PTR_DIFF(p2,*rdata));                /* script_path */
3011                 pstrcpy(p2,vuser && vuser->logon_script ? vuser->logon_script : "");
3012                 p2 = skip_string(p2,1);
3013                 if (uLevel == 2) {
3014                         SIVAL(p,60,0);          /* auth_flags */
3015                         SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
3016                         pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
3017                         p2 = skip_string(p2,1);
3018                         SIVAL(p,68,0);          /* urs_comment */
3019                         SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
3020                         pstrcpy(p2,"");
3021                         p2 = skip_string(p2,1);
3022                         SIVAL(p,76,0);          /* workstations */
3023                         SIVAL(p,80,0);          /* last_logon */
3024                         SIVAL(p,84,0);          /* last_logoff */
3025                         SIVALS(p,88,-1);                /* acct_expires */
3026                         SIVALS(p,92,-1);                /* max_storage */
3027                         SSVAL(p,96,168);        /* units_per_week */
3028                         SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
3029                         memset(p2,-1,21);
3030                         p2 += 21;
3031                         SSVALS(p,102,-1);       /* bad_pw_count */
3032                         SSVALS(p,104,-1);       /* num_logons */
3033                         SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
3034                         pstrcpy(p2,"\\\\%L");
3035                         standard_sub_conn(conn, p2,0);
3036                         p2 = skip_string(p2,1);
3037                         SSVAL(p,110,49);        /* country_code */
3038                         SSVAL(p,112,860);       /* code page */
3039                 }
3040         }
3041
3042         *rdata_len = PTR_DIFF(p2,*rdata);
3043
3044         SSVAL(*rparam,4,*rdata_len);    /* is this right?? */
3045
3046         return(True);
3047 }
3048
3049 static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param,char *data,
3050                                 int mdrcnt,int mprcnt,
3051                                 char **rdata,char **rparam,
3052                                 int *rdata_len,int *rparam_len)
3053 {
3054         char *str1 = param+2;
3055         char *str2 = skip_string(str1,1);
3056         char *p = skip_string(str2,1);
3057         int uLevel;
3058         struct pack_desc desc;
3059         char* name;
3060                 /* With share level security vuid will always be zero.
3061                    Don't depend on vuser being non-null !!. JRA */
3062         user_struct *vuser = get_valid_user_struct(vuid);
3063
3064         if(vuser != NULL) {
3065                 DEBUG(3,("  Username of UID %d is %s\n", (int)vuser->uid, 
3066                         vuser->user.unix_name));
3067         }
3068
3069         uLevel = SVAL(p,0);
3070         name = p + 2;
3071
3072         memset((char *)&desc,'\0',sizeof(desc));
3073
3074         DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
3075
3076         /* check it's a supported varient */
3077         if (strcmp(str1,"OOWb54WrLh") != 0) {
3078                 return False;
3079         }
3080         if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
3081                 return False;
3082         }
3083         if (mdrcnt > 0) {
3084                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3085         }
3086
3087         desc.base = *rdata;
3088         desc.buflen = mdrcnt;
3089         desc.subformat = NULL;
3090         desc.format = str2;
3091   
3092         if (init_package(&desc,1,0)) {
3093                 PACKI(&desc,"W",0);             /* code */
3094                 PACKS(&desc,"B21",name);        /* eff. name */
3095                 PACKS(&desc,"B","");            /* pad */
3096                 PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3097                 PACKI(&desc,"D",0);             /* auth flags XXX */
3098                 PACKI(&desc,"W",0);             /* num logons */
3099                 PACKI(&desc,"W",0);             /* bad pw count */
3100                 PACKI(&desc,"D",0);             /* last logon */
3101                 PACKI(&desc,"D",-1);            /* last logoff */
3102                 PACKI(&desc,"D",-1);            /* logoff time */
3103                 PACKI(&desc,"D",-1);            /* kickoff time */
3104                 PACKI(&desc,"D",0);             /* password age */
3105                 PACKI(&desc,"D",0);             /* password can change */
3106                 PACKI(&desc,"D",-1);            /* password must change */
3107
3108                 {
3109                         fstring mypath;
3110                         fstrcpy(mypath,"\\\\");
3111                         fstrcat(mypath,get_local_machine_name());
3112                         strupper_m(mypath);
3113                         PACKS(&desc,"z",mypath); /* computer */
3114                 }
3115
3116                 PACKS(&desc,"z",lp_workgroup());/* domain */
3117                 PACKS(&desc,"z", vuser && vuser->logon_script ? vuser->logon_script :""); /* script path */
3118                 PACKI(&desc,"D",0x00000000);            /* reserved */
3119         }
3120
3121         *rdata_len = desc.usedlen;
3122         *rparam_len = 6;
3123         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3124         SSVALS(*rparam,0,desc.errcode);
3125         SSVAL(*rparam,2,0);
3126         SSVAL(*rparam,4,desc.neededlen);
3127
3128         DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
3129
3130         return True;
3131 }
3132
3133 /****************************************************************************
3134  api_WAccessGetUserPerms
3135 ****************************************************************************/
3136
3137 static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid, char *param,char *data,
3138                                     int mdrcnt,int mprcnt,
3139                                     char **rdata,char **rparam,
3140                                     int *rdata_len,int *rparam_len)
3141 {
3142         char *str1 = param+2;
3143         char *str2 = skip_string(str1,1);
3144         char *user = skip_string(str2,1);
3145         char *resource = skip_string(user,1);
3146
3147         DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
3148
3149         /* check it's a supported varient */
3150         if (strcmp(str1,"zzh") != 0) {
3151                 return False;
3152         }
3153         if (strcmp(str2,"") != 0) {
3154                 return False;
3155         }
3156
3157         *rparam_len = 6;
3158         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3159         SSVALS(*rparam,0,0);            /* errorcode */
3160         SSVAL(*rparam,2,0);             /* converter word */
3161         SSVAL(*rparam,4,0x7f);  /* permission flags */
3162
3163         return True;
3164 }
3165
3166 /****************************************************************************
3167   api_WPrintJobEnumerate
3168   ****************************************************************************/
3169
3170 static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
3171                                  int mdrcnt,int mprcnt,
3172                                  char **rdata,char **rparam,
3173                                  int *rdata_len,int *rparam_len)
3174 {
3175         char *str1 = param+2;
3176         char *str2 = skip_string(str1,1);
3177         char *p = skip_string(str2,1);
3178         int uLevel;
3179         int count;
3180         int i;
3181         int snum;
3182         fstring sharename;
3183         uint32 jobid;
3184         struct pack_desc desc;
3185         print_queue_struct *queue=NULL;
3186         print_status_struct status;
3187         char *tmpdata=NULL;
3188
3189         uLevel = SVAL(p,2);
3190
3191         memset((char *)&desc,'\0',sizeof(desc));
3192         memset((char *)&status,'\0',sizeof(status));
3193
3194         DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
3195
3196         /* check it's a supported varient */
3197         if (strcmp(str1,"WWrLh") != 0) {
3198                 return False;
3199         }
3200         if (!check_printjob_info(&desc,uLevel,str2)) {
3201                 return False;
3202         }
3203
3204         if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
3205                 return False;
3206         }
3207
3208         snum = lp_servicenumber( sharename);
3209         if (snum < 0 || !VALID_SNUM(snum)) {
3210                 return(False);
3211         }
3212
3213         count = print_queue_status(snum,&queue,&status);
3214         for (i = 0; i < count; i++) {
3215                 if (queue[i].job == jobid) {
3216                         break;
3217                 }
3218         }
3219
3220         if (mdrcnt > 0) {
3221                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3222                 desc.base = *rdata;
3223                 desc.buflen = mdrcnt;
3224         } else {
3225                 /*
3226                  * Don't return data but need to get correct length
3227                  *  init_package will return wrong size if buflen=0
3228                  */
3229                 desc.buflen = getlen(desc.format);
3230                 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3231         }
3232
3233         if (init_package(&desc,1,0)) {
3234                 if (i < count) {
3235                         fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3236                         *rdata_len = desc.usedlen;
3237                 } else {
3238                         desc.errcode = NERR_JobNotFound;
3239                         *rdata_len = 0;
3240                 }
3241         }
3242
3243         *rparam_len = 6;
3244         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3245         SSVALS(*rparam,0,desc.errcode);
3246         SSVAL(*rparam,2,0);
3247         SSVAL(*rparam,4,desc.neededlen);
3248
3249         SAFE_FREE(queue);
3250         SAFE_FREE(tmpdata);
3251
3252         DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
3253
3254         return True;
3255 }
3256
3257 static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *param,char *data,
3258                                    int mdrcnt,int mprcnt,
3259                                    char **rdata,char **rparam,
3260                                    int *rdata_len,int *rparam_len)
3261 {
3262         char *str1 = param+2;
3263         char *str2 = skip_string(str1,1);
3264         char *p = skip_string(str2,1);
3265         char* name = p;
3266         int uLevel;
3267         int count;
3268         int i, succnt=0;
3269         int snum;
3270         struct pack_desc desc;
3271         print_queue_struct *queue=NULL;
3272         print_status_struct status;
3273
3274         memset((char *)&desc,'\0',sizeof(desc));
3275         memset((char *)&status,'\0',sizeof(status));
3276
3277         p = skip_string(p,1);
3278         uLevel = SVAL(p,0);
3279
3280         DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
3281
3282         /* check it's a supported variant */
3283         if (strcmp(str1,"zWrLeh") != 0) {
3284                 return False;
3285         }
3286     
3287         if (uLevel > 2) {
3288                 return False;   /* defined only for uLevel 0,1,2 */
3289         }
3290     
3291         if (!check_printjob_info(&desc,uLevel,str2)) { 
3292                 return False;
3293         }
3294
3295         snum = find_service(name);
3296         if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3297                 return False;
3298         }
3299
3300         count = print_queue_status(snum,&queue,&status);
3301         if (mdrcnt > 0) {
3302                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3303         }
3304         desc.base = *rdata;
3305         desc.buflen = mdrcnt;
3306
3307         if (init_package(&desc,count,0)) {
3308                 succnt = 0;
3309                 for (i = 0; i < count; i++) {
3310                         fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3311                         if (desc.errcode == NERR_Success) {
3312                                 succnt = i+1;
3313                         }
3314                 }
3315         }
3316
3317         *rdata_len = desc.usedlen;
3318
3319         *rparam_len = 8;
3320         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3321         SSVALS(*rparam,0,desc.errcode);
3322         SSVAL(*rparam,2,0);
3323         SSVAL(*rparam,4,succnt);
3324         SSVAL(*rparam,6,count);
3325
3326         SAFE_FREE(queue);
3327
3328         DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
3329
3330         return True;
3331 }
3332
3333 static int check_printdest_info(struct pack_desc* desc,
3334                                 int uLevel, char* id)
3335 {
3336         desc->subformat = NULL;
3337         switch( uLevel ) {
3338                 case 0:
3339                         desc->format = "B9";
3340                         break;
3341                 case 1:
3342                         desc->format = "B9B21WWzW";
3343                         break;
3344                 case 2:
3345                         desc->format = "z";
3346                         break;
3347                 case 3:
3348                         desc->format = "zzzWWzzzWW";
3349                         break;
3350                 default:
3351                         return False;
3352         }
3353         if (strcmp(desc->format,id) != 0) {
3354                 return False;
3355         }
3356         return True;
3357 }
3358
3359 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
3360                                 struct pack_desc* desc)
3361 {
3362         char buf[100];
3363
3364         strncpy(buf,SERVICE(snum),sizeof(buf)-1);
3365         buf[sizeof(buf)-1] = 0;
3366         strupper_m(buf);
3367
3368         if (uLevel <= 1) {
3369                 PACKS(desc,"B9",buf);   /* szName */
3370                 if (uLevel == 1) {
3371                         PACKS(desc,"B21","");   /* szUserName */
3372                         PACKI(desc,"W",0);              /* uJobId */
3373                         PACKI(desc,"W",0);              /* fsStatus */
3374                         PACKS(desc,"z","");     /* pszStatus */
3375                         PACKI(desc,"W",0);              /* time */
3376                 }
3377         }
3378
3379         if (uLevel == 2 || uLevel == 3) {
3380                 PACKS(desc,"z",buf);            /* pszPrinterName */
3381                 if (uLevel == 3) {
3382                         PACKS(desc,"z","");     /* pszUserName */
3383                         PACKS(desc,"z","");     /* pszLogAddr */
3384                         PACKI(desc,"W",0);              /* uJobId */
3385                         PACKI(desc,"W",0);              /* fsStatus */
3386                         PACKS(desc,"z","");     /* pszStatus */
3387                         PACKS(desc,"z","");     /* pszComment */
3388                         PACKS(desc,"z","NULL"); /* pszDrivers */
3389                         PACKI(desc,"W",0);              /* time */
3390                         PACKI(desc,"W",0);              /* pad1 */
3391                 }
3392         }
3393 }
3394
3395 static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
3396                                   int mdrcnt,int mprcnt,
3397                                   char **rdata,char **rparam,
3398                                   int *rdata_len,int *rparam_len)
3399 {
3400         char *str1 = param+2;
3401         char *str2 = skip_string(str1,1);
3402         char *p = skip_string(str2,1);
3403         char* PrinterName = p;
3404         int uLevel;
3405         struct pack_desc desc;
3406         int snum;
3407         char *tmpdata=NULL;
3408
3409         memset((char *)&desc,'\0',sizeof(desc));
3410
3411         p = skip_string(p,1);
3412         uLevel = SVAL(p,0);
3413
3414         DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
3415
3416         /* check it's a supported varient */
3417         if (strcmp(str1,"zWrLh") != 0) {
3418                 return False;
3419         }
3420         if (!check_printdest_info(&desc,uLevel,str2)) {
3421                 return False;
3422         }
3423
3424         snum = find_service(PrinterName);
3425         if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3426                 *rdata_len = 0;
3427                 desc.errcode = NERR_DestNotFound;
3428                 desc.neededlen = 0;
3429         } else {
3430                 if (mdrcnt > 0) {
3431                         *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3432                         desc.base = *rdata;
3433                         desc.buflen = mdrcnt;
3434                 } else {
3435                         /*
3436                          * Don't return data but need to get correct length
3437                          * init_package will return wrong size if buflen=0
3438                          */
3439                         desc.buflen = getlen(desc.format);
3440                         desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3441                 }
3442                 if (init_package(&desc,1,0)) {
3443                         fill_printdest_info(conn,snum,uLevel,&desc);
3444                 }
3445                 *rdata_len = desc.usedlen;
3446         }
3447
3448         *rparam_len = 6;
3449         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3450         SSVALS(*rparam,0,desc.errcode);
3451         SSVAL(*rparam,2,0);
3452         SSVAL(*rparam,4,desc.neededlen);
3453
3454         DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
3455         SAFE_FREE(tmpdata);
3456
3457         return True;
3458 }
3459
3460 static BOOL api_WPrintDestEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3461                                int mdrcnt,int mprcnt,
3462                                char **rdata,char **rparam,
3463                                int *rdata_len,int *rparam_len)
3464 {
3465         char *str1 = param+2;
3466         char *str2 = skip_string(str1,1);
3467         char *p = skip_string(str2,1);
3468         int uLevel;
3469         int queuecnt;
3470         int i, n, succnt=0;
3471         struct pack_desc desc;
3472         int services = lp_numservices();
3473
3474         memset((char *)&desc,'\0',sizeof(desc));
3475
3476         uLevel = SVAL(p,0);
3477
3478         DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
3479
3480         /* check it's a supported varient */
3481         if (strcmp(str1,"WrLeh") != 0) {
3482                 return False;
3483         }
3484         if (!check_printdest_info(&desc,uLevel,str2)) {
3485                 return False;
3486         }
3487
3488         queuecnt = 0;
3489         for (i = 0; i < services; i++) {
3490                 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3491                         queuecnt++;
3492                 }
3493         }
3494
3495         if (mdrcnt > 0) {
3496                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3497         }
3498
3499         desc.base = *rdata;
3500         desc.buflen = mdrcnt;
3501         if (init_package(&desc,queuecnt,0)) {    
3502                 succnt = 0;
3503                 n = 0;
3504                 for (i = 0; i < services; i++) {
3505                         if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3506                                 fill_printdest_info(conn,i,uLevel,&desc);
3507                                 n++;
3508                                 if (desc.errcode == NERR_Success) {
3509                                         succnt = n;
3510                                 }
3511                         }
3512                 }
3513         }
3514
3515         *rdata_len = desc.usedlen;
3516
3517         *rparam_len = 8;
3518         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3519         SSVALS(*rparam,0,desc.errcode);
3520         SSVAL(*rparam,2,0);
3521         SSVAL(*rparam,4,succnt);
3522         SSVAL(*rparam,6,queuecnt);
3523
3524         DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
3525
3526         return True;
3527 }
3528
3529 static BOOL api_WPrintDriverEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3530                                  int mdrcnt,int mprcnt,
3531                                  char **rdata,char **rparam,
3532                                  int *rdata_len,int *rparam_len)
3533 {
3534         char *str1 = param+2;
3535         char *str2 = skip_string(str1,1);
3536         char *p = skip_string(str2,1);
3537         int uLevel;
3538         int succnt;
3539         struct pack_desc desc;
3540
3541         memset((char *)&desc,'\0',sizeof(desc));
3542
3543         uLevel = SVAL(p,0);
3544
3545         DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
3546
3547         /* check it's a supported varient */
3548         if (strcmp(str1,"WrLeh") != 0) {
3549                 return False;
3550         }
3551         if (uLevel != 0 || strcmp(str2,"B41") != 0) {
3552                 return False;
3553         }
3554
3555         if (mdrcnt > 0) {
3556                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3557         }
3558         desc.base = *rdata;
3559         desc.buflen = mdrcnt;
3560         if (init_package(&desc,1,0)) {
3561                 PACKS(&desc,"B41","NULL");
3562         }
3563
3564         succnt = (desc.errcode == NERR_Success ? 1 : 0);
3565
3566         *rdata_len = desc.usedlen;
3567
3568         *rparam_len = 8;
3569         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3570         SSVALS(*rparam,0,desc.errcode);
3571         SSVAL(*rparam,2,0);
3572         SSVAL(*rparam,4,succnt);
3573         SSVAL(*rparam,6,1);
3574
3575         DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
3576
3577         return True;
3578 }
3579
3580 static BOOL api_WPrintQProcEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3581                                 int mdrcnt,int mprcnt,
3582                                 char **rdata,char **rparam,
3583                                 int *rdata_len,int *rparam_len)
3584 {
3585         char *str1 = param+2;
3586         char *str2 = skip_string(str1,1);
3587         char *p = skip_string(str2,1);
3588         int uLevel;
3589         int succnt;
3590         struct pack_desc desc;
3591
3592         memset((char *)&desc,'\0',sizeof(desc));
3593
3594         uLevel = SVAL(p,0);
3595
3596         DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
3597
3598         /* check it's a supported varient */
3599         if (strcmp(str1,"WrLeh") != 0) {
3600                 return False;
3601         }
3602         if (uLevel != 0 || strcmp(str2,"B13") != 0) {
3603                 return False;
3604         }
3605
3606         if (mdrcnt > 0) {
3607                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3608         }
3609         desc.base = *rdata;
3610         desc.buflen = mdrcnt;
3611         desc.format = str2;
3612         if (init_package(&desc,1,0)) {
3613                 PACKS(&desc,"B13","lpd");
3614         }
3615
3616         succnt = (desc.errcode == NERR_Success ? 1 : 0);
3617
3618         *rdata_len = desc.usedlen;
3619
3620         *rparam_len = 8;
3621         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3622         SSVALS(*rparam,0,desc.errcode);
3623         SSVAL(*rparam,2,0);
3624         SSVAL(*rparam,4,succnt);
3625         SSVAL(*rparam,6,1);
3626
3627         DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
3628
3629         return True;
3630 }
3631
3632 static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3633                                int mdrcnt,int mprcnt,
3634                                char **rdata,char **rparam,
3635                                int *rdata_len,int *rparam_len)
3636 {
3637         char *str1 = param+2;
3638         char *str2 = skip_string(str1,1);
3639         char *p = skip_string(str2,1);
3640         int uLevel;
3641         int succnt;
3642         struct pack_desc desc;
3643
3644         memset((char *)&desc,'\0',sizeof(desc));
3645
3646         uLevel = SVAL(p,0);
3647
3648         DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
3649
3650         /* check it's a supported varient */
3651         if (strcmp(str1,"WrLeh") != 0) {
3652                 return False;
3653         }
3654         if (uLevel != 0 || strcmp(str2,"B9") != 0) {
3655                 return False;
3656         }
3657
3658         if (mdrcnt > 0) {
3659                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3660         }
3661         memset((char *)&desc,'\0',sizeof(desc));
3662         desc.base = *rdata;
3663         desc.buflen = mdrcnt;
3664         desc.format = str2;
3665         if (init_package(&desc,1,0)) {
3666                 PACKS(&desc,"B13","lp0");
3667         }
3668
3669         succnt = (desc.errcode == NERR_Success ? 1 : 0);
3670
3671         *rdata_len = desc.usedlen;
3672
3673         *rparam_len = 8;
3674         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3675         SSVALS(*rparam,0,desc.errcode);
3676         SSVAL(*rparam,2,0);
3677         SSVAL(*rparam,4,succnt);
3678         SSVAL(*rparam,6,1);
3679
3680         DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
3681
3682         return True;
3683 }
3684
3685
3686 /****************************************************************************
3687  List open sessions
3688  ****************************************************************************/
3689 static BOOL api_RNetSessionEnum(connection_struct *conn,uint16 vuid, char *param, char *data,
3690                                int mdrcnt,int mprcnt,
3691                                char **rdata,char **rparam,
3692                                int *rdata_len,int *rparam_len)
3693
3694 {
3695         char *str1 = param+2;
3696         char *str2 = skip_string(str1,1);
3697         char *p = skip_string(str2,1);
3698         int uLevel;
3699         struct pack_desc desc;
3700         struct sessionid *session_list;
3701         int i, num_sessions;
3702
3703         memset((char *)&desc,'\0',sizeof(desc));
3704
3705         uLevel = SVAL(p,0);
3706
3707         DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
3708         DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
3709         DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
3710
3711         /* check it's a supported varient */
3712         if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
3713                 return False;
3714         }
3715         if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
3716                 return False;
3717         }
3718
3719         num_sessions = list_sessions(&session_list);
3720
3721         if (mdrcnt > 0) {
3722                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3723         }
3724         memset((char *)&desc,'\0',sizeof(desc));
3725         desc.base = *rdata;
3726         desc.buflen = mdrcnt;
3727         desc.format = str2;
3728         if (!init_package(&desc,num_sessions,0)) {
3729                 return False;
3730         }
3731
3732         for(i=0; i<num_sessions; i++) {
3733                 PACKS(&desc, "z", session_list[i].remote_machine);
3734                 PACKS(&desc, "z", session_list[i].username);
3735                 PACKI(&desc, "W", 1); /* num conns */
3736                 PACKI(&desc, "W", 0); /* num opens */
3737                 PACKI(&desc, "W", 1); /* num users */
3738                 PACKI(&desc, "D", 0); /* session time */
3739                 PACKI(&desc, "D", 0); /* idle time */
3740                 PACKI(&desc, "D", 0); /* flags */
3741                 PACKS(&desc, "z", "Unknown Client"); /* client type string */
3742         }
3743
3744         *rdata_len = desc.usedlen;
3745
3746         *rparam_len = 8;
3747         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3748         SSVALS(*rparam,0,desc.errcode);
3749         SSVAL(*rparam,2,0); /* converter */
3750         SSVAL(*rparam,4,num_sessions); /* count */
3751
3752         DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
3753
3754         return True;
3755 }
3756
3757
3758 /****************************************************************************
3759  The buffer was too small.
3760  ****************************************************************************/
3761
3762 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
3763                          int mdrcnt, int mprcnt,
3764                          char **rdata, char **rparam,
3765                          int *rdata_len, int *rparam_len)
3766 {
3767         *rparam_len = MIN(*rparam_len,mprcnt);
3768         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3769
3770         *rdata_len = 0;
3771
3772         SSVAL(*rparam,0,NERR_BufTooSmall);
3773
3774         DEBUG(3,("Supplied buffer too small in API command\n"));
3775
3776         return True;
3777 }
3778
3779 /****************************************************************************
3780  The request is not supported.
3781  ****************************************************************************/
3782
3783 static BOOL api_Unsupported(connection_struct *conn, uint16 vuid, char *param, char *data,
3784                             int mdrcnt, int mprcnt,
3785                             char **rdata, char **rparam,
3786                             int *rdata_len, int *rparam_len)
3787 {
3788         *rparam_len = 4;
3789         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3790
3791         *rdata_len = 0;
3792
3793         SSVAL(*rparam,0,NERR_notsupported);
3794         SSVAL(*rparam,2,0);             /* converter word */
3795
3796         DEBUG(3,("Unsupported API command\n"));
3797
3798         return True;
3799 }
3800
3801 static const struct {
3802         const char *name;
3803         int id;
3804         BOOL (*fn)(connection_struct *,uint16,char *,char *,
3805                         int,int,char **,char **,int *,int *);
3806         BOOL auth_user;         /* Deny anonymous access? */
3807 } api_commands[] = {
3808         {"RNetShareEnum",       RAP_WshareEnum,         api_RNetShareEnum, True},
3809         {"RNetShareGetInfo",    RAP_WshareGetInfo,      api_RNetShareGetInfo},
3810         {"RNetShareAdd",        RAP_WshareAdd,          api_RNetShareAdd},
3811         {"RNetSessionEnum",     RAP_WsessionEnum,       api_RNetSessionEnum, True},
3812         {"RNetServerGetInfo",   RAP_WserverGetInfo,     api_RNetServerGetInfo},
3813         {"RNetGroupEnum",       RAP_WGroupEnum,         api_RNetGroupEnum, True},
3814         {"RNetGroupGetUsers", RAP_WGroupGetUsers,       api_RNetGroupGetUsers, True},
3815         {"RNetUserEnum",        RAP_WUserEnum,          api_RNetUserEnum, True},
3816         {"RNetUserGetInfo",     RAP_WUserGetInfo,       api_RNetUserGetInfo},
3817         {"NetUserGetGroups",    RAP_WUserGetGroups,     api_NetUserGetGroups},
3818         {"NetWkstaGetInfo",     RAP_WWkstaGetInfo,      api_NetWkstaGetInfo},
3819         {"DosPrintQEnum",       RAP_WPrintQEnum,        api_DosPrintQEnum, True},
3820         {"DosPrintQGetInfo",    RAP_WPrintQGetInfo,     api_DosPrintQGetInfo},
3821         {"WPrintQueuePause",  RAP_WPrintQPause, api_WPrintQueueCtrl},
3822         {"WPrintQueueResume", RAP_WPrintQContinue,      api_WPrintQueueCtrl},
3823         {"WPrintJobEnumerate",RAP_WPrintJobEnum,        api_WPrintJobEnumerate},
3824         {"WPrintJobGetInfo",    RAP_WPrintJobGetInfo,   api_WPrintJobGetInfo},
3825         {"RDosPrintJobDel",     RAP_WPrintJobDel,       api_RDosPrintJobDel},
3826         {"RDosPrintJobPause",   RAP_WPrintJobPause,     api_RDosPrintJobDel},
3827         {"RDosPrintJobResume",RAP_WPrintJobContinue,    api_RDosPrintJobDel},
3828         {"WPrintDestEnum",      RAP_WPrintDestEnum,     api_WPrintDestEnum},
3829         {"WPrintDestGetInfo",   RAP_WPrintDestGetInfo,  api_WPrintDestGetInfo},
3830         {"NetRemoteTOD",        RAP_NetRemoteTOD,       api_NetRemoteTOD},
3831         {"WPrintQueuePurge",    RAP_WPrintQPurge,       api_WPrintQueueCtrl},
3832         {"NetServerEnum",       RAP_NetServerEnum2,     api_RNetServerEnum}, /* anon OK */
3833         {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
3834         {"SetUserPassword",     RAP_WUserPasswordSet2,  api_SetUserPassword},
3835         {"WWkstaUserLogon",     RAP_WWkstaUserLogon,    api_WWkstaUserLogon},
3836         {"PrintJobInfo",        RAP_WPrintJobSetInfo,   api_PrintJobInfo},
3837         {"WPrintDriverEnum",    RAP_WPrintDriverEnum,   api_WPrintDriverEnum},
3838         {"WPrintQProcEnum",     RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
3839         {"WPrintPortEnum",      RAP_WPrintPortEnum,     api_WPrintPortEnum},
3840         {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
3841         {NULL,          -1,     api_Unsupported}
3842         /*  The following RAP calls are not implemented by Samba:
3843
3844         RAP_WFileEnum2 - anon not OK 
3845         */
3846 };
3847
3848
3849 /****************************************************************************
3850  Handle remote api calls
3851  ****************************************************************************/
3852
3853 int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *params,
3854                      int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
3855 {
3856         int api_command;
3857         char *rdata = NULL;
3858         char *rparam = NULL;
3859         int rdata_len = 0;
3860         int rparam_len = 0;
3861         BOOL reply=False;
3862         int i;
3863
3864         if (!params) {
3865                 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
3866                 return 0;
3867         }
3868
3869         api_command = SVAL(params,0);
3870
3871         DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
3872                 api_command,
3873                 params+2,
3874                 skip_string(params+2,1),
3875                 tdscnt,tpscnt,mdrcnt,mprcnt));
3876
3877         for (i=0;api_commands[i].name;i++) {
3878                 if (api_commands[i].id == api_command && api_commands[i].fn) {
3879                         DEBUG(3,("Doing %s\n",api_commands[i].name));
3880                         break;
3881                 }
3882         }
3883
3884         /* Check whether this api call can be done anonymously */
3885
3886         if (api_commands[i].auth_user && lp_restrict_anonymous()) {
3887                 user_struct *user = get_valid_user_struct(vuid);
3888
3889                 if (!user || user->guest) {
3890                         return ERROR_NT(NT_STATUS_ACCESS_DENIED);
3891                 }
3892         }
3893
3894         rdata = (char *)SMB_MALLOC(1024);
3895         if (rdata) {
3896                 memset(rdata,'\0',1024);
3897         }
3898
3899         rparam = (char *)SMB_MALLOC(1024);
3900         if (rparam) {
3901                 memset(rparam,'\0',1024);
3902         }
3903
3904         if(!rdata || !rparam) {
3905                 DEBUG(0,("api_reply: malloc fail !\n"));
3906                 SAFE_FREE(rdata);
3907                 SAFE_FREE(rparam);
3908                 return -1;
3909         }
3910
3911         reply = api_commands[i].fn(conn,vuid,params,data,mdrcnt,mprcnt,
3912                                 &rdata,&rparam,&rdata_len,&rparam_len);
3913
3914
3915         if (rdata_len > mdrcnt || rparam_len > mprcnt) {
3916                 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
3917                                         &rdata,&rparam,&rdata_len,&rparam_len);
3918         }
3919
3920         /* if we get False back then it's actually unsupported */
3921         if (!reply) {
3922                 api_Unsupported(conn,vuid,params,data,mdrcnt,mprcnt,
3923                         &rdata,&rparam,&rdata_len,&rparam_len);
3924         }
3925
3926         send_trans_reply(outbuf, rparam, rparam_len, rdata, rdata_len, False);
3927
3928         SAFE_FREE(rdata);
3929         SAFE_FREE(rparam);
3930         return -1;
3931 }