source: trunk/samba/source/smbd/lanman.c @ 17

Last change on this file since 17 was 1, checked in by Paul Smedley, 14 years ago

Initial code import

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