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