s3-spoolss: Make spoolss_Time_to_time_t public.
[Samba/ekacnet.git] / source3 / smbd / lanman.c
blob6fdad2cb132ba4e77e889837fbabaf1d4117c294
1 /*
2 Unix SMB/CIFS implementation.
3 Inter-process communication and named pipe handling
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Jeremy Allison 2007.
7 SMB Version handling
8 Copyright (C) John H Terpstra 1995-1998
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 This file handles the named pipe and mailslot calls
25 in the SMBtrans protocol
28 #include "includes.h"
29 #include "smbd/globals.h"
30 #include "../librpc/gen_ndr/cli_samr.h"
31 #include "../librpc/gen_ndr/cli_spoolss.h"
32 #include "../librpc/gen_ndr/cli_srvsvc.h"
33 #include "../librpc/gen_ndr/srv_samr.h"
34 #include "../librpc/gen_ndr/srv_spoolss.h"
35 #include "../librpc/gen_ndr/srv_srvsvc.h"
36 #include "../librpc/gen_ndr/rap.h"
37 #include "../lib/util/binsearch.h"
39 #ifdef CHECK_TYPES
40 #undef CHECK_TYPES
41 #endif
42 #define CHECK_TYPES 0
44 #define NERR_Success 0
45 #define NERR_badpass 86
46 #define NERR_notsupported 50
48 #define NERR_BASE (2100)
49 #define NERR_BufTooSmall (NERR_BASE+23)
50 #define NERR_JobNotFound (NERR_BASE+51)
51 #define NERR_DestNotFound (NERR_BASE+52)
53 #define ACCESS_READ 0x01
54 #define ACCESS_WRITE 0x02
55 #define ACCESS_CREATE 0x04
57 #define SHPWLEN 8 /* share password length */
59 /* Limit size of ipc replies */
61 static char *smb_realloc_limit(void *ptr, size_t size)
63 char *val;
65 size = MAX((size),4*1024);
66 val = (char *)SMB_REALLOC(ptr,size);
67 if (val) {
68 memset(val,'\0',size);
70 return val;
73 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
74 char *param, int tpscnt,
75 char *data, int tdscnt,
76 int mdrcnt, int mprcnt,
77 char **rdata, char **rparam,
78 int *rdata_len, int *rparam_len);
80 static bool api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
81 int mdrcnt, int mprcnt,
82 char **rdata, char **rparam,
83 int *rdata_len, int *rparam_len);
86 static int CopyExpanded(connection_struct *conn,
87 int snum, char **dst, char *src, int *p_space_remaining)
89 TALLOC_CTX *ctx = talloc_tos();
90 char *buf = NULL;
91 int l;
93 if (!src || !dst || !p_space_remaining || !(*dst) ||
94 *p_space_remaining <= 0) {
95 return 0;
98 buf = talloc_strdup(ctx, src);
99 if (!buf) {
100 *p_space_remaining = 0;
101 return 0;
103 buf = talloc_string_sub(ctx, buf,"%S",lp_servicename(snum));
104 if (!buf) {
105 *p_space_remaining = 0;
106 return 0;
108 buf = talloc_sub_advanced(ctx,
109 lp_servicename(SNUM(conn)),
110 conn->server_info->unix_name,
111 conn->connectpath,
112 conn->server_info->utok.gid,
113 conn->server_info->sanitized_username,
114 pdb_get_domain(conn->server_info->sam_account),
115 buf);
116 if (!buf) {
117 *p_space_remaining = 0;
118 return 0;
120 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
121 if (l == -1) {
122 return 0;
124 (*dst) += l;
125 (*p_space_remaining) -= l;
126 return l;
129 static int CopyAndAdvance(char **dst, char *src, int *n)
131 int l;
132 if (!src || !dst || !n || !(*dst)) {
133 return 0;
135 l = push_ascii(*dst,src,*n, STR_TERMINATE);
136 if (l == -1) {
137 return 0;
139 (*dst) += l;
140 (*n) -= l;
141 return l;
144 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
146 TALLOC_CTX *ctx = talloc_tos();
147 char *buf = NULL;
148 if (!s) {
149 return 0;
151 buf = talloc_strdup(ctx,s);
152 if (!buf) {
153 return 0;
155 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
156 if (!buf) {
157 return 0;
159 buf = talloc_sub_advanced(ctx,
160 lp_servicename(SNUM(conn)),
161 conn->server_info->unix_name,
162 conn->connectpath,
163 conn->server_info->utok.gid,
164 conn->server_info->sanitized_username,
165 pdb_get_domain(conn->server_info->sam_account),
166 buf);
167 if (!buf) {
168 return 0;
170 return strlen(buf) + 1;
173 /*******************************************************************
174 Check a API string for validity when we only need to check the prefix.
175 ******************************************************************/
177 static bool prefix_ok(const char *str, const char *prefix)
179 return(strncmp(str,prefix,strlen(prefix)) == 0);
182 struct pack_desc {
183 const char *format; /* formatstring for structure */
184 const char *subformat; /* subformat for structure */
185 char *base; /* baseaddress of buffer */
186 int buflen; /* remaining size for fixed part; on init: length of base */
187 int subcount; /* count of substructures */
188 char *structbuf; /* pointer into buffer for remaining fixed part */
189 int stringlen; /* remaining size for variable part */
190 char *stringbuf; /* pointer into buffer for remaining variable part */
191 int neededlen; /* total needed size */
192 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
193 const char *curpos; /* current position; pointer into format or subformat */
194 int errcode;
197 static int get_counter(const char **p)
199 int i, n;
200 if (!p || !(*p)) {
201 return 1;
203 if (!isdigit((int)**p)) {
204 return 1;
206 for (n = 0;;) {
207 i = **p;
208 if (isdigit(i)) {
209 n = 10 * n + (i - '0');
210 } else {
211 return n;
213 (*p)++;
217 static int getlen(const char *p)
219 int n = 0;
220 if (!p) {
221 return 0;
224 while (*p) {
225 switch( *p++ ) {
226 case 'W': /* word (2 byte) */
227 n += 2;
228 break;
229 case 'K': /* status word? (2 byte) */
230 n += 2;
231 break;
232 case 'N': /* count of substructures (word) at end */
233 n += 2;
234 break;
235 case 'D': /* double word (4 byte) */
236 case 'z': /* offset to zero terminated string (4 byte) */
237 case 'l': /* offset to user data (4 byte) */
238 n += 4;
239 break;
240 case 'b': /* offset to data (with counter) (4 byte) */
241 n += 4;
242 get_counter(&p);
243 break;
244 case 'B': /* byte (with optional counter) */
245 n += get_counter(&p);
246 break;
249 return n;
252 static bool init_package(struct pack_desc *p, int count, int subcount)
254 int n = p->buflen;
255 int i;
257 if (!p->format || !p->base) {
258 return False;
261 i = count * getlen(p->format);
262 if (p->subformat) {
263 i += subcount * getlen(p->subformat);
265 p->structbuf = p->base;
266 p->neededlen = 0;
267 p->usedlen = 0;
268 p->subcount = 0;
269 p->curpos = p->format;
270 if (i > n) {
271 p->neededlen = i;
272 i = n = 0;
273 #if 0
275 * This is the old error code we used. Aparently
276 * WinNT/2k systems return ERRbuftoosmall (2123) and
277 * OS/2 needs this. I'm leaving this here so we can revert
278 * if needed. JRA.
280 p->errcode = ERRmoredata;
281 #else
282 p->errcode = ERRbuftoosmall;
283 #endif
284 } else {
285 p->errcode = NERR_Success;
287 p->buflen = i;
288 n -= i;
289 p->stringbuf = p->base + i;
290 p->stringlen = n;
291 return (p->errcode == NERR_Success);
294 static int package(struct pack_desc *p, ...)
296 va_list args;
297 int needed=0, stringneeded;
298 const char *str=NULL;
299 int is_string=0, stringused;
300 int32 temp;
302 va_start(args,p);
304 if (!*p->curpos) {
305 if (!p->subcount) {
306 p->curpos = p->format;
307 } else {
308 p->curpos = p->subformat;
309 p->subcount--;
312 #if CHECK_TYPES
313 str = va_arg(args,char*);
314 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
315 #endif
316 stringneeded = -1;
318 if (!p->curpos) {
319 va_end(args);
320 return 0;
323 switch( *p->curpos++ ) {
324 case 'W': /* word (2 byte) */
325 needed = 2;
326 temp = va_arg(args,int);
327 if (p->buflen >= needed) {
328 SSVAL(p->structbuf,0,temp);
330 break;
331 case 'K': /* status word? (2 byte) */
332 needed = 2;
333 temp = va_arg(args,int);
334 if (p->buflen >= needed) {
335 SSVAL(p->structbuf,0,temp);
337 break;
338 case 'N': /* count of substructures (word) at end */
339 needed = 2;
340 p->subcount = va_arg(args,int);
341 if (p->buflen >= needed) {
342 SSVAL(p->structbuf,0,p->subcount);
344 break;
345 case 'D': /* double word (4 byte) */
346 needed = 4;
347 temp = va_arg(args,int);
348 if (p->buflen >= needed) {
349 SIVAL(p->structbuf,0,temp);
351 break;
352 case 'B': /* byte (with optional counter) */
353 needed = get_counter(&p->curpos);
355 char *s = va_arg(args,char*);
356 if (p->buflen >= needed) {
357 StrnCpy(p->structbuf,s?s:"",needed-1);
360 break;
361 case 'z': /* offset to zero terminated string (4 byte) */
362 str = va_arg(args,char*);
363 stringneeded = (str ? strlen(str)+1 : 0);
364 is_string = 1;
365 break;
366 case 'l': /* offset to user data (4 byte) */
367 str = va_arg(args,char*);
368 stringneeded = va_arg(args,int);
369 is_string = 0;
370 break;
371 case 'b': /* offset to data (with counter) (4 byte) */
372 str = va_arg(args,char*);
373 stringneeded = get_counter(&p->curpos);
374 is_string = 0;
375 break;
378 va_end(args);
379 if (stringneeded >= 0) {
380 needed = 4;
381 if (p->buflen >= needed) {
382 stringused = stringneeded;
383 if (stringused > p->stringlen) {
384 stringused = (is_string ? p->stringlen : 0);
385 if (p->errcode == NERR_Success) {
386 p->errcode = ERRmoredata;
389 if (!stringused) {
390 SIVAL(p->structbuf,0,0);
391 } else {
392 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
393 memcpy(p->stringbuf,str?str:"",stringused);
394 if (is_string) {
395 p->stringbuf[stringused-1] = '\0';
397 p->stringbuf += stringused;
398 p->stringlen -= stringused;
399 p->usedlen += stringused;
402 p->neededlen += stringneeded;
405 p->neededlen += needed;
406 if (p->buflen >= needed) {
407 p->structbuf += needed;
408 p->buflen -= needed;
409 p->usedlen += needed;
410 } else {
411 if (p->errcode == NERR_Success) {
412 p->errcode = ERRmoredata;
415 return 1;
418 #if CHECK_TYPES
419 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
420 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
421 #else
422 #define PACK(desc,t,v) package(desc,v)
423 #define PACKl(desc,t,v,l) package(desc,v,l)
424 #endif
426 static void PACKI(struct pack_desc* desc, const char *t,int v)
428 PACK(desc,t,v);
431 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
433 PACK(desc,t,v);
436 /****************************************************************************
437 Get a print queue.
438 ****************************************************************************/
440 static void PackDriverData(struct pack_desc* desc)
442 char drivdata[4+4+32];
443 SIVAL(drivdata,0,sizeof drivdata); /* cb */
444 SIVAL(drivdata,4,1000); /* lVersion */
445 memset(drivdata+8,0,32); /* szDeviceName */
446 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
447 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
450 static int check_printq_info(struct pack_desc* desc,
451 unsigned int uLevel, char *id1, char *id2)
453 desc->subformat = NULL;
454 switch( uLevel ) {
455 case 0:
456 desc->format = "B13";
457 break;
458 case 1:
459 desc->format = "B13BWWWzzzzzWW";
460 break;
461 case 2:
462 desc->format = "B13BWWWzzzzzWN";
463 desc->subformat = "WB21BB16B10zWWzDDz";
464 break;
465 case 3:
466 desc->format = "zWWWWzzzzWWzzl";
467 break;
468 case 4:
469 desc->format = "zWWWWzzzzWNzzl";
470 desc->subformat = "WWzWWDDzz";
471 break;
472 case 5:
473 desc->format = "z";
474 break;
475 case 51:
476 desc->format = "K";
477 break;
478 case 52:
479 desc->format = "WzzzzzzzzN";
480 desc->subformat = "z";
481 break;
482 default:
483 DEBUG(0,("check_printq_info: invalid level %d\n",
484 uLevel ));
485 return False;
487 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
488 DEBUG(0,("check_printq_info: invalid format %s\n",
489 id1 ? id1 : "<NULL>" ));
490 return False;
492 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
493 DEBUG(0,("check_printq_info: invalid subformat %s\n",
494 id2 ? id2 : "<NULL>" ));
495 return False;
497 return True;
501 #define RAP_JOB_STATUS_QUEUED 0
502 #define RAP_JOB_STATUS_PAUSED 1
503 #define RAP_JOB_STATUS_SPOOLING 2
504 #define RAP_JOB_STATUS_PRINTING 3
505 #define RAP_JOB_STATUS_PRINTED 4
507 #define RAP_QUEUE_STATUS_PAUSED 1
508 #define RAP_QUEUE_STATUS_ERROR 2
510 /* turn a print job status into a on the wire status
512 static int printj_spoolss_status(int v)
514 if (v == JOB_STATUS_QUEUED)
515 return RAP_JOB_STATUS_QUEUED;
516 if (v & JOB_STATUS_PAUSED)
517 return RAP_JOB_STATUS_PAUSED;
518 if (v & JOB_STATUS_SPOOLING)
519 return RAP_JOB_STATUS_SPOOLING;
520 if (v & JOB_STATUS_PRINTING)
521 return RAP_JOB_STATUS_PRINTING;
522 return 0;
525 /* turn a print queue status into a on the wire status
527 static int printq_spoolss_status(int v)
529 if (v == PRINTER_STATUS_OK)
530 return 0;
531 if (v & PRINTER_STATUS_PAUSED)
532 return RAP_QUEUE_STATUS_PAUSED;
533 return RAP_QUEUE_STATUS_ERROR;
536 static void fill_spoolss_printjob_info(int uLevel,
537 struct pack_desc *desc,
538 struct spoolss_JobInfo2 *info2,
539 int n)
541 time_t t = spoolss_Time_to_time_t(&info2->submitted);
543 /* the client expects localtime */
544 t -= get_time_zone(t);
546 PACKI(desc,"W",pjobid_to_rap(info2->printer_name, info2->job_id)); /* uJobId */
547 if (uLevel == 1) {
548 PACKS(desc,"B21", info2->user_name); /* szUserName */
549 PACKS(desc,"B",""); /* pad */
550 PACKS(desc,"B16",""); /* szNotifyName */
551 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
552 PACKS(desc,"z",""); /* pszParms */
553 PACKI(desc,"W",n+1); /* uPosition */
554 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
555 PACKS(desc,"z",""); /* pszStatus */
556 PACKI(desc,"D", t); /* ulSubmitted */
557 PACKI(desc,"D", info2->size); /* ulSize */
558 PACKS(desc,"z", info2->document_name); /* pszComment */
560 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
561 PACKI(desc,"W", info2->priority); /* uPriority */
562 PACKS(desc,"z", info2->user_name); /* pszUserName */
563 PACKI(desc,"W",n+1); /* uPosition */
564 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
565 PACKI(desc,"D",t); /* ulSubmitted */
566 PACKI(desc,"D", info2->size); /* ulSize */
567 PACKS(desc,"z","Samba"); /* pszComment */
568 PACKS(desc,"z", info2->document_name); /* pszDocument */
569 if (uLevel == 3) {
570 PACKS(desc,"z",""); /* pszNotifyName */
571 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
572 PACKS(desc,"z",""); /* pszParms */
573 PACKS(desc,"z",""); /* pszStatus */
574 PACKS(desc,"z", info2->printer_name); /* pszQueue */
575 PACKS(desc,"z","lpd"); /* pszQProcName */
576 PACKS(desc,"z",""); /* pszQProcParms */
577 PACKS(desc,"z","NULL"); /* pszDriverName */
578 PackDriverData(desc); /* pDriverData */
579 PACKS(desc,"z",""); /* pszPrinterName */
580 } else if (uLevel == 4) { /* OS2 */
581 PACKS(desc,"z",""); /* pszSpoolFileName */
582 PACKS(desc,"z",""); /* pszPortName */
583 PACKS(desc,"z",""); /* pszStatus */
584 PACKI(desc,"D",0); /* ulPagesSpooled */
585 PACKI(desc,"D",0); /* ulPagesSent */
586 PACKI(desc,"D",0); /* ulPagesPrinted */
587 PACKI(desc,"D",0); /* ulTimePrinted */
588 PACKI(desc,"D",0); /* ulExtendJobStatus */
589 PACKI(desc,"D",0); /* ulStartPage */
590 PACKI(desc,"D",0); /* ulEndPage */
595 /********************************************************************
596 Respond to the DosPrintQInfo command with a level of 52
597 This is used to get printer driver information for Win9x clients
598 ********************************************************************/
599 static void fill_printq_info_52(struct spoolss_DriverInfo3 *driver,
600 struct pack_desc* desc, int count,
601 const char *printer_name)
603 int i;
604 fstring location;
605 trim_string((char *)driver->driver_path, "\\print$\\WIN40\\0\\", 0);
606 trim_string((char *)driver->data_file, "\\print$\\WIN40\\0\\", 0);
607 trim_string((char *)driver->help_file, "\\print$\\WIN40\\0\\", 0);
609 PACKI(desc, "W", 0x0400); /* don't know */
610 PACKS(desc, "z", driver->driver_name); /* long printer name */
611 PACKS(desc, "z", driver->driver_path); /* Driverfile Name */
612 PACKS(desc, "z", driver->data_file); /* Datafile name */
613 PACKS(desc, "z", driver->monitor_name); /* language monitor */
615 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
616 standard_sub_basic( "", "", location, sizeof(location)-1 );
617 PACKS(desc,"z", location); /* share to retrieve files */
619 PACKS(desc,"z", driver->default_datatype); /* default data type */
620 PACKS(desc,"z", driver->help_file); /* helpfile name */
621 PACKS(desc,"z", driver->driver_path); /* driver name */
623 DEBUG(3,("Printer Driver Name: %s:\n",driver->driver_name));
624 DEBUG(3,("Driver: %s:\n",driver->driver_path));
625 DEBUG(3,("Data File: %s:\n",driver->data_file));
626 DEBUG(3,("Language Monitor: %s:\n",driver->monitor_name));
627 DEBUG(3,("Driver Location: %s:\n",location));
628 DEBUG(3,("Data Type: %s:\n",driver->default_datatype));
629 DEBUG(3,("Help File: %s:\n",driver->help_file));
630 PACKI(desc,"N",count); /* number of files to copy */
632 for ( i=0; i<count && driver->dependent_files && *driver->dependent_files[i]; i++)
634 trim_string((char *)driver->dependent_files[i], "\\print$\\WIN40\\0\\", 0);
635 PACKS(desc,"z",driver->dependent_files[i]); /* driver files to copy */
636 DEBUG(3,("Dependent File: %s:\n", driver->dependent_files[i]));
639 /* sanity check */
640 if ( i != count )
641 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
642 count, i));
644 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", printer_name, i));
646 desc->errcode=NERR_Success;
650 static const char *strip_unc(const char *unc)
652 char *p;
654 if (unc == NULL) {
655 return NULL;
658 if ((p = strrchr(unc, '\\')) != NULL) {
659 return p+1;
662 return unc;
665 static void fill_printq_info(int uLevel,
666 struct pack_desc* desc,
667 int count,
668 union spoolss_JobInfo *job_info,
669 struct spoolss_DriverInfo3 *driver_info,
670 struct spoolss_PrinterInfo2 *printer_info)
672 switch (uLevel) {
673 case 0:
674 case 1:
675 case 2:
676 PACKS(desc,"B13", strip_unc(printer_info->printername));
677 break;
678 case 3:
679 case 4:
680 case 5:
681 PACKS(desc,"z", strip_unc(printer_info->printername));
682 break;
683 case 51:
684 PACKI(desc,"K", printq_spoolss_status(printer_info->status));
685 break;
688 if (uLevel == 1 || uLevel == 2) {
689 PACKS(desc,"B",""); /* alignment */
690 PACKI(desc,"W",5); /* priority */
691 PACKI(desc,"W",0); /* start time */
692 PACKI(desc,"W",0); /* until time */
693 PACKS(desc,"z",""); /* pSepFile */
694 PACKS(desc,"z","lpd"); /* pPrProc */
695 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pDestinations */
696 PACKS(desc,"z",""); /* pParms */
697 if (printer_info->printername == NULL) {
698 PACKS(desc,"z","UNKNOWN PRINTER");
699 PACKI(desc,"W",LPSTAT_ERROR);
700 } else {
701 PACKS(desc,"z", printer_info->comment);
702 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* status */
704 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
707 if (uLevel == 3 || uLevel == 4) {
708 PACKI(desc,"W",5); /* uPriority */
709 PACKI(desc,"W",0); /* uStarttime */
710 PACKI(desc,"W",0); /* uUntiltime */
711 PACKI(desc,"W",5); /* pad1 */
712 PACKS(desc,"z",""); /* pszSepFile */
713 PACKS(desc,"z","WinPrint"); /* pszPrProc */
714 PACKS(desc,"z",NULL); /* pszParms */
715 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
716 /* "don't ask" that it's done this way to fix corrupted
717 Win9X/ME printer comments. */
718 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* fsStatus */
719 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
720 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pszPrinters */
721 PACKS(desc,"z", printer_info->drivername); /* pszDriverName */
722 PackDriverData(desc); /* pDriverData */
725 if (uLevel == 2 || uLevel == 4) {
726 int i;
727 for (i = 0; i < count; i++) {
728 fill_spoolss_printjob_info(uLevel == 2 ? 1 : 2, desc, &job_info[i].info2, i);
732 if (uLevel==52)
733 fill_printq_info_52(driver_info, desc, count, printer_info->printername);
736 /* This function returns the number of files for a given driver */
737 static int get_printerdrivernumber(const struct spoolss_DriverInfo3 *driver)
739 int result = 0;
741 /* count the number of files */
742 while (driver->dependent_files && *driver->dependent_files[result])
743 result++;
745 return result;
748 static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
749 char *param, int tpscnt,
750 char *data, int tdscnt,
751 int mdrcnt,int mprcnt,
752 char **rdata,char **rparam,
753 int *rdata_len,int *rparam_len)
755 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
756 char *str2 = skip_string(param,tpscnt,str1);
757 char *p = skip_string(param,tpscnt,str2);
758 char *QueueName = p;
759 unsigned int uLevel;
760 uint32_t count = 0;
761 char *str3;
762 struct pack_desc desc;
763 char* tmpdata=NULL;
765 WERROR werr = WERR_OK;
766 TALLOC_CTX *mem_ctx = talloc_tos();
767 NTSTATUS status;
768 struct rpc_pipe_client *cli = NULL;
769 struct policy_handle handle;
770 struct spoolss_DevmodeContainer devmode_ctr;
771 union spoolss_DriverInfo driver_info;
772 union spoolss_JobInfo *job_info;
773 union spoolss_PrinterInfo printer_info;
775 if (!str1 || !str2 || !p) {
776 return False;
778 memset((char *)&desc,'\0',sizeof(desc));
780 p = skip_string(param,tpscnt,p);
781 if (!p) {
782 return False;
784 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
785 str3 = get_safe_str_ptr(param,tpscnt,p,4);
786 /* str3 may be null here and is checked in check_printq_info(). */
788 /* remove any trailing username */
789 if ((p = strchr_m(QueueName,'%')))
790 *p = 0;
792 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
794 /* check it's a supported varient */
795 if (!prefix_ok(str1,"zWrLh"))
796 return False;
797 if (!check_printq_info(&desc,uLevel,str2,str3)) {
799 * Patch from Scott Moomaw <scott@bridgewater.edu>
800 * to return the 'invalid info level' error if an
801 * unknown level was requested.
803 *rdata_len = 0;
804 *rparam_len = 6;
805 *rparam = smb_realloc_limit(*rparam,*rparam_len);
806 if (!*rparam) {
807 return False;
809 SSVALS(*rparam,0,ERRunknownlevel);
810 SSVAL(*rparam,2,0);
811 SSVAL(*rparam,4,0);
812 return(True);
815 ZERO_STRUCT(handle);
817 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
818 rpc_spoolss_dispatch, conn->server_info,
819 &cli);
820 if (!NT_STATUS_IS_OK(status)) {
821 DEBUG(0,("api_DosPrintQGetInfo: could not connect to spoolss: %s\n",
822 nt_errstr(status)));
823 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
824 goto out;
827 ZERO_STRUCT(devmode_ctr);
829 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
830 QueueName,
831 NULL,
832 devmode_ctr,
833 SEC_FLAG_MAXIMUM_ALLOWED,
834 &handle,
835 &werr);
836 if (!NT_STATUS_IS_OK(status)) {
837 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
838 goto out;
840 if (!W_ERROR_IS_OK(werr)) {
841 desc.errcode = W_ERROR_V(werr);
842 goto out;
845 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
846 &handle,
849 &printer_info);
850 if (!W_ERROR_IS_OK(werr)) {
851 desc.errcode = W_ERROR_V(werr);
852 goto out;
855 if (uLevel==52) {
856 uint32_t server_major_version;
857 uint32_t server_minor_version;
859 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
860 &handle,
861 "Windows 4.0",
862 3, /* level */
864 0, /* version */
866 &driver_info,
867 &server_major_version,
868 &server_minor_version);
869 if (!W_ERROR_IS_OK(werr)) {
870 desc.errcode = W_ERROR_V(werr);
871 goto out;
874 count = get_printerdrivernumber(&driver_info.info3);
875 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
876 } else {
877 uint32_t num_jobs;
878 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
879 &handle,
880 0, /* firstjob */
881 0xff, /* numjobs */
882 2, /* level */
883 0, /* offered */
884 &num_jobs,
885 &job_info);
886 if (!W_ERROR_IS_OK(werr)) {
887 desc.errcode = W_ERROR_V(werr);
888 goto out;
891 count = num_jobs;
894 if (mdrcnt > 0) {
895 *rdata = smb_realloc_limit(*rdata,mdrcnt);
896 if (!*rdata) {
897 return False;
899 desc.base = *rdata;
900 desc.buflen = mdrcnt;
901 } else {
903 * Don't return data but need to get correct length
904 * init_package will return wrong size if buflen=0
906 desc.buflen = getlen(desc.format);
907 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
910 if (init_package(&desc,1,count)) {
911 desc.subcount = count;
912 fill_printq_info(uLevel,&desc,count, job_info, &driver_info.info3, &printer_info.info2);
915 *rdata_len = desc.usedlen;
918 * We must set the return code to ERRbuftoosmall
919 * in order to support lanman style printing with Win NT/2k
920 * clients --jerry
922 if (!mdrcnt && lp_disable_spoolss())
923 desc.errcode = ERRbuftoosmall;
925 out:
926 if (cli && is_valid_policy_hnd(&handle)) {
927 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
930 *rdata_len = desc.usedlen;
931 *rparam_len = 6;
932 *rparam = smb_realloc_limit(*rparam,*rparam_len);
933 if (!*rparam) {
934 SAFE_FREE(tmpdata);
935 return False;
937 SSVALS(*rparam,0,desc.errcode);
938 SSVAL(*rparam,2,0);
939 SSVAL(*rparam,4,desc.neededlen);
941 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
943 SAFE_FREE(tmpdata);
945 return(True);
948 /****************************************************************************
949 View list of all print jobs on all queues.
950 ****************************************************************************/
952 static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
953 char *param, int tpscnt,
954 char *data, int tdscnt,
955 int mdrcnt, int mprcnt,
956 char **rdata, char** rparam,
957 int *rdata_len, int *rparam_len)
959 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
960 char *output_format1 = skip_string(param,tpscnt,param_format);
961 char *p = skip_string(param,tpscnt,output_format1);
962 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
963 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
964 int i;
965 struct pack_desc desc;
966 int *subcntarr = NULL;
967 int queuecnt = 0, subcnt = 0, succnt = 0;
969 WERROR werr = WERR_OK;
970 TALLOC_CTX *mem_ctx = talloc_tos();
971 NTSTATUS status;
972 struct rpc_pipe_client *cli = NULL;
973 struct spoolss_DevmodeContainer devmode_ctr;
974 uint32_t num_printers;
975 union spoolss_PrinterInfo *printer_info;
976 union spoolss_DriverInfo *driver_info;
977 union spoolss_JobInfo **job_info;
979 if (!param_format || !output_format1 || !p) {
980 return False;
983 memset((char *)&desc,'\0',sizeof(desc));
985 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
987 if (!prefix_ok(param_format,"WrLeh")) {
988 return False;
990 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
992 * Patch from Scott Moomaw <scott@bridgewater.edu>
993 * to return the 'invalid info level' error if an
994 * unknown level was requested.
996 *rdata_len = 0;
997 *rparam_len = 6;
998 *rparam = smb_realloc_limit(*rparam,*rparam_len);
999 if (!*rparam) {
1000 return False;
1002 SSVALS(*rparam,0,ERRunknownlevel);
1003 SSVAL(*rparam,2,0);
1004 SSVAL(*rparam,4,0);
1005 return(True);
1008 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
1009 rpc_spoolss_dispatch, conn->server_info,
1010 &cli);
1011 if (!NT_STATUS_IS_OK(status)) {
1012 DEBUG(0,("api_DosPrintQEnum: could not connect to spoolss: %s\n",
1013 nt_errstr(status)));
1014 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1015 goto out;
1018 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
1019 PRINTER_ENUM_LOCAL,
1020 cli->srv_name_slash,
1023 &num_printers,
1024 &printer_info);
1025 if (!W_ERROR_IS_OK(werr)) {
1026 desc.errcode = W_ERROR_V(werr);
1027 goto out;
1030 queuecnt = num_printers;
1032 job_info = talloc_array(mem_ctx, union spoolss_JobInfo *, num_printers);
1033 if (job_info == NULL) {
1034 goto err;
1037 driver_info = talloc_array(mem_ctx, union spoolss_DriverInfo, num_printers);
1038 if (driver_info == NULL) {
1039 goto err;
1042 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1043 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1044 goto err;
1047 if (mdrcnt > 0) {
1048 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1049 if (!*rdata) {
1050 goto err;
1053 desc.base = *rdata;
1054 desc.buflen = mdrcnt;
1056 subcnt = 0;
1057 for (i = 0; i < num_printers; i++) {
1059 uint32_t num_jobs;
1060 struct policy_handle handle;
1061 const char *printername;
1063 printername = talloc_strdup(mem_ctx, printer_info[i].info2.printername);
1064 if (printername == NULL) {
1065 goto err;
1068 ZERO_STRUCT(handle);
1069 ZERO_STRUCT(devmode_ctr);
1071 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
1072 printername,
1073 NULL,
1074 devmode_ctr,
1075 SEC_FLAG_MAXIMUM_ALLOWED,
1076 &handle,
1077 &werr);
1078 if (!NT_STATUS_IS_OK(status)) {
1079 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1080 goto out;
1082 if (!W_ERROR_IS_OK(werr)) {
1083 desc.errcode = W_ERROR_V(werr);
1084 goto out;
1087 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
1088 &handle,
1089 0, /* firstjob */
1090 0xff, /* numjobs */
1091 2, /* level */
1092 0, /* offered */
1093 &num_jobs,
1094 &job_info[i]);
1095 if (!W_ERROR_IS_OK(werr)) {
1096 desc.errcode = W_ERROR_V(werr);
1097 goto out;
1100 if (uLevel==52) {
1101 uint32_t server_major_version;
1102 uint32_t server_minor_version;
1104 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1105 &handle,
1106 "Windows 4.0",
1107 3, /* level */
1109 0, /* version */
1111 &driver_info[i],
1112 &server_major_version,
1113 &server_minor_version);
1114 if (!W_ERROR_IS_OK(werr)) {
1115 desc.errcode = W_ERROR_V(werr);
1116 goto out;
1120 subcntarr[i] = num_jobs;
1121 subcnt += subcntarr[i];
1123 if (cli && is_valid_policy_hnd(&handle)) {
1124 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
1128 if (init_package(&desc,queuecnt,subcnt)) {
1129 for (i = 0; i < num_printers; i++) {
1130 fill_printq_info(uLevel,&desc,subcntarr[i], job_info[i], &driver_info[i].info3, &printer_info[i].info2);
1131 if (desc.errcode == NERR_Success) {
1132 succnt = i;
1137 SAFE_FREE(subcntarr);
1138 out:
1139 *rdata_len = desc.usedlen;
1140 *rparam_len = 8;
1141 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1142 if (!*rparam) {
1143 goto err;
1145 SSVALS(*rparam,0,desc.errcode);
1146 SSVAL(*rparam,2,0);
1147 SSVAL(*rparam,4,succnt);
1148 SSVAL(*rparam,6,queuecnt);
1150 return True;
1152 err:
1154 SAFE_FREE(subcntarr);
1156 return False;
1159 /****************************************************************************
1160 Get info level for a server list query.
1161 ****************************************************************************/
1163 static bool check_server_info(int uLevel, char* id)
1165 switch( uLevel ) {
1166 case 0:
1167 if (strcmp(id,"B16") != 0) {
1168 return False;
1170 break;
1171 case 1:
1172 if (strcmp(id,"B16BBDz") != 0) {
1173 return False;
1175 break;
1176 default:
1177 return False;
1179 return True;
1182 struct srv_info_struct {
1183 fstring name;
1184 uint32 type;
1185 fstring comment;
1186 fstring domain;
1187 bool server_added;
1190 /*******************************************************************
1191 Get server info lists from the files saved by nmbd. Return the
1192 number of entries.
1193 ******************************************************************/
1195 static int get_server_info(uint32 servertype,
1196 struct srv_info_struct **servers,
1197 const char *domain)
1199 int count=0;
1200 int alloced=0;
1201 char **lines;
1202 bool local_list_only;
1203 int i;
1205 lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
1206 if (!lines) {
1207 DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
1208 return 0;
1211 /* request for everything is code for request all servers */
1212 if (servertype == SV_TYPE_ALL) {
1213 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1216 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1218 DEBUG(4,("Servertype search: %8x\n",servertype));
1220 for (i=0;lines[i];i++) {
1221 fstring stype;
1222 struct srv_info_struct *s;
1223 const char *ptr = lines[i];
1224 bool ok = True;
1225 TALLOC_CTX *frame = NULL;
1226 char *p;
1228 if (!*ptr) {
1229 continue;
1232 if (count == alloced) {
1233 alloced += 10;
1234 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1235 if (!*servers) {
1236 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1237 TALLOC_FREE(lines);
1238 return 0;
1240 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1242 s = &(*servers)[count];
1244 frame = talloc_stackframe();
1245 s->name[0] = '\0';
1246 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1247 TALLOC_FREE(frame);
1248 continue;
1250 fstrcpy(s->name, p);
1252 stype[0] = '\0';
1253 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1254 TALLOC_FREE(frame);
1255 continue;
1257 fstrcpy(stype, p);
1259 s->comment[0] = '\0';
1260 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1261 TALLOC_FREE(frame);
1262 continue;
1264 fstrcpy(s->comment, p);
1265 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1267 s->domain[0] = '\0';
1268 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1269 /* this allows us to cope with an old nmbd */
1270 fstrcpy(s->domain,lp_workgroup());
1271 } else {
1272 fstrcpy(s->domain, p);
1274 TALLOC_FREE(frame);
1276 if (sscanf(stype,"%X",&s->type) != 1) {
1277 DEBUG(4,("r:host file "));
1278 ok = False;
1281 /* Filter the servers/domains we return based on what was asked for. */
1283 /* Check to see if we are being asked for a local list only. */
1284 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1285 DEBUG(4,("r: local list only"));
1286 ok = False;
1289 /* doesn't match up: don't want it */
1290 if (!(servertype & s->type)) {
1291 DEBUG(4,("r:serv type "));
1292 ok = False;
1295 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1296 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1297 DEBUG(4,("s: dom mismatch "));
1298 ok = False;
1301 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1302 ok = False;
1305 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1306 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1308 if (ok) {
1309 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1310 s->name, s->type, s->comment, s->domain));
1311 s->server_added = True;
1312 count++;
1313 } else {
1314 DEBUG(4,("%20s %8x %25s %15s\n",
1315 s->name, s->type, s->comment, s->domain));
1319 TALLOC_FREE(lines);
1320 return count;
1323 /*******************************************************************
1324 Fill in a server info structure.
1325 ******************************************************************/
1327 static int fill_srv_info(struct srv_info_struct *service,
1328 int uLevel, char **buf, int *buflen,
1329 char **stringbuf, int *stringspace, char *baseaddr)
1331 int struct_len;
1332 char* p;
1333 char* p2;
1334 int l2;
1335 int len;
1337 switch (uLevel) {
1338 case 0:
1339 struct_len = 16;
1340 break;
1341 case 1:
1342 struct_len = 26;
1343 break;
1344 default:
1345 return -1;
1348 if (!buf) {
1349 len = 0;
1350 switch (uLevel) {
1351 case 1:
1352 len = strlen(service->comment)+1;
1353 break;
1356 *buflen = struct_len;
1357 *stringspace = len;
1358 return struct_len + len;
1361 len = struct_len;
1362 p = *buf;
1363 if (*buflen < struct_len) {
1364 return -1;
1366 if (stringbuf) {
1367 p2 = *stringbuf;
1368 l2 = *stringspace;
1369 } else {
1370 p2 = p + struct_len;
1371 l2 = *buflen - struct_len;
1373 if (!baseaddr) {
1374 baseaddr = p;
1377 switch (uLevel) {
1378 case 0:
1379 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1380 break;
1382 case 1:
1383 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1384 SIVAL(p,18,service->type);
1385 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1386 len += CopyAndAdvance(&p2,service->comment,&l2);
1387 break;
1390 if (stringbuf) {
1391 *buf = p + struct_len;
1392 *buflen -= struct_len;
1393 *stringbuf = p2;
1394 *stringspace = l2;
1395 } else {
1396 *buf = p2;
1397 *buflen -= len;
1399 return len;
1403 static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1405 return StrCaseCmp(s1->name,s2->name);
1408 /****************************************************************************
1409 View list of servers available (or possibly domains). The info is
1410 extracted from lists saved by nmbd on the local host.
1411 ****************************************************************************/
1413 static bool api_RNetServerEnum2(connection_struct *conn, uint16 vuid,
1414 char *param, int tpscnt,
1415 char *data, int tdscnt,
1416 int mdrcnt, int mprcnt, char **rdata,
1417 char **rparam, int *rdata_len, int *rparam_len)
1419 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1420 char *str2 = skip_string(param,tpscnt,str1);
1421 char *p = skip_string(param,tpscnt,str2);
1422 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1423 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1424 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1425 char *p2;
1426 int data_len, fixed_len, string_len;
1427 int f_len = 0, s_len = 0;
1428 struct srv_info_struct *servers=NULL;
1429 int counted=0,total=0;
1430 int i,missed;
1431 fstring domain;
1432 bool domain_request;
1433 bool local_request;
1435 if (!str1 || !str2 || !p) {
1436 return False;
1439 /* If someone sets all the bits they don't really mean to set
1440 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1441 known servers. */
1443 if (servertype == SV_TYPE_ALL) {
1444 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1447 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1448 any other bit (they may just set this bit on its own) they
1449 want all the locally seen servers. However this bit can be
1450 set on its own so set the requested servers to be
1451 ALL - DOMAIN_ENUM. */
1453 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1454 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1457 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1458 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1460 p += 8;
1462 if (!prefix_ok(str1,"WrLehD")) {
1463 return False;
1465 if (!check_server_info(uLevel,str2)) {
1466 return False;
1469 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1470 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1471 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1473 if (strcmp(str1, "WrLehDz") == 0) {
1474 if (skip_string(param,tpscnt,p) == NULL) {
1475 return False;
1477 pull_ascii_fstring(domain, p);
1478 } else {
1479 fstrcpy(domain, lp_workgroup());
1482 DEBUG(4, ("domain [%s]\n", domain));
1484 if (lp_browse_list()) {
1485 total = get_server_info(servertype,&servers,domain);
1488 data_len = fixed_len = string_len = 0;
1489 missed = 0;
1491 TYPESAFE_QSORT(servers, total, srv_comp);
1494 char *lastname=NULL;
1496 for (i=0;i<total;i++) {
1497 struct srv_info_struct *s = &servers[i];
1499 if (lastname && strequal(lastname,s->name)) {
1500 continue;
1502 lastname = s->name;
1503 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1504 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1505 i, s->name, s->type, s->comment, s->domain));
1507 if (data_len < buf_len) {
1508 counted++;
1509 fixed_len += f_len;
1510 string_len += s_len;
1511 } else {
1512 missed++;
1517 *rdata_len = fixed_len + string_len;
1518 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1519 if (!*rdata) {
1520 return False;
1523 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1524 p = *rdata;
1525 f_len = fixed_len;
1526 s_len = string_len;
1529 char *lastname=NULL;
1530 int count2 = counted;
1532 for (i = 0; i < total && count2;i++) {
1533 struct srv_info_struct *s = &servers[i];
1535 if (lastname && strequal(lastname,s->name)) {
1536 continue;
1538 lastname = s->name;
1539 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1540 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1541 i, s->name, s->type, s->comment, s->domain));
1542 count2--;
1546 *rparam_len = 8;
1547 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1548 if (!*rparam) {
1549 return False;
1551 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1552 SSVAL(*rparam,2,0);
1553 SSVAL(*rparam,4,counted);
1554 SSVAL(*rparam,6,counted+missed);
1556 SAFE_FREE(servers);
1558 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1559 domain,uLevel,counted,counted+missed));
1561 return True;
1564 static int srv_name_match(const char *n1, const char *n2)
1567 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1569 * In Windows, FirstNameToReturn need not be an exact match:
1570 * the server will return a list of servers that exist on
1571 * the network greater than or equal to the FirstNameToReturn.
1573 int ret = StrCaseCmp(n1, n2);
1575 if (ret <= 0) {
1576 return 0;
1579 return ret;
1582 static bool api_RNetServerEnum3(connection_struct *conn, uint16 vuid,
1583 char *param, int tpscnt,
1584 char *data, int tdscnt,
1585 int mdrcnt, int mprcnt, char **rdata,
1586 char **rparam, int *rdata_len, int *rparam_len)
1588 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1589 char *str2 = skip_string(param,tpscnt,str1);
1590 char *p = skip_string(param,tpscnt,str2);
1591 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1592 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1593 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1594 char *p2;
1595 int data_len, fixed_len, string_len;
1596 int f_len = 0, s_len = 0;
1597 struct srv_info_struct *servers=NULL;
1598 int counted=0,first=0,total=0;
1599 int i,missed;
1600 fstring domain;
1601 fstring first_name;
1602 bool domain_request;
1603 bool local_request;
1605 if (!str1 || !str2 || !p) {
1606 return False;
1609 /* If someone sets all the bits they don't really mean to set
1610 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1611 known servers. */
1613 if (servertype == SV_TYPE_ALL) {
1614 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1617 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1618 any other bit (they may just set this bit on its own) they
1619 want all the locally seen servers. However this bit can be
1620 set on its own so set the requested servers to be
1621 ALL - DOMAIN_ENUM. */
1623 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1624 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1627 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1628 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1630 p += 8;
1632 if (strcmp(str1, "WrLehDzz") != 0) {
1633 return false;
1635 if (!check_server_info(uLevel,str2)) {
1636 return False;
1639 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1640 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1641 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1643 if (skip_string(param,tpscnt,p) == NULL) {
1644 return False;
1646 pull_ascii_fstring(domain, p);
1647 if (domain[0] == '\0') {
1648 fstrcpy(domain, lp_workgroup());
1650 p = skip_string(param,tpscnt,p);
1651 if (skip_string(param,tpscnt,p) == NULL) {
1652 return False;
1654 pull_ascii_fstring(first_name, p);
1656 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1657 domain, first_name));
1659 if (lp_browse_list()) {
1660 total = get_server_info(servertype,&servers,domain);
1663 data_len = fixed_len = string_len = 0;
1664 missed = 0;
1666 TYPESAFE_QSORT(servers, total, srv_comp);
1668 if (first_name[0] != '\0') {
1669 struct srv_info_struct *first_server = NULL;
1671 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1672 srv_name_match, first_server);
1673 if (first_server) {
1674 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1676 * The binary search may not find the exact match
1677 * so we need to search backward to find the first match
1679 * This implements the strange matching windows
1680 * implements. (see the comment in srv_name_match().
1682 for (;first > 0;) {
1683 int ret;
1684 ret = StrCaseCmp(first_name,
1685 servers[first-1].name);
1686 if (ret > 0) {
1687 break;
1689 first--;
1691 } else {
1692 /* we should return no entries */
1693 first = total;
1698 char *lastname=NULL;
1700 for (i=first;i<total;i++) {
1701 struct srv_info_struct *s = &servers[i];
1703 if (lastname && strequal(lastname,s->name)) {
1704 continue;
1706 lastname = s->name;
1707 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1708 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1709 i, s->name, s->type, s->comment, s->domain));
1711 if (data_len < buf_len) {
1712 counted++;
1713 fixed_len += f_len;
1714 string_len += s_len;
1715 } else {
1716 missed++;
1721 *rdata_len = fixed_len + string_len;
1722 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1723 if (!*rdata) {
1724 return False;
1727 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1728 p = *rdata;
1729 f_len = fixed_len;
1730 s_len = string_len;
1733 char *lastname=NULL;
1734 int count2 = counted;
1736 for (i = first; i < total && count2;i++) {
1737 struct srv_info_struct *s = &servers[i];
1739 if (lastname && strequal(lastname,s->name)) {
1740 continue;
1742 lastname = s->name;
1743 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1744 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1745 i, s->name, s->type, s->comment, s->domain));
1746 count2--;
1750 *rparam_len = 8;
1751 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1752 if (!*rparam) {
1753 return False;
1755 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1756 SSVAL(*rparam,2,0);
1757 SSVAL(*rparam,4,counted);
1758 SSVAL(*rparam,6,counted+missed);
1760 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1761 domain,uLevel,first,first_name,
1762 first < total ? servers[first].name : "",
1763 counted,counted+missed));
1765 SAFE_FREE(servers);
1767 return True;
1770 /****************************************************************************
1771 command 0x34 - suspected of being a "Lookup Names" stub api
1772 ****************************************************************************/
1774 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1775 char *param, int tpscnt,
1776 char *data, int tdscnt,
1777 int mdrcnt, int mprcnt, char **rdata,
1778 char **rparam, int *rdata_len, int *rparam_len)
1780 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1781 char *str2 = skip_string(param,tpscnt,str1);
1782 char *p = skip_string(param,tpscnt,str2);
1783 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1784 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1785 int counted=0;
1786 int missed=0;
1788 if (!str1 || !str2 || !p) {
1789 return False;
1792 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1793 str1, str2, p, uLevel, buf_len));
1795 if (!prefix_ok(str1,"zWrLeh")) {
1796 return False;
1799 *rdata_len = 0;
1801 *rparam_len = 8;
1802 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1803 if (!*rparam) {
1804 return False;
1807 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1808 SSVAL(*rparam,2,0);
1809 SSVAL(*rparam,4,counted);
1810 SSVAL(*rparam,6,counted+missed);
1812 return True;
1815 /****************************************************************************
1816 get info about a share
1817 ****************************************************************************/
1819 static bool check_share_info(int uLevel, char* id)
1821 switch( uLevel ) {
1822 case 0:
1823 if (strcmp(id,"B13") != 0) {
1824 return False;
1826 break;
1827 case 1:
1828 /* Level-2 descriptor is allowed (and ignored) */
1829 if (strcmp(id,"B13BWz") != 0 &&
1830 strcmp(id,"B13BWzWWWzB9B") != 0) {
1831 return False;
1833 break;
1834 case 2:
1835 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1836 return False;
1838 break;
1839 case 91:
1840 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1841 return False;
1843 break;
1844 default:
1845 return False;
1847 return True;
1850 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1851 char** buf, int* buflen,
1852 char** stringbuf, int* stringspace, char* baseaddr)
1854 int struct_len;
1855 char* p;
1856 char* p2;
1857 int l2;
1858 int len;
1860 switch( uLevel ) {
1861 case 0:
1862 struct_len = 13;
1863 break;
1864 case 1:
1865 struct_len = 20;
1866 break;
1867 case 2:
1868 struct_len = 40;
1869 break;
1870 case 91:
1871 struct_len = 68;
1872 break;
1873 default:
1874 return -1;
1877 if (!buf) {
1878 len = 0;
1880 if (uLevel > 0) {
1881 len += StrlenExpanded(conn,snum,lp_comment(snum));
1883 if (uLevel > 1) {
1884 len += strlen(lp_pathname(snum)) + 1;
1886 if (buflen) {
1887 *buflen = struct_len;
1889 if (stringspace) {
1890 *stringspace = len;
1892 return struct_len + len;
1895 len = struct_len;
1896 p = *buf;
1897 if ((*buflen) < struct_len) {
1898 return -1;
1901 if (stringbuf) {
1902 p2 = *stringbuf;
1903 l2 = *stringspace;
1904 } else {
1905 p2 = p + struct_len;
1906 l2 = (*buflen) - struct_len;
1909 if (!baseaddr) {
1910 baseaddr = p;
1913 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1915 if (uLevel > 0) {
1916 int type;
1918 SCVAL(p,13,0);
1919 type = STYPE_DISKTREE;
1920 if (lp_print_ok(snum)) {
1921 type = STYPE_PRINTQ;
1923 if (strequal("IPC",lp_fstype(snum))) {
1924 type = STYPE_IPC;
1926 SSVAL(p,14,type); /* device type */
1927 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1928 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1931 if (uLevel > 1) {
1932 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1933 SSVALS(p,22,-1); /* max uses */
1934 SSVAL(p,24,1); /* current uses */
1935 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1936 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1937 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1940 if (uLevel > 2) {
1941 memset(p+40,0,SHPWLEN+2);
1942 SSVAL(p,50,0);
1943 SIVAL(p,52,0);
1944 SSVAL(p,56,0);
1945 SSVAL(p,58,0);
1946 SIVAL(p,60,0);
1947 SSVAL(p,64,0);
1948 SSVAL(p,66,0);
1951 if (stringbuf) {
1952 (*buf) = p + struct_len;
1953 (*buflen) -= struct_len;
1954 (*stringbuf) = p2;
1955 (*stringspace) = l2;
1956 } else {
1957 (*buf) = p2;
1958 (*buflen) -= len;
1961 return len;
1964 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1965 char *param, int tpscnt,
1966 char *data, int tdscnt,
1967 int mdrcnt,int mprcnt,
1968 char **rdata,char **rparam,
1969 int *rdata_len,int *rparam_len)
1971 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1972 char *str2 = skip_string(param,tpscnt,str1);
1973 char *netname = skip_string(param,tpscnt,str2);
1974 char *p = skip_string(param,tpscnt,netname);
1975 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1976 int snum;
1978 if (!str1 || !str2 || !netname || !p) {
1979 return False;
1982 snum = find_service(netname);
1983 if (snum < 0) {
1984 return False;
1987 /* check it's a supported varient */
1988 if (!prefix_ok(str1,"zWrLh")) {
1989 return False;
1991 if (!check_share_info(uLevel,str2)) {
1992 return False;
1995 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1996 if (!*rdata) {
1997 return False;
1999 p = *rdata;
2000 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
2001 if (*rdata_len < 0) {
2002 return False;
2005 *rparam_len = 6;
2006 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2007 if (!*rparam) {
2008 return False;
2010 SSVAL(*rparam,0,NERR_Success);
2011 SSVAL(*rparam,2,0); /* converter word */
2012 SSVAL(*rparam,4,*rdata_len);
2014 return True;
2017 /****************************************************************************
2018 View the list of available shares.
2020 This function is the server side of the NetShareEnum() RAP call.
2021 It fills the return buffer with share names and share comments.
2022 Note that the return buffer normally (in all known cases) allows only
2023 twelve byte strings for share names (plus one for a nul terminator).
2024 Share names longer than 12 bytes must be skipped.
2025 ****************************************************************************/
2027 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
2028 char *param, int tpscnt,
2029 char *data, int tdscnt,
2030 int mdrcnt,
2031 int mprcnt,
2032 char **rdata,
2033 char **rparam,
2034 int *rdata_len,
2035 int *rparam_len )
2037 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2038 char *str2 = skip_string(param,tpscnt,str1);
2039 char *p = skip_string(param,tpscnt,str2);
2040 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2041 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
2042 char *p2;
2043 int count = 0;
2044 int total=0,counted=0;
2045 bool missed = False;
2046 int i;
2047 int data_len, fixed_len, string_len;
2048 int f_len = 0, s_len = 0;
2050 if (!str1 || !str2 || !p) {
2051 return False;
2054 if (!prefix_ok(str1,"WrLeh")) {
2055 return False;
2057 if (!check_share_info(uLevel,str2)) {
2058 return False;
2061 /* Ensure all the usershares are loaded. */
2062 become_root();
2063 load_registry_shares();
2064 count = load_usershare_shares();
2065 unbecome_root();
2067 data_len = fixed_len = string_len = 0;
2068 for (i=0;i<count;i++) {
2069 fstring servicename_dos;
2070 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2071 continue;
2073 push_ascii_fstring(servicename_dos, lp_servicename(i));
2074 /* Maximum name length = 13. */
2075 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
2076 total++;
2077 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
2078 if (data_len < buf_len) {
2079 counted++;
2080 fixed_len += f_len;
2081 string_len += s_len;
2082 } else {
2083 missed = True;
2088 *rdata_len = fixed_len + string_len;
2089 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2090 if (!*rdata) {
2091 return False;
2094 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
2095 p = *rdata;
2096 f_len = fixed_len;
2097 s_len = string_len;
2099 for( i = 0; i < count; i++ ) {
2100 fstring servicename_dos;
2101 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2102 continue;
2105 push_ascii_fstring(servicename_dos, lp_servicename(i));
2106 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2107 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2108 break;
2113 *rparam_len = 8;
2114 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2115 if (!*rparam) {
2116 return False;
2118 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2119 SSVAL(*rparam,2,0);
2120 SSVAL(*rparam,4,counted);
2121 SSVAL(*rparam,6,total);
2123 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2124 counted,total,uLevel,
2125 buf_len,*rdata_len,mdrcnt));
2127 return True;
2130 /****************************************************************************
2131 Add a share
2132 ****************************************************************************/
2134 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
2135 char *param, int tpscnt,
2136 char *data, int tdscnt,
2137 int mdrcnt,int mprcnt,
2138 char **rdata,char **rparam,
2139 int *rdata_len,int *rparam_len)
2141 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2142 char *str2 = skip_string(param,tpscnt,str1);
2143 char *p = skip_string(param,tpscnt,str2);
2144 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2145 fstring sharename;
2146 fstring comment;
2147 char *pathname = NULL;
2148 unsigned int offset;
2149 int res = ERRunsup;
2150 size_t converted_size;
2152 WERROR werr = WERR_OK;
2153 TALLOC_CTX *mem_ctx = talloc_tos();
2154 NTSTATUS status;
2155 struct rpc_pipe_client *cli = NULL;
2156 union srvsvc_NetShareInfo info;
2157 struct srvsvc_NetShareInfo2 info2;
2159 if (!str1 || !str2 || !p) {
2160 return False;
2163 /* check it's a supported varient */
2164 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2165 return False;
2167 if (!check_share_info(uLevel,str2)) {
2168 return False;
2170 if (uLevel != 2) {
2171 return False;
2174 /* Do we have a string ? */
2175 if (skip_string(data,mdrcnt,data) == NULL) {
2176 return False;
2178 pull_ascii_fstring(sharename,data);
2180 if (mdrcnt < 28) {
2181 return False;
2184 /* only support disk share adds */
2185 if (SVAL(data,14)!=STYPE_DISKTREE) {
2186 return False;
2189 offset = IVAL(data, 16);
2190 if (offset >= mdrcnt) {
2191 res = ERRinvalidparam;
2192 goto out;
2195 /* Do we have a string ? */
2196 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2197 return False;
2199 pull_ascii_fstring(comment, offset? (data+offset) : "");
2201 offset = IVAL(data, 26);
2203 if (offset >= mdrcnt) {
2204 res = ERRinvalidparam;
2205 goto out;
2208 /* Do we have a string ? */
2209 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2210 return False;
2213 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2214 offset ? (data+offset) : "", &converted_size))
2216 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
2217 strerror(errno)));
2220 if (!pathname) {
2221 return false;
2224 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_srvsvc.syntax_id,
2225 rpc_srvsvc_dispatch, conn->server_info,
2226 &cli);
2227 if (!NT_STATUS_IS_OK(status)) {
2228 DEBUG(0,("api_RNetShareAdd: could not connect to srvsvc: %s\n",
2229 nt_errstr(status)));
2230 res = W_ERROR_V(ntstatus_to_werror(status));
2231 goto out;
2234 info2.name = sharename;
2235 info2.type = STYPE_DISKTREE;
2236 info2.comment = comment;
2237 info2.permissions = 0;
2238 info2.max_users = 0;
2239 info2.current_users = 0;
2240 info2.path = pathname;
2241 info2.password = NULL;
2243 info.info2 = &info2;
2245 status = rpccli_srvsvc_NetShareAdd(cli, mem_ctx,
2246 cli->srv_name_slash,
2248 &info,
2249 NULL,
2250 &werr);
2251 if (!NT_STATUS_IS_OK(status)) {
2252 res = W_ERROR_V(ntstatus_to_werror(status));
2253 goto out;
2255 if (!W_ERROR_IS_OK(werr)) {
2256 res = W_ERROR_V(werr);
2257 goto out;
2260 *rparam_len = 6;
2261 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2262 if (!*rparam) {
2263 return False;
2265 SSVAL(*rparam,0,NERR_Success);
2266 SSVAL(*rparam,2,0); /* converter word */
2267 SSVAL(*rparam,4,*rdata_len);
2268 *rdata_len = 0;
2270 return True;
2272 out:
2274 *rparam_len = 4;
2275 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2276 if (!*rparam) {
2277 return False;
2279 *rdata_len = 0;
2280 SSVAL(*rparam,0,res);
2281 SSVAL(*rparam,2,0);
2282 return True;
2285 /****************************************************************************
2286 view list of groups available
2287 ****************************************************************************/
2289 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
2290 char *param, int tpscnt,
2291 char *data, int tdscnt,
2292 int mdrcnt,int mprcnt,
2293 char **rdata,char **rparam,
2294 int *rdata_len,int *rparam_len)
2296 int i;
2297 int errflags=0;
2298 int resume_context, cli_buf_size;
2299 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2300 char *str2 = skip_string(param,tpscnt,str1);
2301 char *p = skip_string(param,tpscnt,str2);
2303 uint32_t num_groups;
2304 uint32_t resume_handle;
2305 struct rpc_pipe_client *samr_pipe;
2306 struct policy_handle samr_handle, domain_handle;
2307 NTSTATUS status;
2309 if (!str1 || !str2 || !p) {
2310 return False;
2313 if (strcmp(str1,"WrLeh") != 0) {
2314 return False;
2317 /* parameters
2318 * W-> resume context (number of users to skip)
2319 * r -> return parameter pointer to receive buffer
2320 * L -> length of receive buffer
2321 * e -> return parameter number of entries
2322 * h -> return parameter total number of users
2325 if (strcmp("B21",str2) != 0) {
2326 return False;
2329 status = rpc_pipe_open_internal(
2330 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2331 conn->server_info, &samr_pipe);
2332 if (!NT_STATUS_IS_OK(status)) {
2333 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2334 nt_errstr(status)));
2335 return false;
2338 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2339 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2340 if (!NT_STATUS_IS_OK(status)) {
2341 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2342 nt_errstr(status)));
2343 return false;
2346 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2347 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2348 get_global_sam_sid(), &domain_handle);
2349 if (!NT_STATUS_IS_OK(status)) {
2350 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2351 nt_errstr(status)));
2352 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2353 return false;
2356 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2357 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2358 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2359 "%d\n", resume_context, cli_buf_size));
2361 *rdata_len = cli_buf_size;
2362 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2363 if (!*rdata) {
2364 return False;
2367 p = *rdata;
2369 errflags = NERR_Success;
2370 num_groups = 0;
2371 resume_handle = 0;
2373 while (true) {
2374 struct samr_SamArray *sam_entries;
2375 uint32_t num_entries;
2377 status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
2378 &domain_handle,
2379 &resume_handle,
2380 &sam_entries, 1,
2381 &num_entries);
2382 if (!NT_STATUS_IS_OK(status)) {
2383 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2384 "%s\n", nt_errstr(status)));
2385 break;
2388 if (num_entries == 0) {
2389 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2390 "no entries -- done\n"));
2391 break;
2394 for(i=0; i<num_entries; i++) {
2395 const char *name;
2397 name = sam_entries->entries[i].name.string;
2399 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2400 /* set overflow error */
2401 DEBUG(3,("overflow on entry %d group %s\n", i,
2402 name));
2403 errflags=234;
2404 break;
2407 /* truncate the name at 21 chars. */
2408 memset(p, 0, 21);
2409 strlcpy(p, name, 21);
2410 DEBUG(10,("adding entry %d group %s\n", i, p));
2411 p += 21;
2412 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2413 * idea why... */
2414 num_groups += 1;
2417 if (errflags != NERR_Success) {
2418 break;
2421 TALLOC_FREE(sam_entries);
2424 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2425 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2427 *rdata_len = PTR_DIFF(p,*rdata);
2429 *rparam_len = 8;
2430 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2431 if (!*rparam) {
2432 return False;
2434 SSVAL(*rparam, 0, errflags);
2435 SSVAL(*rparam, 2, 0); /* converter word */
2436 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2437 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2439 return(True);
2442 /*******************************************************************
2443 Get groups that a user is a member of.
2444 ******************************************************************/
2446 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2447 char *param, int tpscnt,
2448 char *data, int tdscnt,
2449 int mdrcnt,int mprcnt,
2450 char **rdata,char **rparam,
2451 int *rdata_len,int *rparam_len)
2453 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2454 char *str2 = skip_string(param,tpscnt,str1);
2455 char *UserName = skip_string(param,tpscnt,str2);
2456 char *p = skip_string(param,tpscnt,UserName);
2457 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2458 const char *level_string;
2459 int count=0;
2460 bool ret = False;
2461 uint32_t i;
2462 char *endp = NULL;
2464 struct rpc_pipe_client *samr_pipe;
2465 struct policy_handle samr_handle, domain_handle, user_handle;
2466 struct lsa_String name;
2467 struct lsa_Strings names;
2468 struct samr_Ids type, rid;
2469 struct samr_RidWithAttributeArray *rids;
2470 NTSTATUS status;
2472 if (!str1 || !str2 || !UserName || !p) {
2473 return False;
2476 *rparam_len = 8;
2477 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2478 if (!*rparam) {
2479 return False;
2482 /* check it's a supported varient */
2484 if ( strcmp(str1,"zWrLeh") != 0 )
2485 return False;
2487 switch( uLevel ) {
2488 case 0:
2489 level_string = "B21";
2490 break;
2491 default:
2492 return False;
2495 if (strcmp(level_string,str2) != 0)
2496 return False;
2498 *rdata_len = mdrcnt + 1024;
2499 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2500 if (!*rdata) {
2501 return False;
2504 SSVAL(*rparam,0,NERR_Success);
2505 SSVAL(*rparam,2,0); /* converter word */
2507 p = *rdata;
2508 endp = *rdata + *rdata_len;
2510 status = rpc_pipe_open_internal(
2511 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2512 conn->server_info, &samr_pipe);
2513 if (!NT_STATUS_IS_OK(status)) {
2514 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2515 nt_errstr(status)));
2516 return false;
2519 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2520 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2521 if (!NT_STATUS_IS_OK(status)) {
2522 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2523 nt_errstr(status)));
2524 return false;
2527 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2528 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2529 get_global_sam_sid(), &domain_handle);
2530 if (!NT_STATUS_IS_OK(status)) {
2531 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2532 nt_errstr(status)));
2533 goto close_sam;
2536 name.string = UserName;
2538 status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
2539 &domain_handle, 1, &name,
2540 &rid, &type);
2541 if (!NT_STATUS_IS_OK(status)) {
2542 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2543 nt_errstr(status)));
2544 goto close_domain;
2547 if (type.ids[0] != SID_NAME_USER) {
2548 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2549 sid_type_lookup(type.ids[0])));
2550 goto close_domain;
2553 status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
2554 &domain_handle,
2555 SAMR_USER_ACCESS_GET_GROUPS,
2556 rid.ids[0], &user_handle);
2557 if (!NT_STATUS_IS_OK(status)) {
2558 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2559 nt_errstr(status)));
2560 goto close_domain;
2563 status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
2564 &user_handle, &rids);
2565 if (!NT_STATUS_IS_OK(status)) {
2566 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2567 nt_errstr(status)));
2568 goto close_user;
2571 for (i=0; i<rids->count; i++) {
2573 status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
2574 &domain_handle,
2575 1, &rids->rids[i].rid,
2576 &names, &type);
2577 if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
2578 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2579 p += 21;
2580 count++;
2584 *rdata_len = PTR_DIFF(p,*rdata);
2586 SSVAL(*rparam,4,count); /* is this right?? */
2587 SSVAL(*rparam,6,count); /* is this right?? */
2589 ret = True;
2591 close_user:
2592 rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
2593 close_domain:
2594 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2595 close_sam:
2596 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2598 return ret;
2601 /*******************************************************************
2602 Get all users.
2603 ******************************************************************/
2605 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2606 char *param, int tpscnt,
2607 char *data, int tdscnt,
2608 int mdrcnt,int mprcnt,
2609 char **rdata,char **rparam,
2610 int *rdata_len,int *rparam_len)
2612 int count_sent=0;
2613 int num_users=0;
2614 int errflags=0;
2615 int i, resume_context, cli_buf_size;
2616 uint32_t resume_handle;
2618 struct rpc_pipe_client *samr_pipe;
2619 struct policy_handle samr_handle, domain_handle;
2620 NTSTATUS status;
2622 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2623 char *str2 = skip_string(param,tpscnt,str1);
2624 char *p = skip_string(param,tpscnt,str2);
2625 char *endp = NULL;
2627 if (!str1 || !str2 || !p) {
2628 return False;
2631 if (strcmp(str1,"WrLeh") != 0)
2632 return False;
2633 /* parameters
2634 * W-> resume context (number of users to skip)
2635 * r -> return parameter pointer to receive buffer
2636 * L -> length of receive buffer
2637 * e -> return parameter number of entries
2638 * h -> return parameter total number of users
2641 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2642 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2643 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2644 resume_context, cli_buf_size));
2646 *rparam_len = 8;
2647 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2648 if (!*rparam) {
2649 return False;
2652 /* check it's a supported varient */
2653 if (strcmp("B21",str2) != 0)
2654 return False;
2656 *rdata_len = cli_buf_size;
2657 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2658 if (!*rdata) {
2659 return False;
2662 p = *rdata;
2663 endp = *rdata + *rdata_len;
2665 status = rpc_pipe_open_internal(
2666 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2667 conn->server_info, &samr_pipe);
2668 if (!NT_STATUS_IS_OK(status)) {
2669 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2670 nt_errstr(status)));
2671 return false;
2674 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2675 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2676 if (!NT_STATUS_IS_OK(status)) {
2677 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2678 nt_errstr(status)));
2679 return false;
2682 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2683 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2684 get_global_sam_sid(), &domain_handle);
2685 if (!NT_STATUS_IS_OK(status)) {
2686 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2687 nt_errstr(status)));
2688 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2689 return false;
2692 errflags=NERR_Success;
2694 resume_handle = 0;
2696 while (true) {
2697 struct samr_SamArray *sam_entries;
2698 uint32_t num_entries;
2700 status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
2701 &domain_handle,
2702 &resume_handle,
2703 0, &sam_entries, 1,
2704 &num_entries);
2706 if (!NT_STATUS_IS_OK(status)) {
2707 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2708 "%s\n", nt_errstr(status)));
2709 break;
2712 if (num_entries == 0) {
2713 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2714 "no entries -- done\n"));
2715 break;
2718 for (i=0; i<num_entries; i++) {
2719 const char *name;
2721 name = sam_entries->entries[i].name.string;
2723 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2724 &&(strlen(name)<=21)) {
2725 strlcpy(p,name,PTR_DIFF(endp,p));
2726 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2727 "username %s\n",count_sent,p));
2728 p += 21;
2729 count_sent++;
2730 } else {
2731 /* set overflow error */
2732 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2733 "username %s\n",count_sent,name));
2734 errflags=234;
2735 break;
2739 if (errflags != NERR_Success) {
2740 break;
2743 TALLOC_FREE(sam_entries);
2746 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2747 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2749 *rdata_len = PTR_DIFF(p,*rdata);
2751 SSVAL(*rparam,0,errflags);
2752 SSVAL(*rparam,2,0); /* converter word */
2753 SSVAL(*rparam,4,count_sent); /* is this right?? */
2754 SSVAL(*rparam,6,num_users); /* is this right?? */
2756 return True;
2759 /****************************************************************************
2760 Get the time of day info.
2761 ****************************************************************************/
2763 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2764 char *param, int tpscnt,
2765 char *data, int tdscnt,
2766 int mdrcnt,int mprcnt,
2767 char **rdata,char **rparam,
2768 int *rdata_len,int *rparam_len)
2770 struct tm *t;
2771 time_t unixdate = time(NULL);
2772 char *p;
2774 *rparam_len = 4;
2775 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2776 if (!*rparam) {
2777 return False;
2780 *rdata_len = 21;
2781 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2782 if (!*rdata) {
2783 return False;
2786 SSVAL(*rparam,0,NERR_Success);
2787 SSVAL(*rparam,2,0); /* converter word */
2789 p = *rdata;
2791 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2792 by NT in a "net time" operation,
2793 it seems to ignore the one below */
2795 /* the client expects to get localtime, not GMT, in this bit
2796 (I think, this needs testing) */
2797 t = localtime(&unixdate);
2798 if (!t) {
2799 return False;
2802 SIVAL(p,4,0); /* msecs ? */
2803 SCVAL(p,8,t->tm_hour);
2804 SCVAL(p,9,t->tm_min);
2805 SCVAL(p,10,t->tm_sec);
2806 SCVAL(p,11,0); /* hundredths of seconds */
2807 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2808 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2809 SCVAL(p,16,t->tm_mday);
2810 SCVAL(p,17,t->tm_mon + 1);
2811 SSVAL(p,18,1900+t->tm_year);
2812 SCVAL(p,20,t->tm_wday);
2814 return True;
2817 /****************************************************************************
2818 Set the user password.
2819 *****************************************************************************/
2821 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2822 char *param, int tpscnt,
2823 char *data, int tdscnt,
2824 int mdrcnt,int mprcnt,
2825 char **rdata,char **rparam,
2826 int *rdata_len,int *rparam_len)
2828 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2829 char *p = NULL;
2830 fstring user;
2831 fstring pass1,pass2;
2833 /* Skip 2 strings. */
2834 p = skip_string(param,tpscnt,np);
2835 p = skip_string(param,tpscnt,p);
2837 if (!np || !p) {
2838 return False;
2841 /* Do we have a string ? */
2842 if (skip_string(param,tpscnt,p) == NULL) {
2843 return False;
2845 pull_ascii_fstring(user,p);
2847 p = skip_string(param,tpscnt,p);
2848 if (!p) {
2849 return False;
2852 memset(pass1,'\0',sizeof(pass1));
2853 memset(pass2,'\0',sizeof(pass2));
2855 * We use 31 here not 32 as we're checking
2856 * the last byte we want to access is safe.
2858 if (!is_offset_safe(param,tpscnt,p,31)) {
2859 return False;
2861 memcpy(pass1,p,16);
2862 memcpy(pass2,p+16,16);
2864 *rparam_len = 4;
2865 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2866 if (!*rparam) {
2867 return False;
2870 *rdata_len = 0;
2872 SSVAL(*rparam,0,NERR_badpass);
2873 SSVAL(*rparam,2,0); /* converter word */
2875 DEBUG(3,("Set password for <%s>\n",user));
2878 * Attempt to verify the old password against smbpasswd entries
2879 * Win98 clients send old and new password in plaintext for this call.
2883 struct auth_serversupplied_info *server_info = NULL;
2884 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2886 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2888 become_root();
2889 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2890 SSVAL(*rparam,0,NERR_Success);
2892 unbecome_root();
2894 TALLOC_FREE(server_info);
2896 data_blob_clear_free(&password);
2900 * If the plaintext change failed, attempt
2901 * the old encrypted method. NT will generate this
2902 * after trying the samr method. Note that this
2903 * method is done as a last resort as this
2904 * password change method loses the NT password hash
2905 * and cannot change the UNIX password as no plaintext
2906 * is received.
2909 if(SVAL(*rparam,0) != NERR_Success) {
2910 struct samu *hnd = NULL;
2912 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2913 become_root();
2914 if (change_lanman_password(hnd,(uchar *)pass2)) {
2915 SSVAL(*rparam,0,NERR_Success);
2917 unbecome_root();
2918 TALLOC_FREE(hnd);
2922 memset((char *)pass1,'\0',sizeof(fstring));
2923 memset((char *)pass2,'\0',sizeof(fstring));
2925 return(True);
2928 /****************************************************************************
2929 Set the user password (SamOEM version - gets plaintext).
2930 ****************************************************************************/
2932 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2933 char *param, int tpscnt,
2934 char *data, int tdscnt,
2935 int mdrcnt,int mprcnt,
2936 char **rdata,char **rparam,
2937 int *rdata_len,int *rparam_len)
2939 struct smbd_server_connection *sconn = smbd_server_conn;
2940 fstring user;
2941 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2942 *rparam_len = 2;
2943 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2944 if (!*rparam) {
2945 return False;
2948 if (!p) {
2949 return False;
2951 *rdata_len = 0;
2953 SSVAL(*rparam,0,NERR_badpass);
2956 * Check the parameter definition is correct.
2959 /* Do we have a string ? */
2960 if (skip_string(param,tpscnt,p) == 0) {
2961 return False;
2963 if(!strequal(p, "zsT")) {
2964 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2965 return False;
2967 p = skip_string(param, tpscnt, p);
2968 if (!p) {
2969 return False;
2972 /* Do we have a string ? */
2973 if (skip_string(param,tpscnt,p) == 0) {
2974 return False;
2976 if(!strequal(p, "B516B16")) {
2977 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2978 return False;
2980 p = skip_string(param,tpscnt,p);
2981 if (!p) {
2982 return False;
2984 /* Do we have a string ? */
2985 if (skip_string(param,tpscnt,p) == 0) {
2986 return False;
2988 p += pull_ascii_fstring(user,p);
2990 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2993 * Pass the user through the NT -> unix user mapping
2994 * function.
2997 (void)map_username(sconn, user);
2999 if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
3000 SSVAL(*rparam,0,NERR_Success);
3003 return(True);
3006 /****************************************************************************
3007 delete a print job
3008 Form: <W> <>
3009 ****************************************************************************/
3011 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
3012 char *param, int tpscnt,
3013 char *data, int tdscnt,
3014 int mdrcnt,int mprcnt,
3015 char **rdata,char **rparam,
3016 int *rdata_len,int *rparam_len)
3018 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3019 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3020 char *str2 = skip_string(param,tpscnt,str1);
3021 char *p = skip_string(param,tpscnt,str2);
3022 uint32 jobid;
3023 fstring sharename;
3024 int errcode;
3025 WERROR werr = WERR_OK;
3027 TALLOC_CTX *mem_ctx = talloc_tos();
3028 NTSTATUS status;
3029 struct rpc_pipe_client *cli = NULL;
3030 struct policy_handle handle;
3031 struct spoolss_DevmodeContainer devmode_ctr;
3032 enum spoolss_JobControl command;
3034 if (!str1 || !str2 || !p) {
3035 return False;
3038 * We use 1 here not 2 as we're checking
3039 * the last byte we want to access is safe.
3041 if (!is_offset_safe(param,tpscnt,p,1)) {
3042 return False;
3044 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3045 return False;
3047 /* check it's a supported varient */
3048 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
3049 return(False);
3051 *rparam_len = 4;
3052 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3053 if (!*rparam) {
3054 return False;
3056 *rdata_len = 0;
3058 ZERO_STRUCT(handle);
3060 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3061 rpc_spoolss_dispatch, conn->server_info,
3062 &cli);
3063 if (!NT_STATUS_IS_OK(status)) {
3064 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
3065 nt_errstr(status)));
3066 errcode = W_ERROR_V(ntstatus_to_werror(status));
3067 goto out;
3070 ZERO_STRUCT(devmode_ctr);
3072 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3073 sharename,
3074 NULL,
3075 devmode_ctr,
3076 SEC_FLAG_MAXIMUM_ALLOWED,
3077 &handle,
3078 &werr);
3079 if (!NT_STATUS_IS_OK(status)) {
3080 errcode = W_ERROR_V(ntstatus_to_werror(status));
3081 goto out;
3083 if (!W_ERROR_IS_OK(werr)) {
3084 errcode = W_ERROR_V(werr);
3085 goto out;
3088 /* FIXME: formerly NERR_JobNotFound was returned if job did not exist
3089 * and NERR_DestNotFound if share did not exist */
3091 errcode = NERR_Success;
3093 switch (function) {
3094 case 81: /* delete */
3095 command = SPOOLSS_JOB_CONTROL_DELETE;
3096 break;
3097 case 82: /* pause */
3098 command = SPOOLSS_JOB_CONTROL_PAUSE;
3099 break;
3100 case 83: /* resume */
3101 command = SPOOLSS_JOB_CONTROL_RESUME;
3102 break;
3103 default:
3104 errcode = NERR_notsupported;
3105 goto out;
3108 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3109 &handle,
3110 jobid,
3111 NULL, /* unique ptr ctr */
3112 command,
3113 &werr);
3114 if (!NT_STATUS_IS_OK(status)) {
3115 errcode = W_ERROR_V(ntstatus_to_werror(status));
3116 goto out;
3118 if (!W_ERROR_IS_OK(werr)) {
3119 errcode = W_ERROR_V(werr);
3120 goto out;
3123 out:
3124 if (cli && is_valid_policy_hnd(&handle)) {
3125 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3128 SSVAL(*rparam,0,errcode);
3129 SSVAL(*rparam,2,0); /* converter word */
3131 return(True);
3134 /****************************************************************************
3135 Purge a print queue - or pause or resume it.
3136 ****************************************************************************/
3138 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
3139 char *param, int tpscnt,
3140 char *data, int tdscnt,
3141 int mdrcnt,int mprcnt,
3142 char **rdata,char **rparam,
3143 int *rdata_len,int *rparam_len)
3145 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3146 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3147 char *str2 = skip_string(param,tpscnt,str1);
3148 char *QueueName = skip_string(param,tpscnt,str2);
3149 int errcode = NERR_notsupported;
3150 WERROR werr = WERR_OK;
3151 NTSTATUS status;
3153 TALLOC_CTX *mem_ctx = talloc_tos();
3154 struct rpc_pipe_client *cli = NULL;
3155 struct policy_handle handle;
3156 struct spoolss_SetPrinterInfoCtr info_ctr;
3157 struct spoolss_DevmodeContainer devmode_ctr;
3158 struct sec_desc_buf secdesc_ctr;
3159 enum spoolss_PrinterControl command;
3161 if (!str1 || !str2 || !QueueName) {
3162 return False;
3165 /* check it's a supported varient */
3166 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3167 return(False);
3169 *rparam_len = 4;
3170 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3171 if (!*rparam) {
3172 return False;
3174 *rdata_len = 0;
3176 if (skip_string(param,tpscnt,QueueName) == NULL) {
3177 return False;
3180 ZERO_STRUCT(handle);
3182 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3183 rpc_spoolss_dispatch, conn->server_info,
3184 &cli);
3185 if (!NT_STATUS_IS_OK(status)) {
3186 DEBUG(0,("api_WPrintQueueCtrl: could not connect to spoolss: %s\n",
3187 nt_errstr(status)));
3188 errcode = W_ERROR_V(ntstatus_to_werror(status));
3189 goto out;
3192 ZERO_STRUCT(devmode_ctr);
3194 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3195 QueueName,
3196 NULL,
3197 devmode_ctr,
3198 SEC_FLAG_MAXIMUM_ALLOWED,
3199 &handle,
3200 &werr);
3201 if (!NT_STATUS_IS_OK(status)) {
3202 errcode = W_ERROR_V(ntstatus_to_werror(status));
3203 goto out;
3205 if (!W_ERROR_IS_OK(werr)) {
3206 errcode = W_ERROR_V(werr);
3207 goto out;
3210 switch (function) {
3211 case 74: /* Pause queue */
3212 command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3213 break;
3214 case 75: /* Resume queue */
3215 command = SPOOLSS_PRINTER_CONTROL_RESUME;
3216 break;
3217 case 103: /* Purge */
3218 command = SPOOLSS_PRINTER_CONTROL_PURGE;
3219 break;
3220 default:
3221 werr = WERR_NOT_SUPPORTED;
3222 break;
3225 if (!W_ERROR_IS_OK(werr)) {
3226 errcode = W_ERROR_V(werr);
3227 goto out;
3230 ZERO_STRUCT(info_ctr);
3231 ZERO_STRUCT(secdesc_ctr);
3233 status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
3234 &handle,
3235 &info_ctr,
3236 &devmode_ctr,
3237 &secdesc_ctr,
3238 command,
3239 &werr);
3240 if (!NT_STATUS_IS_OK(status)) {
3241 errcode = W_ERROR_V(ntstatus_to_werror(status));
3242 goto out;
3244 if (!W_ERROR_IS_OK(werr)) {
3245 errcode = W_ERROR_V(werr);
3246 goto out;
3249 errcode = W_ERROR_V(werr);
3251 out:
3253 if (cli && is_valid_policy_hnd(&handle)) {
3254 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3257 SSVAL(*rparam,0,errcode);
3258 SSVAL(*rparam,2,0); /* converter word */
3260 return(True);
3263 /****************************************************************************
3264 set the property of a print job (undocumented?)
3265 ? function = 0xb -> set name of print job
3266 ? function = 0x6 -> move print job up/down
3267 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3268 or <WWsTP> <WB21BB16B10zWWzDDz>
3269 ****************************************************************************/
3271 static int check_printjob_info(struct pack_desc* desc,
3272 int uLevel, char* id)
3274 desc->subformat = NULL;
3275 switch( uLevel ) {
3276 case 0: desc->format = "W"; break;
3277 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3278 case 2: desc->format = "WWzWWDDzz"; break;
3279 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3280 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3281 default:
3282 DEBUG(0,("check_printjob_info: invalid level %d\n",
3283 uLevel ));
3284 return False;
3286 if (id == NULL || strcmp(desc->format,id) != 0) {
3287 DEBUG(0,("check_printjob_info: invalid format %s\n",
3288 id ? id : "<NULL>" ));
3289 return False;
3291 return True;
3294 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
3295 char *param, int tpscnt,
3296 char *data, int tdscnt,
3297 int mdrcnt,int mprcnt,
3298 char **rdata,char **rparam,
3299 int *rdata_len,int *rparam_len)
3301 struct pack_desc desc;
3302 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3303 char *str2 = skip_string(param,tpscnt,str1);
3304 char *p = skip_string(param,tpscnt,str2);
3305 uint32 jobid;
3306 fstring sharename;
3307 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3308 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3309 int errcode;
3311 TALLOC_CTX *mem_ctx = talloc_tos();
3312 WERROR werr;
3313 NTSTATUS status;
3314 struct rpc_pipe_client *cli = NULL;
3315 struct policy_handle handle;
3316 struct spoolss_DevmodeContainer devmode_ctr;
3317 struct spoolss_JobInfoContainer ctr;
3318 union spoolss_JobInfo info;
3319 struct spoolss_SetJobInfo1 info1;
3321 if (!str1 || !str2 || !p) {
3322 return False;
3325 * We use 1 here not 2 as we're checking
3326 * the last byte we want to access is safe.
3328 if (!is_offset_safe(param,tpscnt,p,1)) {
3329 return False;
3331 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3332 return False;
3333 *rparam_len = 4;
3334 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3335 if (!*rparam) {
3336 return False;
3339 *rdata_len = 0;
3341 /* check it's a supported varient */
3342 if ((strcmp(str1,"WWsTP")) ||
3343 (!check_printjob_info(&desc,uLevel,str2)))
3344 return(False);
3346 errcode = NERR_notsupported;
3348 switch (function) {
3349 case 0xb:
3350 /* change print job name, data gives the name */
3351 break;
3352 default:
3353 goto out;
3356 ZERO_STRUCT(handle);
3358 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3359 rpc_spoolss_dispatch, conn->server_info,
3360 &cli);
3361 if (!NT_STATUS_IS_OK(status)) {
3362 DEBUG(0,("api_PrintJobInfo: could not connect to spoolss: %s\n",
3363 nt_errstr(status)));
3364 errcode = W_ERROR_V(ntstatus_to_werror(status));
3365 goto out;
3368 ZERO_STRUCT(devmode_ctr);
3370 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3371 sharename,
3372 NULL,
3373 devmode_ctr,
3374 SEC_FLAG_MAXIMUM_ALLOWED,
3375 &handle,
3376 &werr);
3377 if (!NT_STATUS_IS_OK(status)) {
3378 errcode = W_ERROR_V(ntstatus_to_werror(status));
3379 goto out;
3381 if (!W_ERROR_IS_OK(werr)) {
3382 errcode = W_ERROR_V(werr);
3383 goto out;
3386 werr = rpccli_spoolss_getjob(cli, mem_ctx,
3387 &handle,
3388 jobid,
3389 1, /* level */
3390 0, /* offered */
3391 &info);
3392 if (!W_ERROR_IS_OK(werr)) {
3393 errcode = W_ERROR_V(werr);
3394 goto out;
3397 ZERO_STRUCT(ctr);
3399 info1.job_id = info.info1.job_id;
3400 info1.printer_name = info.info1.printer_name;
3401 info1.user_name = info.info1.user_name;
3402 info1.document_name = data;
3403 info1.data_type = info.info1.data_type;
3404 info1.text_status = info.info1.text_status;
3405 info1.status = info.info1.status;
3406 info1.priority = info.info1.priority;
3407 info1.position = info.info1.position;
3408 info1.total_pages = info.info1.total_pages;
3409 info1.pages_printed = info.info1.pages_printed;
3410 info1.submitted = info.info1.submitted;
3412 ctr.level = 1;
3413 ctr.info.info1 = &info1;
3415 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3416 &handle,
3417 jobid,
3418 &ctr,
3420 &werr);
3421 if (!NT_STATUS_IS_OK(status)) {
3422 errcode = W_ERROR_V(ntstatus_to_werror(status));
3423 goto out;
3425 if (!W_ERROR_IS_OK(werr)) {
3426 errcode = W_ERROR_V(werr);
3427 goto out;
3430 errcode = NERR_Success;
3431 out:
3433 if (cli && is_valid_policy_hnd(&handle)) {
3434 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3437 SSVALS(*rparam,0,errcode);
3438 SSVAL(*rparam,2,0); /* converter word */
3440 return(True);
3444 /****************************************************************************
3445 Get info about the server.
3446 ****************************************************************************/
3448 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
3449 char *param, int tpscnt,
3450 char *data, int tdscnt,
3451 int mdrcnt,int mprcnt,
3452 char **rdata,char **rparam,
3453 int *rdata_len,int *rparam_len)
3455 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3456 char *str2 = skip_string(param,tpscnt,str1);
3457 char *p = skip_string(param,tpscnt,str2);
3458 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3459 char *p2;
3460 int struct_len;
3462 if (!str1 || !str2 || !p) {
3463 return False;
3466 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3468 /* check it's a supported varient */
3469 if (!prefix_ok(str1,"WrLh")) {
3470 return False;
3473 switch( uLevel ) {
3474 case 0:
3475 if (strcmp(str2,"B16") != 0) {
3476 return False;
3478 struct_len = 16;
3479 break;
3480 case 1:
3481 if (strcmp(str2,"B16BBDz") != 0) {
3482 return False;
3484 struct_len = 26;
3485 break;
3486 case 2:
3487 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3488 return False;
3490 struct_len = 134;
3491 break;
3492 case 3:
3493 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3494 return False;
3496 struct_len = 144;
3497 break;
3498 case 20:
3499 if (strcmp(str2,"DN") != 0) {
3500 return False;
3502 struct_len = 6;
3503 break;
3504 case 50:
3505 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3506 return False;
3508 struct_len = 42;
3509 break;
3510 default:
3511 return False;
3514 *rdata_len = mdrcnt;
3515 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3516 if (!*rdata) {
3517 return False;
3520 p = *rdata;
3521 p2 = p + struct_len;
3522 if (uLevel != 20) {
3523 srvstr_push(NULL, 0, p,global_myname(),16,
3524 STR_ASCII|STR_UPPER|STR_TERMINATE);
3526 p += 16;
3527 if (uLevel > 0) {
3528 struct srv_info_struct *servers=NULL;
3529 int i,count;
3530 char *comment = NULL;
3531 TALLOC_CTX *ctx = talloc_tos();
3532 uint32 servertype= lp_default_server_announce();
3534 comment = talloc_strdup(ctx,lp_serverstring());
3535 if (!comment) {
3536 return false;
3539 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
3540 for (i=0;i<count;i++) {
3541 if (strequal(servers[i].name,global_myname())) {
3542 servertype = servers[i].type;
3543 TALLOC_FREE(comment);
3544 comment = talloc_strdup(ctx,
3545 servers[i].comment);
3546 if (comment) {
3547 return false;
3553 SAFE_FREE(servers);
3555 SCVAL(p,0,lp_major_announce_version());
3556 SCVAL(p,1,lp_minor_announce_version());
3557 SIVAL(p,2,servertype);
3559 if (mdrcnt == struct_len) {
3560 SIVAL(p,6,0);
3561 } else {
3562 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3563 comment = talloc_sub_advanced(
3564 ctx,
3565 lp_servicename(SNUM(conn)),
3566 conn->server_info->unix_name,
3567 conn->connectpath,
3568 conn->server_info->utok.gid,
3569 conn->server_info->sanitized_username,
3570 pdb_get_domain(conn->server_info->sam_account),
3571 comment);
3572 if (comment) {
3573 return false;
3575 if (mdrcnt - struct_len <= 0) {
3576 return false;
3578 push_ascii(p2,
3579 comment,
3580 MIN(mdrcnt - struct_len,
3581 MAX_SERVER_STRING_LENGTH),
3582 STR_TERMINATE);
3583 p2 = skip_string(*rdata,*rdata_len,p2);
3584 if (!p2) {
3585 return False;
3590 if (uLevel > 1) {
3591 return False; /* not yet implemented */
3594 *rdata_len = PTR_DIFF(p2,*rdata);
3596 *rparam_len = 6;
3597 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3598 if (!*rparam) {
3599 return False;
3601 SSVAL(*rparam,0,NERR_Success);
3602 SSVAL(*rparam,2,0); /* converter word */
3603 SSVAL(*rparam,4,*rdata_len);
3605 return True;
3608 /****************************************************************************
3609 Get info about the server.
3610 ****************************************************************************/
3612 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3613 char *param, int tpscnt,
3614 char *data, int tdscnt,
3615 int mdrcnt,int mprcnt,
3616 char **rdata,char **rparam,
3617 int *rdata_len,int *rparam_len)
3619 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3620 char *str2 = skip_string(param,tpscnt,str1);
3621 char *p = skip_string(param,tpscnt,str2);
3622 char *p2;
3623 char *endp;
3624 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3626 if (!str1 || !str2 || !p) {
3627 return False;
3630 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3632 *rparam_len = 6;
3633 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3634 if (!*rparam) {
3635 return False;
3638 /* check it's a supported varient */
3639 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3640 return False;
3643 *rdata_len = mdrcnt + 1024;
3644 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3645 if (!*rdata) {
3646 return False;
3649 SSVAL(*rparam,0,NERR_Success);
3650 SSVAL(*rparam,2,0); /* converter word */
3652 p = *rdata;
3653 endp = *rdata + *rdata_len;
3655 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3656 if (!p2) {
3657 return False;
3660 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3661 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3662 strupper_m(p2);
3663 p2 = skip_string(*rdata,*rdata_len,p2);
3664 if (!p2) {
3665 return False;
3667 p += 4;
3669 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3670 strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3671 p2 = skip_string(*rdata,*rdata_len,p2);
3672 if (!p2) {
3673 return False;
3675 p += 4;
3677 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3678 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3679 strupper_m(p2);
3680 p2 = skip_string(*rdata,*rdata_len,p2);
3681 if (!p2) {
3682 return False;
3684 p += 4;
3686 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3687 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3688 p += 2;
3690 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3691 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3692 p2 = skip_string(*rdata,*rdata_len,p2);
3693 if (!p2) {
3694 return False;
3696 p += 4;
3698 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3699 strlcpy(p2,"",PTR_DIFF(endp,p2));
3700 p2 = skip_string(*rdata,*rdata_len,p2);
3701 if (!p2) {
3702 return False;
3704 p += 4;
3706 *rdata_len = PTR_DIFF(p2,*rdata);
3708 SSVAL(*rparam,4,*rdata_len);
3710 return True;
3713 /****************************************************************************
3714 get info about a user
3716 struct user_info_11 {
3717 char usri11_name[21]; 0-20
3718 char usri11_pad; 21
3719 char *usri11_comment; 22-25
3720 char *usri11_usr_comment; 26-29
3721 unsigned short usri11_priv; 30-31
3722 unsigned long usri11_auth_flags; 32-35
3723 long usri11_password_age; 36-39
3724 char *usri11_homedir; 40-43
3725 char *usri11_parms; 44-47
3726 long usri11_last_logon; 48-51
3727 long usri11_last_logoff; 52-55
3728 unsigned short usri11_bad_pw_count; 56-57
3729 unsigned short usri11_num_logons; 58-59
3730 char *usri11_logon_server; 60-63
3731 unsigned short usri11_country_code; 64-65
3732 char *usri11_workstations; 66-69
3733 unsigned long usri11_max_storage; 70-73
3734 unsigned short usri11_units_per_week; 74-75
3735 unsigned char *usri11_logon_hours; 76-79
3736 unsigned short usri11_code_page; 80-81
3739 where:
3741 usri11_name specifies the user name for which information is retrieved
3743 usri11_pad aligns the next data structure element to a word boundary
3745 usri11_comment is a null terminated ASCII comment
3747 usri11_user_comment is a null terminated ASCII comment about the user
3749 usri11_priv specifies the level of the privilege assigned to the user.
3750 The possible values are:
3752 Name Value Description
3753 USER_PRIV_GUEST 0 Guest privilege
3754 USER_PRIV_USER 1 User privilege
3755 USER_PRV_ADMIN 2 Administrator privilege
3757 usri11_auth_flags specifies the account operator privileges. The
3758 possible values are:
3760 Name Value Description
3761 AF_OP_PRINT 0 Print operator
3764 Leach, Naik [Page 28]
3768 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3771 AF_OP_COMM 1 Communications operator
3772 AF_OP_SERVER 2 Server operator
3773 AF_OP_ACCOUNTS 3 Accounts operator
3776 usri11_password_age specifies how many seconds have elapsed since the
3777 password was last changed.
3779 usri11_home_dir points to a null terminated ASCII string that contains
3780 the path name of the user's home directory.
3782 usri11_parms points to a null terminated ASCII string that is set
3783 aside for use by applications.
3785 usri11_last_logon specifies the time when the user last logged on.
3786 This value is stored as the number of seconds elapsed since
3787 00:00:00, January 1, 1970.
3789 usri11_last_logoff specifies the time when the user last logged off.
3790 This value is stored as the number of seconds elapsed since
3791 00:00:00, January 1, 1970. A value of 0 means the last logoff
3792 time is unknown.
3794 usri11_bad_pw_count specifies the number of incorrect passwords
3795 entered since the last successful logon.
3797 usri11_log1_num_logons specifies the number of times this user has
3798 logged on. A value of -1 means the number of logons is unknown.
3800 usri11_logon_server points to a null terminated ASCII string that
3801 contains the name of the server to which logon requests are sent.
3802 A null string indicates logon requests should be sent to the
3803 domain controller.
3805 usri11_country_code specifies the country code for the user's language
3806 of choice.
3808 usri11_workstations points to a null terminated ASCII string that
3809 contains the names of workstations the user may log on from.
3810 There may be up to 8 workstations, with the names separated by
3811 commas. A null strings indicates there are no restrictions.
3813 usri11_max_storage specifies the maximum amount of disk space the user
3814 can occupy. A value of 0xffffffff indicates there are no
3815 restrictions.
3817 usri11_units_per_week specifies the equal number of time units into
3818 which a week is divided. This value must be equal to 168.
3820 usri11_logon_hours points to a 21 byte (168 bits) string that
3821 specifies the time during which the user can log on. Each bit
3822 represents one unique hour in a week. The first bit (bit 0, word
3823 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3827 Leach, Naik [Page 29]
3831 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3834 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3835 are no restrictions.
3837 usri11_code_page specifies the code page for the user's language of
3838 choice
3840 All of the pointers in this data structure need to be treated
3841 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3842 to be ignored. The converter word returned in the parameters section
3843 needs to be subtracted from the lower 16 bits to calculate an offset
3844 into the return buffer where this ASCII string resides.
3846 There is no auxiliary data in the response.
3848 ****************************************************************************/
3850 #define usri11_name 0
3851 #define usri11_pad 21
3852 #define usri11_comment 22
3853 #define usri11_usr_comment 26
3854 #define usri11_full_name 30
3855 #define usri11_priv 34
3856 #define usri11_auth_flags 36
3857 #define usri11_password_age 40
3858 #define usri11_homedir 44
3859 #define usri11_parms 48
3860 #define usri11_last_logon 52
3861 #define usri11_last_logoff 56
3862 #define usri11_bad_pw_count 60
3863 #define usri11_num_logons 62
3864 #define usri11_logon_server 64
3865 #define usri11_country_code 68
3866 #define usri11_workstations 70
3867 #define usri11_max_storage 74
3868 #define usri11_units_per_week 78
3869 #define usri11_logon_hours 80
3870 #define usri11_code_page 84
3871 #define usri11_end 86
3873 #define USER_PRIV_GUEST 0
3874 #define USER_PRIV_USER 1
3875 #define USER_PRIV_ADMIN 2
3877 #define AF_OP_PRINT 0
3878 #define AF_OP_COMM 1
3879 #define AF_OP_SERVER 2
3880 #define AF_OP_ACCOUNTS 3
3883 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3884 char *param, int tpscnt,
3885 char *data, int tdscnt,
3886 int mdrcnt,int mprcnt,
3887 char **rdata,char **rparam,
3888 int *rdata_len,int *rparam_len)
3890 struct smbd_server_connection *sconn = smbd_server_conn;
3891 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3892 char *str2 = skip_string(param,tpscnt,str1);
3893 char *UserName = skip_string(param,tpscnt,str2);
3894 char *p = skip_string(param,tpscnt,UserName);
3895 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3896 char *p2;
3897 char *endp;
3898 const char *level_string;
3900 /* get NIS home of a previously validated user - simeon */
3901 /* With share level security vuid will always be zero.
3902 Don't depend on vuser being non-null !!. JRA */
3903 user_struct *vuser = get_valid_user_struct(sconn, vuid);
3904 if(vuser != NULL) {
3905 DEBUG(3,(" Username of UID %d is %s\n",
3906 (int)vuser->server_info->utok.uid,
3907 vuser->server_info->unix_name));
3910 if (!str1 || !str2 || !UserName || !p) {
3911 return False;
3914 *rparam_len = 6;
3915 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3916 if (!*rparam) {
3917 return False;
3920 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3922 /* check it's a supported variant */
3923 if (strcmp(str1,"zWrLh") != 0) {
3924 return False;
3926 switch( uLevel ) {
3927 case 0: level_string = "B21"; break;
3928 case 1: level_string = "B21BB16DWzzWz"; break;
3929 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3930 case 10: level_string = "B21Bzzz"; break;
3931 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3932 default: return False;
3935 if (strcmp(level_string,str2) != 0) {
3936 return False;
3939 *rdata_len = mdrcnt + 1024;
3940 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3941 if (!*rdata) {
3942 return False;
3945 SSVAL(*rparam,0,NERR_Success);
3946 SSVAL(*rparam,2,0); /* converter word */
3948 p = *rdata;
3949 endp = *rdata + *rdata_len;
3950 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3951 if (!p2) {
3952 return False;
3955 memset(p,0,21);
3956 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3958 if (uLevel > 0) {
3959 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3960 *p2 = 0;
3963 if (uLevel >= 10) {
3964 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3965 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
3966 p2 = skip_string(*rdata,*rdata_len,p2);
3967 if (!p2) {
3968 return False;
3971 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3972 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
3973 p2 = skip_string(*rdata,*rdata_len,p2);
3974 if (!p2) {
3975 return False;
3978 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3979 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3980 strlcpy(p2,((vuser != NULL)
3981 ? pdb_get_fullname(vuser->server_info->sam_account)
3982 : UserName),PTR_DIFF(endp,p2));
3983 p2 = skip_string(*rdata,*rdata_len,p2);
3984 if (!p2) {
3985 return False;
3989 if (uLevel == 11) {
3990 const char *homedir = "";
3991 if (vuser != NULL) {
3992 homedir = pdb_get_homedir(
3993 vuser->server_info->sam_account);
3995 /* modelled after NTAS 3.51 reply */
3996 SSVAL(p,usri11_priv,
3997 (get_current_uid(conn) == sec_initial_uid())?
3998 USER_PRIV_ADMIN:USER_PRIV_USER);
3999 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
4000 SIVALS(p,usri11_password_age,-1); /* password age */
4001 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
4002 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
4003 p2 = skip_string(*rdata,*rdata_len,p2);
4004 if (!p2) {
4005 return False;
4007 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
4008 strlcpy(p2,"",PTR_DIFF(endp,p2));
4009 p2 = skip_string(*rdata,*rdata_len,p2);
4010 if (!p2) {
4011 return False;
4013 SIVAL(p,usri11_last_logon,0); /* last logon */
4014 SIVAL(p,usri11_last_logoff,0); /* last logoff */
4015 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
4016 SSVALS(p,usri11_num_logons,-1); /* num logons */
4017 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
4018 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
4019 p2 = skip_string(*rdata,*rdata_len,p2);
4020 if (!p2) {
4021 return False;
4023 SSVAL(p,usri11_country_code,0); /* country code */
4025 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
4026 strlcpy(p2,"",PTR_DIFF(endp,p2));
4027 p2 = skip_string(*rdata,*rdata_len,p2);
4028 if (!p2) {
4029 return False;
4032 SIVALS(p,usri11_max_storage,-1); /* max storage */
4033 SSVAL(p,usri11_units_per_week,168); /* units per week */
4034 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
4036 /* a simple way to get logon hours at all times. */
4037 memset(p2,0xff,21);
4038 SCVAL(p2,21,0); /* fix zero termination */
4039 p2 = skip_string(*rdata,*rdata_len,p2);
4040 if (!p2) {
4041 return False;
4044 SSVAL(p,usri11_code_page,0); /* code page */
4047 if (uLevel == 1 || uLevel == 2) {
4048 memset(p+22,' ',16); /* password */
4049 SIVALS(p,38,-1); /* password age */
4050 SSVAL(p,42,
4051 (get_current_uid(conn) == sec_initial_uid())?
4052 USER_PRIV_ADMIN:USER_PRIV_USER);
4053 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
4054 strlcpy(p2, vuser ? pdb_get_homedir(
4055 vuser->server_info->sam_account) : "",
4056 PTR_DIFF(endp,p2));
4057 p2 = skip_string(*rdata,*rdata_len,p2);
4058 if (!p2) {
4059 return False;
4061 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
4062 *p2++ = 0;
4063 SSVAL(p,52,0); /* flags */
4064 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
4065 strlcpy(p2, vuser ? pdb_get_logon_script(
4066 vuser->server_info->sam_account) : "",
4067 PTR_DIFF(endp,p2));
4068 p2 = skip_string(*rdata,*rdata_len,p2);
4069 if (!p2) {
4070 return False;
4072 if (uLevel == 2) {
4073 SIVAL(p,60,0); /* auth_flags */
4074 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
4075 strlcpy(p2,((vuser != NULL)
4076 ? pdb_get_fullname(vuser->server_info->sam_account)
4077 : UserName),PTR_DIFF(endp,p2));
4078 p2 = skip_string(*rdata,*rdata_len,p2);
4079 if (!p2) {
4080 return False;
4082 SIVAL(p,68,0); /* urs_comment */
4083 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
4084 strlcpy(p2,"",PTR_DIFF(endp,p2));
4085 p2 = skip_string(*rdata,*rdata_len,p2);
4086 if (!p2) {
4087 return False;
4089 SIVAL(p,76,0); /* workstations */
4090 SIVAL(p,80,0); /* last_logon */
4091 SIVAL(p,84,0); /* last_logoff */
4092 SIVALS(p,88,-1); /* acct_expires */
4093 SIVALS(p,92,-1); /* max_storage */
4094 SSVAL(p,96,168); /* units_per_week */
4095 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
4096 memset(p2,-1,21);
4097 p2 += 21;
4098 SSVALS(p,102,-1); /* bad_pw_count */
4099 SSVALS(p,104,-1); /* num_logons */
4100 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
4102 TALLOC_CTX *ctx = talloc_tos();
4103 int space_rem = *rdata_len - (p2 - *rdata);
4104 char *tmp;
4106 if (space_rem <= 0) {
4107 return false;
4109 tmp = talloc_strdup(ctx, "\\\\%L");
4110 if (!tmp) {
4111 return false;
4113 tmp = talloc_sub_basic(ctx,
4116 tmp);
4117 if (!tmp) {
4118 return false;
4121 push_ascii(p2,
4122 tmp,
4123 space_rem,
4124 STR_TERMINATE);
4126 p2 = skip_string(*rdata,*rdata_len,p2);
4127 if (!p2) {
4128 return False;
4130 SSVAL(p,110,49); /* country_code */
4131 SSVAL(p,112,860); /* code page */
4135 *rdata_len = PTR_DIFF(p2,*rdata);
4137 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
4139 return(True);
4142 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
4143 char *param, int tpscnt,
4144 char *data, int tdscnt,
4145 int mdrcnt,int mprcnt,
4146 char **rdata,char **rparam,
4147 int *rdata_len,int *rparam_len)
4149 struct smbd_server_connection *sconn = smbd_server_conn;
4150 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4151 char *str2 = skip_string(param,tpscnt,str1);
4152 char *p = skip_string(param,tpscnt,str2);
4153 int uLevel;
4154 struct pack_desc desc;
4155 char* name;
4156 /* With share level security vuid will always be zero.
4157 Don't depend on vuser being non-null !!. JRA */
4158 user_struct *vuser = get_valid_user_struct(sconn, vuid);
4160 if (!str1 || !str2 || !p) {
4161 return False;
4164 if(vuser != NULL) {
4165 DEBUG(3,(" Username of UID %d is %s\n",
4166 (int)vuser->server_info->utok.uid,
4167 vuser->server_info->unix_name));
4170 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4171 name = get_safe_str_ptr(param,tpscnt,p,2);
4172 if (!name) {
4173 return False;
4176 memset((char *)&desc,'\0',sizeof(desc));
4178 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
4180 /* check it's a supported varient */
4181 if (strcmp(str1,"OOWb54WrLh") != 0) {
4182 return False;
4184 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
4185 return False;
4187 if (mdrcnt > 0) {
4188 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4189 if (!*rdata) {
4190 return False;
4194 desc.base = *rdata;
4195 desc.buflen = mdrcnt;
4196 desc.subformat = NULL;
4197 desc.format = str2;
4199 if (init_package(&desc,1,0)) {
4200 PACKI(&desc,"W",0); /* code */
4201 PACKS(&desc,"B21",name); /* eff. name */
4202 PACKS(&desc,"B",""); /* pad */
4203 PACKI(&desc,"W",
4204 (get_current_uid(conn) == sec_initial_uid())?
4205 USER_PRIV_ADMIN:USER_PRIV_USER);
4206 PACKI(&desc,"D",0); /* auth flags XXX */
4207 PACKI(&desc,"W",0); /* num logons */
4208 PACKI(&desc,"W",0); /* bad pw count */
4209 PACKI(&desc,"D",0); /* last logon */
4210 PACKI(&desc,"D",-1); /* last logoff */
4211 PACKI(&desc,"D",-1); /* logoff time */
4212 PACKI(&desc,"D",-1); /* kickoff time */
4213 PACKI(&desc,"D",0); /* password age */
4214 PACKI(&desc,"D",0); /* password can change */
4215 PACKI(&desc,"D",-1); /* password must change */
4218 fstring mypath;
4219 fstrcpy(mypath,"\\\\");
4220 fstrcat(mypath,get_local_machine_name());
4221 strupper_m(mypath);
4222 PACKS(&desc,"z",mypath); /* computer */
4225 PACKS(&desc,"z",lp_workgroup());/* domain */
4226 PACKS(&desc,"z", vuser ? pdb_get_logon_script(
4227 vuser->server_info->sam_account) : ""); /* script path */
4228 PACKI(&desc,"D",0x00000000); /* reserved */
4231 *rdata_len = desc.usedlen;
4232 *rparam_len = 6;
4233 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4234 if (!*rparam) {
4235 return False;
4237 SSVALS(*rparam,0,desc.errcode);
4238 SSVAL(*rparam,2,0);
4239 SSVAL(*rparam,4,desc.neededlen);
4241 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4243 return True;
4246 /****************************************************************************
4247 api_WAccessGetUserPerms
4248 ****************************************************************************/
4250 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
4251 char *param, int tpscnt,
4252 char *data, int tdscnt,
4253 int mdrcnt,int mprcnt,
4254 char **rdata,char **rparam,
4255 int *rdata_len,int *rparam_len)
4257 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4258 char *str2 = skip_string(param,tpscnt,str1);
4259 char *user = skip_string(param,tpscnt,str2);
4260 char *resource = skip_string(param,tpscnt,user);
4262 if (!str1 || !str2 || !user || !resource) {
4263 return False;
4266 if (skip_string(param,tpscnt,resource) == NULL) {
4267 return False;
4269 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4271 /* check it's a supported varient */
4272 if (strcmp(str1,"zzh") != 0) {
4273 return False;
4275 if (strcmp(str2,"") != 0) {
4276 return False;
4279 *rparam_len = 6;
4280 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4281 if (!*rparam) {
4282 return False;
4284 SSVALS(*rparam,0,0); /* errorcode */
4285 SSVAL(*rparam,2,0); /* converter word */
4286 SSVAL(*rparam,4,0x7f); /* permission flags */
4288 return True;
4291 /****************************************************************************
4292 api_WPrintJobEnumerate
4293 ****************************************************************************/
4295 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
4296 char *param, int tpscnt,
4297 char *data, int tdscnt,
4298 int mdrcnt,int mprcnt,
4299 char **rdata,char **rparam,
4300 int *rdata_len,int *rparam_len)
4302 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4303 char *str2 = skip_string(param,tpscnt,str1);
4304 char *p = skip_string(param,tpscnt,str2);
4305 int uLevel;
4306 fstring sharename;
4307 uint32 jobid;
4308 struct pack_desc desc;
4309 char *tmpdata=NULL;
4311 TALLOC_CTX *mem_ctx = talloc_tos();
4312 WERROR werr;
4313 NTSTATUS status;
4314 struct rpc_pipe_client *cli = NULL;
4315 struct policy_handle handle;
4316 struct spoolss_DevmodeContainer devmode_ctr;
4317 union spoolss_JobInfo info;
4319 if (!str1 || !str2 || !p) {
4320 return False;
4323 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4325 memset((char *)&desc,'\0',sizeof(desc));
4326 memset((char *)&status,'\0',sizeof(status));
4328 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4330 /* check it's a supported varient */
4331 if (strcmp(str1,"WWrLh") != 0) {
4332 return False;
4334 if (!check_printjob_info(&desc,uLevel,str2)) {
4335 return False;
4338 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4339 return False;
4342 ZERO_STRUCT(handle);
4344 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4345 rpc_spoolss_dispatch, conn->server_info,
4346 &cli);
4347 if (!NT_STATUS_IS_OK(status)) {
4348 DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n",
4349 nt_errstr(status)));
4350 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4351 goto out;
4354 ZERO_STRUCT(devmode_ctr);
4356 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4357 sharename,
4358 NULL,
4359 devmode_ctr,
4360 SEC_FLAG_MAXIMUM_ALLOWED,
4361 &handle,
4362 &werr);
4363 if (!NT_STATUS_IS_OK(status)) {
4364 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4365 goto out;
4367 if (!W_ERROR_IS_OK(werr)) {
4368 desc.errcode = W_ERROR_V(werr);
4369 goto out;
4372 werr = rpccli_spoolss_getjob(cli, mem_ctx,
4373 &handle,
4374 jobid,
4375 2, /* level */
4376 0, /* offered */
4377 &info);
4378 if (!W_ERROR_IS_OK(werr)) {
4379 desc.errcode = W_ERROR_V(werr);
4380 goto out;
4383 if (mdrcnt > 0) {
4384 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4385 if (!*rdata) {
4386 return False;
4388 desc.base = *rdata;
4389 desc.buflen = mdrcnt;
4390 } else {
4392 * Don't return data but need to get correct length
4393 * init_package will return wrong size if buflen=0
4395 desc.buflen = getlen(desc.format);
4396 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4399 if (init_package(&desc,1,0)) {
4400 fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position);
4401 *rdata_len = desc.usedlen;
4402 } else {
4403 desc.errcode = NERR_JobNotFound;
4404 *rdata_len = 0;
4406 out:
4407 if (cli && is_valid_policy_hnd(&handle)) {
4408 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4411 *rparam_len = 6;
4412 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4413 if (!*rparam) {
4414 return False;
4416 SSVALS(*rparam,0,desc.errcode);
4417 SSVAL(*rparam,2,0);
4418 SSVAL(*rparam,4,desc.neededlen);
4420 SAFE_FREE(tmpdata);
4422 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4424 return True;
4427 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
4428 char *param, int tpscnt,
4429 char *data, int tdscnt,
4430 int mdrcnt,int mprcnt,
4431 char **rdata,char **rparam,
4432 int *rdata_len,int *rparam_len)
4434 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4435 char *str2 = skip_string(param,tpscnt,str1);
4436 char *p = skip_string(param,tpscnt,str2);
4437 char *name = p;
4438 int uLevel;
4439 int i, succnt=0;
4440 struct pack_desc desc;
4442 TALLOC_CTX *mem_ctx = talloc_tos();
4443 WERROR werr;
4444 NTSTATUS status;
4445 struct rpc_pipe_client *cli = NULL;
4446 struct policy_handle handle;
4447 struct spoolss_DevmodeContainer devmode_ctr;
4448 uint32_t count;
4449 union spoolss_JobInfo *info;
4451 if (!str1 || !str2 || !p) {
4452 return False;
4455 memset((char *)&desc,'\0',sizeof(desc));
4457 p = skip_string(param,tpscnt,p);
4458 if (!p) {
4459 return False;
4461 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4463 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4465 /* check it's a supported variant */
4466 if (strcmp(str1,"zWrLeh") != 0) {
4467 return False;
4470 if (uLevel > 2) {
4471 return False; /* defined only for uLevel 0,1,2 */
4474 if (!check_printjob_info(&desc,uLevel,str2)) {
4475 return False;
4478 ZERO_STRUCT(handle);
4480 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4481 rpc_spoolss_dispatch, conn->server_info,
4482 &cli);
4483 if (!NT_STATUS_IS_OK(status)) {
4484 DEBUG(0,("api_WPrintJobEnumerate: could not connect to spoolss: %s\n",
4485 nt_errstr(status)));
4486 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4487 goto out;
4490 ZERO_STRUCT(devmode_ctr);
4492 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4493 name,
4494 NULL,
4495 devmode_ctr,
4496 SEC_FLAG_MAXIMUM_ALLOWED,
4497 &handle,
4498 &werr);
4499 if (!NT_STATUS_IS_OK(status)) {
4500 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4501 goto out;
4503 if (!W_ERROR_IS_OK(werr)) {
4504 desc.errcode = W_ERROR_V(werr);
4505 goto out;
4508 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
4509 &handle,
4510 0, /* firstjob */
4511 0xff, /* numjobs */
4512 2, /* level */
4513 0, /* offered */
4514 &count,
4515 &info);
4516 if (!W_ERROR_IS_OK(werr)) {
4517 desc.errcode = W_ERROR_V(werr);
4518 goto out;
4521 if (mdrcnt > 0) {
4522 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4523 if (!*rdata) {
4524 return False;
4527 desc.base = *rdata;
4528 desc.buflen = mdrcnt;
4530 if (init_package(&desc,count,0)) {
4531 succnt = 0;
4532 for (i = 0; i < count; i++) {
4533 fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i);
4534 if (desc.errcode == NERR_Success) {
4535 succnt = i+1;
4539 out:
4540 if (cli && is_valid_policy_hnd(&handle)) {
4541 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4544 *rdata_len = desc.usedlen;
4546 *rparam_len = 8;
4547 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4548 if (!*rparam) {
4549 return False;
4551 SSVALS(*rparam,0,desc.errcode);
4552 SSVAL(*rparam,2,0);
4553 SSVAL(*rparam,4,succnt);
4554 SSVAL(*rparam,6,count);
4556 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4558 return True;
4561 static int check_printdest_info(struct pack_desc* desc,
4562 int uLevel, char* id)
4564 desc->subformat = NULL;
4565 switch( uLevel ) {
4566 case 0:
4567 desc->format = "B9";
4568 break;
4569 case 1:
4570 desc->format = "B9B21WWzW";
4571 break;
4572 case 2:
4573 desc->format = "z";
4574 break;
4575 case 3:
4576 desc->format = "zzzWWzzzWW";
4577 break;
4578 default:
4579 DEBUG(0,("check_printdest_info: invalid level %d\n",
4580 uLevel));
4581 return False;
4583 if (id == NULL || strcmp(desc->format,id) != 0) {
4584 DEBUG(0,("check_printdest_info: invalid string %s\n",
4585 id ? id : "<NULL>" ));
4586 return False;
4588 return True;
4591 static void fill_printdest_info(struct spoolss_PrinterInfo2 *info2, int uLevel,
4592 struct pack_desc* desc)
4594 char buf[100];
4596 strncpy(buf, info2->printername, sizeof(buf)-1);
4597 buf[sizeof(buf)-1] = 0;
4598 strupper_m(buf);
4600 if (uLevel <= 1) {
4601 PACKS(desc,"B9",buf); /* szName */
4602 if (uLevel == 1) {
4603 PACKS(desc,"B21",""); /* szUserName */
4604 PACKI(desc,"W",0); /* uJobId */
4605 PACKI(desc,"W",0); /* fsStatus */
4606 PACKS(desc,"z",""); /* pszStatus */
4607 PACKI(desc,"W",0); /* time */
4611 if (uLevel == 2 || uLevel == 3) {
4612 PACKS(desc,"z",buf); /* pszPrinterName */
4613 if (uLevel == 3) {
4614 PACKS(desc,"z",""); /* pszUserName */
4615 PACKS(desc,"z",""); /* pszLogAddr */
4616 PACKI(desc,"W",0); /* uJobId */
4617 PACKI(desc,"W",0); /* fsStatus */
4618 PACKS(desc,"z",""); /* pszStatus */
4619 PACKS(desc,"z",""); /* pszComment */
4620 PACKS(desc,"z","NULL"); /* pszDrivers */
4621 PACKI(desc,"W",0); /* time */
4622 PACKI(desc,"W",0); /* pad1 */
4627 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
4628 char *param, int tpscnt,
4629 char *data, int tdscnt,
4630 int mdrcnt,int mprcnt,
4631 char **rdata,char **rparam,
4632 int *rdata_len,int *rparam_len)
4634 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4635 char *str2 = skip_string(param,tpscnt,str1);
4636 char *p = skip_string(param,tpscnt,str2);
4637 char* PrinterName = p;
4638 int uLevel;
4639 struct pack_desc desc;
4640 char *tmpdata=NULL;
4642 TALLOC_CTX *mem_ctx = talloc_tos();
4643 WERROR werr;
4644 NTSTATUS status;
4645 struct rpc_pipe_client *cli = NULL;
4646 struct policy_handle handle;
4647 struct spoolss_DevmodeContainer devmode_ctr;
4648 union spoolss_PrinterInfo info;
4650 if (!str1 || !str2 || !p) {
4651 return False;
4654 memset((char *)&desc,'\0',sizeof(desc));
4656 p = skip_string(param,tpscnt,p);
4657 if (!p) {
4658 return False;
4660 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4662 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4664 /* check it's a supported varient */
4665 if (strcmp(str1,"zWrLh") != 0) {
4666 return False;
4668 if (!check_printdest_info(&desc,uLevel,str2)) {
4669 return False;
4672 ZERO_STRUCT(handle);
4674 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4675 rpc_spoolss_dispatch, conn->server_info,
4676 &cli);
4677 if (!NT_STATUS_IS_OK(status)) {
4678 DEBUG(0,("api_WPrintDestGetInfo: could not connect to spoolss: %s\n",
4679 nt_errstr(status)));
4680 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4681 goto out;
4684 ZERO_STRUCT(devmode_ctr);
4686 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4687 PrinterName,
4688 NULL,
4689 devmode_ctr,
4690 SEC_FLAG_MAXIMUM_ALLOWED,
4691 &handle,
4692 &werr);
4693 if (!NT_STATUS_IS_OK(status)) {
4694 *rdata_len = 0;
4695 desc.errcode = NERR_DestNotFound;
4696 desc.neededlen = 0;
4697 goto out;
4699 if (!W_ERROR_IS_OK(werr)) {
4700 *rdata_len = 0;
4701 desc.errcode = NERR_DestNotFound;
4702 desc.neededlen = 0;
4703 goto out;
4706 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
4707 &handle,
4710 &info);
4711 if (!W_ERROR_IS_OK(werr)) {
4712 *rdata_len = 0;
4713 desc.errcode = NERR_DestNotFound;
4714 desc.neededlen = 0;
4715 goto out;
4718 if (mdrcnt > 0) {
4719 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4720 if (!*rdata) {
4721 return False;
4723 desc.base = *rdata;
4724 desc.buflen = mdrcnt;
4725 } else {
4727 * Don't return data but need to get correct length
4728 * init_package will return wrong size if buflen=0
4730 desc.buflen = getlen(desc.format);
4731 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4733 if (init_package(&desc,1,0)) {
4734 fill_printdest_info(&info.info2, uLevel,&desc);
4737 out:
4738 if (cli && is_valid_policy_hnd(&handle)) {
4739 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4742 *rdata_len = desc.usedlen;
4744 *rparam_len = 6;
4745 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4746 if (!*rparam) {
4747 return False;
4749 SSVALS(*rparam,0,desc.errcode);
4750 SSVAL(*rparam,2,0);
4751 SSVAL(*rparam,4,desc.neededlen);
4753 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4754 SAFE_FREE(tmpdata);
4756 return True;
4759 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4760 char *param, int tpscnt,
4761 char *data, int tdscnt,
4762 int mdrcnt,int mprcnt,
4763 char **rdata,char **rparam,
4764 int *rdata_len,int *rparam_len)
4766 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4767 char *str2 = skip_string(param,tpscnt,str1);
4768 char *p = skip_string(param,tpscnt,str2);
4769 int uLevel;
4770 int queuecnt;
4771 int i, n, succnt=0;
4772 struct pack_desc desc;
4774 TALLOC_CTX *mem_ctx = talloc_tos();
4775 WERROR werr;
4776 NTSTATUS status;
4777 struct rpc_pipe_client *cli = NULL;
4778 union spoolss_PrinterInfo *info;
4779 uint32_t count;
4781 if (!str1 || !str2 || !p) {
4782 return False;
4785 memset((char *)&desc,'\0',sizeof(desc));
4787 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4789 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4791 /* check it's a supported varient */
4792 if (strcmp(str1,"WrLeh") != 0) {
4793 return False;
4795 if (!check_printdest_info(&desc,uLevel,str2)) {
4796 return False;
4799 queuecnt = 0;
4801 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4802 rpc_spoolss_dispatch, conn->server_info,
4803 &cli);
4804 if (!NT_STATUS_IS_OK(status)) {
4805 DEBUG(0,("api_WPrintDestEnum: could not connect to spoolss: %s\n",
4806 nt_errstr(status)));
4807 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4808 goto out;
4811 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
4812 PRINTER_ENUM_LOCAL,
4813 cli->srv_name_slash,
4816 &count,
4817 &info);
4818 if (!W_ERROR_IS_OK(werr)) {
4819 desc.errcode = W_ERROR_V(werr);
4820 *rdata_len = 0;
4821 desc.errcode = NERR_DestNotFound;
4822 desc.neededlen = 0;
4823 goto out;
4826 queuecnt = count;
4828 if (mdrcnt > 0) {
4829 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4830 if (!*rdata) {
4831 return False;
4835 desc.base = *rdata;
4836 desc.buflen = mdrcnt;
4837 if (init_package(&desc,queuecnt,0)) {
4838 succnt = 0;
4839 n = 0;
4840 for (i = 0; i < count; i++) {
4841 fill_printdest_info(&info[i].info2, uLevel,&desc);
4842 n++;
4843 if (desc.errcode == NERR_Success) {
4844 succnt = n;
4848 out:
4849 *rdata_len = desc.usedlen;
4851 *rparam_len = 8;
4852 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4853 if (!*rparam) {
4854 return False;
4856 SSVALS(*rparam,0,desc.errcode);
4857 SSVAL(*rparam,2,0);
4858 SSVAL(*rparam,4,succnt);
4859 SSVAL(*rparam,6,queuecnt);
4861 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4863 return True;
4866 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4867 char *param, int tpscnt,
4868 char *data, int tdscnt,
4869 int mdrcnt,int mprcnt,
4870 char **rdata,char **rparam,
4871 int *rdata_len,int *rparam_len)
4873 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4874 char *str2 = skip_string(param,tpscnt,str1);
4875 char *p = skip_string(param,tpscnt,str2);
4876 int uLevel;
4877 int succnt;
4878 struct pack_desc desc;
4880 if (!str1 || !str2 || !p) {
4881 return False;
4884 memset((char *)&desc,'\0',sizeof(desc));
4886 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4888 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4890 /* check it's a supported varient */
4891 if (strcmp(str1,"WrLeh") != 0) {
4892 return False;
4894 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4895 return False;
4898 if (mdrcnt > 0) {
4899 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4900 if (!*rdata) {
4901 return False;
4904 desc.base = *rdata;
4905 desc.buflen = mdrcnt;
4906 if (init_package(&desc,1,0)) {
4907 PACKS(&desc,"B41","NULL");
4910 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4912 *rdata_len = desc.usedlen;
4914 *rparam_len = 8;
4915 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4916 if (!*rparam) {
4917 return False;
4919 SSVALS(*rparam,0,desc.errcode);
4920 SSVAL(*rparam,2,0);
4921 SSVAL(*rparam,4,succnt);
4922 SSVAL(*rparam,6,1);
4924 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4926 return True;
4929 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4930 char *param, int tpscnt,
4931 char *data, int tdscnt,
4932 int mdrcnt,int mprcnt,
4933 char **rdata,char **rparam,
4934 int *rdata_len,int *rparam_len)
4936 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4937 char *str2 = skip_string(param,tpscnt,str1);
4938 char *p = skip_string(param,tpscnt,str2);
4939 int uLevel;
4940 int succnt;
4941 struct pack_desc desc;
4943 if (!str1 || !str2 || !p) {
4944 return False;
4946 memset((char *)&desc,'\0',sizeof(desc));
4948 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4950 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4952 /* check it's a supported varient */
4953 if (strcmp(str1,"WrLeh") != 0) {
4954 return False;
4956 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4957 return False;
4960 if (mdrcnt > 0) {
4961 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4962 if (!*rdata) {
4963 return False;
4966 desc.base = *rdata;
4967 desc.buflen = mdrcnt;
4968 desc.format = str2;
4969 if (init_package(&desc,1,0)) {
4970 PACKS(&desc,"B13","lpd");
4973 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4975 *rdata_len = desc.usedlen;
4977 *rparam_len = 8;
4978 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4979 if (!*rparam) {
4980 return False;
4982 SSVALS(*rparam,0,desc.errcode);
4983 SSVAL(*rparam,2,0);
4984 SSVAL(*rparam,4,succnt);
4985 SSVAL(*rparam,6,1);
4987 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4989 return True;
4992 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4993 char *param, int tpscnt,
4994 char *data, int tdscnt,
4995 int mdrcnt,int mprcnt,
4996 char **rdata,char **rparam,
4997 int *rdata_len,int *rparam_len)
4999 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5000 char *str2 = skip_string(param,tpscnt,str1);
5001 char *p = skip_string(param,tpscnt,str2);
5002 int uLevel;
5003 int succnt;
5004 struct pack_desc desc;
5006 if (!str1 || !str2 || !p) {
5007 return False;
5010 memset((char *)&desc,'\0',sizeof(desc));
5012 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5014 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
5016 /* check it's a supported varient */
5017 if (strcmp(str1,"WrLeh") != 0) {
5018 return False;
5020 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
5021 return False;
5024 if (mdrcnt > 0) {
5025 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5026 if (!*rdata) {
5027 return False;
5030 memset((char *)&desc,'\0',sizeof(desc));
5031 desc.base = *rdata;
5032 desc.buflen = mdrcnt;
5033 desc.format = str2;
5034 if (init_package(&desc,1,0)) {
5035 PACKS(&desc,"B13","lp0");
5038 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5040 *rdata_len = desc.usedlen;
5042 *rparam_len = 8;
5043 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5044 if (!*rparam) {
5045 return False;
5047 SSVALS(*rparam,0,desc.errcode);
5048 SSVAL(*rparam,2,0);
5049 SSVAL(*rparam,4,succnt);
5050 SSVAL(*rparam,6,1);
5052 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
5054 return True;
5057 /****************************************************************************
5058 List open sessions
5059 ****************************************************************************/
5061 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
5062 char *param, int tpscnt,
5063 char *data, int tdscnt,
5064 int mdrcnt,int mprcnt,
5065 char **rdata,char **rparam,
5066 int *rdata_len,int *rparam_len)
5069 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5070 char *str2 = skip_string(param,tpscnt,str1);
5071 char *p = skip_string(param,tpscnt,str2);
5072 int uLevel;
5073 struct pack_desc desc;
5074 struct sessionid *session_list;
5075 int i, num_sessions;
5077 if (!str1 || !str2 || !p) {
5078 return False;
5081 memset((char *)&desc,'\0',sizeof(desc));
5083 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5085 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
5086 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
5087 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
5089 /* check it's a supported varient */
5090 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
5091 return False;
5093 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
5094 return False;
5097 num_sessions = list_sessions(talloc_tos(), &session_list);
5099 if (mdrcnt > 0) {
5100 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5101 if (!*rdata) {
5102 return False;
5105 memset((char *)&desc,'\0',sizeof(desc));
5106 desc.base = *rdata;
5107 desc.buflen = mdrcnt;
5108 desc.format = str2;
5109 if (!init_package(&desc,num_sessions,0)) {
5110 return False;
5113 for(i=0; i<num_sessions; i++) {
5114 PACKS(&desc, "z", session_list[i].remote_machine);
5115 PACKS(&desc, "z", session_list[i].username);
5116 PACKI(&desc, "W", 1); /* num conns */
5117 PACKI(&desc, "W", 0); /* num opens */
5118 PACKI(&desc, "W", 1); /* num users */
5119 PACKI(&desc, "D", 0); /* session time */
5120 PACKI(&desc, "D", 0); /* idle time */
5121 PACKI(&desc, "D", 0); /* flags */
5122 PACKS(&desc, "z", "Unknown Client"); /* client type string */
5125 *rdata_len = desc.usedlen;
5127 *rparam_len = 8;
5128 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5129 if (!*rparam) {
5130 return False;
5132 SSVALS(*rparam,0,desc.errcode);
5133 SSVAL(*rparam,2,0); /* converter */
5134 SSVAL(*rparam,4,num_sessions); /* count */
5136 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
5138 return True;
5142 /****************************************************************************
5143 The buffer was too small.
5144 ****************************************************************************/
5146 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
5147 int mdrcnt, int mprcnt,
5148 char **rdata, char **rparam,
5149 int *rdata_len, int *rparam_len)
5151 *rparam_len = MIN(*rparam_len,mprcnt);
5152 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5153 if (!*rparam) {
5154 return False;
5157 *rdata_len = 0;
5159 SSVAL(*rparam,0,NERR_BufTooSmall);
5161 DEBUG(3,("Supplied buffer too small in API command\n"));
5163 return True;
5166 /****************************************************************************
5167 The request is not supported.
5168 ****************************************************************************/
5170 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
5171 char *param, int tpscnt,
5172 char *data, int tdscnt,
5173 int mdrcnt, int mprcnt,
5174 char **rdata, char **rparam,
5175 int *rdata_len, int *rparam_len)
5177 *rparam_len = 4;
5178 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5179 if (!*rparam) {
5180 return False;
5183 *rdata_len = 0;
5185 SSVAL(*rparam,0,NERR_notsupported);
5186 SSVAL(*rparam,2,0); /* converter word */
5188 DEBUG(3,("Unsupported API command\n"));
5190 return True;
5193 static const struct {
5194 const char *name;
5195 int id;
5196 bool (*fn)(connection_struct *, uint16,
5197 char *, int,
5198 char *, int,
5199 int,int,char **,char **,int *,int *);
5200 bool auth_user; /* Deny anonymous access? */
5201 } api_commands[] = {
5202 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
5203 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
5204 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
5205 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
5206 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
5207 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
5208 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
5209 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
5210 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
5211 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
5212 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
5213 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
5214 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
5215 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
5216 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
5217 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
5218 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
5219 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
5220 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
5221 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
5222 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
5223 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
5224 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
5225 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
5226 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
5227 {"NetServerEnum3", RAP_NetServerEnum3, api_RNetServerEnum3}, /* anon OK */
5228 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
5229 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
5230 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
5231 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
5232 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
5233 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
5234 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
5235 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
5236 {NULL, -1, api_Unsupported}
5237 /* The following RAP calls are not implemented by Samba:
5239 RAP_WFileEnum2 - anon not OK
5244 /****************************************************************************
5245 Handle remote api calls.
5246 ****************************************************************************/
5248 void api_reply(connection_struct *conn, uint16 vuid,
5249 struct smb_request *req,
5250 char *data, char *params,
5251 int tdscnt, int tpscnt,
5252 int mdrcnt, int mprcnt)
5254 struct smbd_server_connection *sconn = smbd_server_conn;
5255 int api_command;
5256 char *rdata = NULL;
5257 char *rparam = NULL;
5258 const char *name1 = NULL;
5259 const char *name2 = NULL;
5260 int rdata_len = 0;
5261 int rparam_len = 0;
5262 bool reply=False;
5263 int i;
5265 if (!params) {
5266 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
5267 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5268 return;
5271 if (tpscnt < 2) {
5272 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5273 return;
5275 api_command = SVAL(params,0);
5276 /* Is there a string at position params+2 ? */
5277 if (skip_string(params,tpscnt,params+2)) {
5278 name1 = params + 2;
5279 } else {
5280 name1 = "";
5282 name2 = skip_string(params,tpscnt,params+2);
5283 if (!name2) {
5284 name2 = "";
5287 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
5288 api_command,
5289 name1,
5290 name2,
5291 tdscnt,tpscnt,mdrcnt,mprcnt));
5293 for (i=0;api_commands[i].name;i++) {
5294 if (api_commands[i].id == api_command && api_commands[i].fn) {
5295 DEBUG(3,("Doing %s\n",api_commands[i].name));
5296 break;
5300 /* Check whether this api call can be done anonymously */
5302 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
5303 user_struct *user = get_valid_user_struct(sconn, vuid);
5305 if (!user || user->server_info->guest) {
5306 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5307 return;
5311 rdata = (char *)SMB_MALLOC(1024);
5312 if (rdata) {
5313 memset(rdata,'\0',1024);
5316 rparam = (char *)SMB_MALLOC(1024);
5317 if (rparam) {
5318 memset(rparam,'\0',1024);
5321 if(!rdata || !rparam) {
5322 DEBUG(0,("api_reply: malloc fail !\n"));
5323 SAFE_FREE(rdata);
5324 SAFE_FREE(rparam);
5325 reply_nterror(req, NT_STATUS_NO_MEMORY);
5326 return;
5329 reply = api_commands[i].fn(conn,
5330 vuid,
5331 params,tpscnt, /* params + length */
5332 data,tdscnt, /* data + length */
5333 mdrcnt,mprcnt,
5334 &rdata,&rparam,&rdata_len,&rparam_len);
5337 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
5338 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
5339 &rdata,&rparam,&rdata_len,&rparam_len);
5342 /* if we get False back then it's actually unsupported */
5343 if (!reply) {
5344 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
5345 &rdata,&rparam,&rdata_len,&rparam_len);
5348 /* If api_Unsupported returns false we can't return anything. */
5349 if (reply) {
5350 send_trans_reply(conn, req, rparam, rparam_len,
5351 rdata, rdata_len, False);
5354 SAFE_FREE(rdata);
5355 SAFE_FREE(rparam);
5356 return;