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