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