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