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