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