s3-lanman: Fix various RAP printing calls according to win98 testing and MS-RAP docs.
[Samba/ekacnet.git] / source3 / smbd / lanman.c
blob744d460e8b8b7dd610d6172944e6876cce75fd1f
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 "rpc_client/cli_spoolss.h"
33 #include "rpc_client/init_spoolss.h"
34 #include "../librpc/gen_ndr/cli_srvsvc.h"
35 #include "../librpc/gen_ndr/srv_samr.h"
36 #include "../librpc/gen_ndr/srv_spoolss.h"
37 #include "../librpc/gen_ndr/srv_srvsvc.h"
38 #include "../librpc/gen_ndr/rap.h"
39 #include "../lib/util/binsearch.h"
41 #ifdef CHECK_TYPES
42 #undef CHECK_TYPES
43 #endif
44 #define CHECK_TYPES 0
46 #define NERR_Success 0
47 #define NERR_badpass 86
48 #define NERR_notsupported 50
50 #define NERR_BASE (2100)
51 #define NERR_BufTooSmall (NERR_BASE+23)
52 #define NERR_JobNotFound (NERR_BASE+51)
53 #define NERR_DestNotFound (NERR_BASE+52)
55 #define ACCESS_READ 0x01
56 #define ACCESS_WRITE 0x02
57 #define ACCESS_CREATE 0x04
59 #define SHPWLEN 8 /* share password length */
61 /* Limit size of ipc replies */
63 static char *smb_realloc_limit(void *ptr, size_t size)
65 char *val;
67 size = MAX((size),4*1024);
68 val = (char *)SMB_REALLOC(ptr,size);
69 if (val) {
70 memset(val,'\0',size);
72 return val;
75 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
76 char *param, int tpscnt,
77 char *data, int tdscnt,
78 int mdrcnt, int mprcnt,
79 char **rdata, char **rparam,
80 int *rdata_len, int *rparam_len);
82 static bool api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
83 int mdrcnt, int mprcnt,
84 char **rdata, char **rparam,
85 int *rdata_len, int *rparam_len);
88 static int CopyExpanded(connection_struct *conn,
89 int snum, char **dst, char *src, int *p_space_remaining)
91 TALLOC_CTX *ctx = talloc_tos();
92 char *buf = NULL;
93 int l;
95 if (!src || !dst || !p_space_remaining || !(*dst) ||
96 *p_space_remaining <= 0) {
97 return 0;
100 buf = talloc_strdup(ctx, src);
101 if (!buf) {
102 *p_space_remaining = 0;
103 return 0;
105 buf = talloc_string_sub(ctx, buf,"%S",lp_servicename(snum));
106 if (!buf) {
107 *p_space_remaining = 0;
108 return 0;
110 buf = talloc_sub_advanced(ctx,
111 lp_servicename(SNUM(conn)),
112 conn->server_info->unix_name,
113 conn->connectpath,
114 conn->server_info->utok.gid,
115 conn->server_info->sanitized_username,
116 pdb_get_domain(conn->server_info->sam_account),
117 buf);
118 if (!buf) {
119 *p_space_remaining = 0;
120 return 0;
122 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
123 if (l == -1) {
124 return 0;
126 (*dst) += l;
127 (*p_space_remaining) -= l;
128 return l;
131 static int CopyAndAdvance(char **dst, char *src, int *n)
133 int l;
134 if (!src || !dst || !n || !(*dst)) {
135 return 0;
137 l = push_ascii(*dst,src,*n, STR_TERMINATE);
138 if (l == -1) {
139 return 0;
141 (*dst) += l;
142 (*n) -= l;
143 return l;
146 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
148 TALLOC_CTX *ctx = talloc_tos();
149 char *buf = NULL;
150 if (!s) {
151 return 0;
153 buf = talloc_strdup(ctx,s);
154 if (!buf) {
155 return 0;
157 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
158 if (!buf) {
159 return 0;
161 buf = talloc_sub_advanced(ctx,
162 lp_servicename(SNUM(conn)),
163 conn->server_info->unix_name,
164 conn->connectpath,
165 conn->server_info->utok.gid,
166 conn->server_info->sanitized_username,
167 pdb_get_domain(conn->server_info->sam_account),
168 buf);
169 if (!buf) {
170 return 0;
172 return strlen(buf) + 1;
175 /*******************************************************************
176 Check a API string for validity when we only need to check the prefix.
177 ******************************************************************/
179 static bool prefix_ok(const char *str, const char *prefix)
181 return(strncmp(str,prefix,strlen(prefix)) == 0);
184 struct pack_desc {
185 const char *format; /* formatstring for structure */
186 const char *subformat; /* subformat for structure */
187 char *base; /* baseaddress of buffer */
188 int buflen; /* remaining size for fixed part; on init: length of base */
189 int subcount; /* count of substructures */
190 char *structbuf; /* pointer into buffer for remaining fixed part */
191 int stringlen; /* remaining size for variable part */
192 char *stringbuf; /* pointer into buffer for remaining variable part */
193 int neededlen; /* total needed size */
194 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
195 const char *curpos; /* current position; pointer into format or subformat */
196 int errcode;
199 static int get_counter(const char **p)
201 int i, n;
202 if (!p || !(*p)) {
203 return 1;
205 if (!isdigit((int)**p)) {
206 return 1;
208 for (n = 0;;) {
209 i = **p;
210 if (isdigit(i)) {
211 n = 10 * n + (i - '0');
212 } else {
213 return n;
215 (*p)++;
219 static int getlen(const char *p)
221 int n = 0;
222 if (!p) {
223 return 0;
226 while (*p) {
227 switch( *p++ ) {
228 case 'W': /* word (2 byte) */
229 n += 2;
230 break;
231 case 'K': /* status word? (2 byte) */
232 n += 2;
233 break;
234 case 'N': /* count of substructures (word) at end */
235 n += 2;
236 break;
237 case 'D': /* double word (4 byte) */
238 case 'z': /* offset to zero terminated string (4 byte) */
239 case 'l': /* offset to user data (4 byte) */
240 n += 4;
241 break;
242 case 'b': /* offset to data (with counter) (4 byte) */
243 n += 4;
244 get_counter(&p);
245 break;
246 case 'B': /* byte (with optional counter) */
247 n += get_counter(&p);
248 break;
251 return n;
254 static bool init_package(struct pack_desc *p, int count, int subcount)
256 int n = p->buflen;
257 int i;
259 if (!p->format || !p->base) {
260 return False;
263 i = count * getlen(p->format);
264 if (p->subformat) {
265 i += subcount * getlen(p->subformat);
267 p->structbuf = p->base;
268 p->neededlen = 0;
269 p->usedlen = 0;
270 p->subcount = 0;
271 p->curpos = p->format;
272 if (i > n) {
273 p->neededlen = i;
274 i = n = 0;
275 #if 0
277 * This is the old error code we used. Aparently
278 * WinNT/2k systems return ERRbuftoosmall (2123) and
279 * OS/2 needs this. I'm leaving this here so we can revert
280 * if needed. JRA.
282 p->errcode = ERRmoredata;
283 #else
284 p->errcode = ERRbuftoosmall;
285 #endif
286 } else {
287 p->errcode = NERR_Success;
289 p->buflen = i;
290 n -= i;
291 p->stringbuf = p->base + i;
292 p->stringlen = n;
293 return (p->errcode == NERR_Success);
296 static int package(struct pack_desc *p, ...)
298 va_list args;
299 int needed=0, stringneeded;
300 const char *str=NULL;
301 int is_string=0, stringused;
302 int32 temp;
304 va_start(args,p);
306 if (!*p->curpos) {
307 if (!p->subcount) {
308 p->curpos = p->format;
309 } else {
310 p->curpos = p->subformat;
311 p->subcount--;
314 #if CHECK_TYPES
315 str = va_arg(args,char*);
316 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
317 #endif
318 stringneeded = -1;
320 if (!p->curpos) {
321 va_end(args);
322 return 0;
325 switch( *p->curpos++ ) {
326 case 'W': /* word (2 byte) */
327 needed = 2;
328 temp = va_arg(args,int);
329 if (p->buflen >= needed) {
330 SSVAL(p->structbuf,0,temp);
332 break;
333 case 'K': /* status word? (2 byte) */
334 needed = 2;
335 temp = va_arg(args,int);
336 if (p->buflen >= needed) {
337 SSVAL(p->structbuf,0,temp);
339 break;
340 case 'N': /* count of substructures (word) at end */
341 needed = 2;
342 p->subcount = va_arg(args,int);
343 if (p->buflen >= needed) {
344 SSVAL(p->structbuf,0,p->subcount);
346 break;
347 case 'D': /* double word (4 byte) */
348 needed = 4;
349 temp = va_arg(args,int);
350 if (p->buflen >= needed) {
351 SIVAL(p->structbuf,0,temp);
353 break;
354 case 'B': /* byte (with optional counter) */
355 needed = get_counter(&p->curpos);
357 char *s = va_arg(args,char*);
358 if (p->buflen >= needed) {
359 StrnCpy(p->structbuf,s?s:"",needed-1);
362 break;
363 case 'z': /* offset to zero terminated string (4 byte) */
364 str = va_arg(args,char*);
365 stringneeded = (str ? strlen(str)+1 : 0);
366 is_string = 1;
367 break;
368 case 'l': /* offset to user data (4 byte) */
369 str = va_arg(args,char*);
370 stringneeded = va_arg(args,int);
371 is_string = 0;
372 break;
373 case 'b': /* offset to data (with counter) (4 byte) */
374 str = va_arg(args,char*);
375 stringneeded = get_counter(&p->curpos);
376 is_string = 0;
377 break;
380 va_end(args);
381 if (stringneeded >= 0) {
382 needed = 4;
383 if (p->buflen >= needed) {
384 stringused = stringneeded;
385 if (stringused > p->stringlen) {
386 stringused = (is_string ? p->stringlen : 0);
387 if (p->errcode == NERR_Success) {
388 p->errcode = ERRmoredata;
391 if (!stringused) {
392 SIVAL(p->structbuf,0,0);
393 } else {
394 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
395 memcpy(p->stringbuf,str?str:"",stringused);
396 if (is_string) {
397 p->stringbuf[stringused-1] = '\0';
399 p->stringbuf += stringused;
400 p->stringlen -= stringused;
401 p->usedlen += stringused;
404 p->neededlen += stringneeded;
407 p->neededlen += needed;
408 if (p->buflen >= needed) {
409 p->structbuf += needed;
410 p->buflen -= needed;
411 p->usedlen += needed;
412 } else {
413 if (p->errcode == NERR_Success) {
414 p->errcode = ERRmoredata;
417 return 1;
420 #if CHECK_TYPES
421 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
422 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
423 #else
424 #define PACK(desc,t,v) package(desc,v)
425 #define PACKl(desc,t,v,l) package(desc,v,l)
426 #endif
428 static void PACKI(struct pack_desc* desc, const char *t,int v)
430 PACK(desc,t,v);
433 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
435 PACK(desc,t,v);
438 /****************************************************************************
439 Get a print queue.
440 ****************************************************************************/
442 static void PackDriverData(struct pack_desc* desc)
444 char drivdata[4+4+32];
445 SIVAL(drivdata,0,sizeof drivdata); /* cb */
446 SIVAL(drivdata,4,1000); /* lVersion */
447 memset(drivdata+8,0,32); /* szDeviceName */
448 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
449 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
452 static int check_printq_info(struct pack_desc* desc,
453 unsigned int uLevel, char *id1, char *id2)
455 desc->subformat = NULL;
456 switch( uLevel ) {
457 case 0:
458 desc->format = "B13";
459 break;
460 case 1:
461 desc->format = "B13BWWWzzzzzWW";
462 break;
463 case 2:
464 desc->format = "B13BWWWzzzzzWN";
465 desc->subformat = "WB21BB16B10zWWzDDz";
466 break;
467 case 3:
468 desc->format = "zWWWWzzzzWWzzl";
469 break;
470 case 4:
471 desc->format = "zWWWWzzzzWNzzl";
472 desc->subformat = "WWzWWDDzz";
473 break;
474 case 5:
475 desc->format = "z";
476 break;
477 case 51:
478 desc->format = "K";
479 break;
480 case 52:
481 desc->format = "WzzzzzzzzN";
482 desc->subformat = "z";
483 break;
484 default:
485 DEBUG(0,("check_printq_info: invalid level %d\n",
486 uLevel ));
487 return False;
489 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
490 DEBUG(0,("check_printq_info: invalid format %s\n",
491 id1 ? id1 : "<NULL>" ));
492 return False;
494 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
495 DEBUG(0,("check_printq_info: invalid subformat %s\n",
496 id2 ? id2 : "<NULL>" ));
497 return False;
499 return True;
503 #define RAP_JOB_STATUS_QUEUED 0
504 #define RAP_JOB_STATUS_PAUSED 1
505 #define RAP_JOB_STATUS_SPOOLING 2
506 #define RAP_JOB_STATUS_PRINTING 3
507 #define RAP_JOB_STATUS_PRINTED 4
509 #define RAP_QUEUE_STATUS_PAUSED 1
510 #define RAP_QUEUE_STATUS_ERROR 2
512 /* turn a print job status into a on the wire status
514 static int printj_spoolss_status(int v)
516 if (v == JOB_STATUS_QUEUED)
517 return RAP_JOB_STATUS_QUEUED;
518 if (v & JOB_STATUS_PAUSED)
519 return RAP_JOB_STATUS_PAUSED;
520 if (v & JOB_STATUS_SPOOLING)
521 return RAP_JOB_STATUS_SPOOLING;
522 if (v & JOB_STATUS_PRINTING)
523 return RAP_JOB_STATUS_PRINTING;
524 return 0;
527 /* turn a print queue status into a on the wire status
529 static int printq_spoolss_status(int v)
531 if (v == PRINTER_STATUS_OK)
532 return 0;
533 if (v & PRINTER_STATUS_PAUSED)
534 return RAP_QUEUE_STATUS_PAUSED;
535 return RAP_QUEUE_STATUS_ERROR;
538 static void fill_spoolss_printjob_info(int uLevel,
539 struct pack_desc *desc,
540 struct spoolss_JobInfo2 *info2,
541 int n)
543 time_t t = spoolss_Time_to_time_t(&info2->submitted);
545 /* the client expects localtime */
546 t -= get_time_zone(t);
548 PACKI(desc,"W",pjobid_to_rap(info2->printer_name, info2->job_id)); /* uJobId */
549 if (uLevel == 1) {
550 PACKS(desc,"B21", info2->user_name); /* szUserName */
551 PACKS(desc,"B",""); /* pad */
552 PACKS(desc,"B16",""); /* szNotifyName */
553 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
554 PACKS(desc,"z",""); /* pszParms */
555 PACKI(desc,"W",n+1); /* uPosition */
556 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
557 PACKS(desc,"z",""); /* pszStatus */
558 PACKI(desc,"D", t); /* ulSubmitted */
559 PACKI(desc,"D", info2->size); /* ulSize */
560 PACKS(desc,"z", info2->document_name); /* pszComment */
562 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
563 PACKI(desc,"W", info2->priority); /* uPriority */
564 PACKS(desc,"z", info2->user_name); /* pszUserName */
565 PACKI(desc,"W",n+1); /* uPosition */
566 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
567 PACKI(desc,"D",t); /* ulSubmitted */
568 PACKI(desc,"D", info2->size); /* ulSize */
569 PACKS(desc,"z","Samba"); /* pszComment */
570 PACKS(desc,"z", info2->document_name); /* pszDocument */
571 if (uLevel == 3) {
572 PACKS(desc,"z",""); /* pszNotifyName */
573 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
574 PACKS(desc,"z",""); /* pszParms */
575 PACKS(desc,"z",""); /* pszStatus */
576 PACKS(desc,"z", info2->printer_name); /* pszQueue */
577 PACKS(desc,"z","lpd"); /* pszQProcName */
578 PACKS(desc,"z",""); /* pszQProcParms */
579 PACKS(desc,"z","NULL"); /* pszDriverName */
580 PackDriverData(desc); /* pDriverData */
581 PACKS(desc,"z",""); /* pszPrinterName */
582 } else if (uLevel == 4) { /* OS2 */
583 PACKS(desc,"z",""); /* pszSpoolFileName */
584 PACKS(desc,"z",""); /* pszPortName */
585 PACKS(desc,"z",""); /* pszStatus */
586 PACKI(desc,"D",0); /* ulPagesSpooled */
587 PACKI(desc,"D",0); /* ulPagesSent */
588 PACKI(desc,"D",0); /* ulPagesPrinted */
589 PACKI(desc,"D",0); /* ulTimePrinted */
590 PACKI(desc,"D",0); /* ulExtendJobStatus */
591 PACKI(desc,"D",0); /* ulStartPage */
592 PACKI(desc,"D",0); /* ulEndPage */
597 /********************************************************************
598 Respond to the DosPrintQInfo command with a level of 52
599 This is used to get printer driver information for Win9x clients
600 ********************************************************************/
601 static void fill_printq_info_52(struct spoolss_DriverInfo3 *driver,
602 struct pack_desc* desc, int count,
603 const char *printer_name)
605 int i;
606 fstring location;
607 trim_string((char *)driver->driver_path, "\\print$\\WIN40\\0\\", 0);
608 trim_string((char *)driver->data_file, "\\print$\\WIN40\\0\\", 0);
609 trim_string((char *)driver->help_file, "\\print$\\WIN40\\0\\", 0);
611 PACKI(desc, "W", 0x0400); /* don't know */
612 PACKS(desc, "z", driver->driver_name); /* long printer name */
613 PACKS(desc, "z", driver->driver_path); /* Driverfile Name */
614 PACKS(desc, "z", driver->data_file); /* Datafile name */
615 PACKS(desc, "z", driver->monitor_name); /* language monitor */
617 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
618 standard_sub_basic( "", "", location, sizeof(location)-1 );
619 PACKS(desc,"z", location); /* share to retrieve files */
621 PACKS(desc,"z", driver->default_datatype); /* default data type */
622 PACKS(desc,"z", driver->help_file); /* helpfile name */
623 PACKS(desc,"z", driver->driver_path); /* driver name */
625 DEBUG(3,("Printer Driver Name: %s:\n",driver->driver_name));
626 DEBUG(3,("Driver: %s:\n",driver->driver_path));
627 DEBUG(3,("Data File: %s:\n",driver->data_file));
628 DEBUG(3,("Language Monitor: %s:\n",driver->monitor_name));
629 DEBUG(3,("Driver Location: %s:\n",location));
630 DEBUG(3,("Data Type: %s:\n",driver->default_datatype));
631 DEBUG(3,("Help File: %s:\n",driver->help_file));
632 PACKI(desc,"N",count); /* number of files to copy */
634 for ( i=0; i<count && driver->dependent_files && *driver->dependent_files[i]; i++)
636 trim_string((char *)driver->dependent_files[i], "\\print$\\WIN40\\0\\", 0);
637 PACKS(desc,"z",driver->dependent_files[i]); /* driver files to copy */
638 DEBUG(3,("Dependent File: %s:\n", driver->dependent_files[i]));
641 /* sanity check */
642 if ( i != count )
643 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
644 count, i));
646 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", printer_name, i));
648 desc->errcode=NERR_Success;
652 static const char *strip_unc(const char *unc)
654 char *p;
656 if (unc == NULL) {
657 return NULL;
660 if ((p = strrchr(unc, '\\')) != NULL) {
661 return p+1;
664 return unc;
667 static void fill_printq_info(int uLevel,
668 struct pack_desc* desc,
669 int count,
670 union spoolss_JobInfo *job_info,
671 struct spoolss_DriverInfo3 *driver_info,
672 struct spoolss_PrinterInfo2 *printer_info)
674 switch (uLevel) {
675 case 0:
676 case 1:
677 case 2:
678 PACKS(desc,"B13", strip_unc(printer_info->printername));
679 break;
680 case 3:
681 case 4:
682 case 5:
683 PACKS(desc,"z", strip_unc(printer_info->printername));
684 break;
685 case 51:
686 PACKI(desc,"K", printq_spoolss_status(printer_info->status));
687 break;
690 if (uLevel == 1 || uLevel == 2) {
691 PACKS(desc,"B",""); /* alignment */
692 PACKI(desc,"W",5); /* priority */
693 PACKI(desc,"W",0); /* start time */
694 PACKI(desc,"W",0); /* until time */
695 PACKS(desc,"z",""); /* pSepFile */
696 PACKS(desc,"z","lpd"); /* pPrProc */
697 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pDestinations */
698 PACKS(desc,"z",""); /* pParms */
699 if (printer_info->printername == NULL) {
700 PACKS(desc,"z","UNKNOWN PRINTER");
701 PACKI(desc,"W",LPSTAT_ERROR);
702 } else {
703 PACKS(desc,"z", printer_info->comment);
704 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* status */
706 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
709 if (uLevel == 3 || uLevel == 4) {
710 PACKI(desc,"W",5); /* uPriority */
711 PACKI(desc,"W",0); /* uStarttime */
712 PACKI(desc,"W",0); /* uUntiltime */
713 PACKI(desc,"W",5); /* pad1 */
714 PACKS(desc,"z",""); /* pszSepFile */
715 PACKS(desc,"z","WinPrint"); /* pszPrProc */
716 PACKS(desc,"z",NULL); /* pszParms */
717 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
718 /* "don't ask" that it's done this way to fix corrupted
719 Win9X/ME printer comments. */
720 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* fsStatus */
721 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
722 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pszPrinters */
723 PACKS(desc,"z", printer_info->drivername); /* pszDriverName */
724 PackDriverData(desc); /* pDriverData */
727 if (uLevel == 2 || uLevel == 4) {
728 int i;
729 for (i = 0; i < count; i++) {
730 fill_spoolss_printjob_info(uLevel == 2 ? 1 : 2, desc, &job_info[i].info2, i);
734 if (uLevel==52)
735 fill_printq_info_52(driver_info, desc, count, printer_info->printername);
738 /* This function returns the number of files for a given driver */
739 static int get_printerdrivernumber(const struct spoolss_DriverInfo3 *driver)
741 int result = 0;
743 /* count the number of files */
744 while (driver->dependent_files && *driver->dependent_files[result])
745 result++;
747 return result;
750 static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
751 char *param, int tpscnt,
752 char *data, int tdscnt,
753 int mdrcnt,int mprcnt,
754 char **rdata,char **rparam,
755 int *rdata_len,int *rparam_len)
757 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
758 char *str2 = skip_string(param,tpscnt,str1);
759 char *p = skip_string(param,tpscnt,str2);
760 char *QueueName = p;
761 unsigned int uLevel;
762 uint32_t count = 0;
763 char *str3;
764 struct pack_desc desc;
765 char* tmpdata=NULL;
767 WERROR werr = WERR_OK;
768 TALLOC_CTX *mem_ctx = talloc_tos();
769 NTSTATUS status;
770 struct rpc_pipe_client *cli = NULL;
771 struct policy_handle handle;
772 struct spoolss_DevmodeContainer devmode_ctr;
773 union spoolss_DriverInfo driver_info;
774 union spoolss_JobInfo *job_info;
775 union spoolss_PrinterInfo printer_info;
777 if (!str1 || !str2 || !p) {
778 return False;
780 memset((char *)&desc,'\0',sizeof(desc));
782 p = skip_string(param,tpscnt,p);
783 if (!p) {
784 return False;
786 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
787 str3 = get_safe_str_ptr(param,tpscnt,p,4);
788 /* str3 may be null here and is checked in check_printq_info(). */
790 /* remove any trailing username */
791 if ((p = strchr_m(QueueName,'%')))
792 *p = 0;
794 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
796 /* check it's a supported varient */
797 if (!prefix_ok(str1,"zWrLh"))
798 return False;
799 if (!check_printq_info(&desc,uLevel,str2,str3)) {
801 * Patch from Scott Moomaw <scott@bridgewater.edu>
802 * to return the 'invalid info level' error if an
803 * unknown level was requested.
805 *rdata_len = 0;
806 *rparam_len = 6;
807 *rparam = smb_realloc_limit(*rparam,*rparam_len);
808 if (!*rparam) {
809 return False;
811 SSVALS(*rparam,0,ERRunknownlevel);
812 SSVAL(*rparam,2,0);
813 SSVAL(*rparam,4,0);
814 return(True);
817 ZERO_STRUCT(handle);
819 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
820 rpc_spoolss_dispatch, conn->server_info,
821 &cli);
822 if (!NT_STATUS_IS_OK(status)) {
823 DEBUG(0,("api_DosPrintQGetInfo: could not connect to spoolss: %s\n",
824 nt_errstr(status)));
825 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
826 goto out;
829 ZERO_STRUCT(devmode_ctr);
831 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
832 QueueName,
833 "RAW",
834 devmode_ctr,
835 PRINTER_ACCESS_USE,
836 &handle,
837 &werr);
838 if (!NT_STATUS_IS_OK(status)) {
839 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
840 goto out;
842 if (!W_ERROR_IS_OK(werr)) {
843 desc.errcode = W_ERROR_V(werr);
844 goto out;
847 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
848 &handle,
851 &printer_info);
852 if (!W_ERROR_IS_OK(werr)) {
853 desc.errcode = W_ERROR_V(werr);
854 goto out;
857 if (uLevel==52) {
858 uint32_t server_major_version;
859 uint32_t server_minor_version;
861 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
862 &handle,
863 "Windows 4.0",
864 3, /* level */
866 0, /* version */
868 &driver_info,
869 &server_major_version,
870 &server_minor_version);
871 if (!W_ERROR_IS_OK(werr)) {
872 desc.errcode = W_ERROR_V(werr);
873 goto out;
876 count = get_printerdrivernumber(&driver_info.info3);
877 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
878 } else {
879 uint32_t num_jobs;
880 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
881 &handle,
882 0, /* firstjob */
883 0xff, /* numjobs */
884 2, /* level */
885 0, /* offered */
886 &num_jobs,
887 &job_info);
888 if (!W_ERROR_IS_OK(werr)) {
889 desc.errcode = W_ERROR_V(werr);
890 goto out;
893 count = num_jobs;
896 if (mdrcnt > 0) {
897 *rdata = smb_realloc_limit(*rdata,mdrcnt);
898 if (!*rdata) {
899 return False;
901 desc.base = *rdata;
902 desc.buflen = mdrcnt;
903 } else {
905 * Don't return data but need to get correct length
906 * init_package will return wrong size if buflen=0
908 desc.buflen = getlen(desc.format);
909 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
912 if (init_package(&desc,1,count)) {
913 desc.subcount = count;
914 fill_printq_info(uLevel,&desc,count, job_info, &driver_info.info3, &printer_info.info2);
917 *rdata_len = desc.usedlen;
920 * We must set the return code to ERRbuftoosmall
921 * in order to support lanman style printing with Win NT/2k
922 * clients --jerry
924 if (!mdrcnt && lp_disable_spoolss())
925 desc.errcode = ERRbuftoosmall;
927 out:
928 if (cli && is_valid_policy_hnd(&handle)) {
929 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
932 *rdata_len = desc.usedlen;
933 *rparam_len = 6;
934 *rparam = smb_realloc_limit(*rparam,*rparam_len);
935 if (!*rparam) {
936 SAFE_FREE(tmpdata);
937 return False;
939 SSVALS(*rparam,0,desc.errcode);
940 SSVAL(*rparam,2,0);
941 SSVAL(*rparam,4,desc.neededlen);
943 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
945 SAFE_FREE(tmpdata);
947 return(True);
950 /****************************************************************************
951 View list of all print jobs on all queues.
952 ****************************************************************************/
954 static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
955 char *param, int tpscnt,
956 char *data, int tdscnt,
957 int mdrcnt, int mprcnt,
958 char **rdata, char** rparam,
959 int *rdata_len, int *rparam_len)
961 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
962 char *output_format1 = skip_string(param,tpscnt,param_format);
963 char *p = skip_string(param,tpscnt,output_format1);
964 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
965 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
966 int i;
967 struct pack_desc desc;
968 int *subcntarr = NULL;
969 int queuecnt = 0, subcnt = 0, succnt = 0;
971 WERROR werr = WERR_OK;
972 TALLOC_CTX *mem_ctx = talloc_tos();
973 NTSTATUS status;
974 struct rpc_pipe_client *cli = NULL;
975 struct spoolss_DevmodeContainer devmode_ctr;
976 uint32_t num_printers;
977 union spoolss_PrinterInfo *printer_info;
978 union spoolss_DriverInfo *driver_info;
979 union spoolss_JobInfo **job_info;
981 if (!param_format || !output_format1 || !p) {
982 return False;
985 memset((char *)&desc,'\0',sizeof(desc));
987 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
989 if (!prefix_ok(param_format,"WrLeh")) {
990 return False;
992 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
994 * Patch from Scott Moomaw <scott@bridgewater.edu>
995 * to return the 'invalid info level' error if an
996 * unknown level was requested.
998 *rdata_len = 0;
999 *rparam_len = 6;
1000 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1001 if (!*rparam) {
1002 return False;
1004 SSVALS(*rparam,0,ERRunknownlevel);
1005 SSVAL(*rparam,2,0);
1006 SSVAL(*rparam,4,0);
1007 return(True);
1010 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
1011 rpc_spoolss_dispatch, conn->server_info,
1012 &cli);
1013 if (!NT_STATUS_IS_OK(status)) {
1014 DEBUG(0,("api_DosPrintQEnum: could not connect to spoolss: %s\n",
1015 nt_errstr(status)));
1016 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1017 goto out;
1020 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
1021 PRINTER_ENUM_LOCAL,
1022 cli->srv_name_slash,
1025 &num_printers,
1026 &printer_info);
1027 if (!W_ERROR_IS_OK(werr)) {
1028 desc.errcode = W_ERROR_V(werr);
1029 goto out;
1032 queuecnt = num_printers;
1034 job_info = talloc_array(mem_ctx, union spoolss_JobInfo *, num_printers);
1035 if (job_info == NULL) {
1036 goto err;
1039 driver_info = talloc_array(mem_ctx, union spoolss_DriverInfo, num_printers);
1040 if (driver_info == NULL) {
1041 goto err;
1044 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1045 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1046 goto err;
1049 if (mdrcnt > 0) {
1050 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1051 if (!*rdata) {
1052 goto err;
1055 desc.base = *rdata;
1056 desc.buflen = mdrcnt;
1058 subcnt = 0;
1059 for (i = 0; i < num_printers; i++) {
1061 uint32_t num_jobs;
1062 struct policy_handle handle;
1063 const char *printername;
1065 printername = talloc_strdup(mem_ctx, printer_info[i].info2.printername);
1066 if (printername == NULL) {
1067 goto err;
1070 ZERO_STRUCT(handle);
1071 ZERO_STRUCT(devmode_ctr);
1073 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
1074 printername,
1075 "RAW",
1076 devmode_ctr,
1077 PRINTER_ACCESS_USE,
1078 &handle,
1079 &werr);
1080 if (!NT_STATUS_IS_OK(status)) {
1081 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1082 goto out;
1084 if (!W_ERROR_IS_OK(werr)) {
1085 desc.errcode = W_ERROR_V(werr);
1086 goto out;
1089 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
1090 &handle,
1091 0, /* firstjob */
1092 0xff, /* numjobs */
1093 2, /* level */
1094 0, /* offered */
1095 &num_jobs,
1096 &job_info[i]);
1097 if (!W_ERROR_IS_OK(werr)) {
1098 desc.errcode = W_ERROR_V(werr);
1099 goto out;
1102 if (uLevel==52) {
1103 uint32_t server_major_version;
1104 uint32_t server_minor_version;
1106 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1107 &handle,
1108 "Windows 4.0",
1109 3, /* level */
1111 0, /* version */
1113 &driver_info[i],
1114 &server_major_version,
1115 &server_minor_version);
1116 if (!W_ERROR_IS_OK(werr)) {
1117 desc.errcode = W_ERROR_V(werr);
1118 goto out;
1122 subcntarr[i] = num_jobs;
1123 subcnt += subcntarr[i];
1125 if (cli && is_valid_policy_hnd(&handle)) {
1126 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
1130 if (init_package(&desc,queuecnt,subcnt)) {
1131 for (i = 0; i < num_printers; i++) {
1132 fill_printq_info(uLevel,&desc,subcntarr[i], job_info[i], &driver_info[i].info3, &printer_info[i].info2);
1133 if (desc.errcode == NERR_Success) {
1134 succnt = i;
1139 SAFE_FREE(subcntarr);
1140 out:
1141 *rdata_len = desc.usedlen;
1142 *rparam_len = 8;
1143 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1144 if (!*rparam) {
1145 goto err;
1147 SSVALS(*rparam,0,desc.errcode);
1148 SSVAL(*rparam,2,0);
1149 SSVAL(*rparam,4,succnt);
1150 SSVAL(*rparam,6,queuecnt);
1152 return True;
1154 err:
1156 SAFE_FREE(subcntarr);
1158 return False;
1161 /****************************************************************************
1162 Get info level for a server list query.
1163 ****************************************************************************/
1165 static bool check_server_info(int uLevel, char* id)
1167 switch( uLevel ) {
1168 case 0:
1169 if (strcmp(id,"B16") != 0) {
1170 return False;
1172 break;
1173 case 1:
1174 if (strcmp(id,"B16BBDz") != 0) {
1175 return False;
1177 break;
1178 default:
1179 return False;
1181 return True;
1184 struct srv_info_struct {
1185 fstring name;
1186 uint32 type;
1187 fstring comment;
1188 fstring domain;
1189 bool server_added;
1192 /*******************************************************************
1193 Get server info lists from the files saved by nmbd. Return the
1194 number of entries.
1195 ******************************************************************/
1197 static int get_server_info(uint32 servertype,
1198 struct srv_info_struct **servers,
1199 const char *domain)
1201 int count=0;
1202 int alloced=0;
1203 char **lines;
1204 bool local_list_only;
1205 int i;
1207 lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
1208 if (!lines) {
1209 DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
1210 return 0;
1213 /* request for everything is code for request all servers */
1214 if (servertype == SV_TYPE_ALL) {
1215 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1218 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1220 DEBUG(4,("Servertype search: %8x\n",servertype));
1222 for (i=0;lines[i];i++) {
1223 fstring stype;
1224 struct srv_info_struct *s;
1225 const char *ptr = lines[i];
1226 bool ok = True;
1227 TALLOC_CTX *frame = NULL;
1228 char *p;
1230 if (!*ptr) {
1231 continue;
1234 if (count == alloced) {
1235 alloced += 10;
1236 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1237 if (!*servers) {
1238 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1239 TALLOC_FREE(lines);
1240 return 0;
1242 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1244 s = &(*servers)[count];
1246 frame = talloc_stackframe();
1247 s->name[0] = '\0';
1248 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1249 TALLOC_FREE(frame);
1250 continue;
1252 fstrcpy(s->name, p);
1254 stype[0] = '\0';
1255 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1256 TALLOC_FREE(frame);
1257 continue;
1259 fstrcpy(stype, p);
1261 s->comment[0] = '\0';
1262 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1263 TALLOC_FREE(frame);
1264 continue;
1266 fstrcpy(s->comment, p);
1267 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1269 s->domain[0] = '\0';
1270 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1271 /* this allows us to cope with an old nmbd */
1272 fstrcpy(s->domain,lp_workgroup());
1273 } else {
1274 fstrcpy(s->domain, p);
1276 TALLOC_FREE(frame);
1278 if (sscanf(stype,"%X",&s->type) != 1) {
1279 DEBUG(4,("r:host file "));
1280 ok = False;
1283 /* Filter the servers/domains we return based on what was asked for. */
1285 /* Check to see if we are being asked for a local list only. */
1286 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1287 DEBUG(4,("r: local list only"));
1288 ok = False;
1291 /* doesn't match up: don't want it */
1292 if (!(servertype & s->type)) {
1293 DEBUG(4,("r:serv type "));
1294 ok = False;
1297 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1298 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1299 DEBUG(4,("s: dom mismatch "));
1300 ok = False;
1303 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1304 ok = False;
1307 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1308 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1310 if (ok) {
1311 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1312 s->name, s->type, s->comment, s->domain));
1313 s->server_added = True;
1314 count++;
1315 } else {
1316 DEBUG(4,("%20s %8x %25s %15s\n",
1317 s->name, s->type, s->comment, s->domain));
1321 TALLOC_FREE(lines);
1322 return count;
1325 /*******************************************************************
1326 Fill in a server info structure.
1327 ******************************************************************/
1329 static int fill_srv_info(struct srv_info_struct *service,
1330 int uLevel, char **buf, int *buflen,
1331 char **stringbuf, int *stringspace, char *baseaddr)
1333 int struct_len;
1334 char* p;
1335 char* p2;
1336 int l2;
1337 int len;
1339 switch (uLevel) {
1340 case 0:
1341 struct_len = 16;
1342 break;
1343 case 1:
1344 struct_len = 26;
1345 break;
1346 default:
1347 return -1;
1350 if (!buf) {
1351 len = 0;
1352 switch (uLevel) {
1353 case 1:
1354 len = strlen(service->comment)+1;
1355 break;
1358 *buflen = struct_len;
1359 *stringspace = len;
1360 return struct_len + len;
1363 len = struct_len;
1364 p = *buf;
1365 if (*buflen < struct_len) {
1366 return -1;
1368 if (stringbuf) {
1369 p2 = *stringbuf;
1370 l2 = *stringspace;
1371 } else {
1372 p2 = p + struct_len;
1373 l2 = *buflen - struct_len;
1375 if (!baseaddr) {
1376 baseaddr = p;
1379 switch (uLevel) {
1380 case 0:
1381 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1382 break;
1384 case 1:
1385 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1386 SIVAL(p,18,service->type);
1387 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1388 len += CopyAndAdvance(&p2,service->comment,&l2);
1389 break;
1392 if (stringbuf) {
1393 *buf = p + struct_len;
1394 *buflen -= struct_len;
1395 *stringbuf = p2;
1396 *stringspace = l2;
1397 } else {
1398 *buf = p2;
1399 *buflen -= len;
1401 return len;
1405 static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1407 return StrCaseCmp(s1->name,s2->name);
1410 /****************************************************************************
1411 View list of servers available (or possibly domains). The info is
1412 extracted from lists saved by nmbd on the local host.
1413 ****************************************************************************/
1415 static bool api_RNetServerEnum2(connection_struct *conn, uint16 vuid,
1416 char *param, int tpscnt,
1417 char *data, int tdscnt,
1418 int mdrcnt, int mprcnt, char **rdata,
1419 char **rparam, int *rdata_len, int *rparam_len)
1421 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1422 char *str2 = skip_string(param,tpscnt,str1);
1423 char *p = skip_string(param,tpscnt,str2);
1424 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1425 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1426 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1427 char *p2;
1428 int data_len, fixed_len, string_len;
1429 int f_len = 0, s_len = 0;
1430 struct srv_info_struct *servers=NULL;
1431 int counted=0,total=0;
1432 int i,missed;
1433 fstring domain;
1434 bool domain_request;
1435 bool local_request;
1437 if (!str1 || !str2 || !p) {
1438 return False;
1441 /* If someone sets all the bits they don't really mean to set
1442 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1443 known servers. */
1445 if (servertype == SV_TYPE_ALL) {
1446 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1449 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1450 any other bit (they may just set this bit on its own) they
1451 want all the locally seen servers. However this bit can be
1452 set on its own so set the requested servers to be
1453 ALL - DOMAIN_ENUM. */
1455 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1456 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1459 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1460 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1462 p += 8;
1464 if (!prefix_ok(str1,"WrLehD")) {
1465 return False;
1467 if (!check_server_info(uLevel,str2)) {
1468 return False;
1471 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1472 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1473 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1475 if (strcmp(str1, "WrLehDz") == 0) {
1476 if (skip_string(param,tpscnt,p) == NULL) {
1477 return False;
1479 pull_ascii_fstring(domain, p);
1480 } else {
1481 fstrcpy(domain, lp_workgroup());
1484 DEBUG(4, ("domain [%s]\n", domain));
1486 if (lp_browse_list()) {
1487 total = get_server_info(servertype,&servers,domain);
1490 data_len = fixed_len = string_len = 0;
1491 missed = 0;
1493 TYPESAFE_QSORT(servers, total, srv_comp);
1496 char *lastname=NULL;
1498 for (i=0;i<total;i++) {
1499 struct srv_info_struct *s = &servers[i];
1501 if (lastname && strequal(lastname,s->name)) {
1502 continue;
1504 lastname = s->name;
1505 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1506 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1507 i, s->name, s->type, s->comment, s->domain));
1509 if (data_len < buf_len) {
1510 counted++;
1511 fixed_len += f_len;
1512 string_len += s_len;
1513 } else {
1514 missed++;
1519 *rdata_len = fixed_len + string_len;
1520 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1521 if (!*rdata) {
1522 return False;
1525 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1526 p = *rdata;
1527 f_len = fixed_len;
1528 s_len = string_len;
1531 char *lastname=NULL;
1532 int count2 = counted;
1534 for (i = 0; i < total && count2;i++) {
1535 struct srv_info_struct *s = &servers[i];
1537 if (lastname && strequal(lastname,s->name)) {
1538 continue;
1540 lastname = s->name;
1541 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1542 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1543 i, s->name, s->type, s->comment, s->domain));
1544 count2--;
1548 *rparam_len = 8;
1549 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1550 if (!*rparam) {
1551 return False;
1553 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1554 SSVAL(*rparam,2,0);
1555 SSVAL(*rparam,4,counted);
1556 SSVAL(*rparam,6,counted+missed);
1558 SAFE_FREE(servers);
1560 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1561 domain,uLevel,counted,counted+missed));
1563 return True;
1566 static int srv_name_match(const char *n1, const char *n2)
1569 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1571 * In Windows, FirstNameToReturn need not be an exact match:
1572 * the server will return a list of servers that exist on
1573 * the network greater than or equal to the FirstNameToReturn.
1575 int ret = StrCaseCmp(n1, n2);
1577 if (ret <= 0) {
1578 return 0;
1581 return ret;
1584 static bool api_RNetServerEnum3(connection_struct *conn, uint16 vuid,
1585 char *param, int tpscnt,
1586 char *data, int tdscnt,
1587 int mdrcnt, int mprcnt, char **rdata,
1588 char **rparam, int *rdata_len, int *rparam_len)
1590 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1591 char *str2 = skip_string(param,tpscnt,str1);
1592 char *p = skip_string(param,tpscnt,str2);
1593 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1594 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1595 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1596 char *p2;
1597 int data_len, fixed_len, string_len;
1598 int f_len = 0, s_len = 0;
1599 struct srv_info_struct *servers=NULL;
1600 int counted=0,first=0,total=0;
1601 int i,missed;
1602 fstring domain;
1603 fstring first_name;
1604 bool domain_request;
1605 bool local_request;
1607 if (!str1 || !str2 || !p) {
1608 return False;
1611 /* If someone sets all the bits they don't really mean to set
1612 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1613 known servers. */
1615 if (servertype == SV_TYPE_ALL) {
1616 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1619 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1620 any other bit (they may just set this bit on its own) they
1621 want all the locally seen servers. However this bit can be
1622 set on its own so set the requested servers to be
1623 ALL - DOMAIN_ENUM. */
1625 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1626 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1629 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1630 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1632 p += 8;
1634 if (strcmp(str1, "WrLehDzz") != 0) {
1635 return false;
1637 if (!check_server_info(uLevel,str2)) {
1638 return False;
1641 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1642 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1643 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1645 if (skip_string(param,tpscnt,p) == NULL) {
1646 return False;
1648 pull_ascii_fstring(domain, p);
1649 if (domain[0] == '\0') {
1650 fstrcpy(domain, lp_workgroup());
1652 p = skip_string(param,tpscnt,p);
1653 if (skip_string(param,tpscnt,p) == NULL) {
1654 return False;
1656 pull_ascii_fstring(first_name, p);
1658 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1659 domain, first_name));
1661 if (lp_browse_list()) {
1662 total = get_server_info(servertype,&servers,domain);
1665 data_len = fixed_len = string_len = 0;
1666 missed = 0;
1668 TYPESAFE_QSORT(servers, total, srv_comp);
1670 if (first_name[0] != '\0') {
1671 struct srv_info_struct *first_server = NULL;
1673 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1674 srv_name_match, first_server);
1675 if (first_server) {
1676 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1678 * The binary search may not find the exact match
1679 * so we need to search backward to find the first match
1681 * This implements the strange matching windows
1682 * implements. (see the comment in srv_name_match().
1684 for (;first > 0;) {
1685 int ret;
1686 ret = StrCaseCmp(first_name,
1687 servers[first-1].name);
1688 if (ret > 0) {
1689 break;
1691 first--;
1693 } else {
1694 /* we should return no entries */
1695 first = total;
1700 char *lastname=NULL;
1702 for (i=first;i<total;i++) {
1703 struct srv_info_struct *s = &servers[i];
1705 if (lastname && strequal(lastname,s->name)) {
1706 continue;
1708 lastname = s->name;
1709 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1710 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1711 i, s->name, s->type, s->comment, s->domain));
1713 if (data_len < buf_len) {
1714 counted++;
1715 fixed_len += f_len;
1716 string_len += s_len;
1717 } else {
1718 missed++;
1723 *rdata_len = fixed_len + string_len;
1724 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1725 if (!*rdata) {
1726 return False;
1729 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1730 p = *rdata;
1731 f_len = fixed_len;
1732 s_len = string_len;
1735 char *lastname=NULL;
1736 int count2 = counted;
1738 for (i = first; i < total && count2;i++) {
1739 struct srv_info_struct *s = &servers[i];
1741 if (lastname && strequal(lastname,s->name)) {
1742 continue;
1744 lastname = s->name;
1745 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1746 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1747 i, s->name, s->type, s->comment, s->domain));
1748 count2--;
1752 *rparam_len = 8;
1753 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1754 if (!*rparam) {
1755 return False;
1757 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1758 SSVAL(*rparam,2,0);
1759 SSVAL(*rparam,4,counted);
1760 SSVAL(*rparam,6,counted+missed);
1762 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1763 domain,uLevel,first,first_name,
1764 first < total ? servers[first].name : "",
1765 counted,counted+missed));
1767 SAFE_FREE(servers);
1769 return True;
1772 /****************************************************************************
1773 command 0x34 - suspected of being a "Lookup Names" stub api
1774 ****************************************************************************/
1776 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1777 char *param, int tpscnt,
1778 char *data, int tdscnt,
1779 int mdrcnt, int mprcnt, char **rdata,
1780 char **rparam, int *rdata_len, int *rparam_len)
1782 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1783 char *str2 = skip_string(param,tpscnt,str1);
1784 char *p = skip_string(param,tpscnt,str2);
1785 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1786 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1787 int counted=0;
1788 int missed=0;
1790 if (!str1 || !str2 || !p) {
1791 return False;
1794 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1795 str1, str2, p, uLevel, buf_len));
1797 if (!prefix_ok(str1,"zWrLeh")) {
1798 return False;
1801 *rdata_len = 0;
1803 *rparam_len = 8;
1804 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1805 if (!*rparam) {
1806 return False;
1809 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1810 SSVAL(*rparam,2,0);
1811 SSVAL(*rparam,4,counted);
1812 SSVAL(*rparam,6,counted+missed);
1814 return True;
1817 /****************************************************************************
1818 get info about a share
1819 ****************************************************************************/
1821 static bool check_share_info(int uLevel, char* id)
1823 switch( uLevel ) {
1824 case 0:
1825 if (strcmp(id,"B13") != 0) {
1826 return False;
1828 break;
1829 case 1:
1830 /* Level-2 descriptor is allowed (and ignored) */
1831 if (strcmp(id,"B13BWz") != 0 &&
1832 strcmp(id,"B13BWzWWWzB9B") != 0) {
1833 return False;
1835 break;
1836 case 2:
1837 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1838 return False;
1840 break;
1841 case 91:
1842 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1843 return False;
1845 break;
1846 default:
1847 return False;
1849 return True;
1852 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1853 char** buf, int* buflen,
1854 char** stringbuf, int* stringspace, char* baseaddr)
1856 int struct_len;
1857 char* p;
1858 char* p2;
1859 int l2;
1860 int len;
1862 switch( uLevel ) {
1863 case 0:
1864 struct_len = 13;
1865 break;
1866 case 1:
1867 struct_len = 20;
1868 break;
1869 case 2:
1870 struct_len = 40;
1871 break;
1872 case 91:
1873 struct_len = 68;
1874 break;
1875 default:
1876 return -1;
1879 if (!buf) {
1880 len = 0;
1882 if (uLevel > 0) {
1883 len += StrlenExpanded(conn,snum,lp_comment(snum));
1885 if (uLevel > 1) {
1886 len += strlen(lp_pathname(snum)) + 1;
1888 if (buflen) {
1889 *buflen = struct_len;
1891 if (stringspace) {
1892 *stringspace = len;
1894 return struct_len + len;
1897 len = struct_len;
1898 p = *buf;
1899 if ((*buflen) < struct_len) {
1900 return -1;
1903 if (stringbuf) {
1904 p2 = *stringbuf;
1905 l2 = *stringspace;
1906 } else {
1907 p2 = p + struct_len;
1908 l2 = (*buflen) - struct_len;
1911 if (!baseaddr) {
1912 baseaddr = p;
1915 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1917 if (uLevel > 0) {
1918 int type;
1920 SCVAL(p,13,0);
1921 type = STYPE_DISKTREE;
1922 if (lp_print_ok(snum)) {
1923 type = STYPE_PRINTQ;
1925 if (strequal("IPC",lp_fstype(snum))) {
1926 type = STYPE_IPC;
1928 SSVAL(p,14,type); /* device type */
1929 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1930 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1933 if (uLevel > 1) {
1934 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1935 SSVALS(p,22,-1); /* max uses */
1936 SSVAL(p,24,1); /* current uses */
1937 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1938 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1939 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1942 if (uLevel > 2) {
1943 memset(p+40,0,SHPWLEN+2);
1944 SSVAL(p,50,0);
1945 SIVAL(p,52,0);
1946 SSVAL(p,56,0);
1947 SSVAL(p,58,0);
1948 SIVAL(p,60,0);
1949 SSVAL(p,64,0);
1950 SSVAL(p,66,0);
1953 if (stringbuf) {
1954 (*buf) = p + struct_len;
1955 (*buflen) -= struct_len;
1956 (*stringbuf) = p2;
1957 (*stringspace) = l2;
1958 } else {
1959 (*buf) = p2;
1960 (*buflen) -= len;
1963 return len;
1966 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1967 char *param, int tpscnt,
1968 char *data, int tdscnt,
1969 int mdrcnt,int mprcnt,
1970 char **rdata,char **rparam,
1971 int *rdata_len,int *rparam_len)
1973 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1974 char *str2 = skip_string(param,tpscnt,str1);
1975 char *netname = skip_string(param,tpscnt,str2);
1976 char *p = skip_string(param,tpscnt,netname);
1977 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1978 int snum;
1980 if (!str1 || !str2 || !netname || !p) {
1981 return False;
1984 snum = find_service(netname);
1985 if (snum < 0) {
1986 return False;
1989 /* check it's a supported varient */
1990 if (!prefix_ok(str1,"zWrLh")) {
1991 return False;
1993 if (!check_share_info(uLevel,str2)) {
1994 return False;
1997 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1998 if (!*rdata) {
1999 return False;
2001 p = *rdata;
2002 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
2003 if (*rdata_len < 0) {
2004 return False;
2007 *rparam_len = 6;
2008 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2009 if (!*rparam) {
2010 return False;
2012 SSVAL(*rparam,0,NERR_Success);
2013 SSVAL(*rparam,2,0); /* converter word */
2014 SSVAL(*rparam,4,*rdata_len);
2016 return True;
2019 /****************************************************************************
2020 View the list of available shares.
2022 This function is the server side of the NetShareEnum() RAP call.
2023 It fills the return buffer with share names and share comments.
2024 Note that the return buffer normally (in all known cases) allows only
2025 twelve byte strings for share names (plus one for a nul terminator).
2026 Share names longer than 12 bytes must be skipped.
2027 ****************************************************************************/
2029 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
2030 char *param, int tpscnt,
2031 char *data, int tdscnt,
2032 int mdrcnt,
2033 int mprcnt,
2034 char **rdata,
2035 char **rparam,
2036 int *rdata_len,
2037 int *rparam_len )
2039 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2040 char *str2 = skip_string(param,tpscnt,str1);
2041 char *p = skip_string(param,tpscnt,str2);
2042 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2043 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
2044 char *p2;
2045 int count = 0;
2046 int total=0,counted=0;
2047 bool missed = False;
2048 int i;
2049 int data_len, fixed_len, string_len;
2050 int f_len = 0, s_len = 0;
2052 if (!str1 || !str2 || !p) {
2053 return False;
2056 if (!prefix_ok(str1,"WrLeh")) {
2057 return False;
2059 if (!check_share_info(uLevel,str2)) {
2060 return False;
2063 /* Ensure all the usershares are loaded. */
2064 become_root();
2065 load_registry_shares();
2066 count = load_usershare_shares();
2067 unbecome_root();
2069 data_len = fixed_len = string_len = 0;
2070 for (i=0;i<count;i++) {
2071 fstring servicename_dos;
2072 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2073 continue;
2075 push_ascii_fstring(servicename_dos, lp_servicename(i));
2076 /* Maximum name length = 13. */
2077 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
2078 total++;
2079 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
2080 if (data_len < buf_len) {
2081 counted++;
2082 fixed_len += f_len;
2083 string_len += s_len;
2084 } else {
2085 missed = True;
2090 *rdata_len = fixed_len + string_len;
2091 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2092 if (!*rdata) {
2093 return False;
2096 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
2097 p = *rdata;
2098 f_len = fixed_len;
2099 s_len = string_len;
2101 for( i = 0; i < count; i++ ) {
2102 fstring servicename_dos;
2103 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2104 continue;
2107 push_ascii_fstring(servicename_dos, lp_servicename(i));
2108 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2109 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2110 break;
2115 *rparam_len = 8;
2116 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2117 if (!*rparam) {
2118 return False;
2120 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2121 SSVAL(*rparam,2,0);
2122 SSVAL(*rparam,4,counted);
2123 SSVAL(*rparam,6,total);
2125 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2126 counted,total,uLevel,
2127 buf_len,*rdata_len,mdrcnt));
2129 return True;
2132 /****************************************************************************
2133 Add a share
2134 ****************************************************************************/
2136 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
2137 char *param, int tpscnt,
2138 char *data, int tdscnt,
2139 int mdrcnt,int mprcnt,
2140 char **rdata,char **rparam,
2141 int *rdata_len,int *rparam_len)
2143 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2144 char *str2 = skip_string(param,tpscnt,str1);
2145 char *p = skip_string(param,tpscnt,str2);
2146 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2147 fstring sharename;
2148 fstring comment;
2149 char *pathname = NULL;
2150 unsigned int offset;
2151 int res = ERRunsup;
2152 size_t converted_size;
2154 WERROR werr = WERR_OK;
2155 TALLOC_CTX *mem_ctx = talloc_tos();
2156 NTSTATUS status;
2157 struct rpc_pipe_client *cli = NULL;
2158 union srvsvc_NetShareInfo info;
2159 struct srvsvc_NetShareInfo2 info2;
2161 if (!str1 || !str2 || !p) {
2162 return False;
2165 /* check it's a supported varient */
2166 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2167 return False;
2169 if (!check_share_info(uLevel,str2)) {
2170 return False;
2172 if (uLevel != 2) {
2173 return False;
2176 /* Do we have a string ? */
2177 if (skip_string(data,mdrcnt,data) == NULL) {
2178 return False;
2180 pull_ascii_fstring(sharename,data);
2182 if (mdrcnt < 28) {
2183 return False;
2186 /* only support disk share adds */
2187 if (SVAL(data,14)!=STYPE_DISKTREE) {
2188 return False;
2191 offset = IVAL(data, 16);
2192 if (offset >= mdrcnt) {
2193 res = ERRinvalidparam;
2194 goto out;
2197 /* Do we have a string ? */
2198 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2199 return False;
2201 pull_ascii_fstring(comment, offset? (data+offset) : "");
2203 offset = IVAL(data, 26);
2205 if (offset >= mdrcnt) {
2206 res = ERRinvalidparam;
2207 goto out;
2210 /* Do we have a string ? */
2211 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2212 return False;
2215 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2216 offset ? (data+offset) : "", &converted_size))
2218 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
2219 strerror(errno)));
2222 if (!pathname) {
2223 return false;
2226 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_srvsvc.syntax_id,
2227 rpc_srvsvc_dispatch, conn->server_info,
2228 &cli);
2229 if (!NT_STATUS_IS_OK(status)) {
2230 DEBUG(0,("api_RNetShareAdd: could not connect to srvsvc: %s\n",
2231 nt_errstr(status)));
2232 res = W_ERROR_V(ntstatus_to_werror(status));
2233 goto out;
2236 info2.name = sharename;
2237 info2.type = STYPE_DISKTREE;
2238 info2.comment = comment;
2239 info2.permissions = 0;
2240 info2.max_users = 0;
2241 info2.current_users = 0;
2242 info2.path = pathname;
2243 info2.password = NULL;
2245 info.info2 = &info2;
2247 status = rpccli_srvsvc_NetShareAdd(cli, mem_ctx,
2248 cli->srv_name_slash,
2250 &info,
2251 NULL,
2252 &werr);
2253 if (!NT_STATUS_IS_OK(status)) {
2254 res = W_ERROR_V(ntstatus_to_werror(status));
2255 goto out;
2257 if (!W_ERROR_IS_OK(werr)) {
2258 res = W_ERROR_V(werr);
2259 goto out;
2262 *rparam_len = 6;
2263 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2264 if (!*rparam) {
2265 return False;
2267 SSVAL(*rparam,0,NERR_Success);
2268 SSVAL(*rparam,2,0); /* converter word */
2269 SSVAL(*rparam,4,*rdata_len);
2270 *rdata_len = 0;
2272 return True;
2274 out:
2276 *rparam_len = 4;
2277 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2278 if (!*rparam) {
2279 return False;
2281 *rdata_len = 0;
2282 SSVAL(*rparam,0,res);
2283 SSVAL(*rparam,2,0);
2284 return True;
2287 /****************************************************************************
2288 view list of groups available
2289 ****************************************************************************/
2291 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
2292 char *param, int tpscnt,
2293 char *data, int tdscnt,
2294 int mdrcnt,int mprcnt,
2295 char **rdata,char **rparam,
2296 int *rdata_len,int *rparam_len)
2298 int i;
2299 int errflags=0;
2300 int resume_context, cli_buf_size;
2301 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2302 char *str2 = skip_string(param,tpscnt,str1);
2303 char *p = skip_string(param,tpscnt,str2);
2305 uint32_t num_groups;
2306 uint32_t resume_handle;
2307 struct rpc_pipe_client *samr_pipe;
2308 struct policy_handle samr_handle, domain_handle;
2309 NTSTATUS status;
2311 if (!str1 || !str2 || !p) {
2312 return False;
2315 if (strcmp(str1,"WrLeh") != 0) {
2316 return False;
2319 /* parameters
2320 * W-> resume context (number of users to skip)
2321 * r -> return parameter pointer to receive buffer
2322 * L -> length of receive buffer
2323 * e -> return parameter number of entries
2324 * h -> return parameter total number of users
2327 if (strcmp("B21",str2) != 0) {
2328 return False;
2331 status = rpc_pipe_open_internal(
2332 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2333 conn->server_info, &samr_pipe);
2334 if (!NT_STATUS_IS_OK(status)) {
2335 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2336 nt_errstr(status)));
2337 return false;
2340 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2341 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2342 if (!NT_STATUS_IS_OK(status)) {
2343 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2344 nt_errstr(status)));
2345 return false;
2348 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2349 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2350 get_global_sam_sid(), &domain_handle);
2351 if (!NT_STATUS_IS_OK(status)) {
2352 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2353 nt_errstr(status)));
2354 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2355 return false;
2358 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2359 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2360 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2361 "%d\n", resume_context, cli_buf_size));
2363 *rdata_len = cli_buf_size;
2364 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2365 if (!*rdata) {
2366 return False;
2369 p = *rdata;
2371 errflags = NERR_Success;
2372 num_groups = 0;
2373 resume_handle = 0;
2375 while (true) {
2376 struct samr_SamArray *sam_entries;
2377 uint32_t num_entries;
2379 status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
2380 &domain_handle,
2381 &resume_handle,
2382 &sam_entries, 1,
2383 &num_entries);
2384 if (!NT_STATUS_IS_OK(status)) {
2385 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2386 "%s\n", nt_errstr(status)));
2387 break;
2390 if (num_entries == 0) {
2391 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2392 "no entries -- done\n"));
2393 break;
2396 for(i=0; i<num_entries; i++) {
2397 const char *name;
2399 name = sam_entries->entries[i].name.string;
2401 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2402 /* set overflow error */
2403 DEBUG(3,("overflow on entry %d group %s\n", i,
2404 name));
2405 errflags=234;
2406 break;
2409 /* truncate the name at 21 chars. */
2410 memset(p, 0, 21);
2411 strlcpy(p, name, 21);
2412 DEBUG(10,("adding entry %d group %s\n", i, p));
2413 p += 21;
2414 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2415 * idea why... */
2416 num_groups += 1;
2419 if (errflags != NERR_Success) {
2420 break;
2423 TALLOC_FREE(sam_entries);
2426 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2427 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2429 *rdata_len = PTR_DIFF(p,*rdata);
2431 *rparam_len = 8;
2432 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2433 if (!*rparam) {
2434 return False;
2436 SSVAL(*rparam, 0, errflags);
2437 SSVAL(*rparam, 2, 0); /* converter word */
2438 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2439 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2441 return(True);
2444 /*******************************************************************
2445 Get groups that a user is a member of.
2446 ******************************************************************/
2448 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2449 char *param, int tpscnt,
2450 char *data, int tdscnt,
2451 int mdrcnt,int mprcnt,
2452 char **rdata,char **rparam,
2453 int *rdata_len,int *rparam_len)
2455 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2456 char *str2 = skip_string(param,tpscnt,str1);
2457 char *UserName = skip_string(param,tpscnt,str2);
2458 char *p = skip_string(param,tpscnt,UserName);
2459 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2460 const char *level_string;
2461 int count=0;
2462 bool ret = False;
2463 uint32_t i;
2464 char *endp = NULL;
2466 struct rpc_pipe_client *samr_pipe;
2467 struct policy_handle samr_handle, domain_handle, user_handle;
2468 struct lsa_String name;
2469 struct lsa_Strings names;
2470 struct samr_Ids type, rid;
2471 struct samr_RidWithAttributeArray *rids;
2472 NTSTATUS status;
2474 if (!str1 || !str2 || !UserName || !p) {
2475 return False;
2478 *rparam_len = 8;
2479 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2480 if (!*rparam) {
2481 return False;
2484 /* check it's a supported varient */
2486 if ( strcmp(str1,"zWrLeh") != 0 )
2487 return False;
2489 switch( uLevel ) {
2490 case 0:
2491 level_string = "B21";
2492 break;
2493 default:
2494 return False;
2497 if (strcmp(level_string,str2) != 0)
2498 return False;
2500 *rdata_len = mdrcnt + 1024;
2501 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2502 if (!*rdata) {
2503 return False;
2506 SSVAL(*rparam,0,NERR_Success);
2507 SSVAL(*rparam,2,0); /* converter word */
2509 p = *rdata;
2510 endp = *rdata + *rdata_len;
2512 status = rpc_pipe_open_internal(
2513 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2514 conn->server_info, &samr_pipe);
2515 if (!NT_STATUS_IS_OK(status)) {
2516 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2517 nt_errstr(status)));
2518 return false;
2521 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2522 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2523 if (!NT_STATUS_IS_OK(status)) {
2524 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2525 nt_errstr(status)));
2526 return false;
2529 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2530 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2531 get_global_sam_sid(), &domain_handle);
2532 if (!NT_STATUS_IS_OK(status)) {
2533 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2534 nt_errstr(status)));
2535 goto close_sam;
2538 name.string = UserName;
2540 status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
2541 &domain_handle, 1, &name,
2542 &rid, &type);
2543 if (!NT_STATUS_IS_OK(status)) {
2544 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2545 nt_errstr(status)));
2546 goto close_domain;
2549 if (type.ids[0] != SID_NAME_USER) {
2550 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2551 sid_type_lookup(type.ids[0])));
2552 goto close_domain;
2555 status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
2556 &domain_handle,
2557 SAMR_USER_ACCESS_GET_GROUPS,
2558 rid.ids[0], &user_handle);
2559 if (!NT_STATUS_IS_OK(status)) {
2560 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2561 nt_errstr(status)));
2562 goto close_domain;
2565 status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
2566 &user_handle, &rids);
2567 if (!NT_STATUS_IS_OK(status)) {
2568 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2569 nt_errstr(status)));
2570 goto close_user;
2573 for (i=0; i<rids->count; i++) {
2575 status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
2576 &domain_handle,
2577 1, &rids->rids[i].rid,
2578 &names, &type);
2579 if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
2580 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2581 p += 21;
2582 count++;
2586 *rdata_len = PTR_DIFF(p,*rdata);
2588 SSVAL(*rparam,4,count); /* is this right?? */
2589 SSVAL(*rparam,6,count); /* is this right?? */
2591 ret = True;
2593 close_user:
2594 rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
2595 close_domain:
2596 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2597 close_sam:
2598 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2600 return ret;
2603 /*******************************************************************
2604 Get all users.
2605 ******************************************************************/
2607 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2608 char *param, int tpscnt,
2609 char *data, int tdscnt,
2610 int mdrcnt,int mprcnt,
2611 char **rdata,char **rparam,
2612 int *rdata_len,int *rparam_len)
2614 int count_sent=0;
2615 int num_users=0;
2616 int errflags=0;
2617 int i, resume_context, cli_buf_size;
2618 uint32_t resume_handle;
2620 struct rpc_pipe_client *samr_pipe;
2621 struct policy_handle samr_handle, domain_handle;
2622 NTSTATUS status;
2624 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2625 char *str2 = skip_string(param,tpscnt,str1);
2626 char *p = skip_string(param,tpscnt,str2);
2627 char *endp = NULL;
2629 if (!str1 || !str2 || !p) {
2630 return False;
2633 if (strcmp(str1,"WrLeh") != 0)
2634 return False;
2635 /* parameters
2636 * W-> resume context (number of users to skip)
2637 * r -> return parameter pointer to receive buffer
2638 * L -> length of receive buffer
2639 * e -> return parameter number of entries
2640 * h -> return parameter total number of users
2643 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2644 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2645 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2646 resume_context, cli_buf_size));
2648 *rparam_len = 8;
2649 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2650 if (!*rparam) {
2651 return False;
2654 /* check it's a supported varient */
2655 if (strcmp("B21",str2) != 0)
2656 return False;
2658 *rdata_len = cli_buf_size;
2659 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2660 if (!*rdata) {
2661 return False;
2664 p = *rdata;
2665 endp = *rdata + *rdata_len;
2667 status = rpc_pipe_open_internal(
2668 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2669 conn->server_info, &samr_pipe);
2670 if (!NT_STATUS_IS_OK(status)) {
2671 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2672 nt_errstr(status)));
2673 return false;
2676 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2677 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2678 if (!NT_STATUS_IS_OK(status)) {
2679 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2680 nt_errstr(status)));
2681 return false;
2684 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2685 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2686 get_global_sam_sid(), &domain_handle);
2687 if (!NT_STATUS_IS_OK(status)) {
2688 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2689 nt_errstr(status)));
2690 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2691 return false;
2694 errflags=NERR_Success;
2696 resume_handle = 0;
2698 while (true) {
2699 struct samr_SamArray *sam_entries;
2700 uint32_t num_entries;
2702 status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
2703 &domain_handle,
2704 &resume_handle,
2705 0, &sam_entries, 1,
2706 &num_entries);
2708 if (!NT_STATUS_IS_OK(status)) {
2709 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2710 "%s\n", nt_errstr(status)));
2711 break;
2714 if (num_entries == 0) {
2715 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2716 "no entries -- done\n"));
2717 break;
2720 for (i=0; i<num_entries; i++) {
2721 const char *name;
2723 name = sam_entries->entries[i].name.string;
2725 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2726 &&(strlen(name)<=21)) {
2727 strlcpy(p,name,PTR_DIFF(endp,p));
2728 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2729 "username %s\n",count_sent,p));
2730 p += 21;
2731 count_sent++;
2732 } else {
2733 /* set overflow error */
2734 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2735 "username %s\n",count_sent,name));
2736 errflags=234;
2737 break;
2741 if (errflags != NERR_Success) {
2742 break;
2745 TALLOC_FREE(sam_entries);
2748 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2749 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2751 *rdata_len = PTR_DIFF(p,*rdata);
2753 SSVAL(*rparam,0,errflags);
2754 SSVAL(*rparam,2,0); /* converter word */
2755 SSVAL(*rparam,4,count_sent); /* is this right?? */
2756 SSVAL(*rparam,6,num_users); /* is this right?? */
2758 return True;
2761 /****************************************************************************
2762 Get the time of day info.
2763 ****************************************************************************/
2765 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2766 char *param, int tpscnt,
2767 char *data, int tdscnt,
2768 int mdrcnt,int mprcnt,
2769 char **rdata,char **rparam,
2770 int *rdata_len,int *rparam_len)
2772 struct tm *t;
2773 time_t unixdate = time(NULL);
2774 char *p;
2776 *rparam_len = 4;
2777 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2778 if (!*rparam) {
2779 return False;
2782 *rdata_len = 21;
2783 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2784 if (!*rdata) {
2785 return False;
2788 SSVAL(*rparam,0,NERR_Success);
2789 SSVAL(*rparam,2,0); /* converter word */
2791 p = *rdata;
2793 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2794 by NT in a "net time" operation,
2795 it seems to ignore the one below */
2797 /* the client expects to get localtime, not GMT, in this bit
2798 (I think, this needs testing) */
2799 t = localtime(&unixdate);
2800 if (!t) {
2801 return False;
2804 SIVAL(p,4,0); /* msecs ? */
2805 SCVAL(p,8,t->tm_hour);
2806 SCVAL(p,9,t->tm_min);
2807 SCVAL(p,10,t->tm_sec);
2808 SCVAL(p,11,0); /* hundredths of seconds */
2809 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2810 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2811 SCVAL(p,16,t->tm_mday);
2812 SCVAL(p,17,t->tm_mon + 1);
2813 SSVAL(p,18,1900+t->tm_year);
2814 SCVAL(p,20,t->tm_wday);
2816 return True;
2819 /****************************************************************************
2820 Set the user password.
2821 *****************************************************************************/
2823 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2824 char *param, int tpscnt,
2825 char *data, int tdscnt,
2826 int mdrcnt,int mprcnt,
2827 char **rdata,char **rparam,
2828 int *rdata_len,int *rparam_len)
2830 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2831 char *p = NULL;
2832 fstring user;
2833 fstring pass1,pass2;
2835 /* Skip 2 strings. */
2836 p = skip_string(param,tpscnt,np);
2837 p = skip_string(param,tpscnt,p);
2839 if (!np || !p) {
2840 return False;
2843 /* Do we have a string ? */
2844 if (skip_string(param,tpscnt,p) == NULL) {
2845 return False;
2847 pull_ascii_fstring(user,p);
2849 p = skip_string(param,tpscnt,p);
2850 if (!p) {
2851 return False;
2854 memset(pass1,'\0',sizeof(pass1));
2855 memset(pass2,'\0',sizeof(pass2));
2857 * We use 31 here not 32 as we're checking
2858 * the last byte we want to access is safe.
2860 if (!is_offset_safe(param,tpscnt,p,31)) {
2861 return False;
2863 memcpy(pass1,p,16);
2864 memcpy(pass2,p+16,16);
2866 *rparam_len = 4;
2867 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2868 if (!*rparam) {
2869 return False;
2872 *rdata_len = 0;
2874 SSVAL(*rparam,0,NERR_badpass);
2875 SSVAL(*rparam,2,0); /* converter word */
2877 DEBUG(3,("Set password for <%s>\n",user));
2880 * Attempt to verify the old password against smbpasswd entries
2881 * Win98 clients send old and new password in plaintext for this call.
2885 struct auth_serversupplied_info *server_info = NULL;
2886 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2888 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2890 become_root();
2891 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2892 SSVAL(*rparam,0,NERR_Success);
2894 unbecome_root();
2896 TALLOC_FREE(server_info);
2898 data_blob_clear_free(&password);
2902 * If the plaintext change failed, attempt
2903 * the old encrypted method. NT will generate this
2904 * after trying the samr method. Note that this
2905 * method is done as a last resort as this
2906 * password change method loses the NT password hash
2907 * and cannot change the UNIX password as no plaintext
2908 * is received.
2911 if(SVAL(*rparam,0) != NERR_Success) {
2912 struct samu *hnd = NULL;
2914 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2915 become_root();
2916 if (change_lanman_password(hnd,(uchar *)pass2)) {
2917 SSVAL(*rparam,0,NERR_Success);
2919 unbecome_root();
2920 TALLOC_FREE(hnd);
2924 memset((char *)pass1,'\0',sizeof(fstring));
2925 memset((char *)pass2,'\0',sizeof(fstring));
2927 return(True);
2930 /****************************************************************************
2931 Set the user password (SamOEM version - gets plaintext).
2932 ****************************************************************************/
2934 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2935 char *param, int tpscnt,
2936 char *data, int tdscnt,
2937 int mdrcnt,int mprcnt,
2938 char **rdata,char **rparam,
2939 int *rdata_len,int *rparam_len)
2941 fstring user;
2942 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2944 TALLOC_CTX *mem_ctx = talloc_tos();
2945 NTSTATUS status;
2946 struct rpc_pipe_client *cli = NULL;
2947 struct lsa_AsciiString server, account;
2948 struct samr_CryptPassword password;
2949 struct samr_Password hash;
2950 int errcode = NERR_badpass;
2951 int bufsize;
2953 *rparam_len = 4;
2954 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2955 if (!*rparam) {
2956 return False;
2959 if (!p) {
2960 return False;
2962 *rdata_len = 0;
2964 SSVAL(*rparam,0,NERR_badpass);
2967 * Check the parameter definition is correct.
2970 /* Do we have a string ? */
2971 if (skip_string(param,tpscnt,p) == 0) {
2972 return False;
2974 if(!strequal(p, "zsT")) {
2975 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2976 return False;
2978 p = skip_string(param, tpscnt, p);
2979 if (!p) {
2980 return False;
2983 /* Do we have a string ? */
2984 if (skip_string(param,tpscnt,p) == 0) {
2985 return False;
2987 if(!strequal(p, "B516B16")) {
2988 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2989 return False;
2991 p = skip_string(param,tpscnt,p);
2992 if (!p) {
2993 return False;
2995 /* Do we have a string ? */
2996 if (skip_string(param,tpscnt,p) == 0) {
2997 return False;
2999 p += pull_ascii_fstring(user,p);
3001 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
3003 if (tdscnt != 532) {
3004 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3005 goto out;
3008 bufsize = get_safe_SVAL(param,tpscnt,p,0,-1);
3009 if (bufsize != 532) {
3010 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3011 goto out;
3014 memcpy(password.data, data, 516);
3015 memcpy(hash.hash, data+516, 16);
3017 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_samr.syntax_id,
3018 rpc_samr_dispatch, conn->server_info,
3019 &cli);
3020 if (!NT_STATUS_IS_OK(status)) {
3021 DEBUG(0,("api_SamOEMChangePassword: could not connect to samr: %s\n",
3022 nt_errstr(status)));
3023 errcode = W_ERROR_V(ntstatus_to_werror(status));
3024 goto out;
3027 init_lsa_AsciiString(&server, global_myname());
3028 init_lsa_AsciiString(&account, user);
3030 status = rpccli_samr_OemChangePasswordUser2(cli, mem_ctx,
3031 &server,
3032 &account,
3033 &password,
3034 &hash);
3035 if (!NT_STATUS_IS_OK(status)) {
3036 errcode = W_ERROR_V(ntstatus_to_werror(status));
3037 goto out;
3040 errcode = NERR_Success;
3041 out:
3042 SSVAL(*rparam,0,errcode);
3043 SSVAL(*rparam,2,0); /* converter word */
3045 return(True);
3048 /****************************************************************************
3049 delete a print job
3050 Form: <W> <>
3051 ****************************************************************************/
3053 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
3054 char *param, int tpscnt,
3055 char *data, int tdscnt,
3056 int mdrcnt,int mprcnt,
3057 char **rdata,char **rparam,
3058 int *rdata_len,int *rparam_len)
3060 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3061 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3062 char *str2 = skip_string(param,tpscnt,str1);
3063 char *p = skip_string(param,tpscnt,str2);
3064 uint32 jobid;
3065 fstring sharename;
3066 int errcode;
3067 WERROR werr = WERR_OK;
3069 TALLOC_CTX *mem_ctx = talloc_tos();
3070 NTSTATUS status;
3071 struct rpc_pipe_client *cli = NULL;
3072 struct policy_handle handle;
3073 struct spoolss_DevmodeContainer devmode_ctr;
3074 enum spoolss_JobControl command;
3076 if (!str1 || !str2 || !p) {
3077 return False;
3080 * We use 1 here not 2 as we're checking
3081 * the last byte we want to access is safe.
3083 if (!is_offset_safe(param,tpscnt,p,1)) {
3084 return False;
3086 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3087 return False;
3089 /* check it's a supported varient */
3090 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
3091 return(False);
3093 *rparam_len = 4;
3094 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3095 if (!*rparam) {
3096 return False;
3098 *rdata_len = 0;
3100 ZERO_STRUCT(handle);
3102 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3103 rpc_spoolss_dispatch, conn->server_info,
3104 &cli);
3105 if (!NT_STATUS_IS_OK(status)) {
3106 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
3107 nt_errstr(status)));
3108 errcode = W_ERROR_V(ntstatus_to_werror(status));
3109 goto out;
3112 ZERO_STRUCT(devmode_ctr);
3114 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3115 sharename,
3116 "RAW",
3117 devmode_ctr,
3118 JOB_ACCESS_ADMINISTER,
3119 &handle,
3120 &werr);
3121 if (!NT_STATUS_IS_OK(status)) {
3122 errcode = W_ERROR_V(ntstatus_to_werror(status));
3123 goto out;
3125 if (!W_ERROR_IS_OK(werr)) {
3126 errcode = W_ERROR_V(werr);
3127 goto out;
3130 /* FIXME: formerly NERR_JobNotFound was returned if job did not exist
3131 * and NERR_DestNotFound if share did not exist */
3133 errcode = NERR_Success;
3135 switch (function) {
3136 case 81: /* delete */
3137 command = SPOOLSS_JOB_CONTROL_DELETE;
3138 break;
3139 case 82: /* pause */
3140 command = SPOOLSS_JOB_CONTROL_PAUSE;
3141 break;
3142 case 83: /* resume */
3143 command = SPOOLSS_JOB_CONTROL_RESUME;
3144 break;
3145 default:
3146 errcode = NERR_notsupported;
3147 goto out;
3150 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3151 &handle,
3152 jobid,
3153 NULL, /* unique ptr ctr */
3154 command,
3155 &werr);
3156 if (!NT_STATUS_IS_OK(status)) {
3157 errcode = W_ERROR_V(ntstatus_to_werror(status));
3158 goto out;
3160 if (!W_ERROR_IS_OK(werr)) {
3161 errcode = W_ERROR_V(werr);
3162 goto out;
3165 out:
3166 if (cli && is_valid_policy_hnd(&handle)) {
3167 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3170 SSVAL(*rparam,0,errcode);
3171 SSVAL(*rparam,2,0); /* converter word */
3173 return(True);
3176 /****************************************************************************
3177 Purge a print queue - or pause or resume it.
3178 ****************************************************************************/
3180 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
3181 char *param, int tpscnt,
3182 char *data, int tdscnt,
3183 int mdrcnt,int mprcnt,
3184 char **rdata,char **rparam,
3185 int *rdata_len,int *rparam_len)
3187 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3188 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3189 char *str2 = skip_string(param,tpscnt,str1);
3190 char *QueueName = skip_string(param,tpscnt,str2);
3191 int errcode = NERR_notsupported;
3192 WERROR werr = WERR_OK;
3193 NTSTATUS status;
3195 TALLOC_CTX *mem_ctx = talloc_tos();
3196 struct rpc_pipe_client *cli = NULL;
3197 struct policy_handle handle;
3198 struct spoolss_SetPrinterInfoCtr info_ctr;
3199 struct spoolss_DevmodeContainer devmode_ctr;
3200 struct sec_desc_buf secdesc_ctr;
3201 enum spoolss_PrinterControl command;
3203 if (!str1 || !str2 || !QueueName) {
3204 return False;
3207 /* check it's a supported varient */
3208 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3209 return(False);
3211 *rparam_len = 4;
3212 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3213 if (!*rparam) {
3214 return False;
3216 *rdata_len = 0;
3218 if (skip_string(param,tpscnt,QueueName) == NULL) {
3219 return False;
3222 ZERO_STRUCT(handle);
3224 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3225 rpc_spoolss_dispatch, conn->server_info,
3226 &cli);
3227 if (!NT_STATUS_IS_OK(status)) {
3228 DEBUG(0,("api_WPrintQueueCtrl: could not connect to spoolss: %s\n",
3229 nt_errstr(status)));
3230 errcode = W_ERROR_V(ntstatus_to_werror(status));
3231 goto out;
3234 ZERO_STRUCT(devmode_ctr);
3236 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3237 QueueName,
3238 NULL,
3239 devmode_ctr,
3240 SEC_FLAG_MAXIMUM_ALLOWED,
3241 &handle,
3242 &werr);
3243 if (!NT_STATUS_IS_OK(status)) {
3244 errcode = W_ERROR_V(ntstatus_to_werror(status));
3245 goto out;
3247 if (!W_ERROR_IS_OK(werr)) {
3248 errcode = W_ERROR_V(werr);
3249 goto out;
3252 switch (function) {
3253 case 74: /* Pause queue */
3254 command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3255 break;
3256 case 75: /* Resume queue */
3257 command = SPOOLSS_PRINTER_CONTROL_RESUME;
3258 break;
3259 case 103: /* Purge */
3260 command = SPOOLSS_PRINTER_CONTROL_PURGE;
3261 break;
3262 default:
3263 werr = WERR_NOT_SUPPORTED;
3264 break;
3267 if (!W_ERROR_IS_OK(werr)) {
3268 errcode = W_ERROR_V(werr);
3269 goto out;
3272 ZERO_STRUCT(info_ctr);
3273 ZERO_STRUCT(secdesc_ctr);
3275 status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
3276 &handle,
3277 &info_ctr,
3278 &devmode_ctr,
3279 &secdesc_ctr,
3280 command,
3281 &werr);
3282 if (!NT_STATUS_IS_OK(status)) {
3283 errcode = W_ERROR_V(ntstatus_to_werror(status));
3284 goto out;
3286 if (!W_ERROR_IS_OK(werr)) {
3287 errcode = W_ERROR_V(werr);
3288 goto out;
3291 errcode = W_ERROR_V(werr);
3293 out:
3295 if (cli && is_valid_policy_hnd(&handle)) {
3296 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3299 SSVAL(*rparam,0,errcode);
3300 SSVAL(*rparam,2,0); /* converter word */
3302 return(True);
3305 /****************************************************************************
3306 set the property of a print job (undocumented?)
3307 ? function = 0xb -> set name of print job
3308 ? function = 0x6 -> move print job up/down
3309 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3310 or <WWsTP> <WB21BB16B10zWWzDDz>
3311 ****************************************************************************/
3313 static int check_printjob_info(struct pack_desc* desc,
3314 int uLevel, char* id)
3316 desc->subformat = NULL;
3317 switch( uLevel ) {
3318 case 0: desc->format = "W"; break;
3319 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3320 case 2: desc->format = "WWzWWDDzz"; break;
3321 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3322 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3323 default:
3324 DEBUG(0,("check_printjob_info: invalid level %d\n",
3325 uLevel ));
3326 return False;
3328 if (id == NULL || strcmp(desc->format,id) != 0) {
3329 DEBUG(0,("check_printjob_info: invalid format %s\n",
3330 id ? id : "<NULL>" ));
3331 return False;
3333 return True;
3336 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
3337 char *param, int tpscnt,
3338 char *data, int tdscnt,
3339 int mdrcnt,int mprcnt,
3340 char **rdata,char **rparam,
3341 int *rdata_len,int *rparam_len)
3343 struct pack_desc desc;
3344 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3345 char *str2 = skip_string(param,tpscnt,str1);
3346 char *p = skip_string(param,tpscnt,str2);
3347 uint32 jobid;
3348 fstring sharename;
3349 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3350 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3351 int errcode;
3353 TALLOC_CTX *mem_ctx = talloc_tos();
3354 WERROR werr;
3355 NTSTATUS status;
3356 struct rpc_pipe_client *cli = NULL;
3357 struct policy_handle handle;
3358 struct spoolss_DevmodeContainer devmode_ctr;
3359 struct spoolss_JobInfoContainer ctr;
3360 union spoolss_JobInfo info;
3361 struct spoolss_SetJobInfo1 info1;
3363 if (!str1 || !str2 || !p) {
3364 return False;
3367 * We use 1 here not 2 as we're checking
3368 * the last byte we want to access is safe.
3370 if (!is_offset_safe(param,tpscnt,p,1)) {
3371 return False;
3373 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3374 return False;
3375 *rparam_len = 4;
3376 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3377 if (!*rparam) {
3378 return False;
3381 *rdata_len = 0;
3383 /* check it's a supported varient */
3384 if ((strcmp(str1,"WWsTP")) ||
3385 (!check_printjob_info(&desc,uLevel,str2)))
3386 return(False);
3388 errcode = NERR_notsupported;
3390 switch (function) {
3391 case 0xb:
3392 /* change print job name, data gives the name */
3393 break;
3394 default:
3395 goto out;
3398 ZERO_STRUCT(handle);
3400 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3401 rpc_spoolss_dispatch, conn->server_info,
3402 &cli);
3403 if (!NT_STATUS_IS_OK(status)) {
3404 DEBUG(0,("api_PrintJobInfo: could not connect to spoolss: %s\n",
3405 nt_errstr(status)));
3406 errcode = W_ERROR_V(ntstatus_to_werror(status));
3407 goto out;
3410 ZERO_STRUCT(devmode_ctr);
3412 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3413 sharename,
3414 "RAW",
3415 devmode_ctr,
3416 PRINTER_ACCESS_USE,
3417 &handle,
3418 &werr);
3419 if (!NT_STATUS_IS_OK(status)) {
3420 errcode = W_ERROR_V(ntstatus_to_werror(status));
3421 goto out;
3423 if (!W_ERROR_IS_OK(werr)) {
3424 errcode = W_ERROR_V(werr);
3425 goto out;
3428 werr = rpccli_spoolss_getjob(cli, mem_ctx,
3429 &handle,
3430 jobid,
3431 1, /* level */
3432 0, /* offered */
3433 &info);
3434 if (!W_ERROR_IS_OK(werr)) {
3435 errcode = W_ERROR_V(werr);
3436 goto out;
3439 ZERO_STRUCT(ctr);
3441 info1.job_id = info.info1.job_id;
3442 info1.printer_name = info.info1.printer_name;
3443 info1.user_name = info.info1.user_name;
3444 info1.document_name = data;
3445 info1.data_type = info.info1.data_type;
3446 info1.text_status = info.info1.text_status;
3447 info1.status = info.info1.status;
3448 info1.priority = info.info1.priority;
3449 info1.position = info.info1.position;
3450 info1.total_pages = info.info1.total_pages;
3451 info1.pages_printed = info.info1.pages_printed;
3452 info1.submitted = info.info1.submitted;
3454 ctr.level = 1;
3455 ctr.info.info1 = &info1;
3457 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3458 &handle,
3459 jobid,
3460 &ctr,
3462 &werr);
3463 if (!NT_STATUS_IS_OK(status)) {
3464 errcode = W_ERROR_V(ntstatus_to_werror(status));
3465 goto out;
3467 if (!W_ERROR_IS_OK(werr)) {
3468 errcode = W_ERROR_V(werr);
3469 goto out;
3472 errcode = NERR_Success;
3473 out:
3475 if (cli && is_valid_policy_hnd(&handle)) {
3476 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3479 SSVALS(*rparam,0,errcode);
3480 SSVAL(*rparam,2,0); /* converter word */
3482 return(True);
3486 /****************************************************************************
3487 Get info about the server.
3488 ****************************************************************************/
3490 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
3491 char *param, int tpscnt,
3492 char *data, int tdscnt,
3493 int mdrcnt,int mprcnt,
3494 char **rdata,char **rparam,
3495 int *rdata_len,int *rparam_len)
3497 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3498 char *str2 = skip_string(param,tpscnt,str1);
3499 char *p = skip_string(param,tpscnt,str2);
3500 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3501 char *p2;
3502 int struct_len;
3504 NTSTATUS status;
3505 WERROR werr;
3506 TALLOC_CTX *mem_ctx = talloc_tos();
3507 struct rpc_pipe_client *cli = NULL;
3508 union srvsvc_NetSrvInfo info;
3509 int errcode;
3511 if (!str1 || !str2 || !p) {
3512 return False;
3515 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3517 /* check it's a supported varient */
3518 if (!prefix_ok(str1,"WrLh")) {
3519 return False;
3522 switch( uLevel ) {
3523 case 0:
3524 if (strcmp(str2,"B16") != 0) {
3525 return False;
3527 struct_len = 16;
3528 break;
3529 case 1:
3530 if (strcmp(str2,"B16BBDz") != 0) {
3531 return False;
3533 struct_len = 26;
3534 break;
3535 case 2:
3536 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3537 return False;
3539 struct_len = 134;
3540 break;
3541 case 3:
3542 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3543 return False;
3545 struct_len = 144;
3546 break;
3547 case 20:
3548 if (strcmp(str2,"DN") != 0) {
3549 return False;
3551 struct_len = 6;
3552 break;
3553 case 50:
3554 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3555 return False;
3557 struct_len = 42;
3558 break;
3559 default:
3560 return False;
3563 *rdata_len = mdrcnt;
3564 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3565 if (!*rdata) {
3566 return False;
3569 p = *rdata;
3570 p2 = p + struct_len;
3572 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_srvsvc.syntax_id,
3573 rpc_srvsvc_dispatch, conn->server_info,
3574 &cli);
3575 if (!NT_STATUS_IS_OK(status)) {
3576 DEBUG(0,("api_RNetServerGetInfo: could not connect to srvsvc: %s\n",
3577 nt_errstr(status)));
3578 errcode = W_ERROR_V(ntstatus_to_werror(status));
3579 goto out;
3582 status = rpccli_srvsvc_NetSrvGetInfo(cli, mem_ctx,
3583 NULL,
3584 101,
3585 &info,
3586 &werr);
3587 if (!NT_STATUS_IS_OK(status)) {
3588 errcode = W_ERROR_V(ntstatus_to_werror(status));
3589 goto out;
3591 if (!W_ERROR_IS_OK(werr)) {
3592 errcode = W_ERROR_V(werr);
3593 goto out;
3596 if (info.info101 == NULL) {
3597 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3598 goto out;
3601 if (uLevel != 20) {
3602 srvstr_push(NULL, 0, p, info.info101->server_name, 16,
3603 STR_ASCII|STR_UPPER|STR_TERMINATE);
3605 p += 16;
3606 if (uLevel > 0) {
3607 SCVAL(p,0,info.info101->version_major);
3608 SCVAL(p,1,info.info101->version_minor);
3609 SIVAL(p,2,info.info101->server_type);
3611 if (mdrcnt == struct_len) {
3612 SIVAL(p,6,0);
3613 } else {
3614 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3615 if (mdrcnt - struct_len <= 0) {
3616 return false;
3618 push_ascii(p2,
3619 info.info101->comment,
3620 MIN(mdrcnt - struct_len,
3621 MAX_SERVER_STRING_LENGTH),
3622 STR_TERMINATE);
3623 p2 = skip_string(*rdata,*rdata_len,p2);
3624 if (!p2) {
3625 return False;
3630 if (uLevel > 1) {
3631 return False; /* not yet implemented */
3634 errcode = NERR_Success;
3636 out:
3638 *rdata_len = PTR_DIFF(p2,*rdata);
3640 *rparam_len = 6;
3641 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3642 if (!*rparam) {
3643 return False;
3645 SSVAL(*rparam,0,errcode);
3646 SSVAL(*rparam,2,0); /* converter word */
3647 SSVAL(*rparam,4,*rdata_len);
3649 return True;
3652 /****************************************************************************
3653 Get info about the server.
3654 ****************************************************************************/
3656 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3657 char *param, int tpscnt,
3658 char *data, int tdscnt,
3659 int mdrcnt,int mprcnt,
3660 char **rdata,char **rparam,
3661 int *rdata_len,int *rparam_len)
3663 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3664 char *str2 = skip_string(param,tpscnt,str1);
3665 char *p = skip_string(param,tpscnt,str2);
3666 char *p2;
3667 char *endp;
3668 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3670 if (!str1 || !str2 || !p) {
3671 return False;
3674 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3676 *rparam_len = 6;
3677 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3678 if (!*rparam) {
3679 return False;
3682 /* check it's a supported varient */
3683 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3684 return False;
3687 *rdata_len = mdrcnt + 1024;
3688 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3689 if (!*rdata) {
3690 return False;
3693 SSVAL(*rparam,0,NERR_Success);
3694 SSVAL(*rparam,2,0); /* converter word */
3696 p = *rdata;
3697 endp = *rdata + *rdata_len;
3699 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3700 if (!p2) {
3701 return False;
3704 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3705 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3706 strupper_m(p2);
3707 p2 = skip_string(*rdata,*rdata_len,p2);
3708 if (!p2) {
3709 return False;
3711 p += 4;
3713 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3714 strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3715 p2 = skip_string(*rdata,*rdata_len,p2);
3716 if (!p2) {
3717 return False;
3719 p += 4;
3721 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3722 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3723 strupper_m(p2);
3724 p2 = skip_string(*rdata,*rdata_len,p2);
3725 if (!p2) {
3726 return False;
3728 p += 4;
3730 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3731 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3732 p += 2;
3734 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3735 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3736 p2 = skip_string(*rdata,*rdata_len,p2);
3737 if (!p2) {
3738 return False;
3740 p += 4;
3742 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3743 strlcpy(p2,"",PTR_DIFF(endp,p2));
3744 p2 = skip_string(*rdata,*rdata_len,p2);
3745 if (!p2) {
3746 return False;
3748 p += 4;
3750 *rdata_len = PTR_DIFF(p2,*rdata);
3752 SSVAL(*rparam,4,*rdata_len);
3754 return True;
3757 /****************************************************************************
3758 get info about a user
3760 struct user_info_11 {
3761 char usri11_name[21]; 0-20
3762 char usri11_pad; 21
3763 char *usri11_comment; 22-25
3764 char *usri11_usr_comment; 26-29
3765 unsigned short usri11_priv; 30-31
3766 unsigned long usri11_auth_flags; 32-35
3767 long usri11_password_age; 36-39
3768 char *usri11_homedir; 40-43
3769 char *usri11_parms; 44-47
3770 long usri11_last_logon; 48-51
3771 long usri11_last_logoff; 52-55
3772 unsigned short usri11_bad_pw_count; 56-57
3773 unsigned short usri11_num_logons; 58-59
3774 char *usri11_logon_server; 60-63
3775 unsigned short usri11_country_code; 64-65
3776 char *usri11_workstations; 66-69
3777 unsigned long usri11_max_storage; 70-73
3778 unsigned short usri11_units_per_week; 74-75
3779 unsigned char *usri11_logon_hours; 76-79
3780 unsigned short usri11_code_page; 80-81
3783 where:
3785 usri11_name specifies the user name for which information is retrieved
3787 usri11_pad aligns the next data structure element to a word boundary
3789 usri11_comment is a null terminated ASCII comment
3791 usri11_user_comment is a null terminated ASCII comment about the user
3793 usri11_priv specifies the level of the privilege assigned to the user.
3794 The possible values are:
3796 Name Value Description
3797 USER_PRIV_GUEST 0 Guest privilege
3798 USER_PRIV_USER 1 User privilege
3799 USER_PRV_ADMIN 2 Administrator privilege
3801 usri11_auth_flags specifies the account operator privileges. The
3802 possible values are:
3804 Name Value Description
3805 AF_OP_PRINT 0 Print operator
3808 Leach, Naik [Page 28]
3812 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3815 AF_OP_COMM 1 Communications operator
3816 AF_OP_SERVER 2 Server operator
3817 AF_OP_ACCOUNTS 3 Accounts operator
3820 usri11_password_age specifies how many seconds have elapsed since the
3821 password was last changed.
3823 usri11_home_dir points to a null terminated ASCII string that contains
3824 the path name of the user's home directory.
3826 usri11_parms points to a null terminated ASCII string that is set
3827 aside for use by applications.
3829 usri11_last_logon specifies the time when the user last logged on.
3830 This value is stored as the number of seconds elapsed since
3831 00:00:00, January 1, 1970.
3833 usri11_last_logoff specifies the time when the user last logged off.
3834 This value is stored as the number of seconds elapsed since
3835 00:00:00, January 1, 1970. A value of 0 means the last logoff
3836 time is unknown.
3838 usri11_bad_pw_count specifies the number of incorrect passwords
3839 entered since the last successful logon.
3841 usri11_log1_num_logons specifies the number of times this user has
3842 logged on. A value of -1 means the number of logons is unknown.
3844 usri11_logon_server points to a null terminated ASCII string that
3845 contains the name of the server to which logon requests are sent.
3846 A null string indicates logon requests should be sent to the
3847 domain controller.
3849 usri11_country_code specifies the country code for the user's language
3850 of choice.
3852 usri11_workstations points to a null terminated ASCII string that
3853 contains the names of workstations the user may log on from.
3854 There may be up to 8 workstations, with the names separated by
3855 commas. A null strings indicates there are no restrictions.
3857 usri11_max_storage specifies the maximum amount of disk space the user
3858 can occupy. A value of 0xffffffff indicates there are no
3859 restrictions.
3861 usri11_units_per_week specifies the equal number of time units into
3862 which a week is divided. This value must be equal to 168.
3864 usri11_logon_hours points to a 21 byte (168 bits) string that
3865 specifies the time during which the user can log on. Each bit
3866 represents one unique hour in a week. The first bit (bit 0, word
3867 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3871 Leach, Naik [Page 29]
3875 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3878 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3879 are no restrictions.
3881 usri11_code_page specifies the code page for the user's language of
3882 choice
3884 All of the pointers in this data structure need to be treated
3885 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3886 to be ignored. The converter word returned in the parameters section
3887 needs to be subtracted from the lower 16 bits to calculate an offset
3888 into the return buffer where this ASCII string resides.
3890 There is no auxiliary data in the response.
3892 ****************************************************************************/
3894 #define usri11_name 0
3895 #define usri11_pad 21
3896 #define usri11_comment 22
3897 #define usri11_usr_comment 26
3898 #define usri11_full_name 30
3899 #define usri11_priv 34
3900 #define usri11_auth_flags 36
3901 #define usri11_password_age 40
3902 #define usri11_homedir 44
3903 #define usri11_parms 48
3904 #define usri11_last_logon 52
3905 #define usri11_last_logoff 56
3906 #define usri11_bad_pw_count 60
3907 #define usri11_num_logons 62
3908 #define usri11_logon_server 64
3909 #define usri11_country_code 68
3910 #define usri11_workstations 70
3911 #define usri11_max_storage 74
3912 #define usri11_units_per_week 78
3913 #define usri11_logon_hours 80
3914 #define usri11_code_page 84
3915 #define usri11_end 86
3917 #define USER_PRIV_GUEST 0
3918 #define USER_PRIV_USER 1
3919 #define USER_PRIV_ADMIN 2
3921 #define AF_OP_PRINT 0
3922 #define AF_OP_COMM 1
3923 #define AF_OP_SERVER 2
3924 #define AF_OP_ACCOUNTS 3
3927 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3928 char *param, int tpscnt,
3929 char *data, int tdscnt,
3930 int mdrcnt,int mprcnt,
3931 char **rdata,char **rparam,
3932 int *rdata_len,int *rparam_len)
3934 struct smbd_server_connection *sconn = smbd_server_conn;
3935 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3936 char *str2 = skip_string(param,tpscnt,str1);
3937 char *UserName = skip_string(param,tpscnt,str2);
3938 char *p = skip_string(param,tpscnt,UserName);
3939 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3940 char *p2;
3941 char *endp;
3942 const char *level_string;
3944 /* get NIS home of a previously validated user - simeon */
3945 /* With share level security vuid will always be zero.
3946 Don't depend on vuser being non-null !!. JRA */
3947 user_struct *vuser = get_valid_user_struct(sconn, vuid);
3948 if(vuser != NULL) {
3949 DEBUG(3,(" Username of UID %d is %s\n",
3950 (int)vuser->server_info->utok.uid,
3951 vuser->server_info->unix_name));
3954 if (!str1 || !str2 || !UserName || !p) {
3955 return False;
3958 *rparam_len = 6;
3959 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3960 if (!*rparam) {
3961 return False;
3964 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3966 /* check it's a supported variant */
3967 if (strcmp(str1,"zWrLh") != 0) {
3968 return False;
3970 switch( uLevel ) {
3971 case 0: level_string = "B21"; break;
3972 case 1: level_string = "B21BB16DWzzWz"; break;
3973 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3974 case 10: level_string = "B21Bzzz"; break;
3975 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3976 default: return False;
3979 if (strcmp(level_string,str2) != 0) {
3980 return False;
3983 *rdata_len = mdrcnt + 1024;
3984 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3985 if (!*rdata) {
3986 return False;
3989 SSVAL(*rparam,0,NERR_Success);
3990 SSVAL(*rparam,2,0); /* converter word */
3992 p = *rdata;
3993 endp = *rdata + *rdata_len;
3994 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3995 if (!p2) {
3996 return False;
3999 memset(p,0,21);
4000 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
4002 if (uLevel > 0) {
4003 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
4004 *p2 = 0;
4007 if (uLevel >= 10) {
4008 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
4009 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
4010 p2 = skip_string(*rdata,*rdata_len,p2);
4011 if (!p2) {
4012 return False;
4015 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
4016 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
4017 p2 = skip_string(*rdata,*rdata_len,p2);
4018 if (!p2) {
4019 return False;
4022 /* EEK! the cifsrap.txt doesn't have this in!!!! */
4023 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
4024 strlcpy(p2,((vuser != NULL)
4025 ? pdb_get_fullname(vuser->server_info->sam_account)
4026 : UserName),PTR_DIFF(endp,p2));
4027 p2 = skip_string(*rdata,*rdata_len,p2);
4028 if (!p2) {
4029 return False;
4033 if (uLevel == 11) {
4034 const char *homedir = "";
4035 if (vuser != NULL) {
4036 homedir = pdb_get_homedir(
4037 vuser->server_info->sam_account);
4039 /* modelled after NTAS 3.51 reply */
4040 SSVAL(p,usri11_priv,
4041 (get_current_uid(conn) == sec_initial_uid())?
4042 USER_PRIV_ADMIN:USER_PRIV_USER);
4043 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
4044 SIVALS(p,usri11_password_age,-1); /* password age */
4045 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
4046 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
4047 p2 = skip_string(*rdata,*rdata_len,p2);
4048 if (!p2) {
4049 return False;
4051 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
4052 strlcpy(p2,"",PTR_DIFF(endp,p2));
4053 p2 = skip_string(*rdata,*rdata_len,p2);
4054 if (!p2) {
4055 return False;
4057 SIVAL(p,usri11_last_logon,0); /* last logon */
4058 SIVAL(p,usri11_last_logoff,0); /* last logoff */
4059 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
4060 SSVALS(p,usri11_num_logons,-1); /* num logons */
4061 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
4062 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
4063 p2 = skip_string(*rdata,*rdata_len,p2);
4064 if (!p2) {
4065 return False;
4067 SSVAL(p,usri11_country_code,0); /* country code */
4069 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
4070 strlcpy(p2,"",PTR_DIFF(endp,p2));
4071 p2 = skip_string(*rdata,*rdata_len,p2);
4072 if (!p2) {
4073 return False;
4076 SIVALS(p,usri11_max_storage,-1); /* max storage */
4077 SSVAL(p,usri11_units_per_week,168); /* units per week */
4078 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
4080 /* a simple way to get logon hours at all times. */
4081 memset(p2,0xff,21);
4082 SCVAL(p2,21,0); /* fix zero termination */
4083 p2 = skip_string(*rdata,*rdata_len,p2);
4084 if (!p2) {
4085 return False;
4088 SSVAL(p,usri11_code_page,0); /* code page */
4091 if (uLevel == 1 || uLevel == 2) {
4092 memset(p+22,' ',16); /* password */
4093 SIVALS(p,38,-1); /* password age */
4094 SSVAL(p,42,
4095 (get_current_uid(conn) == sec_initial_uid())?
4096 USER_PRIV_ADMIN:USER_PRIV_USER);
4097 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
4098 strlcpy(p2, vuser ? pdb_get_homedir(
4099 vuser->server_info->sam_account) : "",
4100 PTR_DIFF(endp,p2));
4101 p2 = skip_string(*rdata,*rdata_len,p2);
4102 if (!p2) {
4103 return False;
4105 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
4106 *p2++ = 0;
4107 SSVAL(p,52,0); /* flags */
4108 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
4109 strlcpy(p2, vuser ? pdb_get_logon_script(
4110 vuser->server_info->sam_account) : "",
4111 PTR_DIFF(endp,p2));
4112 p2 = skip_string(*rdata,*rdata_len,p2);
4113 if (!p2) {
4114 return False;
4116 if (uLevel == 2) {
4117 SIVAL(p,60,0); /* auth_flags */
4118 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
4119 strlcpy(p2,((vuser != NULL)
4120 ? pdb_get_fullname(vuser->server_info->sam_account)
4121 : UserName),PTR_DIFF(endp,p2));
4122 p2 = skip_string(*rdata,*rdata_len,p2);
4123 if (!p2) {
4124 return False;
4126 SIVAL(p,68,0); /* urs_comment */
4127 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
4128 strlcpy(p2,"",PTR_DIFF(endp,p2));
4129 p2 = skip_string(*rdata,*rdata_len,p2);
4130 if (!p2) {
4131 return False;
4133 SIVAL(p,76,0); /* workstations */
4134 SIVAL(p,80,0); /* last_logon */
4135 SIVAL(p,84,0); /* last_logoff */
4136 SIVALS(p,88,-1); /* acct_expires */
4137 SIVALS(p,92,-1); /* max_storage */
4138 SSVAL(p,96,168); /* units_per_week */
4139 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
4140 memset(p2,-1,21);
4141 p2 += 21;
4142 SSVALS(p,102,-1); /* bad_pw_count */
4143 SSVALS(p,104,-1); /* num_logons */
4144 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
4146 TALLOC_CTX *ctx = talloc_tos();
4147 int space_rem = *rdata_len - (p2 - *rdata);
4148 char *tmp;
4150 if (space_rem <= 0) {
4151 return false;
4153 tmp = talloc_strdup(ctx, "\\\\%L");
4154 if (!tmp) {
4155 return false;
4157 tmp = talloc_sub_basic(ctx,
4160 tmp);
4161 if (!tmp) {
4162 return false;
4165 push_ascii(p2,
4166 tmp,
4167 space_rem,
4168 STR_TERMINATE);
4170 p2 = skip_string(*rdata,*rdata_len,p2);
4171 if (!p2) {
4172 return False;
4174 SSVAL(p,110,49); /* country_code */
4175 SSVAL(p,112,860); /* code page */
4179 *rdata_len = PTR_DIFF(p2,*rdata);
4181 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
4183 return(True);
4186 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
4187 char *param, int tpscnt,
4188 char *data, int tdscnt,
4189 int mdrcnt,int mprcnt,
4190 char **rdata,char **rparam,
4191 int *rdata_len,int *rparam_len)
4193 struct smbd_server_connection *sconn = smbd_server_conn;
4194 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4195 char *str2 = skip_string(param,tpscnt,str1);
4196 char *p = skip_string(param,tpscnt,str2);
4197 int uLevel;
4198 struct pack_desc desc;
4199 char* name;
4200 /* With share level security vuid will always be zero.
4201 Don't depend on vuser being non-null !!. JRA */
4202 user_struct *vuser = get_valid_user_struct(sconn, vuid);
4204 if (!str1 || !str2 || !p) {
4205 return False;
4208 if(vuser != NULL) {
4209 DEBUG(3,(" Username of UID %d is %s\n",
4210 (int)vuser->server_info->utok.uid,
4211 vuser->server_info->unix_name));
4214 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4215 name = get_safe_str_ptr(param,tpscnt,p,2);
4216 if (!name) {
4217 return False;
4220 memset((char *)&desc,'\0',sizeof(desc));
4222 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
4224 /* check it's a supported varient */
4225 if (strcmp(str1,"OOWb54WrLh") != 0) {
4226 return False;
4228 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
4229 return False;
4231 if (mdrcnt > 0) {
4232 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4233 if (!*rdata) {
4234 return False;
4238 desc.base = *rdata;
4239 desc.buflen = mdrcnt;
4240 desc.subformat = NULL;
4241 desc.format = str2;
4243 if (init_package(&desc,1,0)) {
4244 PACKI(&desc,"W",0); /* code */
4245 PACKS(&desc,"B21",name); /* eff. name */
4246 PACKS(&desc,"B",""); /* pad */
4247 PACKI(&desc,"W",
4248 (get_current_uid(conn) == sec_initial_uid())?
4249 USER_PRIV_ADMIN:USER_PRIV_USER);
4250 PACKI(&desc,"D",0); /* auth flags XXX */
4251 PACKI(&desc,"W",0); /* num logons */
4252 PACKI(&desc,"W",0); /* bad pw count */
4253 PACKI(&desc,"D",0); /* last logon */
4254 PACKI(&desc,"D",-1); /* last logoff */
4255 PACKI(&desc,"D",-1); /* logoff time */
4256 PACKI(&desc,"D",-1); /* kickoff time */
4257 PACKI(&desc,"D",0); /* password age */
4258 PACKI(&desc,"D",0); /* password can change */
4259 PACKI(&desc,"D",-1); /* password must change */
4262 fstring mypath;
4263 fstrcpy(mypath,"\\\\");
4264 fstrcat(mypath,get_local_machine_name());
4265 strupper_m(mypath);
4266 PACKS(&desc,"z",mypath); /* computer */
4269 PACKS(&desc,"z",lp_workgroup());/* domain */
4270 PACKS(&desc,"z", vuser ? pdb_get_logon_script(
4271 vuser->server_info->sam_account) : ""); /* script path */
4272 PACKI(&desc,"D",0x00000000); /* reserved */
4275 *rdata_len = desc.usedlen;
4276 *rparam_len = 6;
4277 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4278 if (!*rparam) {
4279 return False;
4281 SSVALS(*rparam,0,desc.errcode);
4282 SSVAL(*rparam,2,0);
4283 SSVAL(*rparam,4,desc.neededlen);
4285 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4287 return True;
4290 /****************************************************************************
4291 api_WAccessGetUserPerms
4292 ****************************************************************************/
4294 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
4295 char *param, int tpscnt,
4296 char *data, int tdscnt,
4297 int mdrcnt,int mprcnt,
4298 char **rdata,char **rparam,
4299 int *rdata_len,int *rparam_len)
4301 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4302 char *str2 = skip_string(param,tpscnt,str1);
4303 char *user = skip_string(param,tpscnt,str2);
4304 char *resource = skip_string(param,tpscnt,user);
4306 if (!str1 || !str2 || !user || !resource) {
4307 return False;
4310 if (skip_string(param,tpscnt,resource) == NULL) {
4311 return False;
4313 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4315 /* check it's a supported varient */
4316 if (strcmp(str1,"zzh") != 0) {
4317 return False;
4319 if (strcmp(str2,"") != 0) {
4320 return False;
4323 *rparam_len = 6;
4324 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4325 if (!*rparam) {
4326 return False;
4328 SSVALS(*rparam,0,0); /* errorcode */
4329 SSVAL(*rparam,2,0); /* converter word */
4330 SSVAL(*rparam,4,0x7f); /* permission flags */
4332 return True;
4335 /****************************************************************************
4336 api_WPrintJobEnumerate
4337 ****************************************************************************/
4339 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
4340 char *param, int tpscnt,
4341 char *data, int tdscnt,
4342 int mdrcnt,int mprcnt,
4343 char **rdata,char **rparam,
4344 int *rdata_len,int *rparam_len)
4346 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4347 char *str2 = skip_string(param,tpscnt,str1);
4348 char *p = skip_string(param,tpscnt,str2);
4349 int uLevel;
4350 fstring sharename;
4351 uint32 jobid;
4352 struct pack_desc desc;
4353 char *tmpdata=NULL;
4355 TALLOC_CTX *mem_ctx = talloc_tos();
4356 WERROR werr;
4357 NTSTATUS status;
4358 struct rpc_pipe_client *cli = NULL;
4359 struct policy_handle handle;
4360 struct spoolss_DevmodeContainer devmode_ctr;
4361 union spoolss_JobInfo info;
4363 if (!str1 || !str2 || !p) {
4364 return False;
4367 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4369 memset((char *)&desc,'\0',sizeof(desc));
4370 memset((char *)&status,'\0',sizeof(status));
4372 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4374 /* check it's a supported varient */
4375 if (strcmp(str1,"WWrLh") != 0) {
4376 return False;
4378 if (!check_printjob_info(&desc,uLevel,str2)) {
4379 return False;
4382 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4383 return False;
4386 ZERO_STRUCT(handle);
4388 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4389 rpc_spoolss_dispatch, conn->server_info,
4390 &cli);
4391 if (!NT_STATUS_IS_OK(status)) {
4392 DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n",
4393 nt_errstr(status)));
4394 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4395 goto out;
4398 ZERO_STRUCT(devmode_ctr);
4400 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4401 sharename,
4402 "RAW",
4403 devmode_ctr,
4404 PRINTER_ACCESS_USE,
4405 &handle,
4406 &werr);
4407 if (!NT_STATUS_IS_OK(status)) {
4408 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4409 goto out;
4411 if (!W_ERROR_IS_OK(werr)) {
4412 desc.errcode = W_ERROR_V(werr);
4413 goto out;
4416 werr = rpccli_spoolss_getjob(cli, mem_ctx,
4417 &handle,
4418 jobid,
4419 2, /* level */
4420 0, /* offered */
4421 &info);
4422 if (!W_ERROR_IS_OK(werr)) {
4423 desc.errcode = W_ERROR_V(werr);
4424 goto out;
4427 if (mdrcnt > 0) {
4428 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4429 if (!*rdata) {
4430 return False;
4432 desc.base = *rdata;
4433 desc.buflen = mdrcnt;
4434 } else {
4436 * Don't return data but need to get correct length
4437 * init_package will return wrong size if buflen=0
4439 desc.buflen = getlen(desc.format);
4440 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4443 if (init_package(&desc,1,0)) {
4444 fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position);
4445 *rdata_len = desc.usedlen;
4446 } else {
4447 desc.errcode = NERR_JobNotFound;
4448 *rdata_len = 0;
4450 out:
4451 if (cli && is_valid_policy_hnd(&handle)) {
4452 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4455 *rparam_len = 6;
4456 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4457 if (!*rparam) {
4458 return False;
4460 SSVALS(*rparam,0,desc.errcode);
4461 SSVAL(*rparam,2,0);
4462 SSVAL(*rparam,4,desc.neededlen);
4464 SAFE_FREE(tmpdata);
4466 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4468 return True;
4471 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
4472 char *param, int tpscnt,
4473 char *data, int tdscnt,
4474 int mdrcnt,int mprcnt,
4475 char **rdata,char **rparam,
4476 int *rdata_len,int *rparam_len)
4478 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4479 char *str2 = skip_string(param,tpscnt,str1);
4480 char *p = skip_string(param,tpscnt,str2);
4481 char *name = p;
4482 int uLevel;
4483 int i, succnt=0;
4484 struct pack_desc desc;
4486 TALLOC_CTX *mem_ctx = talloc_tos();
4487 WERROR werr;
4488 NTSTATUS status;
4489 struct rpc_pipe_client *cli = NULL;
4490 struct policy_handle handle;
4491 struct spoolss_DevmodeContainer devmode_ctr;
4492 uint32_t count;
4493 union spoolss_JobInfo *info;
4495 if (!str1 || !str2 || !p) {
4496 return False;
4499 memset((char *)&desc,'\0',sizeof(desc));
4501 p = skip_string(param,tpscnt,p);
4502 if (!p) {
4503 return False;
4505 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4507 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4509 /* check it's a supported variant */
4510 if (strcmp(str1,"zWrLeh") != 0) {
4511 return False;
4514 if (uLevel > 2) {
4515 return False; /* defined only for uLevel 0,1,2 */
4518 if (!check_printjob_info(&desc,uLevel,str2)) {
4519 return False;
4522 ZERO_STRUCT(handle);
4524 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4525 rpc_spoolss_dispatch, conn->server_info,
4526 &cli);
4527 if (!NT_STATUS_IS_OK(status)) {
4528 DEBUG(0,("api_WPrintJobEnumerate: could not connect to spoolss: %s\n",
4529 nt_errstr(status)));
4530 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4531 goto out;
4534 ZERO_STRUCT(devmode_ctr);
4536 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4537 name,
4538 NULL,
4539 devmode_ctr,
4540 SEC_FLAG_MAXIMUM_ALLOWED,
4541 &handle,
4542 &werr);
4543 if (!NT_STATUS_IS_OK(status)) {
4544 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4545 goto out;
4547 if (!W_ERROR_IS_OK(werr)) {
4548 desc.errcode = W_ERROR_V(werr);
4549 goto out;
4552 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
4553 &handle,
4554 0, /* firstjob */
4555 0xff, /* numjobs */
4556 2, /* level */
4557 0, /* offered */
4558 &count,
4559 &info);
4560 if (!W_ERROR_IS_OK(werr)) {
4561 desc.errcode = W_ERROR_V(werr);
4562 goto out;
4565 if (mdrcnt > 0) {
4566 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4567 if (!*rdata) {
4568 return False;
4571 desc.base = *rdata;
4572 desc.buflen = mdrcnt;
4574 if (init_package(&desc,count,0)) {
4575 succnt = 0;
4576 for (i = 0; i < count; i++) {
4577 fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i);
4578 if (desc.errcode == NERR_Success) {
4579 succnt = i+1;
4583 out:
4584 if (cli && is_valid_policy_hnd(&handle)) {
4585 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4588 *rdata_len = desc.usedlen;
4590 *rparam_len = 8;
4591 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4592 if (!*rparam) {
4593 return False;
4595 SSVALS(*rparam,0,desc.errcode);
4596 SSVAL(*rparam,2,0);
4597 SSVAL(*rparam,4,succnt);
4598 SSVAL(*rparam,6,count);
4600 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4602 return True;
4605 static int check_printdest_info(struct pack_desc* desc,
4606 int uLevel, char* id)
4608 desc->subformat = NULL;
4609 switch( uLevel ) {
4610 case 0:
4611 desc->format = "B9";
4612 break;
4613 case 1:
4614 desc->format = "B9B21WWzW";
4615 break;
4616 case 2:
4617 desc->format = "z";
4618 break;
4619 case 3:
4620 desc->format = "zzzWWzzzWW";
4621 break;
4622 default:
4623 DEBUG(0,("check_printdest_info: invalid level %d\n",
4624 uLevel));
4625 return False;
4627 if (id == NULL || strcmp(desc->format,id) != 0) {
4628 DEBUG(0,("check_printdest_info: invalid string %s\n",
4629 id ? id : "<NULL>" ));
4630 return False;
4632 return True;
4635 static void fill_printdest_info(struct spoolss_PrinterInfo2 *info2, int uLevel,
4636 struct pack_desc* desc)
4638 char buf[100];
4640 strncpy(buf, info2->printername, sizeof(buf)-1);
4641 buf[sizeof(buf)-1] = 0;
4642 strupper_m(buf);
4644 if (uLevel <= 1) {
4645 PACKS(desc,"B9",buf); /* szName */
4646 if (uLevel == 1) {
4647 PACKS(desc,"B21",""); /* szUserName */
4648 PACKI(desc,"W",0); /* uJobId */
4649 PACKI(desc,"W",0); /* fsStatus */
4650 PACKS(desc,"z",""); /* pszStatus */
4651 PACKI(desc,"W",0); /* time */
4655 if (uLevel == 2 || uLevel == 3) {
4656 PACKS(desc,"z",buf); /* pszPrinterName */
4657 if (uLevel == 3) {
4658 PACKS(desc,"z",""); /* pszUserName */
4659 PACKS(desc,"z",""); /* pszLogAddr */
4660 PACKI(desc,"W",0); /* uJobId */
4661 PACKI(desc,"W",0); /* fsStatus */
4662 PACKS(desc,"z",""); /* pszStatus */
4663 PACKS(desc,"z",""); /* pszComment */
4664 PACKS(desc,"z","NULL"); /* pszDrivers */
4665 PACKI(desc,"W",0); /* time */
4666 PACKI(desc,"W",0); /* pad1 */
4671 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
4672 char *param, int tpscnt,
4673 char *data, int tdscnt,
4674 int mdrcnt,int mprcnt,
4675 char **rdata,char **rparam,
4676 int *rdata_len,int *rparam_len)
4678 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4679 char *str2 = skip_string(param,tpscnt,str1);
4680 char *p = skip_string(param,tpscnt,str2);
4681 char* PrinterName = p;
4682 int uLevel;
4683 struct pack_desc desc;
4684 char *tmpdata=NULL;
4686 TALLOC_CTX *mem_ctx = talloc_tos();
4687 WERROR werr;
4688 NTSTATUS status;
4689 struct rpc_pipe_client *cli = NULL;
4690 struct policy_handle handle;
4691 struct spoolss_DevmodeContainer devmode_ctr;
4692 union spoolss_PrinterInfo info;
4694 if (!str1 || !str2 || !p) {
4695 return False;
4698 memset((char *)&desc,'\0',sizeof(desc));
4700 p = skip_string(param,tpscnt,p);
4701 if (!p) {
4702 return False;
4704 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4706 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4708 /* check it's a supported varient */
4709 if (strcmp(str1,"zWrLh") != 0) {
4710 return False;
4712 if (!check_printdest_info(&desc,uLevel,str2)) {
4713 return False;
4716 ZERO_STRUCT(handle);
4718 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4719 rpc_spoolss_dispatch, conn->server_info,
4720 &cli);
4721 if (!NT_STATUS_IS_OK(status)) {
4722 DEBUG(0,("api_WPrintDestGetInfo: could not connect to spoolss: %s\n",
4723 nt_errstr(status)));
4724 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4725 goto out;
4728 ZERO_STRUCT(devmode_ctr);
4730 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4731 PrinterName,
4732 NULL,
4733 devmode_ctr,
4734 SEC_FLAG_MAXIMUM_ALLOWED,
4735 &handle,
4736 &werr);
4737 if (!NT_STATUS_IS_OK(status)) {
4738 *rdata_len = 0;
4739 desc.errcode = NERR_DestNotFound;
4740 desc.neededlen = 0;
4741 goto out;
4743 if (!W_ERROR_IS_OK(werr)) {
4744 *rdata_len = 0;
4745 desc.errcode = NERR_DestNotFound;
4746 desc.neededlen = 0;
4747 goto out;
4750 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
4751 &handle,
4754 &info);
4755 if (!W_ERROR_IS_OK(werr)) {
4756 *rdata_len = 0;
4757 desc.errcode = NERR_DestNotFound;
4758 desc.neededlen = 0;
4759 goto out;
4762 if (mdrcnt > 0) {
4763 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4764 if (!*rdata) {
4765 return False;
4767 desc.base = *rdata;
4768 desc.buflen = mdrcnt;
4769 } else {
4771 * Don't return data but need to get correct length
4772 * init_package will return wrong size if buflen=0
4774 desc.buflen = getlen(desc.format);
4775 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4777 if (init_package(&desc,1,0)) {
4778 fill_printdest_info(&info.info2, uLevel,&desc);
4781 out:
4782 if (cli && is_valid_policy_hnd(&handle)) {
4783 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4786 *rdata_len = desc.usedlen;
4788 *rparam_len = 6;
4789 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4790 if (!*rparam) {
4791 return False;
4793 SSVALS(*rparam,0,desc.errcode);
4794 SSVAL(*rparam,2,0);
4795 SSVAL(*rparam,4,desc.neededlen);
4797 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4798 SAFE_FREE(tmpdata);
4800 return True;
4803 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4804 char *param, int tpscnt,
4805 char *data, int tdscnt,
4806 int mdrcnt,int mprcnt,
4807 char **rdata,char **rparam,
4808 int *rdata_len,int *rparam_len)
4810 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4811 char *str2 = skip_string(param,tpscnt,str1);
4812 char *p = skip_string(param,tpscnt,str2);
4813 int uLevel;
4814 int queuecnt;
4815 int i, n, succnt=0;
4816 struct pack_desc desc;
4818 TALLOC_CTX *mem_ctx = talloc_tos();
4819 WERROR werr;
4820 NTSTATUS status;
4821 struct rpc_pipe_client *cli = NULL;
4822 union spoolss_PrinterInfo *info;
4823 uint32_t count;
4825 if (!str1 || !str2 || !p) {
4826 return False;
4829 memset((char *)&desc,'\0',sizeof(desc));
4831 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4833 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4835 /* check it's a supported varient */
4836 if (strcmp(str1,"WrLeh") != 0) {
4837 return False;
4839 if (!check_printdest_info(&desc,uLevel,str2)) {
4840 return False;
4843 queuecnt = 0;
4845 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4846 rpc_spoolss_dispatch, conn->server_info,
4847 &cli);
4848 if (!NT_STATUS_IS_OK(status)) {
4849 DEBUG(0,("api_WPrintDestEnum: could not connect to spoolss: %s\n",
4850 nt_errstr(status)));
4851 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4852 goto out;
4855 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
4856 PRINTER_ENUM_LOCAL,
4857 cli->srv_name_slash,
4860 &count,
4861 &info);
4862 if (!W_ERROR_IS_OK(werr)) {
4863 desc.errcode = W_ERROR_V(werr);
4864 *rdata_len = 0;
4865 desc.errcode = NERR_DestNotFound;
4866 desc.neededlen = 0;
4867 goto out;
4870 queuecnt = count;
4872 if (mdrcnt > 0) {
4873 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4874 if (!*rdata) {
4875 return False;
4879 desc.base = *rdata;
4880 desc.buflen = mdrcnt;
4881 if (init_package(&desc,queuecnt,0)) {
4882 succnt = 0;
4883 n = 0;
4884 for (i = 0; i < count; i++) {
4885 fill_printdest_info(&info[i].info2, uLevel,&desc);
4886 n++;
4887 if (desc.errcode == NERR_Success) {
4888 succnt = n;
4892 out:
4893 *rdata_len = desc.usedlen;
4895 *rparam_len = 8;
4896 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4897 if (!*rparam) {
4898 return False;
4900 SSVALS(*rparam,0,desc.errcode);
4901 SSVAL(*rparam,2,0);
4902 SSVAL(*rparam,4,succnt);
4903 SSVAL(*rparam,6,queuecnt);
4905 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4907 return True;
4910 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4911 char *param, int tpscnt,
4912 char *data, int tdscnt,
4913 int mdrcnt,int mprcnt,
4914 char **rdata,char **rparam,
4915 int *rdata_len,int *rparam_len)
4917 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4918 char *str2 = skip_string(param,tpscnt,str1);
4919 char *p = skip_string(param,tpscnt,str2);
4920 int uLevel;
4921 int succnt;
4922 struct pack_desc desc;
4924 if (!str1 || !str2 || !p) {
4925 return False;
4928 memset((char *)&desc,'\0',sizeof(desc));
4930 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4932 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4934 /* check it's a supported varient */
4935 if (strcmp(str1,"WrLeh") != 0) {
4936 return False;
4938 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4939 return False;
4942 if (mdrcnt > 0) {
4943 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4944 if (!*rdata) {
4945 return False;
4948 desc.base = *rdata;
4949 desc.buflen = mdrcnt;
4950 if (init_package(&desc,1,0)) {
4951 PACKS(&desc,"B41","NULL");
4954 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4956 *rdata_len = desc.usedlen;
4958 *rparam_len = 8;
4959 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4960 if (!*rparam) {
4961 return False;
4963 SSVALS(*rparam,0,desc.errcode);
4964 SSVAL(*rparam,2,0);
4965 SSVAL(*rparam,4,succnt);
4966 SSVAL(*rparam,6,1);
4968 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4970 return True;
4973 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4974 char *param, int tpscnt,
4975 char *data, int tdscnt,
4976 int mdrcnt,int mprcnt,
4977 char **rdata,char **rparam,
4978 int *rdata_len,int *rparam_len)
4980 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4981 char *str2 = skip_string(param,tpscnt,str1);
4982 char *p = skip_string(param,tpscnt,str2);
4983 int uLevel;
4984 int succnt;
4985 struct pack_desc desc;
4987 if (!str1 || !str2 || !p) {
4988 return False;
4990 memset((char *)&desc,'\0',sizeof(desc));
4992 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4994 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4996 /* check it's a supported varient */
4997 if (strcmp(str1,"WrLeh") != 0) {
4998 return False;
5000 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
5001 return False;
5004 if (mdrcnt > 0) {
5005 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5006 if (!*rdata) {
5007 return False;
5010 desc.base = *rdata;
5011 desc.buflen = mdrcnt;
5012 desc.format = str2;
5013 if (init_package(&desc,1,0)) {
5014 PACKS(&desc,"B13","lpd");
5017 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5019 *rdata_len = desc.usedlen;
5021 *rparam_len = 8;
5022 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5023 if (!*rparam) {
5024 return False;
5026 SSVALS(*rparam,0,desc.errcode);
5027 SSVAL(*rparam,2,0);
5028 SSVAL(*rparam,4,succnt);
5029 SSVAL(*rparam,6,1);
5031 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
5033 return True;
5036 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
5037 char *param, int tpscnt,
5038 char *data, int tdscnt,
5039 int mdrcnt,int mprcnt,
5040 char **rdata,char **rparam,
5041 int *rdata_len,int *rparam_len)
5043 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5044 char *str2 = skip_string(param,tpscnt,str1);
5045 char *p = skip_string(param,tpscnt,str2);
5046 int uLevel;
5047 int succnt;
5048 struct pack_desc desc;
5050 if (!str1 || !str2 || !p) {
5051 return False;
5054 memset((char *)&desc,'\0',sizeof(desc));
5056 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5058 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
5060 /* check it's a supported varient */
5061 if (strcmp(str1,"WrLeh") != 0) {
5062 return False;
5064 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
5065 return False;
5068 if (mdrcnt > 0) {
5069 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5070 if (!*rdata) {
5071 return False;
5074 memset((char *)&desc,'\0',sizeof(desc));
5075 desc.base = *rdata;
5076 desc.buflen = mdrcnt;
5077 desc.format = str2;
5078 if (init_package(&desc,1,0)) {
5079 PACKS(&desc,"B13","lp0");
5082 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5084 *rdata_len = desc.usedlen;
5086 *rparam_len = 8;
5087 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5088 if (!*rparam) {
5089 return False;
5091 SSVALS(*rparam,0,desc.errcode);
5092 SSVAL(*rparam,2,0);
5093 SSVAL(*rparam,4,succnt);
5094 SSVAL(*rparam,6,1);
5096 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
5098 return True;
5101 /****************************************************************************
5102 List open sessions
5103 ****************************************************************************/
5105 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
5106 char *param, int tpscnt,
5107 char *data, int tdscnt,
5108 int mdrcnt,int mprcnt,
5109 char **rdata,char **rparam,
5110 int *rdata_len,int *rparam_len)
5113 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5114 char *str2 = skip_string(param,tpscnt,str1);
5115 char *p = skip_string(param,tpscnt,str2);
5116 int uLevel;
5117 struct pack_desc desc;
5118 struct sessionid *session_list;
5119 int i, num_sessions;
5121 if (!str1 || !str2 || !p) {
5122 return False;
5125 memset((char *)&desc,'\0',sizeof(desc));
5127 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5129 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
5130 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
5131 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
5133 /* check it's a supported varient */
5134 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
5135 return False;
5137 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
5138 return False;
5141 num_sessions = list_sessions(talloc_tos(), &session_list);
5143 if (mdrcnt > 0) {
5144 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5145 if (!*rdata) {
5146 return False;
5149 memset((char *)&desc,'\0',sizeof(desc));
5150 desc.base = *rdata;
5151 desc.buflen = mdrcnt;
5152 desc.format = str2;
5153 if (!init_package(&desc,num_sessions,0)) {
5154 return False;
5157 for(i=0; i<num_sessions; i++) {
5158 PACKS(&desc, "z", session_list[i].remote_machine);
5159 PACKS(&desc, "z", session_list[i].username);
5160 PACKI(&desc, "W", 1); /* num conns */
5161 PACKI(&desc, "W", 0); /* num opens */
5162 PACKI(&desc, "W", 1); /* num users */
5163 PACKI(&desc, "D", 0); /* session time */
5164 PACKI(&desc, "D", 0); /* idle time */
5165 PACKI(&desc, "D", 0); /* flags */
5166 PACKS(&desc, "z", "Unknown Client"); /* client type string */
5169 *rdata_len = desc.usedlen;
5171 *rparam_len = 8;
5172 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5173 if (!*rparam) {
5174 return False;
5176 SSVALS(*rparam,0,desc.errcode);
5177 SSVAL(*rparam,2,0); /* converter */
5178 SSVAL(*rparam,4,num_sessions); /* count */
5180 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
5182 return True;
5186 /****************************************************************************
5187 The buffer was too small.
5188 ****************************************************************************/
5190 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
5191 int mdrcnt, int mprcnt,
5192 char **rdata, char **rparam,
5193 int *rdata_len, int *rparam_len)
5195 *rparam_len = MIN(*rparam_len,mprcnt);
5196 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5197 if (!*rparam) {
5198 return False;
5201 *rdata_len = 0;
5203 SSVAL(*rparam,0,NERR_BufTooSmall);
5205 DEBUG(3,("Supplied buffer too small in API command\n"));
5207 return True;
5210 /****************************************************************************
5211 The request is not supported.
5212 ****************************************************************************/
5214 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
5215 char *param, int tpscnt,
5216 char *data, int tdscnt,
5217 int mdrcnt, int mprcnt,
5218 char **rdata, char **rparam,
5219 int *rdata_len, int *rparam_len)
5221 *rparam_len = 4;
5222 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5223 if (!*rparam) {
5224 return False;
5227 *rdata_len = 0;
5229 SSVAL(*rparam,0,NERR_notsupported);
5230 SSVAL(*rparam,2,0); /* converter word */
5232 DEBUG(3,("Unsupported API command\n"));
5234 return True;
5237 static const struct {
5238 const char *name;
5239 int id;
5240 bool (*fn)(connection_struct *, uint16,
5241 char *, int,
5242 char *, int,
5243 int,int,char **,char **,int *,int *);
5244 bool auth_user; /* Deny anonymous access? */
5245 } api_commands[] = {
5246 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
5247 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
5248 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
5249 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
5250 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
5251 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
5252 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
5253 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
5254 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
5255 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
5256 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
5257 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
5258 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
5259 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
5260 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
5261 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
5262 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
5263 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
5264 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
5265 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
5266 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
5267 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
5268 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
5269 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
5270 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
5271 {"NetServerEnum3", RAP_NetServerEnum3, api_RNetServerEnum3}, /* anon OK */
5272 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
5273 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
5274 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
5275 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
5276 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
5277 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
5278 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
5279 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
5280 {NULL, -1, api_Unsupported}
5281 /* The following RAP calls are not implemented by Samba:
5283 RAP_WFileEnum2 - anon not OK
5288 /****************************************************************************
5289 Handle remote api calls.
5290 ****************************************************************************/
5292 void api_reply(connection_struct *conn, uint16 vuid,
5293 struct smb_request *req,
5294 char *data, char *params,
5295 int tdscnt, int tpscnt,
5296 int mdrcnt, int mprcnt)
5298 struct smbd_server_connection *sconn = smbd_server_conn;
5299 int api_command;
5300 char *rdata = NULL;
5301 char *rparam = NULL;
5302 const char *name1 = NULL;
5303 const char *name2 = NULL;
5304 int rdata_len = 0;
5305 int rparam_len = 0;
5306 bool reply=False;
5307 int i;
5309 if (!params) {
5310 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
5311 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5312 return;
5315 if (tpscnt < 2) {
5316 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5317 return;
5319 api_command = SVAL(params,0);
5320 /* Is there a string at position params+2 ? */
5321 if (skip_string(params,tpscnt,params+2)) {
5322 name1 = params + 2;
5323 } else {
5324 name1 = "";
5326 name2 = skip_string(params,tpscnt,params+2);
5327 if (!name2) {
5328 name2 = "";
5331 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
5332 api_command,
5333 name1,
5334 name2,
5335 tdscnt,tpscnt,mdrcnt,mprcnt));
5337 for (i=0;api_commands[i].name;i++) {
5338 if (api_commands[i].id == api_command && api_commands[i].fn) {
5339 DEBUG(3,("Doing %s\n",api_commands[i].name));
5340 break;
5344 /* Check whether this api call can be done anonymously */
5346 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
5347 user_struct *user = get_valid_user_struct(sconn, vuid);
5349 if (!user || user->server_info->guest) {
5350 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5351 return;
5355 rdata = (char *)SMB_MALLOC(1024);
5356 if (rdata) {
5357 memset(rdata,'\0',1024);
5360 rparam = (char *)SMB_MALLOC(1024);
5361 if (rparam) {
5362 memset(rparam,'\0',1024);
5365 if(!rdata || !rparam) {
5366 DEBUG(0,("api_reply: malloc fail !\n"));
5367 SAFE_FREE(rdata);
5368 SAFE_FREE(rparam);
5369 reply_nterror(req, NT_STATUS_NO_MEMORY);
5370 return;
5373 reply = api_commands[i].fn(conn,
5374 vuid,
5375 params,tpscnt, /* params + length */
5376 data,tdscnt, /* data + length */
5377 mdrcnt,mprcnt,
5378 &rdata,&rparam,&rdata_len,&rparam_len);
5381 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
5382 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
5383 &rdata,&rparam,&rdata_len,&rparam_len);
5386 /* if we get False back then it's actually unsupported */
5387 if (!reply) {
5388 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
5389 &rdata,&rparam,&rdata_len,&rparam_len);
5392 /* If api_Unsupported returns false we can't return anything. */
5393 if (reply) {
5394 send_trans_reply(conn, req, rparam, rparam_len,
5395 rdata, rdata_len, False);
5398 SAFE_FREE(rdata);
5399 SAFE_FREE(rparam);
5400 return;