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