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