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