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