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