s3: Remove the typedef for "auth_serversupplied_info"
[kai/samba.git] / source3 / smbd / lanman.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Inter-process communication and named pipe handling
4    Copyright (C) Andrew Tridgell 1992-1998
5    Copyright (C) Jeremy Allison 2007.
6
7    SMB Version handling
8    Copyright (C) John H Terpstra 1995-1998
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22    */
23 /*
24    This file handles the named pipe and mailslot calls
25    in the SMBtrans protocol
26    */
27
28 #include "includes.h"
29 #include "smbd/globals.h"
30 #include "../librpc/gen_ndr/cli_samr.h"
31 #include "../librpc/gen_ndr/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_RNetServerEnum(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         if (lp_browse_list()) {
1433                 total = get_server_info(servertype,&servers,domain);
1434         }
1435
1436         data_len = fixed_len = string_len = 0;
1437         missed = 0;
1438
1439         if (total > 0) {
1440                 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1441         }
1442
1443         {
1444                 char *lastname=NULL;
1445
1446                 for (i=0;i<total;i++) {
1447                         struct srv_info_struct *s = &servers[i];
1448
1449                         if (lastname && strequal(lastname,s->name)) {
1450                                 continue;
1451                         }
1452                         lastname = s->name;
1453                         data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1454                         DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1455                                 s->name, s->type, s->comment, s->domain));
1456
1457                         if (data_len <= buf_len) {
1458                                 counted++;
1459                                 fixed_len += f_len;
1460                                 string_len += s_len;
1461                         } else {
1462                                 missed++;
1463                         }
1464                 }
1465         }
1466
1467         *rdata_len = fixed_len + string_len;
1468         *rdata = smb_realloc_limit(*rdata,*rdata_len);
1469         if (!*rdata) {
1470                 return False;
1471         }
1472
1473         p2 = (*rdata) + fixed_len;      /* auxilliary data (strings) will go here */
1474         p = *rdata;
1475         f_len = fixed_len;
1476         s_len = string_len;
1477
1478         {
1479                 char *lastname=NULL;
1480                 int count2 = counted;
1481
1482                 for (i = 0; i < total && count2;i++) {
1483                         struct srv_info_struct *s = &servers[i];
1484
1485                         if (lastname && strequal(lastname,s->name)) {
1486                                 continue;
1487                         }
1488                         lastname = s->name;
1489                         fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1490                         DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1491                                 s->name, s->type, s->comment, s->domain));
1492                         count2--;
1493                 }
1494         }
1495
1496         *rparam_len = 8;
1497         *rparam = smb_realloc_limit(*rparam,*rparam_len);
1498         if (!*rparam) {
1499                 return False;
1500         }
1501         SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1502         SSVAL(*rparam,2,0);
1503         SSVAL(*rparam,4,counted);
1504         SSVAL(*rparam,6,counted+missed);
1505
1506         SAFE_FREE(servers);
1507
1508         DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1509                 domain,uLevel,counted,counted+missed));
1510
1511         return True;
1512 }
1513
1514 /****************************************************************************
1515   command 0x34 - suspected of being a "Lookup Names" stub api
1516   ****************************************************************************/
1517
1518 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1519                                 char *param, int tpscnt,
1520                                 char *data, int tdscnt,
1521                                 int mdrcnt, int mprcnt, char **rdata, 
1522                                 char **rparam, int *rdata_len, int *rparam_len)
1523 {
1524         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1525         char *str2 = skip_string(param,tpscnt,str1);
1526         char *p = skip_string(param,tpscnt,str2);
1527         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1528         int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1529         int counted=0;
1530         int missed=0;
1531
1532         if (!str1 || !str2 || !p) {
1533                 return False;
1534         }
1535
1536         DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1537                 str1, str2, p, uLevel, buf_len));
1538
1539         if (!prefix_ok(str1,"zWrLeh")) {
1540                 return False;
1541         }
1542
1543         *rdata_len = 0;
1544
1545         *rparam_len = 8;
1546         *rparam = smb_realloc_limit(*rparam,*rparam_len);
1547         if (!*rparam) {
1548                 return False;
1549         }
1550
1551         SSVAL(*rparam,0,0x08AC); /* informational warning message */
1552         SSVAL(*rparam,2,0);
1553         SSVAL(*rparam,4,counted);
1554         SSVAL(*rparam,6,counted+missed);
1555
1556         return True;
1557 }
1558
1559 /****************************************************************************
1560   get info about a share
1561   ****************************************************************************/
1562
1563 static bool check_share_info(int uLevel, char* id)
1564 {
1565         switch( uLevel ) {
1566                 case 0:
1567                         if (strcmp(id,"B13") != 0) {
1568                                 return False;
1569                         }
1570                         break;
1571                 case 1:
1572                         if (strcmp(id,"B13BWz") != 0) {
1573                                 return False;
1574                         }
1575                         break;
1576                 case 2:
1577                         if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1578                                 return False;
1579                         }
1580                         break;
1581                 case 91:
1582                         if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1583                                 return False;
1584                         }
1585                         break;
1586                 default:
1587                         return False;
1588         }
1589         return True;
1590 }
1591
1592 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1593                            char** buf, int* buflen,
1594                            char** stringbuf, int* stringspace, char* baseaddr)
1595 {
1596         int struct_len;
1597         char* p;
1598         char* p2;
1599         int l2;
1600         int len;
1601
1602         switch( uLevel ) {
1603                 case 0:
1604                         struct_len = 13;
1605                         break;
1606                 case 1:
1607                         struct_len = 20;
1608                         break;
1609                 case 2:
1610                         struct_len = 40;
1611                         break;
1612                 case 91:
1613                         struct_len = 68;
1614                         break;
1615                 default:
1616                         return -1;
1617         }
1618
1619         if (!buf) {
1620                 len = 0;
1621
1622                 if (uLevel > 0) {
1623                         len += StrlenExpanded(conn,snum,lp_comment(snum));
1624                 }
1625                 if (uLevel > 1) {
1626                         len += strlen(lp_pathname(snum)) + 1;
1627                 }
1628                 if (buflen) {
1629                         *buflen = struct_len;
1630                 }
1631                 if (stringspace) {
1632                         *stringspace = len;
1633                 }
1634                 return struct_len + len;
1635         }
1636
1637         len = struct_len;
1638         p = *buf;
1639         if ((*buflen) < struct_len) {
1640                 return -1;
1641         }
1642
1643         if (stringbuf) {
1644                 p2 = *stringbuf;
1645                 l2 = *stringspace;
1646         } else {
1647                 p2 = p + struct_len;
1648                 l2 = (*buflen) - struct_len;
1649         }
1650
1651         if (!baseaddr) {
1652                 baseaddr = p;
1653         }
1654
1655         push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1656
1657         if (uLevel > 0) {
1658                 int type;
1659
1660                 SCVAL(p,13,0);
1661                 type = STYPE_DISKTREE;
1662                 if (lp_print_ok(snum)) {
1663                         type = STYPE_PRINTQ;
1664                 }
1665                 if (strequal("IPC",lp_fstype(snum))) {
1666                         type = STYPE_IPC;
1667                 }
1668                 SSVAL(p,14,type);               /* device type */
1669                 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1670                 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1671         }
1672
1673         if (uLevel > 1) {
1674                 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1675                 SSVALS(p,22,-1);                /* max uses */
1676                 SSVAL(p,24,1); /* current uses */
1677                 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1678                 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1679                 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1680         }
1681
1682         if (uLevel > 2) {
1683                 memset(p+40,0,SHPWLEN+2);
1684                 SSVAL(p,50,0);
1685                 SIVAL(p,52,0);
1686                 SSVAL(p,56,0);
1687                 SSVAL(p,58,0);
1688                 SIVAL(p,60,0);
1689                 SSVAL(p,64,0);
1690                 SSVAL(p,66,0);
1691         }
1692
1693         if (stringbuf) {
1694                 (*buf) = p + struct_len;
1695                 (*buflen) -= struct_len;
1696                 (*stringbuf) = p2;
1697                 (*stringspace) = l2;
1698         } else {
1699                 (*buf) = p2;
1700                 (*buflen) -= len;
1701         }
1702
1703         return len;
1704 }
1705
1706 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1707                                 char *param, int tpscnt,
1708                                 char *data, int tdscnt,
1709                                 int mdrcnt,int mprcnt,
1710                                 char **rdata,char **rparam,
1711                                 int *rdata_len,int *rparam_len)
1712 {
1713         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1714         char *str2 = skip_string(param,tpscnt,str1);
1715         char *netname = skip_string(param,tpscnt,str2);
1716         char *p = skip_string(param,tpscnt,netname);
1717         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1718         int snum;
1719
1720         if (!str1 || !str2 || !netname || !p) {
1721                 return False;
1722         }
1723
1724         snum = find_service(netname);
1725         if (snum < 0) {
1726                 return False;
1727         }
1728
1729         /* check it's a supported varient */
1730         if (!prefix_ok(str1,"zWrLh")) {
1731                 return False;
1732         }
1733         if (!check_share_info(uLevel,str2)) {
1734                 return False;
1735         }
1736
1737         *rdata = smb_realloc_limit(*rdata,mdrcnt);
1738         if (!*rdata) {
1739                 return False;
1740         }
1741         p = *rdata;
1742         *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1743         if (*rdata_len < 0) {
1744                 return False;
1745         }
1746
1747         *rparam_len = 6;
1748         *rparam = smb_realloc_limit(*rparam,*rparam_len);
1749         if (!*rparam) {
1750                 return False;
1751         }
1752         SSVAL(*rparam,0,NERR_Success);
1753         SSVAL(*rparam,2,0);             /* converter word */
1754         SSVAL(*rparam,4,*rdata_len);
1755
1756         return True;
1757 }
1758
1759 /****************************************************************************
1760   View the list of available shares.
1761
1762   This function is the server side of the NetShareEnum() RAP call.
1763   It fills the return buffer with share names and share comments.
1764   Note that the return buffer normally (in all known cases) allows only
1765   twelve byte strings for share names (plus one for a nul terminator).
1766   Share names longer than 12 bytes must be skipped.
1767  ****************************************************************************/
1768
1769 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
1770                                 char *param, int tpscnt,
1771                                 char *data, int tdscnt,
1772                                 int                mdrcnt,
1773                                 int                mprcnt,
1774                                 char             **rdata,
1775                                 char             **rparam,
1776                                 int               *rdata_len,
1777                                 int               *rparam_len )
1778 {
1779         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1780         char *str2 = skip_string(param,tpscnt,str1);
1781         char *p = skip_string(param,tpscnt,str2);
1782         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1783         int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1784         char *p2;
1785         int count = 0;
1786         int total=0,counted=0;
1787         bool missed = False;
1788         int i;
1789         int data_len, fixed_len, string_len;
1790         int f_len = 0, s_len = 0;
1791
1792         if (!str1 || !str2 || !p) {
1793                 return False;
1794         }
1795
1796         if (!prefix_ok(str1,"WrLeh")) {
1797                 return False;
1798         }
1799         if (!check_share_info(uLevel,str2)) {
1800                 return False;
1801         }
1802
1803         /* Ensure all the usershares are loaded. */
1804         become_root();
1805         load_registry_shares();
1806         count = load_usershare_shares();
1807         unbecome_root();
1808
1809         data_len = fixed_len = string_len = 0;
1810         for (i=0;i<count;i++) {
1811                 fstring servicename_dos;
1812                 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1813                         continue;
1814                 }
1815                 push_ascii_fstring(servicename_dos, lp_servicename(i));
1816                 /* Maximum name length = 13. */
1817                 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
1818                         total++;
1819                         data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1820                         if (data_len <= buf_len) {
1821                                 counted++;
1822                                 fixed_len += f_len;
1823                                 string_len += s_len;
1824                         } else {
1825                                 missed = True;
1826                         }
1827                 }
1828         }
1829
1830         *rdata_len = fixed_len + string_len;
1831         *rdata = smb_realloc_limit(*rdata,*rdata_len);
1832         if (!*rdata) {
1833                 return False;
1834         }
1835
1836         p2 = (*rdata) + fixed_len;      /* auxiliary data (strings) will go here */
1837         p = *rdata;
1838         f_len = fixed_len;
1839         s_len = string_len;
1840
1841         for( i = 0; i < count; i++ ) {
1842                 fstring servicename_dos;
1843                 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1844                         continue;
1845                 }
1846
1847                 push_ascii_fstring(servicename_dos, lp_servicename(i));
1848                 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
1849                         if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
1850                                 break;
1851                         }
1852                 }
1853         }
1854
1855         *rparam_len = 8;
1856         *rparam = smb_realloc_limit(*rparam,*rparam_len);
1857         if (!*rparam) {
1858                 return False;
1859         }
1860         SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1861         SSVAL(*rparam,2,0);
1862         SSVAL(*rparam,4,counted);
1863         SSVAL(*rparam,6,total);
1864
1865         DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1866                 counted,total,uLevel,
1867                 buf_len,*rdata_len,mdrcnt));
1868
1869         return True;
1870 }
1871
1872 /****************************************************************************
1873   Add a share
1874   ****************************************************************************/
1875
1876 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
1877                                 char *param, int tpscnt,
1878                                 char *data, int tdscnt,
1879                                 int mdrcnt,int mprcnt,
1880                                 char **rdata,char **rparam,
1881                                 int *rdata_len,int *rparam_len)
1882 {
1883         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1884         char *str2 = skip_string(param,tpscnt,str1);
1885         char *p = skip_string(param,tpscnt,str2);
1886         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1887         fstring sharename;
1888         fstring comment;
1889         char *pathname = NULL;
1890         char *command, *cmdname;
1891         unsigned int offset;
1892         int snum;
1893         int res = ERRunsup;
1894         size_t converted_size;
1895
1896         if (!str1 || !str2 || !p) {
1897                 return False;
1898         }
1899
1900         /* check it's a supported varient */
1901         if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
1902                 return False;
1903         }
1904         if (!check_share_info(uLevel,str2)) {
1905                 return False;
1906         }
1907         if (uLevel != 2) {
1908                 return False;
1909         }
1910
1911         /* Do we have a string ? */
1912         if (skip_string(data,mdrcnt,data) == NULL) {
1913                 return False;
1914         }
1915         pull_ascii_fstring(sharename,data);
1916         snum = find_service(sharename);
1917         if (snum >= 0) { /* already exists */
1918                 res = ERRfilexists;
1919                 goto error_exit;
1920         }
1921
1922         if (mdrcnt < 28) {
1923                 return False;
1924         }
1925
1926         /* only support disk share adds */
1927         if (SVAL(data,14)!=STYPE_DISKTREE) {
1928                 return False;
1929         }
1930
1931         offset = IVAL(data, 16);
1932         if (offset >= mdrcnt) {
1933                 res = ERRinvalidparam;
1934                 goto error_exit;
1935         }
1936
1937         /* Do we have a string ? */
1938         if (skip_string(data,mdrcnt,data+offset) == NULL) {
1939                 return False;
1940         }
1941         pull_ascii_fstring(comment, offset? (data+offset) : "");
1942
1943         offset = IVAL(data, 26);
1944
1945         if (offset >= mdrcnt) {
1946                 res = ERRinvalidparam;
1947                 goto error_exit;
1948         }
1949
1950         /* Do we have a string ? */
1951         if (skip_string(data,mdrcnt,data+offset) == NULL) {
1952                 return False;
1953         }
1954
1955         if (!pull_ascii_talloc(talloc_tos(), &pathname,
1956                                offset ? (data+offset) : "", &converted_size))
1957         {
1958                 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
1959                          strerror(errno)));
1960         }
1961
1962         if (!pathname) {
1963                 return false;
1964         }
1965
1966         string_replace(sharename, '"', ' ');
1967         string_replace(pathname, '"', ' ');
1968         string_replace(comment, '"', ' ');
1969
1970         cmdname = lp_add_share_cmd();
1971
1972         if (!cmdname || *cmdname == '\0') {
1973                 return False;
1974         }
1975
1976         if (asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
1977                      lp_add_share_cmd(), get_dyn_CONFIGFILE(), sharename,
1978                      pathname, comment) == -1) {
1979                 return false;
1980         }
1981
1982         DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
1983
1984         if ((res = smbrun(command, NULL)) != 0) {
1985                 DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n",
1986                          command, res ));
1987                 SAFE_FREE(command);
1988                 res = ERRnoaccess;
1989                 goto error_exit;
1990         } else {
1991                 SAFE_FREE(command);
1992                 message_send_all(smbd_messaging_context(),
1993                                  MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
1994         }
1995
1996         *rparam_len = 6;
1997         *rparam = smb_realloc_limit(*rparam,*rparam_len);
1998         if (!*rparam) {
1999                 return False;
2000         }
2001         SSVAL(*rparam,0,NERR_Success);
2002         SSVAL(*rparam,2,0);             /* converter word */
2003         SSVAL(*rparam,4,*rdata_len);
2004         *rdata_len = 0;
2005
2006         return True;
2007
2008   error_exit:
2009
2010         *rparam_len = 4;
2011         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2012         if (!*rparam) {
2013                 return False;
2014         }
2015         *rdata_len = 0;
2016         SSVAL(*rparam,0,res);
2017         SSVAL(*rparam,2,0);
2018         return True;
2019 }
2020
2021 /****************************************************************************
2022   view list of groups available
2023   ****************************************************************************/
2024
2025 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
2026                                 char *param, int tpscnt,
2027                                 char *data, int tdscnt,
2028                                 int mdrcnt,int mprcnt,
2029                                 char **rdata,char **rparam,
2030                                 int *rdata_len,int *rparam_len)
2031 {
2032         int i;
2033         int errflags=0;
2034         int resume_context, cli_buf_size;
2035         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2036         char *str2 = skip_string(param,tpscnt,str1);
2037         char *p = skip_string(param,tpscnt,str2);
2038
2039         uint32_t num_groups;
2040         uint32_t resume_handle;
2041         struct rpc_pipe_client *samr_pipe;
2042         struct policy_handle samr_handle, domain_handle;
2043         NTSTATUS status;
2044
2045         if (!str1 || !str2 || !p) {
2046                 return False;
2047         }
2048
2049         if (strcmp(str1,"WrLeh") != 0) {
2050                 return False;
2051         }
2052
2053         /* parameters  
2054          * W-> resume context (number of users to skip)
2055          * r -> return parameter pointer to receive buffer 
2056          * L -> length of receive buffer
2057          * e -> return parameter number of entries
2058          * h -> return parameter total number of users
2059          */
2060
2061         if (strcmp("B21",str2) != 0) {
2062                 return False;
2063         }
2064
2065         status = rpc_pipe_open_internal(
2066                 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2067                 conn->server_info, &samr_pipe);
2068         if (!NT_STATUS_IS_OK(status)) {
2069                 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2070                           nt_errstr(status)));
2071                 return false;
2072         }
2073
2074         status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2075                                       SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2076         if (!NT_STATUS_IS_OK(status)) {
2077                 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2078                           nt_errstr(status)));
2079                 return false;
2080         }
2081
2082         status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2083                                         SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2084                                         get_global_sam_sid(), &domain_handle);
2085         if (!NT_STATUS_IS_OK(status)) {
2086                 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2087                           nt_errstr(status)));
2088                 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2089                 return false;
2090         }
2091
2092         resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2093         cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2094         DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2095                   "%d\n", resume_context, cli_buf_size));
2096
2097         *rdata_len = cli_buf_size;
2098         *rdata = smb_realloc_limit(*rdata,*rdata_len);
2099         if (!*rdata) {
2100                 return False;
2101         }
2102
2103         p = *rdata;
2104
2105         errflags = NERR_Success;
2106         num_groups = 0;
2107         resume_handle = 0;
2108
2109         while (true) {
2110                 struct samr_SamArray *sam_entries;
2111                 uint32_t num_entries;
2112
2113                 status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
2114                                                       &domain_handle,
2115                                                       &resume_handle,
2116                                                       &sam_entries, 1,
2117                                                       &num_entries);
2118                 if (!NT_STATUS_IS_OK(status)) {
2119                         DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2120                                    "%s\n", nt_errstr(status)));
2121                         break;
2122                 }
2123
2124                 if (num_entries == 0) {
2125                         DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2126                                    "no entries -- done\n"));
2127                         break;
2128                 }
2129
2130                 for(i=0; i<num_entries; i++) {
2131                         const char *name;
2132
2133                         name = sam_entries->entries[i].name.string;
2134
2135                         if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2136                                 /* set overflow error */
2137                                 DEBUG(3,("overflow on entry %d group %s\n", i,
2138                                          name));
2139                                 errflags=234;
2140                                 break;
2141                         }
2142
2143                         /* truncate the name at 21 chars. */
2144                         memset(p, 0, 21);
2145                         strlcpy(p, name, 21);
2146                         DEBUG(10,("adding entry %d group %s\n", i, p));
2147                         p += 21;
2148                         p += 5; /* Both NT4 and W2k3SP1 do padding here.  No
2149                                  * idea why... */
2150                         num_groups += 1;
2151                 }
2152
2153                 if (errflags != NERR_Success) {
2154                         break;
2155                 }
2156
2157                 TALLOC_FREE(sam_entries);
2158         }
2159
2160         rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2161         rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2162
2163         *rdata_len = PTR_DIFF(p,*rdata);
2164
2165         *rparam_len = 8;
2166         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2167         if (!*rparam) {
2168                 return False;
2169         }
2170         SSVAL(*rparam, 0, errflags);
2171         SSVAL(*rparam, 2, 0);           /* converter word */
2172         SSVAL(*rparam, 4, num_groups);  /* is this right?? */
2173         SSVAL(*rparam, 6, resume_context+num_groups);   /* is this right?? */
2174
2175         return(True);
2176 }
2177
2178 /*******************************************************************
2179  Get groups that a user is a member of.
2180 ******************************************************************/
2181
2182 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2183                                 char *param, int tpscnt,
2184                                 char *data, int tdscnt,
2185                                 int mdrcnt,int mprcnt,
2186                                 char **rdata,char **rparam,
2187                                 int *rdata_len,int *rparam_len)
2188 {
2189         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2190         char *str2 = skip_string(param,tpscnt,str1);
2191         char *UserName = skip_string(param,tpscnt,str2);
2192         char *p = skip_string(param,tpscnt,UserName);
2193         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2194         const char *level_string;
2195         int count=0;
2196         bool ret = False;
2197         uint32_t i;
2198         char *endp = NULL;
2199
2200         struct rpc_pipe_client *samr_pipe;
2201         struct policy_handle samr_handle, domain_handle, user_handle;
2202         struct lsa_String name;
2203         struct lsa_Strings names;
2204         struct samr_Ids type, rid;
2205         struct samr_RidWithAttributeArray *rids;
2206         NTSTATUS status;
2207
2208         if (!str1 || !str2 || !UserName || !p) {
2209                 return False;
2210         }
2211
2212         *rparam_len = 8;
2213         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2214         if (!*rparam) {
2215                 return False;
2216         }
2217
2218         /* check it's a supported varient */
2219
2220         if ( strcmp(str1,"zWrLeh") != 0 )
2221                 return False;
2222
2223         switch( uLevel ) {
2224                 case 0:
2225                         level_string = "B21";
2226                         break;
2227                 default:
2228                         return False;
2229         }
2230
2231         if (strcmp(level_string,str2) != 0)
2232                 return False;
2233
2234         *rdata_len = mdrcnt + 1024;
2235         *rdata = smb_realloc_limit(*rdata,*rdata_len);
2236         if (!*rdata) {
2237                 return False;
2238         }
2239
2240         SSVAL(*rparam,0,NERR_Success);
2241         SSVAL(*rparam,2,0);             /* converter word */
2242
2243         p = *rdata;
2244         endp = *rdata + *rdata_len;
2245
2246         status = rpc_pipe_open_internal(
2247                 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2248                 conn->server_info, &samr_pipe);
2249         if (!NT_STATUS_IS_OK(status)) {
2250                 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2251                           nt_errstr(status)));
2252                 return false;
2253         }
2254
2255         status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2256                                       SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2257         if (!NT_STATUS_IS_OK(status)) {
2258                 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2259                           nt_errstr(status)));
2260                 return false;
2261         }
2262
2263         status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2264                                         SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2265                                         get_global_sam_sid(), &domain_handle);
2266         if (!NT_STATUS_IS_OK(status)) {
2267                 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2268                           nt_errstr(status)));
2269                 goto close_sam;
2270         }
2271
2272         name.string = UserName;
2273
2274         status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
2275                                          &domain_handle, 1, &name,
2276                                          &rid, &type);
2277         if (!NT_STATUS_IS_OK(status)) {
2278                 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2279                           nt_errstr(status)));
2280                 goto close_domain;
2281         }
2282
2283         if (type.ids[0] != SID_NAME_USER) {
2284                 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2285                            sid_type_lookup(type.ids[0])));
2286                 goto close_domain;
2287         }
2288
2289         status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
2290                                       &domain_handle,
2291                                       SAMR_USER_ACCESS_GET_GROUPS,
2292                                       rid.ids[0], &user_handle);
2293         if (!NT_STATUS_IS_OK(status)) {
2294                 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2295                           nt_errstr(status)));
2296                 goto close_domain;
2297         }
2298
2299         status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
2300                                               &user_handle, &rids);
2301         if (!NT_STATUS_IS_OK(status)) {
2302                 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2303                           nt_errstr(status)));
2304                 goto close_user;
2305         }
2306
2307         for (i=0; i<rids->count; i++) {
2308
2309                 status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
2310                                                 &domain_handle,
2311                                                 1, &rids->rids[i].rid,
2312                                                 &names, &type);
2313                 if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
2314                         strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2315                         p += 21;
2316                         count++;
2317                 }
2318         }
2319
2320         *rdata_len = PTR_DIFF(p,*rdata);
2321
2322         SSVAL(*rparam,4,count); /* is this right?? */
2323         SSVAL(*rparam,6,count); /* is this right?? */
2324
2325         ret = True;
2326
2327  close_user:
2328         rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
2329  close_domain:
2330         rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2331  close_sam:
2332         rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2333
2334         return ret;
2335 }
2336
2337 /*******************************************************************
2338  Get all users.
2339 ******************************************************************/
2340
2341 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2342                                 char *param, int tpscnt,
2343                                 char *data, int tdscnt,
2344                                 int mdrcnt,int mprcnt,
2345                                 char **rdata,char **rparam,
2346                                 int *rdata_len,int *rparam_len)
2347 {
2348         int count_sent=0;
2349         int num_users=0;
2350         int errflags=0;
2351         int i, resume_context, cli_buf_size;
2352         uint32_t resume_handle;
2353
2354         struct rpc_pipe_client *samr_pipe;
2355         struct policy_handle samr_handle, domain_handle;
2356         NTSTATUS status;
2357
2358         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2359         char *str2 = skip_string(param,tpscnt,str1);
2360         char *p = skip_string(param,tpscnt,str2);
2361         char *endp = NULL;
2362
2363         if (!str1 || !str2 || !p) {
2364                 return False;
2365         }
2366
2367         if (strcmp(str1,"WrLeh") != 0)
2368                 return False;
2369         /* parameters
2370           * W-> resume context (number of users to skip)
2371           * r -> return parameter pointer to receive buffer
2372           * L -> length of receive buffer
2373           * e -> return parameter number of entries
2374           * h -> return parameter total number of users
2375           */
2376
2377         resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2378         cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2379         DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2380                         resume_context, cli_buf_size));
2381
2382         *rparam_len = 8;
2383         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2384         if (!*rparam) {
2385                 return False;
2386         }
2387
2388         /* check it's a supported varient */
2389         if (strcmp("B21",str2) != 0)
2390                 return False;
2391
2392         *rdata_len = cli_buf_size;
2393         *rdata = smb_realloc_limit(*rdata,*rdata_len);
2394         if (!*rdata) {
2395                 return False;
2396         }
2397
2398         p = *rdata;
2399         endp = *rdata + *rdata_len;
2400
2401         status = rpc_pipe_open_internal(
2402                 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2403                 conn->server_info, &samr_pipe);
2404         if (!NT_STATUS_IS_OK(status)) {
2405                 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2406                           nt_errstr(status)));
2407                 return false;
2408         }
2409
2410         status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2411                                       SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2412         if (!NT_STATUS_IS_OK(status)) {
2413                 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2414                           nt_errstr(status)));
2415                 return false;
2416         }
2417
2418         status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2419                                         SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2420                                         get_global_sam_sid(), &domain_handle);
2421         if (!NT_STATUS_IS_OK(status)) {
2422                 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2423                           nt_errstr(status)));
2424                 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2425                 return false;
2426         }
2427
2428         errflags=NERR_Success;
2429
2430         resume_handle = 0;
2431
2432         while (true) {
2433                 struct samr_SamArray *sam_entries;
2434                 uint32_t num_entries;
2435
2436                 status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
2437                                                      &domain_handle,
2438                                                      &resume_handle,
2439                                                      0, &sam_entries, 1,
2440                                                      &num_entries);
2441
2442                 if (!NT_STATUS_IS_OK(status)) {
2443                         DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2444                                    "%s\n", nt_errstr(status)));
2445                         break;
2446                 }
2447
2448                 if (num_entries == 0) {
2449                         DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2450                                    "no entries -- done\n"));
2451                         break;
2452                 }
2453
2454                 for (i=0; i<num_entries; i++) {
2455                         const char *name;
2456
2457                         name = sam_entries->entries[i].name.string;
2458
2459                         if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2460                            &&(strlen(name)<=21)) {
2461                                 strlcpy(p,name,PTR_DIFF(endp,p));
2462                                 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2463                                           "username %s\n",count_sent,p));
2464                                 p += 21;
2465                                 count_sent++;
2466                         } else {
2467                                 /* set overflow error */
2468                                 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2469                                           "username %s\n",count_sent,name));
2470                                 errflags=234;
2471                                 break;
2472                         }
2473                 }
2474
2475                 if (errflags != NERR_Success) {
2476                         break;
2477                 }
2478
2479                 TALLOC_FREE(sam_entries);
2480         }
2481
2482         rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2483         rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2484
2485         *rdata_len = PTR_DIFF(p,*rdata);
2486
2487         SSVAL(*rparam,0,errflags);
2488         SSVAL(*rparam,2,0);           /* converter word */
2489         SSVAL(*rparam,4,count_sent);  /* is this right?? */
2490         SSVAL(*rparam,6,num_users); /* is this right?? */
2491
2492         return True;
2493 }
2494
2495 /****************************************************************************
2496  Get the time of day info.
2497 ****************************************************************************/
2498
2499 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2500                                 char *param, int tpscnt,
2501                                 char *data, int tdscnt,
2502                                 int mdrcnt,int mprcnt,
2503                                 char **rdata,char **rparam,
2504                                 int *rdata_len,int *rparam_len)
2505 {
2506         struct tm *t;
2507         time_t unixdate = time(NULL);
2508         char *p;
2509
2510         *rparam_len = 4;
2511         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2512         if (!*rparam) {
2513                 return False;
2514         }
2515
2516         *rdata_len = 21;
2517         *rdata = smb_realloc_limit(*rdata,*rdata_len);
2518         if (!*rdata) {
2519                 return False;
2520         }
2521
2522         SSVAL(*rparam,0,NERR_Success);
2523         SSVAL(*rparam,2,0);             /* converter word */
2524
2525         p = *rdata;
2526
2527         srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2528                                             by NT in a "net time" operation,
2529                                             it seems to ignore the one below */
2530
2531         /* the client expects to get localtime, not GMT, in this bit 
2532                 (I think, this needs testing) */
2533         t = localtime(&unixdate);
2534         if (!t) {
2535                 return False;
2536         }
2537
2538         SIVAL(p,4,0);           /* msecs ? */
2539         SCVAL(p,8,t->tm_hour);
2540         SCVAL(p,9,t->tm_min);
2541         SCVAL(p,10,t->tm_sec);
2542         SCVAL(p,11,0);          /* hundredths of seconds */
2543         SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2544         SSVAL(p,14,10000);              /* timer interval in 0.0001 of sec */
2545         SCVAL(p,16,t->tm_mday);
2546         SCVAL(p,17,t->tm_mon + 1);
2547         SSVAL(p,18,1900+t->tm_year);
2548         SCVAL(p,20,t->tm_wday);
2549
2550         return True;
2551 }
2552
2553 /****************************************************************************
2554  Set the user password.
2555 *****************************************************************************/
2556
2557 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2558                                 char *param, int tpscnt,
2559                                 char *data, int tdscnt,
2560                                 int mdrcnt,int mprcnt,
2561                                 char **rdata,char **rparam,
2562                                 int *rdata_len,int *rparam_len)
2563 {
2564         char *np = get_safe_str_ptr(param,tpscnt,param,2);
2565         char *p = NULL;
2566         fstring user;
2567         fstring pass1,pass2;
2568
2569         /* Skip 2 strings. */
2570         p = skip_string(param,tpscnt,np);
2571         p = skip_string(param,tpscnt,p);
2572
2573         if (!np || !p) {
2574                 return False;
2575         }
2576
2577         /* Do we have a string ? */
2578         if (skip_string(param,tpscnt,p) == NULL) {
2579                 return False;
2580         }
2581         pull_ascii_fstring(user,p);
2582
2583         p = skip_string(param,tpscnt,p);
2584         if (!p) {
2585                 return False;
2586         }
2587
2588         memset(pass1,'\0',sizeof(pass1));
2589         memset(pass2,'\0',sizeof(pass2));
2590         /*
2591          * We use 31 here not 32 as we're checking
2592          * the last byte we want to access is safe.
2593          */
2594         if (!is_offset_safe(param,tpscnt,p,31)) {
2595                 return False;
2596         }
2597         memcpy(pass1,p,16);
2598         memcpy(pass2,p+16,16);
2599
2600         *rparam_len = 4;
2601         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2602         if (!*rparam) {
2603                 return False;
2604         }
2605
2606         *rdata_len = 0;
2607
2608         SSVAL(*rparam,0,NERR_badpass);
2609         SSVAL(*rparam,2,0);             /* converter word */
2610
2611         DEBUG(3,("Set password for <%s>\n",user));
2612
2613         /*
2614          * Attempt to verify the old password against smbpasswd entries
2615          * Win98 clients send old and new password in plaintext for this call.
2616          */
2617
2618         {
2619                 struct auth_serversupplied_info *server_info = NULL;
2620                 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2621
2622                 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2623
2624                         become_root();
2625                         if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2626                                 SSVAL(*rparam,0,NERR_Success);
2627                         }
2628                         unbecome_root();
2629
2630                         TALLOC_FREE(server_info);
2631                 }
2632                 data_blob_clear_free(&password);
2633         }
2634
2635         /*
2636          * If the plaintext change failed, attempt
2637          * the old encrypted method. NT will generate this
2638          * after trying the samr method. Note that this
2639          * method is done as a last resort as this
2640          * password change method loses the NT password hash
2641          * and cannot change the UNIX password as no plaintext
2642          * is received.
2643          */
2644
2645         if(SVAL(*rparam,0) != NERR_Success) {
2646                 struct samu *hnd = NULL;
2647
2648                 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2649                         become_root();
2650                         if (change_lanman_password(hnd,(uchar *)pass2)) {
2651                                 SSVAL(*rparam,0,NERR_Success);
2652                         }
2653                         unbecome_root();
2654                         TALLOC_FREE(hnd);
2655                 }
2656         }
2657
2658         memset((char *)pass1,'\0',sizeof(fstring));
2659         memset((char *)pass2,'\0',sizeof(fstring));      
2660
2661         return(True);
2662 }
2663
2664 /****************************************************************************
2665   Set the user password (SamOEM version - gets plaintext).
2666 ****************************************************************************/
2667
2668 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2669                                 char *param, int tpscnt,
2670                                 char *data, int tdscnt,
2671                                 int mdrcnt,int mprcnt,
2672                                 char **rdata,char **rparam,
2673                                 int *rdata_len,int *rparam_len)
2674 {
2675         struct smbd_server_connection *sconn = smbd_server_conn;
2676         fstring user;
2677         char *p = get_safe_str_ptr(param,tpscnt,param,2);
2678         *rparam_len = 2;
2679         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2680         if (!*rparam) {
2681                 return False;
2682         }
2683
2684         if (!p) {
2685                 return False;
2686         }
2687         *rdata_len = 0;
2688
2689         SSVAL(*rparam,0,NERR_badpass);
2690
2691         /*
2692          * Check the parameter definition is correct.
2693          */
2694
2695         /* Do we have a string ? */
2696         if (skip_string(param,tpscnt,p) == 0) {
2697                 return False;
2698         }
2699         if(!strequal(p, "zsT")) {
2700                 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2701                 return False;
2702         }
2703         p = skip_string(param, tpscnt, p);
2704         if (!p) {
2705                 return False;
2706         }
2707
2708         /* Do we have a string ? */
2709         if (skip_string(param,tpscnt,p) == 0) {
2710                 return False;
2711         }
2712         if(!strequal(p, "B516B16")) {
2713                 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2714                 return False;
2715         }
2716         p = skip_string(param,tpscnt,p);
2717         if (!p) {
2718                 return False;
2719         }
2720         /* Do we have a string ? */
2721         if (skip_string(param,tpscnt,p) == 0) {
2722                 return False;
2723         }
2724         p += pull_ascii_fstring(user,p);
2725
2726         DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2727
2728         /*
2729          * Pass the user through the NT -> unix user mapping
2730          * function.
2731          */
2732
2733         (void)map_username(sconn, user);
2734
2735         if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2736                 SSVAL(*rparam,0,NERR_Success);
2737         }
2738
2739         return(True);
2740 }
2741
2742 /****************************************************************************
2743   delete a print job
2744   Form: <W> <> 
2745   ****************************************************************************/
2746
2747 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
2748                                 char *param, int tpscnt,
2749                                 char *data, int tdscnt,
2750                                 int mdrcnt,int mprcnt,
2751                                 char **rdata,char **rparam,
2752                                 int *rdata_len,int *rparam_len)
2753 {
2754         int function = get_safe_SVAL(param,tpscnt,param,0,0);
2755         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2756         char *str2 = skip_string(param,tpscnt,str1);
2757         char *p = skip_string(param,tpscnt,str2);
2758         uint32 jobid;
2759         int snum;
2760         fstring sharename;
2761         int errcode;
2762         WERROR werr = WERR_OK;
2763
2764         if (!str1 || !str2 || !p) {
2765                 return False;
2766         }
2767         /*
2768          * We use 1 here not 2 as we're checking
2769          * the last byte we want to access is safe.
2770          */
2771         if (!is_offset_safe(param,tpscnt,p,1)) {
2772                 return False;
2773         }
2774         if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2775                 return False;
2776
2777         /* check it's a supported varient */
2778         if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2779                 return(False);
2780
2781         *rparam_len = 4;
2782         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2783         if (!*rparam) {
2784                 return False;
2785         }
2786         *rdata_len = 0;
2787
2788         if (!print_job_exists(sharename, jobid)) {
2789                 errcode = NERR_JobNotFound;
2790                 goto out;
2791         }
2792
2793         snum = lp_servicenumber( sharename);
2794         if (snum == -1) {
2795                 errcode = NERR_DestNotFound;
2796                 goto out;
2797         }
2798
2799         errcode = NERR_notsupported;
2800
2801         switch (function) {
2802         case 81:                /* delete */ 
2803                 if (print_job_delete(conn->server_info, snum, jobid, &werr))
2804                         errcode = NERR_Success;
2805                 break;
2806         case 82:                /* pause */
2807                 if (print_job_pause(conn->server_info, snum, jobid, &werr))
2808                         errcode = NERR_Success;
2809                 break;
2810         case 83:                /* resume */
2811                 if (print_job_resume(conn->server_info, snum, jobid, &werr))
2812                         errcode = NERR_Success;
2813                 break;
2814         }
2815
2816         if (!W_ERROR_IS_OK(werr))
2817                 errcode = W_ERROR_V(werr);
2818
2819  out:
2820         SSVAL(*rparam,0,errcode);       
2821         SSVAL(*rparam,2,0);             /* converter word */
2822
2823         return(True);
2824 }
2825
2826 /****************************************************************************
2827   Purge a print queue - or pause or resume it.
2828   ****************************************************************************/
2829
2830 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
2831                                 char *param, int tpscnt,
2832                                 char *data, int tdscnt,
2833                                 int mdrcnt,int mprcnt,
2834                                 char **rdata,char **rparam,
2835                                 int *rdata_len,int *rparam_len)
2836 {
2837         int function = get_safe_SVAL(param,tpscnt,param,0,0);
2838         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2839         char *str2 = skip_string(param,tpscnt,str1);
2840         char *QueueName = skip_string(param,tpscnt,str2);
2841         int errcode = NERR_notsupported;
2842         int snum;
2843         WERROR werr = WERR_OK;
2844
2845         if (!str1 || !str2 || !QueueName) {
2846                 return False;
2847         }
2848
2849         /* check it's a supported varient */
2850         if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
2851                 return(False);
2852
2853         *rparam_len = 4;
2854         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2855         if (!*rparam) {
2856                 return False;
2857         }
2858         *rdata_len = 0;
2859
2860         if (skip_string(param,tpscnt,QueueName) == NULL) {
2861                 return False;
2862         }
2863         snum = print_queue_snum(QueueName);
2864
2865         if (snum == -1) {
2866                 errcode = NERR_JobNotFound;
2867                 goto out;
2868         }
2869
2870         switch (function) {
2871         case 74: /* Pause queue */
2872                 werr = print_queue_pause(conn->server_info, snum);
2873                 break;
2874         case 75: /* Resume queue */
2875                 werr = print_queue_resume(conn->server_info, snum);
2876                 break;
2877         case 103: /* Purge */
2878                 werr = print_queue_purge(conn->server_info, snum);
2879                 break;
2880         default:
2881                 werr = WERR_NOT_SUPPORTED;
2882                 break;
2883         }
2884
2885         errcode = W_ERROR_V(werr);
2886
2887  out:
2888         SSVAL(*rparam,0,errcode);
2889         SSVAL(*rparam,2,0);             /* converter word */
2890
2891         return(True);
2892 }
2893
2894 /****************************************************************************
2895   set the property of a print job (undocumented?)
2896   ? function = 0xb -> set name of print job
2897   ? function = 0x6 -> move print job up/down
2898   Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz> 
2899   or   <WWsTP> <WB21BB16B10zWWzDDz> 
2900 ****************************************************************************/
2901
2902 static int check_printjob_info(struct pack_desc* desc,
2903                                int uLevel, char* id)
2904 {
2905         desc->subformat = NULL;
2906         switch( uLevel ) {
2907         case 0: desc->format = "W"; break;
2908         case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2909         case 2: desc->format = "WWzWWDDzz"; break;
2910         case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2911         case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2912         default:
2913                 DEBUG(0,("check_printjob_info: invalid level %d\n",
2914                         uLevel ));
2915                 return False;
2916         }
2917         if (id == NULL || strcmp(desc->format,id) != 0) {
2918                 DEBUG(0,("check_printjob_info: invalid format %s\n",
2919                         id ? id : "<NULL>" ));
2920                 return False;
2921         }
2922         return True;
2923 }
2924
2925 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
2926                                 char *param, int tpscnt,
2927                                 char *data, int tdscnt,
2928                                 int mdrcnt,int mprcnt,
2929                                 char **rdata,char **rparam,
2930                                 int *rdata_len,int *rparam_len)
2931 {
2932         struct pack_desc desc;
2933         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2934         char *str2 = skip_string(param,tpscnt,str1);
2935         char *p = skip_string(param,tpscnt,str2);
2936         uint32 jobid;
2937         fstring sharename;
2938         int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
2939         int function = get_safe_SVAL(param,tpscnt,p,4,-1);
2940         int place, errcode;
2941
2942         if (!str1 || !str2 || !p) {
2943                 return False;
2944         }
2945         /*
2946          * We use 1 here not 2 as we're checking
2947          * the last byte we want to access is safe.
2948          */
2949         if (!is_offset_safe(param,tpscnt,p,1)) {
2950                 return False;
2951         }
2952         if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2953                 return False;
2954         *rparam_len = 4;
2955         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2956         if (!*rparam) {
2957                 return False;
2958         }
2959
2960         if (!share_defined(sharename)) {
2961                 DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
2962                          sharename));
2963                 return False;
2964         }
2965
2966         *rdata_len = 0;
2967
2968         /* check it's a supported varient */
2969         if ((strcmp(str1,"WWsTP")) || 
2970             (!check_printjob_info(&desc,uLevel,str2)))
2971                 return(False);
2972
2973         if (!print_job_exists(sharename, jobid)) {
2974                 errcode=NERR_JobNotFound;
2975                 goto out;
2976         }
2977
2978         errcode = NERR_notsupported;
2979
2980         switch (function) {
2981         case 0x6:
2982                 /* change job place in the queue, 
2983                    data gives the new place */
2984                 place = SVAL(data,0);
2985                 if (print_job_set_place(sharename, jobid, place)) {
2986                         errcode=NERR_Success;
2987                 }
2988                 break;
2989
2990         case 0xb:   
2991                 /* change print job name, data gives the name */
2992                 if (print_job_set_name(sharename, jobid, data)) {
2993                         errcode=NERR_Success;
2994                 }
2995                 break;
2996
2997         default:
2998                 return False;
2999         }
3000
3001  out:
3002         SSVALS(*rparam,0,errcode);
3003         SSVAL(*rparam,2,0);             /* converter word */
3004
3005         return(True);
3006 }
3007
3008
3009 /****************************************************************************
3010  Get info about the server.
3011 ****************************************************************************/
3012
3013 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
3014                                 char *param, int tpscnt,
3015                                 char *data, int tdscnt,
3016                                 int mdrcnt,int mprcnt,
3017                                 char **rdata,char **rparam,
3018                                 int *rdata_len,int *rparam_len)
3019 {
3020         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3021         char *str2 = skip_string(param,tpscnt,str1);
3022         char *p = skip_string(param,tpscnt,str2);
3023         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3024         char *p2;
3025         int struct_len;
3026
3027         if (!str1 || !str2 || !p) {
3028                 return False;
3029         }
3030
3031         DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3032
3033         /* check it's a supported varient */
3034         if (!prefix_ok(str1,"WrLh")) {
3035                 return False;
3036         }
3037
3038         switch( uLevel ) {
3039                 case 0:
3040                         if (strcmp(str2,"B16") != 0) {
3041                                 return False;
3042                         }
3043                         struct_len = 16;
3044                         break;
3045                 case 1:
3046                         if (strcmp(str2,"B16BBDz") != 0) {
3047                                 return False;
3048                         }
3049                         struct_len = 26;
3050                         break;
3051                 case 2:
3052                         if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3053                                 return False;
3054                         }
3055                         struct_len = 134;
3056                         break;
3057                 case 3:
3058                         if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3059                                 return False;
3060                         }
3061                         struct_len = 144;
3062                         break;
3063                 case 20:
3064                         if (strcmp(str2,"DN") != 0) {
3065                                 return False;
3066                         }
3067                         struct_len = 6;
3068                         break;
3069                 case 50:
3070                         if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3071                                 return False;
3072                         }
3073                         struct_len = 42;
3074                         break;
3075                 default:
3076                         return False;
3077         }
3078
3079         *rdata_len = mdrcnt;
3080         *rdata = smb_realloc_limit(*rdata,*rdata_len);
3081         if (!*rdata) {
3082                 return False;
3083         }
3084
3085         p = *rdata;
3086         p2 = p + struct_len;
3087         if (uLevel != 20) {
3088                 srvstr_push(NULL, 0, p,global_myname(),16,
3089                         STR_ASCII|STR_UPPER|STR_TERMINATE);
3090         }
3091         p += 16;
3092         if (uLevel > 0) {
3093                 struct srv_info_struct *servers=NULL;
3094                 int i,count;
3095                 char *comment = NULL;
3096                 TALLOC_CTX *ctx = talloc_tos();
3097                 uint32 servertype= lp_default_server_announce();
3098
3099                 comment = talloc_strdup(ctx,lp_serverstring());
3100                 if (!comment) {
3101                         return false;
3102                 }
3103
3104                 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
3105                         for (i=0;i<count;i++) {
3106                                 if (strequal(servers[i].name,global_myname())) {
3107                                         servertype = servers[i].type;
3108                                         TALLOC_FREE(comment);
3109                                         comment = talloc_strdup(ctx,
3110                                                         servers[i].comment);
3111                                         if (comment) {
3112                                                 return false;
3113                                         }
3114                                 }
3115                         }
3116                 }
3117
3118                 SAFE_FREE(servers);
3119
3120                 SCVAL(p,0,lp_major_announce_version());
3121                 SCVAL(p,1,lp_minor_announce_version());
3122                 SIVAL(p,2,servertype);
3123
3124                 if (mdrcnt == struct_len) {
3125                         SIVAL(p,6,0);
3126                 } else {
3127                         SIVAL(p,6,PTR_DIFF(p2,*rdata));
3128                         comment = talloc_sub_advanced(
3129                                 ctx,
3130                                 lp_servicename(SNUM(conn)),
3131                                 conn->server_info->unix_name,
3132                                 conn->connectpath,
3133                                 conn->server_info->utok.gid,
3134                                 conn->server_info->sanitized_username,
3135                                 pdb_get_domain(conn->server_info->sam_account),
3136                                 comment);
3137                         if (comment) {
3138                                 return false;
3139                         }
3140                         if (mdrcnt - struct_len <= 0) {
3141                                 return false;
3142                         }
3143                         push_ascii(p2,
3144                                 comment,
3145                                 MIN(mdrcnt - struct_len,
3146                                         MAX_SERVER_STRING_LENGTH),
3147                                 STR_TERMINATE);
3148                         p2 = skip_string(*rdata,*rdata_len,p2);
3149                         if (!p2) {
3150                                 return False;
3151                         }
3152                 }
3153         }
3154
3155         if (uLevel > 1) {
3156                 return False;           /* not yet implemented */
3157         }
3158
3159         *rdata_len = PTR_DIFF(p2,*rdata);
3160
3161         *rparam_len = 6;
3162         *rparam = smb_realloc_limit(*rparam,*rparam_len);
3163         if (!*rparam) {
3164                 return False;
3165         }
3166         SSVAL(*rparam,0,NERR_Success);
3167         SSVAL(*rparam,2,0);             /* converter word */
3168         SSVAL(*rparam,4,*rdata_len);
3169
3170         return True;
3171 }
3172
3173 /****************************************************************************
3174  Get info about the server.
3175 ****************************************************************************/
3176
3177 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3178                                 char *param, int tpscnt,
3179                                 char *data, int tdscnt,
3180                                 int mdrcnt,int mprcnt,
3181                                 char **rdata,char **rparam,
3182                                 int *rdata_len,int *rparam_len)
3183 {
3184         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3185         char *str2 = skip_string(param,tpscnt,str1);
3186         char *p = skip_string(param,tpscnt,str2);
3187         char *p2;
3188         char *endp;
3189         int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3190
3191         if (!str1 || !str2 || !p) {
3192                 return False;
3193         }
3194
3195         DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3196
3197         *rparam_len = 6;
3198         *rparam = smb_realloc_limit(*rparam,*rparam_len);
3199         if (!*rparam) {
3200                 return False;
3201         }
3202
3203         /* check it's a supported varient */
3204         if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3205                 return False;
3206         }
3207
3208         *rdata_len = mdrcnt + 1024;
3209         *rdata = smb_realloc_limit(*rdata,*rdata_len);
3210         if (!*rdata) {
3211                 return False;
3212         }
3213
3214         SSVAL(*rparam,0,NERR_Success);
3215         SSVAL(*rparam,2,0);             /* converter word */
3216
3217         p = *rdata;
3218         endp = *rdata + *rdata_len;
3219
3220         p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3221         if (!p2) {
3222                 return False;
3223         }
3224
3225         SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3226         strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3227         strupper_m(p2);
3228         p2 = skip_string(*rdata,*rdata_len,p2);
3229         if (!p2) {
3230                 return False;
3231         }
3232         p += 4;
3233
3234         SIVAL(p,0,PTR_DIFF(p2,*rdata));
3235         strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3236         p2 = skip_string(*rdata,*rdata_len,p2);
3237         if (!p2) {
3238                 return False;
3239         }
3240         p += 4;
3241
3242         SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3243         strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3244         strupper_m(p2);
3245         p2 = skip_string(*rdata,*rdata_len,p2);
3246         if (!p2) {
3247                 return False;
3248         }
3249         p += 4;
3250
3251         SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3252         SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3253         p += 2;
3254
3255         SIVAL(p,0,PTR_DIFF(p2,*rdata));
3256         strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));   /* don't know.  login domain?? */
3257         p2 = skip_string(*rdata,*rdata_len,p2);
3258         if (!p2) {
3259                 return False;
3260         }
3261         p += 4;
3262
3263         SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3264         strlcpy(p2,"",PTR_DIFF(endp,p2));
3265         p2 = skip_string(*rdata,*rdata_len,p2);
3266         if (!p2) {
3267                 return False;
3268         }
3269         p += 4;
3270
3271         *rdata_len = PTR_DIFF(p2,*rdata);
3272
3273         SSVAL(*rparam,4,*rdata_len);
3274
3275         return True;
3276 }
3277
3278 /****************************************************************************
3279   get info about a user
3280
3281     struct user_info_11 {
3282         char                usri11_name[21];  0-20 
3283         char                usri11_pad;       21 
3284         char                *usri11_comment;  22-25 
3285         char            *usri11_usr_comment;  26-29
3286         unsigned short      usri11_priv;      30-31
3287         unsigned long       usri11_auth_flags; 32-35
3288         long                usri11_password_age; 36-39
3289         char                *usri11_homedir; 40-43
3290         char            *usri11_parms; 44-47
3291         long                usri11_last_logon; 48-51
3292         long                usri11_last_logoff; 52-55
3293         unsigned short      usri11_bad_pw_count; 56-57
3294         unsigned short      usri11_num_logons; 58-59
3295         char                *usri11_logon_server; 60-63
3296         unsigned short      usri11_country_code; 64-65
3297         char            *usri11_workstations; 66-69
3298         unsigned long       usri11_max_storage; 70-73
3299         unsigned short      usri11_units_per_week; 74-75
3300         unsigned char       *usri11_logon_hours; 76-79
3301         unsigned short      usri11_code_page; 80-81
3302     };
3303
3304 where:
3305
3306   usri11_name specifies the user name for which information is retrieved
3307
3308   usri11_pad aligns the next data structure element to a word boundary
3309
3310   usri11_comment is a null terminated ASCII comment
3311
3312   usri11_user_comment is a null terminated ASCII comment about the user
3313
3314   usri11_priv specifies the level of the privilege assigned to the user.
3315        The possible values are:
3316
3317 Name             Value  Description
3318 USER_PRIV_GUEST  0      Guest privilege
3319 USER_PRIV_USER   1      User privilege
3320 USER_PRV_ADMIN   2      Administrator privilege
3321
3322   usri11_auth_flags specifies the account operator privileges. The
3323        possible values are:
3324
3325 Name            Value   Description
3326 AF_OP_PRINT     0       Print operator
3327
3328
3329 Leach, Naik                                        [Page 28]
3330 \f
3331
3332
3333 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
3334
3335
3336 AF_OP_COMM      1       Communications operator
3337 AF_OP_SERVER    2       Server operator
3338 AF_OP_ACCOUNTS  3       Accounts operator
3339
3340
3341   usri11_password_age specifies how many seconds have elapsed since the
3342        password was last changed.
3343
3344   usri11_home_dir points to a null terminated ASCII string that contains
3345        the path name of the user's home directory.
3346
3347   usri11_parms points to a null terminated ASCII string that is set
3348        aside for use by applications.
3349
3350   usri11_last_logon specifies the time when the user last logged on.
3351        This value is stored as the number of seconds elapsed since
3352        00:00:00, January 1, 1970.
3353
3354   usri11_last_logoff specifies the time when the user last logged off.
3355        This value is stored as the number of seconds elapsed since
3356        00:00:00, January 1, 1970. A value of 0 means the last logoff
3357        time is unknown.
3358
3359   usri11_bad_pw_count specifies the number of incorrect passwords
3360        entered since the last successful logon.
3361
3362   usri11_log1_num_logons specifies the number of times this user has
3363        logged on. A value of -1 means the number of logons is unknown.
3364
3365   usri11_logon_server points to a null terminated ASCII string that
3366        contains the name of the server to which logon requests are sent.
3367        A null string indicates logon requests should be sent to the
3368        domain controller.
3369
3370   usri11_country_code specifies the country code for the user's language
3371        of choice.
3372
3373   usri11_workstations points to a null terminated ASCII string that
3374        contains the names of workstations the user may log on from.
3375        There may be up to 8 workstations, with the names separated by
3376        commas. A null strings indicates there are no restrictions.
3377
3378   usri11_max_storage specifies the maximum amount of disk space the user
3379        can occupy. A value of 0xffffffff indicates there are no
3380        restrictions.
3381
3382   usri11_units_per_week specifies the equal number of time units into
3383        which a week is divided. This value must be equal to 168.
3384
3385   usri11_logon_hours points to a 21 byte (168 bits) string that
3386        specifies the time during which the user can log on. Each bit
3387        represents one unique hour in a week. The first bit (bit 0, word
3388        0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3389
3390
3391
3392 Leach, Naik                                        [Page 29]
3393 \f
3394
3395
3396 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
3397
3398
3399        Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3400        are no restrictions.
3401
3402   usri11_code_page specifies the code page for the user's language of
3403        choice
3404
3405 All of the pointers in this data structure need to be treated
3406 specially. The  pointer is a 32 bit pointer. The higher 16 bits need
3407 to be ignored. The converter word returned in the parameters section
3408 needs to be subtracted from the lower 16 bits to calculate an offset
3409 into the return buffer where this ASCII string resides.
3410
3411 There is no auxiliary data in the response.
3412
3413   ****************************************************************************/
3414
3415 #define usri11_name           0 
3416 #define usri11_pad            21
3417 #define usri11_comment        22
3418 #define usri11_usr_comment    26
3419 #define usri11_full_name      30
3420 #define usri11_priv           34
3421 #define usri11_auth_flags     36
3422 #define usri11_password_age   40
3423 #define usri11_homedir        44
3424 #define usri11_parms          48
3425 #define usri11_last_logon     52
3426 #define usri11_last_logoff    56
3427 #define usri11_bad_pw_count   60
3428 #define usri11_num_logons     62
3429 #define usri11_logon_server   64
3430 #define usri11_country_code   68
3431 #define usri11_workstations   70
3432 #define usri11_max_storage    74
3433 #define usri11_units_per_week 78
3434 #define usri11_logon_hours    80
3435 #define usri11_code_page      84
3436 #define usri11_end            86
3437
3438 #define USER_PRIV_GUEST 0
3439 #define USER_PRIV_USER 1
3440 #define USER_PRIV_ADMIN 2
3441
3442 #define AF_OP_PRINT     0 
3443 #define AF_OP_COMM      1
3444 #define AF_OP_SERVER    2
3445 #define AF_OP_ACCOUNTS  3
3446
3447
3448 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3449                                 char *param, int tpscnt,
3450                                 char *data, int tdscnt,
3451                                 int mdrcnt,int mprcnt,
3452                                 char **rdata,char **rparam,
3453                                 int *rdata_len,int *rparam_len)
3454 {
3455         struct smbd_server_connection *sconn = smbd_server_conn;
3456         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3457         char *str2 = skip_string(param,tpscnt,str1);
3458         char *UserName = skip_string(param,tpscnt,str2);
3459         char *p = skip_string(param,tpscnt,UserName);
3460         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3461         char *p2;
3462         char *endp;
3463         const char *level_string;
3464
3465         /* get NIS home of a previously validated user - simeon */
3466         /* With share level security vuid will always be zero.
3467            Don't depend on vuser being non-null !!. JRA */
3468         user_struct *vuser = get_valid_user_struct(sconn, vuid);
3469         if(vuser != NULL) {
3470                 DEBUG(3,("  Username of UID %d is %s\n",
3471                          (int)vuser->server_info->utok.uid,
3472                          vuser->server_info->unix_name));
3473         }
3474
3475         if (!str1 || !str2 || !UserName || !p) {
3476                 return False;
3477         }
3478
3479         *rparam_len = 6;
3480         *rparam = smb_realloc_limit(*rparam,*rparam_len);
3481         if (!*rparam) {
3482                 return False;
3483         }
3484
3485         DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3486
3487         /* check it's a supported variant */
3488         if (strcmp(str1,"zWrLh") != 0) {
3489                 return False;
3490         }
3491         switch( uLevel ) {
3492                 case 0: level_string = "B21"; break;
3493                 case 1: level_string = "B21BB16DWzzWz"; break;
3494                 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3495                 case 10: level_string = "B21Bzzz"; break;
3496                 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3497                 default: return False;
3498         }
3499
3500         if (strcmp(level_string,str2) != 0) {
3501                 return False;
3502         }
3503
3504         *rdata_len = mdrcnt + 1024;
3505         *rdata = smb_realloc_limit(*rdata,*rdata_len);
3506         if (!*rdata) {
3507                 return False;
3508         }
3509
3510         SSVAL(*rparam,0,NERR_Success);
3511         SSVAL(*rparam,2,0);             /* converter word */
3512
3513         p = *rdata;
3514         endp = *rdata + *rdata_len;
3515         p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3516         if (!p2) {
3517                 return False;
3518         }
3519
3520         memset(p,0,21);
3521         fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3522
3523         if (uLevel > 0) {
3524                 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3525                 *p2 = 0;
3526         }
3527
3528         if (uLevel >= 10) {
3529                 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3530                 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
3531                 p2 = skip_string(*rdata,*rdata_len,p2);
3532                 if (!p2) {
3533                         return False;
3534                 }
3535
3536                 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3537                 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
3538                 p2 = skip_string(*rdata,*rdata_len,p2);
3539                 if (!p2) {
3540                         return False;
3541                 }
3542
3543                 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3544                 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3545                 strlcpy(p2,((vuser != NULL)
3546                             ? pdb_get_fullname(vuser->server_info->sam_account)
3547                             : UserName),PTR_DIFF(endp,p2));
3548                 p2 = skip_string(*rdata,*rdata_len,p2);
3549                 if (!p2) {
3550                         return False;
3551                 }
3552         }
3553
3554         if (uLevel == 11) {
3555                 const char *homedir = "";
3556                 if (vuser != NULL) {
3557                         homedir = pdb_get_homedir(
3558                                 vuser->server_info->sam_account);
3559                 }
3560                 /* modelled after NTAS 3.51 reply */
3561                 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); 
3562                 SIVAL(p,usri11_auth_flags,AF_OP_PRINT);         /* auth flags */
3563                 SIVALS(p,usri11_password_age,-1);               /* password age */
3564                 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3565                 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
3566                 p2 = skip_string(*rdata,*rdata_len,p2);
3567                 if (!p2) {
3568                         return False;
3569                 }
3570                 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3571                 strlcpy(p2,"",PTR_DIFF(endp,p2));
3572                 p2 = skip_string(*rdata,*rdata_len,p2);
3573                 if (!p2) {
3574                         return False;
3575                 }
3576                 SIVAL(p,usri11_last_logon,0);           /* last logon */
3577                 SIVAL(p,usri11_last_logoff,0);          /* last logoff */
3578                 SSVALS(p,usri11_bad_pw_count,-1);       /* bad pw counts */
3579                 SSVALS(p,usri11_num_logons,-1);         /* num logons */
3580                 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3581                 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
3582                 p2 = skip_string(*rdata,*rdata_len,p2);
3583                 if (!p2) {
3584                         return False;
3585                 }
3586                 SSVAL(p,usri11_country_code,0);         /* country code */
3587
3588                 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3589                 strlcpy(p2,"",PTR_DIFF(endp,p2));
3590                 p2 = skip_string(*rdata,*rdata_len,p2);
3591                 if (!p2) {
3592                         return False;
3593                 }
3594
3595                 SIVALS(p,usri11_max_storage,-1);                /* max storage */
3596                 SSVAL(p,usri11_units_per_week,168);             /* units per week */
3597                 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
3598
3599                 /* a simple way to get logon hours at all times. */
3600                 memset(p2,0xff,21);
3601                 SCVAL(p2,21,0);           /* fix zero termination */
3602                 p2 = skip_string(*rdata,*rdata_len,p2);
3603                 if (!p2) {
3604                         return False;
3605                 }
3606
3607                 SSVAL(p,usri11_code_page,0);            /* code page */
3608         }
3609
3610         if (uLevel == 1 || uLevel == 2) {
3611                 memset(p+22,' ',16);    /* password */
3612                 SIVALS(p,38,-1);                /* password age */
3613                 SSVAL(p,42,
3614                 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3615                 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
3616                 strlcpy(p2, vuser ? pdb_get_homedir(
3617                                 vuser->server_info->sam_account) : "",
3618                         PTR_DIFF(endp,p2));
3619                 p2 = skip_string(*rdata,*rdata_len,p2);
3620                 if (!p2) {
3621                         return False;
3622                 }
3623                 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
3624                 *p2++ = 0;
3625                 SSVAL(p,52,0);          /* flags */
3626                 SIVAL(p,54,PTR_DIFF(p2,*rdata));                /* script_path */
3627                 strlcpy(p2, vuser ? pdb_get_logon_script(
3628                                 vuser->server_info->sam_account) : "",
3629                         PTR_DIFF(endp,p2));
3630                 p2 = skip_string(*rdata,*rdata_len,p2);
3631                 if (!p2) {
3632                         return False;
3633                 }
3634                 if (uLevel == 2) {
3635                         SIVAL(p,60,0);          /* auth_flags */
3636                         SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
3637                         strlcpy(p2,((vuser != NULL)
3638                                     ? pdb_get_fullname(vuser->server_info->sam_account)
3639                                     : UserName),PTR_DIFF(endp,p2));
3640                         p2 = skip_string(*rdata,*rdata_len,p2);
3641                         if (!p2) {
3642                                 return False;
3643                         }
3644                         SIVAL(p,68,0);          /* urs_comment */
3645                         SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
3646                         strlcpy(p2,"",PTR_DIFF(endp,p2));
3647                         p2 = skip_string(*rdata,*rdata_len,p2);
3648                         if (!p2) {
3649                                 return False;
3650                         }
3651                         SIVAL(p,76,0);          /* workstations */
3652                         SIVAL(p,80,0);          /* last_logon */
3653                         SIVAL(p,84,0);          /* last_logoff */
3654                         SIVALS(p,88,-1);                /* acct_expires */
3655                         SIVALS(p,92,-1);                /* max_storage */
3656                         SSVAL(p,96,168);        /* units_per_week */
3657                         SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
3658                         memset(p2,-1,21);
3659                         p2 += 21;
3660                         SSVALS(p,102,-1);       /* bad_pw_count */
3661                         SSVALS(p,104,-1);       /* num_logons */
3662                         SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
3663                         {
3664                                 TALLOC_CTX *ctx = talloc_tos();
3665                                 int space_rem = *rdata_len - (p2 - *rdata);
3666                                 char *tmp;
3667
3668                                 if (space_rem <= 0) {
3669                                         return false;
3670                                 }
3671                                 tmp = talloc_strdup(ctx, "\\\\%L");
3672                                 if (!tmp) {
3673                                         return false;
3674                                 }
3675                                 tmp = talloc_sub_basic(ctx,
3676                                                 "",
3677                                                 "",
3678                                                 tmp);
3679                                 if (!tmp) {
3680                                         return false;
3681                                 }
3682
3683                                 push_ascii(p2,
3684                                         tmp,
3685                                         space_rem,
3686                                         STR_TERMINATE);
3687                         }
3688                         p2 = skip_string(*rdata,*rdata_len,p2);
3689                         if (!p2) {
3690                                 return False;
3691                         }
3692                         SSVAL(p,110,49);        /* country_code */
3693                         SSVAL(p,112,860);       /* code page */
3694                 }
3695         }
3696
3697         *rdata_len = PTR_DIFF(p2,*rdata);
3698
3699         SSVAL(*rparam,4,*rdata_len);    /* is this right?? */
3700
3701         return(True);
3702 }
3703
3704 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
3705                                 char *param, int tpscnt,
3706                                 char *data, int tdscnt,
3707                                 int mdrcnt,int mprcnt,
3708                                 char **rdata,char **rparam,
3709                                 int *rdata_len,int *rparam_len)
3710 {
3711         struct smbd_server_connection *sconn = smbd_server_conn;
3712         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3713         char *str2 = skip_string(param,tpscnt,str1);
3714         char *p = skip_string(param,tpscnt,str2);
3715         int uLevel;
3716         struct pack_desc desc;
3717         char* name;
3718                 /* With share level security vuid will always be zero.
3719                    Don't depend on vuser being non-null !!. JRA */
3720         user_struct *vuser = get_valid_user_struct(sconn, vuid);
3721
3722         if (!str1 || !str2 || !p) {
3723                 return False;
3724         }
3725
3726         if(vuser != NULL) {
3727                 DEBUG(3,("  Username of UID %d is %s\n",
3728                          (int)vuser->server_info->utok.uid,
3729                          vuser->server_info->unix_name));
3730         }
3731
3732         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3733         name = get_safe_str_ptr(param,tpscnt,p,2);
3734         if (!name) {
3735                 return False;
3736         }
3737
3738         memset((char *)&desc,'\0',sizeof(desc));
3739
3740         DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
3741
3742         /* check it's a supported varient */
3743         if (strcmp(str1,"OOWb54WrLh") != 0) {
3744                 return False;
3745         }
3746         if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
3747                 return False;
3748         }
3749         if (mdrcnt > 0) {
3750                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3751                 if (!*rdata) {
3752                         return False;
3753                 }
3754         }
3755
3756         desc.base = *rdata;
3757         desc.buflen = mdrcnt;
3758         desc.subformat = NULL;
3759         desc.format = str2;
3760
3761         if (init_package(&desc,1,0)) {
3762                 PACKI(&desc,"W",0);             /* code */
3763                 PACKS(&desc,"B21",name);        /* eff. name */
3764                 PACKS(&desc,"B","");            /* pad */
3765                 PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3766                 PACKI(&desc,"D",0);             /* auth flags XXX */
3767                 PACKI(&desc,"W",0);             /* num logons */
3768                 PACKI(&desc,"W",0);             /* bad pw count */
3769                 PACKI(&desc,"D",0);             /* last logon */
3770                 PACKI(&desc,"D",-1);            /* last logoff */
3771                 PACKI(&desc,"D",-1);            /* logoff time */
3772                 PACKI(&desc,"D",-1);            /* kickoff time */
3773                 PACKI(&desc,"D",0);             /* password age */
3774                 PACKI(&desc,"D",0);             /* password can change */
3775                 PACKI(&desc,"D",-1);            /* password must change */
3776
3777                 {
3778                         fstring mypath;
3779                         fstrcpy(mypath,"\\\\");
3780                         fstrcat(mypath,get_local_machine_name());
3781                         strupper_m(mypath);
3782                         PACKS(&desc,"z",mypath); /* computer */
3783                 }
3784
3785                 PACKS(&desc,"z",lp_workgroup());/* domain */
3786                 PACKS(&desc,"z", vuser ? pdb_get_logon_script(
3787                               vuser->server_info->sam_account) : ""); /* script path */
3788                 PACKI(&desc,"D",0x00000000);            /* reserved */
3789         }
3790
3791         *rdata_len = desc.usedlen;
3792         *rparam_len = 6;
3793         *rparam = smb_realloc_limit(*rparam,*rparam_len);
3794         if (!*rparam) {
3795                 return False;
3796         }
3797         SSVALS(*rparam,0,desc.errcode);
3798         SSVAL(*rparam,2,0);
3799         SSVAL(*rparam,4,desc.neededlen);
3800
3801         DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
3802
3803         return True;
3804 }
3805
3806 /****************************************************************************
3807  api_WAccessGetUserPerms
3808 ****************************************************************************/
3809
3810 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
3811                                 char *param, int tpscnt,
3812                                 char *data, int tdscnt,
3813                                 int mdrcnt,int mprcnt,
3814                                 char **rdata,char **rparam,
3815                                 int *rdata_len,int *rparam_len)
3816 {
3817         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3818         char *str2 = skip_string(param,tpscnt,str1);
3819         char *user = skip_string(param,tpscnt,str2);
3820         char *resource = skip_string(param,tpscnt,user);
3821
3822         if (!str1 || !str2 || !user || !resource) {
3823                 return False;
3824         }
3825
3826         if (skip_string(param,tpscnt,resource) == NULL) {
3827                 return False;
3828         }
3829         DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
3830
3831         /* check it's a supported varient */
3832         if (strcmp(str1,"zzh") != 0) {
3833                 return False;
3834         }
3835         if (strcmp(str2,"") != 0) {
3836                 return False;
3837         }
3838
3839         *rparam_len = 6;
3840         *rparam = smb_realloc_limit(*rparam,*rparam_len);
3841         if (!*rparam) {
3842                 return False;
3843         }
3844         SSVALS(*rparam,0,0);            /* errorcode */
3845         SSVAL(*rparam,2,0);             /* converter word */
3846         SSVAL(*rparam,4,0x7f);  /* permission flags */
3847
3848         return True;
3849 }
3850
3851 /****************************************************************************
3852   api_WPrintJobEnumerate
3853   ****************************************************************************/
3854
3855 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
3856                                 char *param, int tpscnt,
3857                                 char *data, int tdscnt,
3858                                 int mdrcnt,int mprcnt,
3859                                 char **rdata,char **rparam,
3860                                 int *rdata_len,int *rparam_len)
3861 {
3862         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3863         char *str2 = skip_string(param,tpscnt,str1);
3864         char *p = skip_string(param,tpscnt,str2);
3865         int uLevel;
3866         int count;
3867         int i;
3868         int snum;
3869         fstring sharename;
3870         uint32 jobid;
3871         struct pack_desc desc;
3872         print_queue_struct *queue=NULL;
3873         print_status_struct status;
3874         char *tmpdata=NULL;
3875
3876         if (!str1 || !str2 || !p) {
3877                 return False;
3878         }
3879
3880         uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3881
3882         memset((char *)&desc,'\0',sizeof(desc));
3883         memset((char *)&status,'\0',sizeof(status));
3884
3885         DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
3886
3887         /* check it's a supported varient */
3888         if (strcmp(str1,"WWrLh") != 0) {
3889                 return False;
3890         }
3891         if (!check_printjob_info(&desc,uLevel,str2)) {
3892                 return False;
3893         }
3894
3895         if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
3896                 return False;
3897         }
3898
3899         snum = lp_servicenumber( sharename);
3900         if (snum < 0 || !VALID_SNUM(snum)) {
3901                 return(False);
3902         }
3903
3904         count = print_queue_status(snum,&queue,&status);
3905         for (i = 0; i < count; i++) {
3906                 if (queue[i].job == jobid) {
3907                         break;
3908                 }
3909         }
3910
3911         if (mdrcnt > 0) {
3912                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3913                 if (!*rdata) {
3914                         return False;
3915                 }
3916                 desc.base = *rdata;
3917                 desc.buflen = mdrcnt;
3918         } else {
3919                 /*
3920                  * Don't return data but need to get correct length
3921                  *  init_package will return wrong size if buflen=0
3922                  */
3923                 desc.buflen = getlen(desc.format);
3924                 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3925         }
3926
3927         if (init_package(&desc,1,0)) {
3928                 if (i < count) {
3929                         fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3930                         *rdata_len = desc.usedlen;
3931                 } else {
3932                         desc.errcode = NERR_JobNotFound;
3933                         *rdata_len = 0;
3934                 }
3935         }
3936
3937         *rparam_len = 6;
3938         *rparam = smb_realloc_limit(*rparam,*rparam_len);
3939         if (!*rparam) {
3940                 return False;
3941         }
3942         SSVALS(*rparam,0,desc.errcode);
3943         SSVAL(*rparam,2,0);
3944         SSVAL(*rparam,4,desc.neededlen);
3945
3946         SAFE_FREE(queue);
3947         SAFE_FREE(tmpdata);
3948
3949         DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
3950
3951         return True;
3952 }
3953
3954 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
3955                                 char *param, int tpscnt,
3956                                 char *data, int tdscnt,
3957                                 int mdrcnt,int mprcnt,
3958                                 char **rdata,char **rparam,
3959                                 int *rdata_len,int *rparam_len)
3960 {
3961         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3962         char *str2 = skip_string(param,tpscnt,str1);
3963         char *p = skip_string(param,tpscnt,str2);
3964         char *name = p;
3965         int uLevel;
3966         int count;
3967         int i, succnt=0;
3968         int snum;
3969         struct pack_desc desc;
3970         print_queue_struct *queue=NULL;
3971         print_status_struct status;
3972
3973         if (!str1 || !str2 || !p) {
3974                 return False;
3975         }
3976
3977         memset((char *)&desc,'\0',sizeof(desc));
3978         memset((char *)&status,'\0',sizeof(status));
3979
3980         p = skip_string(param,tpscnt,p);
3981         if (!p) {
3982                 return False;
3983         }
3984         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3985
3986         DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
3987
3988         /* check it's a supported variant */
3989         if (strcmp(str1,"zWrLeh") != 0) {
3990                 return False;
3991         }
3992
3993         if (uLevel > 2) {
3994                 return False;   /* defined only for uLevel 0,1,2 */
3995         }
3996
3997         if (!check_printjob_info(&desc,uLevel,str2)) { 
3998                 return False;
3999         }
4000
4001         snum = find_service(name);
4002         if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
4003                 return False;
4004         }
4005
4006         count = print_queue_status(snum,&queue,&status);
4007         if (mdrcnt > 0) {
4008                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4009                 if (!*rdata) {
4010                         return False;
4011                 }
4012         }
4013         desc.base = *rdata;
4014         desc.buflen = mdrcnt;
4015
4016         if (init_package(&desc,count,0)) {
4017                 succnt = 0;
4018                 for (i = 0; i < count; i++) {
4019                         fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
4020                         if (desc.errcode == NERR_Success) {
4021                                 succnt = i+1;
4022                         }
4023                 }
4024         }
4025
4026         *rdata_len = desc.usedlen;
4027
4028         *rparam_len = 8;
4029         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4030         if (!*rparam) {
4031                 return False;
4032         }
4033         SSVALS(*rparam,0,desc.errcode);
4034         SSVAL(*rparam,2,0);
4035         SSVAL(*rparam,4,succnt);
4036         SSVAL(*rparam,6,count);
4037
4038         SAFE_FREE(queue);
4039
4040         DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4041
4042         return True;
4043 }
4044
4045 static int check_printdest_info(struct pack_desc* desc,
4046                                 int uLevel, char* id)
4047 {
4048         desc->subformat = NULL;
4049         switch( uLevel ) {
4050                 case 0:
4051                         desc->format = "B9";
4052                         break;
4053                 case 1:
4054                         desc->format = "B9B21WWzW";
4055                         break;
4056                 case 2:
4057                         desc->format = "z";
4058                         break;
4059                 case 3:
4060                         desc->format = "zzzWWzzzWW";
4061                         break;
4062                 default:
4063                         DEBUG(0,("check_printdest_info: invalid level %d\n",
4064                                 uLevel));
4065                         return False;
4066         }
4067         if (id == NULL || strcmp(desc->format,id) != 0) {
4068                 DEBUG(0,("check_printdest_info: invalid string %s\n", 
4069                         id ? id : "<NULL>" ));
4070                 return False;
4071         }
4072         return True;
4073 }
4074
4075 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
4076                                 struct pack_desc* desc)
4077 {
4078         char buf[100];
4079
4080         strncpy(buf,SERVICE(snum),sizeof(buf)-1);
4081         buf[sizeof(buf)-1] = 0;
4082         strupper_m(buf);
4083
4084         if (uLevel <= 1) {
4085                 PACKS(desc,"B9",buf);   /* szName */
4086                 if (uLevel == 1) {
4087                         PACKS(desc,"B21","");   /* szUserName */
4088                         PACKI(desc,"W",0);              /* uJobId */
4089                         PACKI(desc,"W",0);              /* fsStatus */
4090                         PACKS(desc,"z","");     /* pszStatus */
4091                         PACKI(desc,"W",0);              /* time */
4092                 }
4093         }
4094
4095         if (uLevel == 2 || uLevel == 3) {
4096                 PACKS(desc,"z",buf);            /* pszPrinterName */
4097                 if (uLevel == 3) {
4098                         PACKS(desc,"z","");     /* pszUserName */
4099                         PACKS(desc,"z","");     /* pszLogAddr */
4100                         PACKI(desc,"W",0);              /* uJobId */
4101                         PACKI(desc,"W",0);              /* fsStatus */
4102                         PACKS(desc,"z","");     /* pszStatus */
4103                         PACKS(desc,"z","");     /* pszComment */
4104                         PACKS(desc,"z","NULL"); /* pszDrivers */
4105                         PACKI(desc,"W",0);              /* time */
4106                         PACKI(desc,"W",0);              /* pad1 */
4107                 }
4108         }
4109 }
4110
4111 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
4112                                 char *param, int tpscnt,
4113                                 char *data, int tdscnt,
4114                                 int mdrcnt,int mprcnt,
4115                                 char **rdata,char **rparam,
4116                                 int *rdata_len,int *rparam_len)
4117 {
4118         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4119         char *str2 = skip_string(param,tpscnt,str1);
4120         char *p = skip_string(param,tpscnt,str2);
4121         char* PrinterName = p;
4122         int uLevel;
4123         struct pack_desc desc;
4124         int snum;
4125         char *tmpdata=NULL;
4126
4127         if (!str1 || !str2 || !p) {
4128                 return False;
4129         }
4130
4131         memset((char *)&desc,'\0',sizeof(desc));
4132
4133         p = skip_string(param,tpscnt,p);
4134         if (!p) {
4135                 return False;
4136         }
4137         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4138
4139         DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4140
4141         /* check it's a supported varient */
4142         if (strcmp(str1,"zWrLh") != 0) {
4143                 return False;
4144         }
4145         if (!check_printdest_info(&desc,uLevel,str2)) {
4146                 return False;
4147         }
4148
4149         snum = find_service(PrinterName);
4150         if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
4151                 *rdata_len = 0;
4152                 desc.errcode = NERR_DestNotFound;
4153                 desc.neededlen = 0;
4154         } else {
4155                 if (mdrcnt > 0) {
4156                         *rdata = smb_realloc_limit(*rdata,mdrcnt);
4157                         if (!*rdata) {
4158                                 return False;
4159                         }
4160                         desc.base = *rdata;
4161                         desc.buflen = mdrcnt;
4162                 } else {
4163                         /*
4164                          * Don't return data but need to get correct length
4165                          * init_package will return wrong size if buflen=0
4166                          */
4167                         desc.buflen = getlen(desc.format);
4168                         desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4169                 }
4170                 if (init_package(&desc,1,0)) {
4171                         fill_printdest_info(conn,snum,uLevel,&desc);
4172                 }
4173                 *rdata_len = desc.usedlen;
4174         }
4175
4176         *rparam_len = 6;
4177         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4178         if (!*rparam) {
4179                 return False;
4180         }
4181         SSVALS(*rparam,0,desc.errcode);
4182         SSVAL(*rparam,2,0);
4183         SSVAL(*rparam,4,desc.neededlen);
4184
4185         DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4186         SAFE_FREE(tmpdata);
4187
4188         return True;
4189 }
4190
4191 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4192                                 char *param, int tpscnt,
4193                                 char *data, int tdscnt,
4194                                 int mdrcnt,int mprcnt,
4195                                 char **rdata,char **rparam,
4196                                 int *rdata_len,int *rparam_len)
4197 {
4198         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4199         char *str2 = skip_string(param,tpscnt,str1);
4200         char *p = skip_string(param,tpscnt,str2);
4201         int uLevel;
4202         int queuecnt;
4203         int i, n, succnt=0;
4204         struct pack_desc desc;
4205         int services = lp_numservices();
4206
4207         if (!str1 || !str2 || !p) {
4208                 return False;
4209         }
4210
4211         memset((char *)&desc,'\0',sizeof(desc));
4212
4213         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4214
4215         DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4216
4217         /* check it's a supported varient */
4218         if (strcmp(str1,"WrLeh") != 0) {
4219                 return False;
4220         }
4221         if (!check_printdest_info(&desc,uLevel,str2)) {
4222                 return False;
4223         }
4224
4225         queuecnt = 0;
4226         for (i = 0; i < services; i++) {
4227                 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4228                         queuecnt++;
4229                 }
4230         }
4231
4232         if (mdrcnt > 0) {
4233                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4234                 if (!*rdata) {
4235                         return False;
4236                 }
4237         }
4238
4239         desc.base = *rdata;
4240         desc.buflen = mdrcnt;
4241         if (init_package(&desc,queuecnt,0)) {    
4242                 succnt = 0;
4243                 n = 0;
4244                 for (i = 0; i < services; i++) {
4245                         if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4246                                 fill_printdest_info(conn,i,uLevel,&desc);
4247                                 n++;
4248                                 if (desc.errcode == NERR_Success) {
4249                                         succnt = n;
4250                                 }
4251                         }
4252                 }
4253         }
4254
4255         *rdata_len = desc.usedlen;
4256
4257         *rparam_len = 8;
4258         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4259         if (!*rparam) {
4260                 return False;
4261         }
4262         SSVALS(*rparam,0,desc.errcode);
4263         SSVAL(*rparam,2,0);
4264         SSVAL(*rparam,4,succnt);
4265         SSVAL(*rparam,6,queuecnt);
4266
4267         DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4268
4269         return True;
4270 }
4271
4272 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4273                                 char *param, int tpscnt,
4274                                 char *data, int tdscnt,
4275                                 int mdrcnt,int mprcnt,
4276                                 char **rdata,char **rparam,
4277                                 int *rdata_len,int *rparam_len)
4278 {
4279         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4280         char *str2 = skip_string(param,tpscnt,str1);
4281         char *p = skip_string(param,tpscnt,str2);
4282         int uLevel;
4283         int succnt;
4284         struct pack_desc desc;
4285
4286         if (!str1 || !str2 || !p) {
4287                 return False;
4288         }
4289
4290         memset((char *)&desc,'\0',sizeof(desc));
4291
4292         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4293
4294         DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4295
4296         /* check it's a supported varient */
4297         if (strcmp(str1,"WrLeh") != 0) {
4298                 return False;
4299         }
4300         if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4301                 return False;
4302         }
4303
4304         if (mdrcnt > 0) {
4305                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4306                 if (!*rdata) {
4307                         return False;
4308                 }
4309         }
4310         desc.base = *rdata;
4311         desc.buflen = mdrcnt;
4312         if (init_package(&desc,1,0)) {
4313                 PACKS(&desc,"B41","NULL");
4314         }
4315
4316         succnt = (desc.errcode == NERR_Success ? 1 : 0);
4317
4318         *rdata_len = desc.usedlen;
4319
4320         *rparam_len = 8;
4321         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4322         if (!*rparam) {
4323                 return False;
4324         }
4325         SSVALS(*rparam,0,desc.errcode);
4326         SSVAL(*rparam,2,0);
4327         SSVAL(*rparam,4,succnt);
4328         SSVAL(*rparam,6,1);
4329
4330         DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4331
4332         return True;
4333 }
4334
4335 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4336                                 char *param, int tpscnt,
4337                                 char *data, int tdscnt,
4338                                 int mdrcnt,int mprcnt,
4339                                 char **rdata,char **rparam,
4340                                 int *rdata_len,int *rparam_len)
4341 {
4342         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4343         char *str2 = skip_string(param,tpscnt,str1);
4344         char *p = skip_string(param,tpscnt,str2);
4345         int uLevel;
4346         int succnt;
4347         struct pack_desc desc;
4348
4349         if (!str1 || !str2 || !p) {
4350                 return False;
4351         }
4352         memset((char *)&desc,'\0',sizeof(desc));
4353
4354         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4355
4356         DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4357
4358         /* check it's a supported varient */
4359         if (strcmp(str1,"WrLeh") != 0) {
4360                 return False;
4361         }
4362         if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4363                 return False;
4364         }
4365
4366         if (mdrcnt > 0) {
4367                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4368                 if (!*rdata) {
4369                         return False;
4370                 }
4371         }
4372         desc.base = *rdata;
4373         desc.buflen = mdrcnt;
4374         desc.format = str2;
4375         if (init_package(&desc,1,0)) {
4376                 PACKS(&desc,"B13","lpd");
4377         }
4378
4379         succnt = (desc.errcode == NERR_Success ? 1 : 0);
4380
4381         *rdata_len = desc.usedlen;
4382
4383         *rparam_len = 8;
4384         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4385         if (!*rparam) {
4386                 return False;
4387         }
4388         SSVALS(*rparam,0,desc.errcode);
4389         SSVAL(*rparam,2,0);
4390         SSVAL(*rparam,4,succnt);
4391         SSVAL(*rparam,6,1);
4392
4393         DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4394
4395         return True;
4396 }
4397
4398 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4399                                 char *param, int tpscnt,
4400                                 char *data, int tdscnt,
4401                                 int mdrcnt,int mprcnt,
4402                                 char **rdata,char **rparam,
4403                                 int *rdata_len,int *rparam_len)
4404 {
4405         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4406         char *str2 = skip_string(param,tpscnt,str1);
4407         char *p = skip_string(param,tpscnt,str2);
4408         int uLevel;
4409         int succnt;
4410         struct pack_desc desc;
4411
4412         if (!str1 || !str2 || !p) {
4413                 return False;
4414         }
4415
4416         memset((char *)&desc,'\0',sizeof(desc));
4417
4418         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4419
4420         DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4421
4422         /* check it's a supported varient */
4423         if (strcmp(str1,"WrLeh") != 0) {
4424                 return False;
4425         }
4426         if (uLevel != 0 || strcmp(str2,"B9") != 0) {
4427                 return False;
4428         }
4429
4430         if (mdrcnt > 0) {
4431                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4432                 if (!*rdata) {
4433                         return False;
4434                 }
4435         }
4436         memset((char *)&desc,'\0',sizeof(desc));
4437         desc.base = *rdata;
4438         desc.buflen = mdrcnt;
4439         desc.format = str2;
4440         if (init_package(&desc,1,0)) {
4441                 PACKS(&desc,"B13","lp0");
4442         }
4443
4444         succnt = (desc.errcode == NERR_Success ? 1 : 0);
4445
4446         *rdata_len = desc.usedlen;
4447
4448         *rparam_len = 8;
4449         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4450         if (!*rparam) {
4451                 return False;
4452         }
4453         SSVALS(*rparam,0,desc.errcode);
4454         SSVAL(*rparam,2,0);
4455         SSVAL(*rparam,4,succnt);
4456         SSVAL(*rparam,6,1);
4457
4458         DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
4459
4460         return True;
4461 }
4462
4463 /****************************************************************************
4464  List open sessions
4465  ****************************************************************************/
4466
4467 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
4468                                 char *param, int tpscnt,
4469                                 char *data, int tdscnt,
4470                                 int mdrcnt,int mprcnt,
4471                                 char **rdata,char **rparam,
4472                                 int *rdata_len,int *rparam_len)
4473
4474 {
4475         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4476         char *str2 = skip_string(param,tpscnt,str1);
4477         char *p = skip_string(param,tpscnt,str2);
4478         int uLevel;
4479         struct pack_desc desc;
4480         struct sessionid *session_list;
4481         int i, num_sessions;
4482
4483         if (!str1 || !str2 || !p) {
4484                 return False;
4485         }
4486
4487         memset((char *)&desc,'\0',sizeof(desc));
4488
4489         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4490
4491         DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
4492         DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
4493         DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
4494
4495         /* check it's a supported varient */
4496         if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
4497                 return False;
4498         }
4499         if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
4500                 return False;
4501         }
4502
4503         num_sessions = list_sessions(talloc_tos(), &session_list);
4504
4505         if (mdrcnt > 0) {
4506                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4507                 if (!*rdata) {
4508                         return False;
4509                 }
4510         }
4511         memset((char *)&desc,'\0',sizeof(desc));
4512         desc.base = *rdata;
4513         desc.buflen = mdrcnt;
4514         desc.format = str2;
4515         if (!init_package(&desc,num_sessions,0)) {
4516                 return False;
4517         }
4518
4519         for(i=0; i<num_sessions; i++) {
4520                 PACKS(&desc, "z", session_list[i].remote_machine);
4521                 PACKS(&desc, "z", session_list[i].username);
4522                 PACKI(&desc, "W", 1); /* num conns */
4523                 PACKI(&desc, "W", 0); /* num opens */
4524                 PACKI(&desc, "W", 1); /* num users */
4525                 PACKI(&desc, "D", 0); /* session time */
4526                 PACKI(&desc, "D", 0); /* idle time */
4527                 PACKI(&desc, "D", 0); /* flags */
4528                 PACKS(&desc, "z", "Unknown Client"); /* client type string */
4529         }
4530
4531         *rdata_len = desc.usedlen;
4532
4533         *rparam_len = 8;
4534         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4535         if (!*rparam) {
4536                 return False;
4537         }
4538         SSVALS(*rparam,0,desc.errcode);
4539         SSVAL(*rparam,2,0); /* converter */
4540         SSVAL(*rparam,4,num_sessions); /* count */
4541
4542         DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
4543
4544         return True;
4545 }
4546
4547
4548 /****************************************************************************
4549  The buffer was too small.
4550  ****************************************************************************/
4551
4552 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
4553                          int mdrcnt, int mprcnt,
4554                          char **rdata, char **rparam,
4555                          int *rdata_len, int *rparam_len)
4556 {
4557         *rparam_len = MIN(*rparam_len,mprcnt);
4558         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4559         if (!*rparam) {
4560                 return False;
4561         }
4562
4563         *rdata_len = 0;
4564
4565         SSVAL(*rparam,0,NERR_BufTooSmall);
4566
4567         DEBUG(3,("Supplied buffer too small in API command\n"));
4568
4569         return True;
4570 }
4571
4572 /****************************************************************************
4573  The request is not supported.
4574  ****************************************************************************/
4575
4576 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
4577                                 char *param, int tpscnt,
4578                                 char *data, int tdscnt,
4579                                 int mdrcnt, int mprcnt,
4580                                 char **rdata, char **rparam,
4581                                 int *rdata_len, int *rparam_len)
4582 {
4583         *rparam_len = 4;
4584         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4585         if (!*rparam) {
4586                 return False;
4587         }
4588
4589         *rdata_len = 0;
4590
4591         SSVAL(*rparam,0,NERR_notsupported);
4592         SSVAL(*rparam,2,0);             /* converter word */
4593
4594         DEBUG(3,("Unsupported API command\n"));
4595
4596         return True;
4597 }
4598
4599 static const struct {
4600         const char *name;
4601         int id;
4602         bool (*fn)(connection_struct *, uint16,
4603                         char *, int,
4604                         char *, int,
4605                         int,int,char **,char **,int *,int *);
4606         bool auth_user;         /* Deny anonymous access? */
4607 } api_commands[] = {
4608         {"RNetShareEnum",       RAP_WshareEnum,         api_RNetShareEnum, True},
4609         {"RNetShareGetInfo",    RAP_WshareGetInfo,      api_RNetShareGetInfo},
4610         {"RNetShareAdd",        RAP_WshareAdd,          api_RNetShareAdd},
4611         {"RNetSessionEnum",     RAP_WsessionEnum,       api_RNetSessionEnum, True},
4612         {"RNetServerGetInfo",   RAP_WserverGetInfo,     api_RNetServerGetInfo},
4613         {"RNetGroupEnum",       RAP_WGroupEnum,         api_RNetGroupEnum, True},
4614         {"RNetGroupGetUsers", RAP_WGroupGetUsers,       api_RNetGroupGetUsers, True},
4615         {"RNetUserEnum",        RAP_WUserEnum,          api_RNetUserEnum, True},
4616         {"RNetUserGetInfo",     RAP_WUserGetInfo,       api_RNetUserGetInfo},
4617         {"NetUserGetGroups",    RAP_WUserGetGroups,     api_NetUserGetGroups},
4618         {"NetWkstaGetInfo",     RAP_WWkstaGetInfo,      api_NetWkstaGetInfo},
4619         {"DosPrintQEnum",       RAP_WPrintQEnum,        api_DosPrintQEnum, True},
4620         {"DosPrintQGetInfo",    RAP_WPrintQGetInfo,     api_DosPrintQGetInfo},
4621         {"WPrintQueuePause",  RAP_WPrintQPause, api_WPrintQueueCtrl},
4622         {"WPrintQueueResume", RAP_WPrintQContinue,      api_WPrintQueueCtrl},
4623         {"WPrintJobEnumerate",RAP_WPrintJobEnum,        api_WPrintJobEnumerate},
4624         {"WPrintJobGetInfo",    RAP_WPrintJobGetInfo,   api_WPrintJobGetInfo},
4625         {"RDosPrintJobDel",     RAP_WPrintJobDel,       api_RDosPrintJobDel},
4626         {"RDosPrintJobPause",   RAP_WPrintJobPause,     api_RDosPrintJobDel},
4627         {"RDosPrintJobResume",RAP_WPrintJobContinue,    api_RDosPrintJobDel},
4628         {"WPrintDestEnum",      RAP_WPrintDestEnum,     api_WPrintDestEnum},
4629         {"WPrintDestGetInfo",   RAP_WPrintDestGetInfo,  api_WPrintDestGetInfo},
4630         {"NetRemoteTOD",        RAP_NetRemoteTOD,       api_NetRemoteTOD},
4631         {"WPrintQueuePurge",    RAP_WPrintQPurge,       api_WPrintQueueCtrl},
4632         {"NetServerEnum",       RAP_NetServerEnum2,     api_RNetServerEnum}, /* anon OK */
4633         {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
4634         {"SetUserPassword",     RAP_WUserPasswordSet2,  api_SetUserPassword},
4635         {"WWkstaUserLogon",     RAP_WWkstaUserLogon,    api_WWkstaUserLogon},
4636         {"PrintJobInfo",        RAP_WPrintJobSetInfo,   api_PrintJobInfo},
4637         {"WPrintDriverEnum",    RAP_WPrintDriverEnum,   api_WPrintDriverEnum},
4638         {"WPrintQProcEnum",     RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
4639         {"WPrintPortEnum",      RAP_WPrintPortEnum,     api_WPrintPortEnum},
4640         {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
4641         {NULL,          -1,     api_Unsupported}
4642         /*  The following RAP calls are not implemented by Samba:
4643
4644         RAP_WFileEnum2 - anon not OK 
4645         */
4646 };
4647
4648
4649 /****************************************************************************
4650  Handle remote api calls.
4651 ****************************************************************************/
4652
4653 void api_reply(connection_struct *conn, uint16 vuid,
4654                struct smb_request *req,
4655                char *data, char *params,
4656                int tdscnt, int tpscnt,
4657                int mdrcnt, int mprcnt)
4658 {
4659         struct smbd_server_connection *sconn = smbd_server_conn;
4660         int api_command;
4661         char *rdata = NULL;
4662         char *rparam = NULL;
4663         const char *name1 = NULL;
4664         const char *name2 = NULL;
4665         int rdata_len = 0;
4666         int rparam_len = 0;
4667         bool reply=False;
4668         int i;
4669
4670         if (!params) {
4671                 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
4672                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4673                 return;
4674         }
4675
4676         if (tpscnt < 2) {
4677                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4678                 return;
4679         }
4680         api_command = SVAL(params,0);
4681         /* Is there a string at position params+2 ? */
4682         if (skip_string(params,tpscnt,params+2)) {
4683                 name1 = params + 2;
4684         } else {
4685                 name1 = "";
4686         }
4687         name2 = skip_string(params,tpscnt,params+2);
4688         if (!name2) {
4689                 name2 = "";
4690         }
4691
4692         DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
4693                 api_command,
4694                 name1,
4695                 name2,
4696                 tdscnt,tpscnt,mdrcnt,mprcnt));
4697
4698         for (i=0;api_commands[i].name;i++) {
4699                 if (api_commands[i].id == api_command && api_commands[i].fn) {
4700                         DEBUG(3,("Doing %s\n",api_commands[i].name));
4701                         break;
4702                 }
4703         }
4704
4705         /* Check whether this api call can be done anonymously */
4706
4707         if (api_commands[i].auth_user && lp_restrict_anonymous()) {
4708                 user_struct *user = get_valid_user_struct(sconn, vuid);
4709
4710                 if (!user || user->server_info->guest) {
4711                         reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4712                         return;
4713                 }
4714         }
4715
4716         rdata = (char *)SMB_MALLOC(1024);
4717         if (rdata) {
4718                 memset(rdata,'\0',1024);
4719         }
4720
4721         rparam = (char *)SMB_MALLOC(1024);
4722         if (rparam) {
4723                 memset(rparam,'\0',1024);
4724         }
4725
4726         if(!rdata || !rparam) {
4727                 DEBUG(0,("api_reply: malloc fail !\n"));
4728                 SAFE_FREE(rdata);
4729                 SAFE_FREE(rparam);
4730                 reply_nterror(req, NT_STATUS_NO_MEMORY);
4731                 return;
4732         }
4733
4734         reply = api_commands[i].fn(conn,
4735                                 vuid,
4736                                 params,tpscnt,  /* params + length */
4737                                 data,tdscnt,    /* data + length */
4738                                 mdrcnt,mprcnt,
4739                                 &rdata,&rparam,&rdata_len,&rparam_len);
4740
4741
4742         if (rdata_len > mdrcnt || rparam_len > mprcnt) {
4743                 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
4744                                         &rdata,&rparam,&rdata_len,&rparam_len);
4745         }
4746
4747         /* if we get False back then it's actually unsupported */
4748         if (!reply) {
4749                 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
4750                         &rdata,&rparam,&rdata_len,&rparam_len);
4751         }
4752
4753         /* If api_Unsupported returns false we can't return anything. */
4754         if (reply) {
4755                 send_trans_reply(conn, req, rparam, rparam_len,
4756                                  rdata, rdata_len, False);
4757         }
4758
4759         SAFE_FREE(rdata);
4760         SAFE_FREE(rparam);
4761         return;
4762 }