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