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