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