s3-lanman: Migrated to rpc_connect_spoolss_pipe().
[Samba/ekacnet.git] / source3 / smbd / lanman.c
blob0d5cda777d1cae657312be280ecaed712643bbdf
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_srvsvc.h"
37 #include "../librpc/gen_ndr/rap.h"
38 #include "../lib/util/binsearch.h"
40 #ifdef CHECK_TYPES
41 #undef CHECK_TYPES
42 #endif
43 #define CHECK_TYPES 0
45 #define NERR_Success 0
46 #define NERR_badpass 86
47 #define NERR_notsupported 50
49 #define NERR_BASE (2100)
50 #define NERR_BufTooSmall (NERR_BASE+23)
51 #define NERR_JobNotFound (NERR_BASE+51)
52 #define NERR_DestNotFound (NERR_BASE+52)
54 #define ACCESS_READ 0x01
55 #define ACCESS_WRITE 0x02
56 #define ACCESS_CREATE 0x04
58 #define SHPWLEN 8 /* share password length */
60 /* Limit size of ipc replies */
62 static char *smb_realloc_limit(void *ptr, size_t size)
64 char *val;
66 size = MAX((size),4*1024);
67 val = (char *)SMB_REALLOC(ptr,size);
68 if (val) {
69 memset(val,'\0',size);
71 return val;
74 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
75 char *param, int tpscnt,
76 char *data, int tdscnt,
77 int mdrcnt, int mprcnt,
78 char **rdata, char **rparam,
79 int *rdata_len, int *rparam_len);
81 static bool api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
82 int mdrcnt, int mprcnt,
83 char **rdata, char **rparam,
84 int *rdata_len, int *rparam_len);
87 static int CopyExpanded(connection_struct *conn,
88 int snum, char **dst, char *src, int *p_space_remaining)
90 TALLOC_CTX *ctx = talloc_tos();
91 char *buf = NULL;
92 int l;
94 if (!src || !dst || !p_space_remaining || !(*dst) ||
95 *p_space_remaining <= 0) {
96 return 0;
99 buf = talloc_strdup(ctx, src);
100 if (!buf) {
101 *p_space_remaining = 0;
102 return 0;
104 buf = talloc_string_sub(ctx, buf,"%S",lp_servicename(snum));
105 if (!buf) {
106 *p_space_remaining = 0;
107 return 0;
109 buf = talloc_sub_advanced(ctx,
110 lp_servicename(SNUM(conn)),
111 conn->server_info->unix_name,
112 conn->connectpath,
113 conn->server_info->utok.gid,
114 conn->server_info->sanitized_username,
115 pdb_get_domain(conn->server_info->sam_account),
116 buf);
117 if (!buf) {
118 *p_space_remaining = 0;
119 return 0;
121 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
122 if (l == -1) {
123 return 0;
125 (*dst) += l;
126 (*p_space_remaining) -= l;
127 return l;
130 static int CopyAndAdvance(char **dst, char *src, int *n)
132 int l;
133 if (!src || !dst || !n || !(*dst)) {
134 return 0;
136 l = push_ascii(*dst,src,*n, STR_TERMINATE);
137 if (l == -1) {
138 return 0;
140 (*dst) += l;
141 (*n) -= l;
142 return l;
145 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
147 TALLOC_CTX *ctx = talloc_tos();
148 char *buf = NULL;
149 if (!s) {
150 return 0;
152 buf = talloc_strdup(ctx,s);
153 if (!buf) {
154 return 0;
156 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
157 if (!buf) {
158 return 0;
160 buf = talloc_sub_advanced(ctx,
161 lp_servicename(SNUM(conn)),
162 conn->server_info->unix_name,
163 conn->connectpath,
164 conn->server_info->utok.gid,
165 conn->server_info->sanitized_username,
166 pdb_get_domain(conn->server_info->sam_account),
167 buf);
168 if (!buf) {
169 return 0;
171 return strlen(buf) + 1;
174 /*******************************************************************
175 Check a API string for validity when we only need to check the prefix.
176 ******************************************************************/
178 static bool prefix_ok(const char *str, const char *prefix)
180 return(strncmp(str,prefix,strlen(prefix)) == 0);
183 struct pack_desc {
184 const char *format; /* formatstring for structure */
185 const char *subformat; /* subformat for structure */
186 char *base; /* baseaddress of buffer */
187 int buflen; /* remaining size for fixed part; on init: length of base */
188 int subcount; /* count of substructures */
189 char *structbuf; /* pointer into buffer for remaining fixed part */
190 int stringlen; /* remaining size for variable part */
191 char *stringbuf; /* pointer into buffer for remaining variable part */
192 int neededlen; /* total needed size */
193 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
194 const char *curpos; /* current position; pointer into format or subformat */
195 int errcode;
198 static int get_counter(const char **p)
200 int i, n;
201 if (!p || !(*p)) {
202 return 1;
204 if (!isdigit((int)**p)) {
205 return 1;
207 for (n = 0;;) {
208 i = **p;
209 if (isdigit(i)) {
210 n = 10 * n + (i - '0');
211 } else {
212 return n;
214 (*p)++;
218 static int getlen(const char *p)
220 int n = 0;
221 if (!p) {
222 return 0;
225 while (*p) {
226 switch( *p++ ) {
227 case 'W': /* word (2 byte) */
228 n += 2;
229 break;
230 case 'K': /* status word? (2 byte) */
231 n += 2;
232 break;
233 case 'N': /* count of substructures (word) at end */
234 n += 2;
235 break;
236 case 'D': /* double word (4 byte) */
237 case 'z': /* offset to zero terminated string (4 byte) */
238 case 'l': /* offset to user data (4 byte) */
239 n += 4;
240 break;
241 case 'b': /* offset to data (with counter) (4 byte) */
242 n += 4;
243 get_counter(&p);
244 break;
245 case 'B': /* byte (with optional counter) */
246 n += get_counter(&p);
247 break;
250 return n;
253 static bool init_package(struct pack_desc *p, int count, int subcount)
255 int n = p->buflen;
256 int i;
258 if (!p->format || !p->base) {
259 return False;
262 i = count * getlen(p->format);
263 if (p->subformat) {
264 i += subcount * getlen(p->subformat);
266 p->structbuf = p->base;
267 p->neededlen = 0;
268 p->usedlen = 0;
269 p->subcount = 0;
270 p->curpos = p->format;
271 if (i > n) {
272 p->neededlen = i;
273 i = n = 0;
274 #if 0
276 * This is the old error code we used. Aparently
277 * WinNT/2k systems return ERRbuftoosmall (2123) and
278 * OS/2 needs this. I'm leaving this here so we can revert
279 * if needed. JRA.
281 p->errcode = ERRmoredata;
282 #else
283 p->errcode = ERRbuftoosmall;
284 #endif
285 } else {
286 p->errcode = NERR_Success;
288 p->buflen = i;
289 n -= i;
290 p->stringbuf = p->base + i;
291 p->stringlen = n;
292 return (p->errcode == NERR_Success);
295 static int package(struct pack_desc *p, ...)
297 va_list args;
298 int needed=0, stringneeded;
299 const char *str=NULL;
300 int is_string=0, stringused;
301 int32 temp;
303 va_start(args,p);
305 if (!*p->curpos) {
306 if (!p->subcount) {
307 p->curpos = p->format;
308 } else {
309 p->curpos = p->subformat;
310 p->subcount--;
313 #if CHECK_TYPES
314 str = va_arg(args,char*);
315 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
316 #endif
317 stringneeded = -1;
319 if (!p->curpos) {
320 va_end(args);
321 return 0;
324 switch( *p->curpos++ ) {
325 case 'W': /* word (2 byte) */
326 needed = 2;
327 temp = va_arg(args,int);
328 if (p->buflen >= needed) {
329 SSVAL(p->structbuf,0,temp);
331 break;
332 case 'K': /* status word? (2 byte) */
333 needed = 2;
334 temp = va_arg(args,int);
335 if (p->buflen >= needed) {
336 SSVAL(p->structbuf,0,temp);
338 break;
339 case 'N': /* count of substructures (word) at end */
340 needed = 2;
341 p->subcount = va_arg(args,int);
342 if (p->buflen >= needed) {
343 SSVAL(p->structbuf,0,p->subcount);
345 break;
346 case 'D': /* double word (4 byte) */
347 needed = 4;
348 temp = va_arg(args,int);
349 if (p->buflen >= needed) {
350 SIVAL(p->structbuf,0,temp);
352 break;
353 case 'B': /* byte (with optional counter) */
354 needed = get_counter(&p->curpos);
356 char *s = va_arg(args,char*);
357 if (p->buflen >= needed) {
358 StrnCpy(p->structbuf,s?s:"",needed-1);
361 break;
362 case 'z': /* offset to zero terminated string (4 byte) */
363 str = va_arg(args,char*);
364 stringneeded = (str ? strlen(str)+1 : 0);
365 is_string = 1;
366 break;
367 case 'l': /* offset to user data (4 byte) */
368 str = va_arg(args,char*);
369 stringneeded = va_arg(args,int);
370 is_string = 0;
371 break;
372 case 'b': /* offset to data (with counter) (4 byte) */
373 str = va_arg(args,char*);
374 stringneeded = get_counter(&p->curpos);
375 is_string = 0;
376 break;
379 va_end(args);
380 if (stringneeded >= 0) {
381 needed = 4;
382 if (p->buflen >= needed) {
383 stringused = stringneeded;
384 if (stringused > p->stringlen) {
385 stringused = (is_string ? p->stringlen : 0);
386 if (p->errcode == NERR_Success) {
387 p->errcode = ERRmoredata;
390 if (!stringused) {
391 SIVAL(p->structbuf,0,0);
392 } else {
393 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
394 memcpy(p->stringbuf,str?str:"",stringused);
395 if (is_string) {
396 p->stringbuf[stringused-1] = '\0';
398 p->stringbuf += stringused;
399 p->stringlen -= stringused;
400 p->usedlen += stringused;
403 p->neededlen += stringneeded;
406 p->neededlen += needed;
407 if (p->buflen >= needed) {
408 p->structbuf += needed;
409 p->buflen -= needed;
410 p->usedlen += needed;
411 } else {
412 if (p->errcode == NERR_Success) {
413 p->errcode = ERRmoredata;
416 return 1;
419 #if CHECK_TYPES
420 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
421 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
422 #else
423 #define PACK(desc,t,v) package(desc,v)
424 #define PACKl(desc,t,v,l) package(desc,v,l)
425 #endif
427 static void PACKI(struct pack_desc* desc, const char *t,int v)
429 PACK(desc,t,v);
432 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
434 PACK(desc,t,v);
437 /****************************************************************************
438 Get a print queue.
439 ****************************************************************************/
441 static void PackDriverData(struct pack_desc* desc)
443 char drivdata[4+4+32];
444 SIVAL(drivdata,0,sizeof drivdata); /* cb */
445 SIVAL(drivdata,4,1000); /* lVersion */
446 memset(drivdata+8,0,32); /* szDeviceName */
447 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
448 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
451 static int check_printq_info(struct pack_desc* desc,
452 unsigned int uLevel, char *id1, char *id2)
454 desc->subformat = NULL;
455 switch( uLevel ) {
456 case 0:
457 desc->format = "B13";
458 break;
459 case 1:
460 desc->format = "B13BWWWzzzzzWW";
461 break;
462 case 2:
463 desc->format = "B13BWWWzzzzzWN";
464 desc->subformat = "WB21BB16B10zWWzDDz";
465 break;
466 case 3:
467 desc->format = "zWWWWzzzzWWzzl";
468 break;
469 case 4:
470 desc->format = "zWWWWzzzzWNzzl";
471 desc->subformat = "WWzWWDDzz";
472 break;
473 case 5:
474 desc->format = "z";
475 break;
476 case 51:
477 desc->format = "K";
478 break;
479 case 52:
480 desc->format = "WzzzzzzzzN";
481 desc->subformat = "z";
482 break;
483 default:
484 DEBUG(0,("check_printq_info: invalid level %d\n",
485 uLevel ));
486 return False;
488 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
489 DEBUG(0,("check_printq_info: invalid format %s\n",
490 id1 ? id1 : "<NULL>" ));
491 return False;
493 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
494 DEBUG(0,("check_printq_info: invalid subformat %s\n",
495 id2 ? id2 : "<NULL>" ));
496 return False;
498 return True;
502 #define RAP_JOB_STATUS_QUEUED 0
503 #define RAP_JOB_STATUS_PAUSED 1
504 #define RAP_JOB_STATUS_SPOOLING 2
505 #define RAP_JOB_STATUS_PRINTING 3
506 #define RAP_JOB_STATUS_PRINTED 4
508 #define RAP_QUEUE_STATUS_PAUSED 1
509 #define RAP_QUEUE_STATUS_ERROR 2
511 /* turn a print job status into a on the wire status
513 static int printj_spoolss_status(int v)
515 if (v == JOB_STATUS_QUEUED)
516 return RAP_JOB_STATUS_QUEUED;
517 if (v & JOB_STATUS_PAUSED)
518 return RAP_JOB_STATUS_PAUSED;
519 if (v & JOB_STATUS_SPOOLING)
520 return RAP_JOB_STATUS_SPOOLING;
521 if (v & JOB_STATUS_PRINTING)
522 return RAP_JOB_STATUS_PRINTING;
523 return 0;
526 /* turn a print queue status into a on the wire status
528 static int printq_spoolss_status(int v)
530 if (v == PRINTER_STATUS_OK)
531 return 0;
532 if (v & PRINTER_STATUS_PAUSED)
533 return RAP_QUEUE_STATUS_PAUSED;
534 return RAP_QUEUE_STATUS_ERROR;
537 static void fill_spoolss_printjob_info(int uLevel,
538 struct pack_desc *desc,
539 struct spoolss_JobInfo2 *info2,
540 int n)
542 time_t t = spoolss_Time_to_time_t(&info2->submitted);
544 /* the client expects localtime */
545 t -= get_time_zone(t);
547 PACKI(desc,"W",pjobid_to_rap(info2->printer_name, info2->job_id)); /* uJobId */
548 if (uLevel == 1) {
549 PACKS(desc,"B21", info2->user_name); /* szUserName */
550 PACKS(desc,"B",""); /* pad */
551 PACKS(desc,"B16",""); /* szNotifyName */
552 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
553 PACKS(desc,"z",""); /* pszParms */
554 PACKI(desc,"W",n+1); /* uPosition */
555 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
556 PACKS(desc,"z",""); /* pszStatus */
557 PACKI(desc,"D", t); /* ulSubmitted */
558 PACKI(desc,"D", info2->size); /* ulSize */
559 PACKS(desc,"z", info2->document_name); /* pszComment */
561 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
562 PACKI(desc,"W", info2->priority); /* uPriority */
563 PACKS(desc,"z", info2->user_name); /* pszUserName */
564 PACKI(desc,"W",n+1); /* uPosition */
565 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
566 PACKI(desc,"D",t); /* ulSubmitted */
567 PACKI(desc,"D", info2->size); /* ulSize */
568 PACKS(desc,"z","Samba"); /* pszComment */
569 PACKS(desc,"z", info2->document_name); /* pszDocument */
570 if (uLevel == 3) {
571 PACKS(desc,"z",""); /* pszNotifyName */
572 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
573 PACKS(desc,"z",""); /* pszParms */
574 PACKS(desc,"z",""); /* pszStatus */
575 PACKS(desc,"z", info2->printer_name); /* pszQueue */
576 PACKS(desc,"z","lpd"); /* pszQProcName */
577 PACKS(desc,"z",""); /* pszQProcParms */
578 PACKS(desc,"z","NULL"); /* pszDriverName */
579 PackDriverData(desc); /* pDriverData */
580 PACKS(desc,"z",""); /* pszPrinterName */
581 } else if (uLevel == 4) { /* OS2 */
582 PACKS(desc,"z",""); /* pszSpoolFileName */
583 PACKS(desc,"z",""); /* pszPortName */
584 PACKS(desc,"z",""); /* pszStatus */
585 PACKI(desc,"D",0); /* ulPagesSpooled */
586 PACKI(desc,"D",0); /* ulPagesSent */
587 PACKI(desc,"D",0); /* ulPagesPrinted */
588 PACKI(desc,"D",0); /* ulTimePrinted */
589 PACKI(desc,"D",0); /* ulExtendJobStatus */
590 PACKI(desc,"D",0); /* ulStartPage */
591 PACKI(desc,"D",0); /* ulEndPage */
596 /********************************************************************
597 Respond to the DosPrintQInfo command with a level of 52
598 This is used to get printer driver information for Win9x clients
599 ********************************************************************/
600 static void fill_printq_info_52(struct spoolss_DriverInfo3 *driver,
601 struct pack_desc* desc, int count,
602 const char *printer_name)
604 int i;
605 fstring location;
606 trim_string((char *)driver->driver_path, "\\print$\\WIN40\\0\\", 0);
607 trim_string((char *)driver->data_file, "\\print$\\WIN40\\0\\", 0);
608 trim_string((char *)driver->help_file, "\\print$\\WIN40\\0\\", 0);
610 PACKI(desc, "W", 0x0400); /* don't know */
611 PACKS(desc, "z", driver->driver_name); /* long printer name */
612 PACKS(desc, "z", driver->driver_path); /* Driverfile Name */
613 PACKS(desc, "z", driver->data_file); /* Datafile name */
614 PACKS(desc, "z", driver->monitor_name); /* language monitor */
616 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
617 standard_sub_basic( "", "", location, sizeof(location)-1 );
618 PACKS(desc,"z", location); /* share to retrieve files */
620 PACKS(desc,"z", driver->default_datatype); /* default data type */
621 PACKS(desc,"z", driver->help_file); /* helpfile name */
622 PACKS(desc,"z", driver->driver_path); /* driver name */
624 DEBUG(3,("Printer Driver Name: %s:\n",driver->driver_name));
625 DEBUG(3,("Driver: %s:\n",driver->driver_path));
626 DEBUG(3,("Data File: %s:\n",driver->data_file));
627 DEBUG(3,("Language Monitor: %s:\n",driver->monitor_name));
628 DEBUG(3,("Driver Location: %s:\n",location));
629 DEBUG(3,("Data Type: %s:\n",driver->default_datatype));
630 DEBUG(3,("Help File: %s:\n",driver->help_file));
631 PACKI(desc,"N",count); /* number of files to copy */
633 for ( i=0; i<count && driver->dependent_files && *driver->dependent_files[i]; i++)
635 trim_string((char *)driver->dependent_files[i], "\\print$\\WIN40\\0\\", 0);
636 PACKS(desc,"z",driver->dependent_files[i]); /* driver files to copy */
637 DEBUG(3,("Dependent File: %s:\n", driver->dependent_files[i]));
640 /* sanity check */
641 if ( i != count )
642 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
643 count, i));
645 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", printer_name, i));
647 desc->errcode=NERR_Success;
651 static const char *strip_unc(const char *unc)
653 char *p;
655 if (unc == NULL) {
656 return NULL;
659 if ((p = strrchr(unc, '\\')) != NULL) {
660 return p+1;
663 return unc;
666 static void fill_printq_info(int uLevel,
667 struct pack_desc* desc,
668 int count,
669 union spoolss_JobInfo *job_info,
670 struct spoolss_DriverInfo3 *driver_info,
671 struct spoolss_PrinterInfo2 *printer_info)
673 switch (uLevel) {
674 case 0:
675 case 1:
676 case 2:
677 PACKS(desc,"B13", strip_unc(printer_info->printername));
678 break;
679 case 3:
680 case 4:
681 case 5:
682 PACKS(desc,"z", strip_unc(printer_info->printername));
683 break;
684 case 51:
685 PACKI(desc,"K", printq_spoolss_status(printer_info->status));
686 break;
689 if (uLevel == 1 || uLevel == 2) {
690 PACKS(desc,"B",""); /* alignment */
691 PACKI(desc,"W",5); /* priority */
692 PACKI(desc,"W",0); /* start time */
693 PACKI(desc,"W",0); /* until time */
694 PACKS(desc,"z",""); /* pSepFile */
695 PACKS(desc,"z","lpd"); /* pPrProc */
696 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pDestinations */
697 PACKS(desc,"z",""); /* pParms */
698 if (printer_info->printername == NULL) {
699 PACKS(desc,"z","UNKNOWN PRINTER");
700 PACKI(desc,"W",LPSTAT_ERROR);
701 } else {
702 PACKS(desc,"z", printer_info->comment);
703 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* status */
705 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
708 if (uLevel == 3 || uLevel == 4) {
709 PACKI(desc,"W",5); /* uPriority */
710 PACKI(desc,"W",0); /* uStarttime */
711 PACKI(desc,"W",0); /* uUntiltime */
712 PACKI(desc,"W",5); /* pad1 */
713 PACKS(desc,"z",""); /* pszSepFile */
714 PACKS(desc,"z","WinPrint"); /* pszPrProc */
715 PACKS(desc,"z",NULL); /* pszParms */
716 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
717 /* "don't ask" that it's done this way to fix corrupted
718 Win9X/ME printer comments. */
719 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* fsStatus */
720 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
721 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pszPrinters */
722 PACKS(desc,"z", printer_info->drivername); /* pszDriverName */
723 PackDriverData(desc); /* pDriverData */
726 if (uLevel == 2 || uLevel == 4) {
727 int i;
728 for (i = 0; i < count; i++) {
729 fill_spoolss_printjob_info(uLevel == 2 ? 1 : 2, desc, &job_info[i].info2, i);
733 if (uLevel==52)
734 fill_printq_info_52(driver_info, desc, count, printer_info->printername);
737 /* This function returns the number of files for a given driver */
738 static int get_printerdrivernumber(const struct spoolss_DriverInfo3 *driver)
740 int result = 0;
742 /* count the number of files */
743 while (driver->dependent_files && *driver->dependent_files[result])
744 result++;
746 return result;
749 static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
750 char *param, int tpscnt,
751 char *data, int tdscnt,
752 int mdrcnt,int mprcnt,
753 char **rdata,char **rparam,
754 int *rdata_len,int *rparam_len)
756 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
757 char *str2 = skip_string(param,tpscnt,str1);
758 char *p = skip_string(param,tpscnt,str2);
759 char *QueueName = p;
760 unsigned int uLevel;
761 uint32_t count = 0;
762 char *str3;
763 struct pack_desc desc;
764 char* tmpdata=NULL;
766 WERROR werr = WERR_OK;
767 TALLOC_CTX *mem_ctx = talloc_tos();
768 NTSTATUS status;
769 struct rpc_pipe_client *cli = NULL;
770 struct policy_handle handle;
771 struct spoolss_DevmodeContainer devmode_ctr;
772 union spoolss_DriverInfo driver_info;
773 union spoolss_JobInfo *job_info;
774 union spoolss_PrinterInfo printer_info;
776 if (!str1 || !str2 || !p) {
777 return False;
779 memset((char *)&desc,'\0',sizeof(desc));
781 p = skip_string(param,tpscnt,p);
782 if (!p) {
783 return False;
785 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
786 str3 = get_safe_str_ptr(param,tpscnt,p,4);
787 /* str3 may be null here and is checked in check_printq_info(). */
789 /* remove any trailing username */
790 if ((p = strchr_m(QueueName,'%')))
791 *p = 0;
793 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
795 /* check it's a supported varient */
796 if (!prefix_ok(str1,"zWrLh"))
797 return False;
798 if (!check_printq_info(&desc,uLevel,str2,str3)) {
800 * Patch from Scott Moomaw <scott@bridgewater.edu>
801 * to return the 'invalid info level' error if an
802 * unknown level was requested.
804 *rdata_len = 0;
805 *rparam_len = 6;
806 *rparam = smb_realloc_limit(*rparam,*rparam_len);
807 if (!*rparam) {
808 return False;
810 SSVALS(*rparam,0,ERRunknownlevel);
811 SSVAL(*rparam,2,0);
812 SSVAL(*rparam,4,0);
813 return(True);
816 ZERO_STRUCT(handle);
818 status = rpc_connect_spoolss_pipe(conn, &cli);
819 if (!NT_STATUS_IS_OK(status)) {
820 DEBUG(0,("api_DosPrintQGetInfo: could not connect to spoolss: %s\n",
821 nt_errstr(status)));
822 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
823 goto out;
826 ZERO_STRUCT(devmode_ctr);
828 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
829 QueueName,
830 "RAW",
831 devmode_ctr,
832 PRINTER_ACCESS_USE,
833 &handle,
834 &werr);
835 if (!NT_STATUS_IS_OK(status)) {
836 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
837 goto out;
839 if (!W_ERROR_IS_OK(werr)) {
840 desc.errcode = W_ERROR_V(werr);
841 goto out;
844 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
845 &handle,
848 &printer_info);
849 if (!W_ERROR_IS_OK(werr)) {
850 desc.errcode = W_ERROR_V(werr);
851 goto out;
854 if (uLevel==52) {
855 uint32_t server_major_version;
856 uint32_t server_minor_version;
858 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
859 &handle,
860 "Windows 4.0",
861 3, /* level */
863 0, /* version */
865 &driver_info,
866 &server_major_version,
867 &server_minor_version);
868 if (!W_ERROR_IS_OK(werr)) {
869 desc.errcode = W_ERROR_V(werr);
870 goto out;
873 count = get_printerdrivernumber(&driver_info.info3);
874 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
875 } else {
876 uint32_t num_jobs;
877 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
878 &handle,
879 0, /* firstjob */
880 0xff, /* numjobs */
881 2, /* level */
882 0, /* offered */
883 &num_jobs,
884 &job_info);
885 if (!W_ERROR_IS_OK(werr)) {
886 desc.errcode = W_ERROR_V(werr);
887 goto out;
890 count = num_jobs;
893 if (mdrcnt > 0) {
894 *rdata = smb_realloc_limit(*rdata,mdrcnt);
895 if (!*rdata) {
896 return False;
898 desc.base = *rdata;
899 desc.buflen = mdrcnt;
900 } else {
902 * Don't return data but need to get correct length
903 * init_package will return wrong size if buflen=0
905 desc.buflen = getlen(desc.format);
906 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
909 if (init_package(&desc,1,count)) {
910 desc.subcount = count;
911 fill_printq_info(uLevel,&desc,count, job_info, &driver_info.info3, &printer_info.info2);
914 *rdata_len = desc.usedlen;
917 * We must set the return code to ERRbuftoosmall
918 * in order to support lanman style printing with Win NT/2k
919 * clients --jerry
921 if (!mdrcnt && lp_disable_spoolss())
922 desc.errcode = ERRbuftoosmall;
924 out:
925 if (cli && is_valid_policy_hnd(&handle)) {
926 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
929 *rdata_len = desc.usedlen;
930 *rparam_len = 6;
931 *rparam = smb_realloc_limit(*rparam,*rparam_len);
932 if (!*rparam) {
933 SAFE_FREE(tmpdata);
934 return False;
936 SSVALS(*rparam,0,desc.errcode);
937 SSVAL(*rparam,2,0);
938 SSVAL(*rparam,4,desc.neededlen);
940 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
942 SAFE_FREE(tmpdata);
944 return(True);
947 /****************************************************************************
948 View list of all print jobs on all queues.
949 ****************************************************************************/
951 static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
952 char *param, int tpscnt,
953 char *data, int tdscnt,
954 int mdrcnt, int mprcnt,
955 char **rdata, char** rparam,
956 int *rdata_len, int *rparam_len)
958 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
959 char *output_format1 = skip_string(param,tpscnt,param_format);
960 char *p = skip_string(param,tpscnt,output_format1);
961 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
962 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
963 int i;
964 struct pack_desc desc;
965 int *subcntarr = NULL;
966 int queuecnt = 0, subcnt = 0, succnt = 0;
968 WERROR werr = WERR_OK;
969 TALLOC_CTX *mem_ctx = talloc_tos();
970 NTSTATUS status;
971 struct rpc_pipe_client *cli = NULL;
972 struct spoolss_DevmodeContainer devmode_ctr;
973 uint32_t num_printers;
974 union spoolss_PrinterInfo *printer_info;
975 union spoolss_DriverInfo *driver_info;
976 union spoolss_JobInfo **job_info;
978 if (!param_format || !output_format1 || !p) {
979 return False;
982 memset((char *)&desc,'\0',sizeof(desc));
984 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
986 if (!prefix_ok(param_format,"WrLeh")) {
987 return False;
989 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
991 * Patch from Scott Moomaw <scott@bridgewater.edu>
992 * to return the 'invalid info level' error if an
993 * unknown level was requested.
995 *rdata_len = 0;
996 *rparam_len = 6;
997 *rparam = smb_realloc_limit(*rparam,*rparam_len);
998 if (!*rparam) {
999 return False;
1001 SSVALS(*rparam,0,ERRunknownlevel);
1002 SSVAL(*rparam,2,0);
1003 SSVAL(*rparam,4,0);
1004 return(True);
1007 status = rpc_connect_spoolss_pipe(conn, &cli);
1008 if (!NT_STATUS_IS_OK(status)) {
1009 DEBUG(0,("api_DosPrintQEnum: could not connect to spoolss: %s\n",
1010 nt_errstr(status)));
1011 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1012 goto out;
1015 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
1016 PRINTER_ENUM_LOCAL,
1017 cli->srv_name_slash,
1020 &num_printers,
1021 &printer_info);
1022 if (!W_ERROR_IS_OK(werr)) {
1023 desc.errcode = W_ERROR_V(werr);
1024 goto out;
1027 queuecnt = num_printers;
1029 job_info = talloc_array(mem_ctx, union spoolss_JobInfo *, num_printers);
1030 if (job_info == NULL) {
1031 goto err;
1034 driver_info = talloc_array(mem_ctx, union spoolss_DriverInfo, num_printers);
1035 if (driver_info == NULL) {
1036 goto err;
1039 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1040 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1041 goto err;
1044 if (mdrcnt > 0) {
1045 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1046 if (!*rdata) {
1047 goto err;
1050 desc.base = *rdata;
1051 desc.buflen = mdrcnt;
1053 subcnt = 0;
1054 for (i = 0; i < num_printers; i++) {
1056 uint32_t num_jobs;
1057 struct policy_handle handle;
1058 const char *printername;
1060 printername = talloc_strdup(mem_ctx, printer_info[i].info2.printername);
1061 if (printername == NULL) {
1062 goto err;
1065 ZERO_STRUCT(handle);
1066 ZERO_STRUCT(devmode_ctr);
1068 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
1069 printername,
1070 "RAW",
1071 devmode_ctr,
1072 PRINTER_ACCESS_USE,
1073 &handle,
1074 &werr);
1075 if (!NT_STATUS_IS_OK(status)) {
1076 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1077 goto out;
1079 if (!W_ERROR_IS_OK(werr)) {
1080 desc.errcode = W_ERROR_V(werr);
1081 goto out;
1084 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
1085 &handle,
1086 0, /* firstjob */
1087 0xff, /* numjobs */
1088 2, /* level */
1089 0, /* offered */
1090 &num_jobs,
1091 &job_info[i]);
1092 if (!W_ERROR_IS_OK(werr)) {
1093 desc.errcode = W_ERROR_V(werr);
1094 goto out;
1097 if (uLevel==52) {
1098 uint32_t server_major_version;
1099 uint32_t server_minor_version;
1101 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1102 &handle,
1103 "Windows 4.0",
1104 3, /* level */
1106 0, /* version */
1108 &driver_info[i],
1109 &server_major_version,
1110 &server_minor_version);
1111 if (!W_ERROR_IS_OK(werr)) {
1112 desc.errcode = W_ERROR_V(werr);
1113 goto out;
1117 subcntarr[i] = num_jobs;
1118 subcnt += subcntarr[i];
1120 if (cli && is_valid_policy_hnd(&handle)) {
1121 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
1125 if (init_package(&desc,queuecnt,subcnt)) {
1126 for (i = 0; i < num_printers; i++) {
1127 fill_printq_info(uLevel,&desc,subcntarr[i], job_info[i], &driver_info[i].info3, &printer_info[i].info2);
1128 if (desc.errcode == NERR_Success) {
1129 succnt = i;
1134 SAFE_FREE(subcntarr);
1135 out:
1136 *rdata_len = desc.usedlen;
1137 *rparam_len = 8;
1138 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1139 if (!*rparam) {
1140 goto err;
1142 SSVALS(*rparam,0,desc.errcode);
1143 SSVAL(*rparam,2,0);
1144 SSVAL(*rparam,4,succnt);
1145 SSVAL(*rparam,6,queuecnt);
1147 return True;
1149 err:
1151 SAFE_FREE(subcntarr);
1153 return False;
1156 /****************************************************************************
1157 Get info level for a server list query.
1158 ****************************************************************************/
1160 static bool check_server_info(int uLevel, char* id)
1162 switch( uLevel ) {
1163 case 0:
1164 if (strcmp(id,"B16") != 0) {
1165 return False;
1167 break;
1168 case 1:
1169 if (strcmp(id,"B16BBDz") != 0) {
1170 return False;
1172 break;
1173 default:
1174 return False;
1176 return True;
1179 struct srv_info_struct {
1180 fstring name;
1181 uint32 type;
1182 fstring comment;
1183 fstring domain;
1184 bool server_added;
1187 /*******************************************************************
1188 Get server info lists from the files saved by nmbd. Return the
1189 number of entries.
1190 ******************************************************************/
1192 static int get_server_info(uint32 servertype,
1193 struct srv_info_struct **servers,
1194 const char *domain)
1196 int count=0;
1197 int alloced=0;
1198 char **lines;
1199 bool local_list_only;
1200 int i;
1202 lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
1203 if (!lines) {
1204 DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
1205 return 0;
1208 /* request for everything is code for request all servers */
1209 if (servertype == SV_TYPE_ALL) {
1210 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1213 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1215 DEBUG(4,("Servertype search: %8x\n",servertype));
1217 for (i=0;lines[i];i++) {
1218 fstring stype;
1219 struct srv_info_struct *s;
1220 const char *ptr = lines[i];
1221 bool ok = True;
1222 TALLOC_CTX *frame = NULL;
1223 char *p;
1225 if (!*ptr) {
1226 continue;
1229 if (count == alloced) {
1230 alloced += 10;
1231 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1232 if (!*servers) {
1233 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1234 TALLOC_FREE(lines);
1235 return 0;
1237 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1239 s = &(*servers)[count];
1241 frame = talloc_stackframe();
1242 s->name[0] = '\0';
1243 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1244 TALLOC_FREE(frame);
1245 continue;
1247 fstrcpy(s->name, p);
1249 stype[0] = '\0';
1250 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1251 TALLOC_FREE(frame);
1252 continue;
1254 fstrcpy(stype, p);
1256 s->comment[0] = '\0';
1257 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1258 TALLOC_FREE(frame);
1259 continue;
1261 fstrcpy(s->comment, p);
1262 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1264 s->domain[0] = '\0';
1265 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1266 /* this allows us to cope with an old nmbd */
1267 fstrcpy(s->domain,lp_workgroup());
1268 } else {
1269 fstrcpy(s->domain, p);
1271 TALLOC_FREE(frame);
1273 if (sscanf(stype,"%X",&s->type) != 1) {
1274 DEBUG(4,("r:host file "));
1275 ok = False;
1278 /* Filter the servers/domains we return based on what was asked for. */
1280 /* Check to see if we are being asked for a local list only. */
1281 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1282 DEBUG(4,("r: local list only"));
1283 ok = False;
1286 /* doesn't match up: don't want it */
1287 if (!(servertype & s->type)) {
1288 DEBUG(4,("r:serv type "));
1289 ok = False;
1292 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1293 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1294 DEBUG(4,("s: dom mismatch "));
1295 ok = False;
1298 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1299 ok = False;
1302 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1303 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1305 if (ok) {
1306 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1307 s->name, s->type, s->comment, s->domain));
1308 s->server_added = True;
1309 count++;
1310 } else {
1311 DEBUG(4,("%20s %8x %25s %15s\n",
1312 s->name, s->type, s->comment, s->domain));
1316 TALLOC_FREE(lines);
1317 return count;
1320 /*******************************************************************
1321 Fill in a server info structure.
1322 ******************************************************************/
1324 static int fill_srv_info(struct srv_info_struct *service,
1325 int uLevel, char **buf, int *buflen,
1326 char **stringbuf, int *stringspace, char *baseaddr)
1328 int struct_len;
1329 char* p;
1330 char* p2;
1331 int l2;
1332 int len;
1334 switch (uLevel) {
1335 case 0:
1336 struct_len = 16;
1337 break;
1338 case 1:
1339 struct_len = 26;
1340 break;
1341 default:
1342 return -1;
1345 if (!buf) {
1346 len = 0;
1347 switch (uLevel) {
1348 case 1:
1349 len = strlen(service->comment)+1;
1350 break;
1353 *buflen = struct_len;
1354 *stringspace = len;
1355 return struct_len + len;
1358 len = struct_len;
1359 p = *buf;
1360 if (*buflen < struct_len) {
1361 return -1;
1363 if (stringbuf) {
1364 p2 = *stringbuf;
1365 l2 = *stringspace;
1366 } else {
1367 p2 = p + struct_len;
1368 l2 = *buflen - struct_len;
1370 if (!baseaddr) {
1371 baseaddr = p;
1374 switch (uLevel) {
1375 case 0:
1376 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1377 break;
1379 case 1:
1380 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1381 SIVAL(p,18,service->type);
1382 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1383 len += CopyAndAdvance(&p2,service->comment,&l2);
1384 break;
1387 if (stringbuf) {
1388 *buf = p + struct_len;
1389 *buflen -= struct_len;
1390 *stringbuf = p2;
1391 *stringspace = l2;
1392 } else {
1393 *buf = p2;
1394 *buflen -= len;
1396 return len;
1400 static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1402 return StrCaseCmp(s1->name,s2->name);
1405 /****************************************************************************
1406 View list of servers available (or possibly domains). The info is
1407 extracted from lists saved by nmbd on the local host.
1408 ****************************************************************************/
1410 static bool api_RNetServerEnum2(connection_struct *conn, uint16 vuid,
1411 char *param, int tpscnt,
1412 char *data, int tdscnt,
1413 int mdrcnt, int mprcnt, char **rdata,
1414 char **rparam, int *rdata_len, int *rparam_len)
1416 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1417 char *str2 = skip_string(param,tpscnt,str1);
1418 char *p = skip_string(param,tpscnt,str2);
1419 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1420 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1421 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1422 char *p2;
1423 int data_len, fixed_len, string_len;
1424 int f_len = 0, s_len = 0;
1425 struct srv_info_struct *servers=NULL;
1426 int counted=0,total=0;
1427 int i,missed;
1428 fstring domain;
1429 bool domain_request;
1430 bool local_request;
1432 if (!str1 || !str2 || !p) {
1433 return False;
1436 /* If someone sets all the bits they don't really mean to set
1437 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1438 known servers. */
1440 if (servertype == SV_TYPE_ALL) {
1441 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1444 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1445 any other bit (they may just set this bit on its own) they
1446 want all the locally seen servers. However this bit can be
1447 set on its own so set the requested servers to be
1448 ALL - DOMAIN_ENUM. */
1450 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1451 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1454 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1455 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1457 p += 8;
1459 if (!prefix_ok(str1,"WrLehD")) {
1460 return False;
1462 if (!check_server_info(uLevel,str2)) {
1463 return False;
1466 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1467 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1468 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1470 if (strcmp(str1, "WrLehDz") == 0) {
1471 if (skip_string(param,tpscnt,p) == NULL) {
1472 return False;
1474 pull_ascii_fstring(domain, p);
1475 } else {
1476 fstrcpy(domain, lp_workgroup());
1479 DEBUG(4, ("domain [%s]\n", domain));
1481 if (lp_browse_list()) {
1482 total = get_server_info(servertype,&servers,domain);
1485 data_len = fixed_len = string_len = 0;
1486 missed = 0;
1488 TYPESAFE_QSORT(servers, total, srv_comp);
1491 char *lastname=NULL;
1493 for (i=0;i<total;i++) {
1494 struct srv_info_struct *s = &servers[i];
1496 if (lastname && strequal(lastname,s->name)) {
1497 continue;
1499 lastname = s->name;
1500 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1501 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1502 i, s->name, s->type, s->comment, s->domain));
1504 if (data_len < buf_len) {
1505 counted++;
1506 fixed_len += f_len;
1507 string_len += s_len;
1508 } else {
1509 missed++;
1514 *rdata_len = fixed_len + string_len;
1515 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1516 if (!*rdata) {
1517 return False;
1520 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1521 p = *rdata;
1522 f_len = fixed_len;
1523 s_len = string_len;
1526 char *lastname=NULL;
1527 int count2 = counted;
1529 for (i = 0; i < total && count2;i++) {
1530 struct srv_info_struct *s = &servers[i];
1532 if (lastname && strequal(lastname,s->name)) {
1533 continue;
1535 lastname = s->name;
1536 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1537 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1538 i, s->name, s->type, s->comment, s->domain));
1539 count2--;
1543 *rparam_len = 8;
1544 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1545 if (!*rparam) {
1546 return False;
1548 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1549 SSVAL(*rparam,2,0);
1550 SSVAL(*rparam,4,counted);
1551 SSVAL(*rparam,6,counted+missed);
1553 SAFE_FREE(servers);
1555 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1556 domain,uLevel,counted,counted+missed));
1558 return True;
1561 static int srv_name_match(const char *n1, const char *n2)
1564 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1566 * In Windows, FirstNameToReturn need not be an exact match:
1567 * the server will return a list of servers that exist on
1568 * the network greater than or equal to the FirstNameToReturn.
1570 int ret = StrCaseCmp(n1, n2);
1572 if (ret <= 0) {
1573 return 0;
1576 return ret;
1579 static bool api_RNetServerEnum3(connection_struct *conn, uint16 vuid,
1580 char *param, int tpscnt,
1581 char *data, int tdscnt,
1582 int mdrcnt, int mprcnt, char **rdata,
1583 char **rparam, int *rdata_len, int *rparam_len)
1585 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1586 char *str2 = skip_string(param,tpscnt,str1);
1587 char *p = skip_string(param,tpscnt,str2);
1588 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1589 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1590 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1591 char *p2;
1592 int data_len, fixed_len, string_len;
1593 int f_len = 0, s_len = 0;
1594 struct srv_info_struct *servers=NULL;
1595 int counted=0,first=0,total=0;
1596 int i,missed;
1597 fstring domain;
1598 fstring first_name;
1599 bool domain_request;
1600 bool local_request;
1602 if (!str1 || !str2 || !p) {
1603 return False;
1606 /* If someone sets all the bits they don't really mean to set
1607 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1608 known servers. */
1610 if (servertype == SV_TYPE_ALL) {
1611 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1614 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1615 any other bit (they may just set this bit on its own) they
1616 want all the locally seen servers. However this bit can be
1617 set on its own so set the requested servers to be
1618 ALL - DOMAIN_ENUM. */
1620 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1621 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1624 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1625 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1627 p += 8;
1629 if (strcmp(str1, "WrLehDzz") != 0) {
1630 return false;
1632 if (!check_server_info(uLevel,str2)) {
1633 return False;
1636 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1637 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1638 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1640 if (skip_string(param,tpscnt,p) == NULL) {
1641 return False;
1643 pull_ascii_fstring(domain, p);
1644 if (domain[0] == '\0') {
1645 fstrcpy(domain, lp_workgroup());
1647 p = skip_string(param,tpscnt,p);
1648 if (skip_string(param,tpscnt,p) == NULL) {
1649 return False;
1651 pull_ascii_fstring(first_name, p);
1653 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1654 domain, first_name));
1656 if (lp_browse_list()) {
1657 total = get_server_info(servertype,&servers,domain);
1660 data_len = fixed_len = string_len = 0;
1661 missed = 0;
1663 TYPESAFE_QSORT(servers, total, srv_comp);
1665 if (first_name[0] != '\0') {
1666 struct srv_info_struct *first_server = NULL;
1668 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1669 srv_name_match, first_server);
1670 if (first_server) {
1671 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1673 * The binary search may not find the exact match
1674 * so we need to search backward to find the first match
1676 * This implements the strange matching windows
1677 * implements. (see the comment in srv_name_match().
1679 for (;first > 0;) {
1680 int ret;
1681 ret = StrCaseCmp(first_name,
1682 servers[first-1].name);
1683 if (ret > 0) {
1684 break;
1686 first--;
1688 } else {
1689 /* we should return no entries */
1690 first = total;
1695 char *lastname=NULL;
1697 for (i=first;i<total;i++) {
1698 struct srv_info_struct *s = &servers[i];
1700 if (lastname && strequal(lastname,s->name)) {
1701 continue;
1703 lastname = s->name;
1704 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1705 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1706 i, s->name, s->type, s->comment, s->domain));
1708 if (data_len < buf_len) {
1709 counted++;
1710 fixed_len += f_len;
1711 string_len += s_len;
1712 } else {
1713 missed++;
1718 *rdata_len = fixed_len + string_len;
1719 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1720 if (!*rdata) {
1721 return False;
1724 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1725 p = *rdata;
1726 f_len = fixed_len;
1727 s_len = string_len;
1730 char *lastname=NULL;
1731 int count2 = counted;
1733 for (i = first; i < total && count2;i++) {
1734 struct srv_info_struct *s = &servers[i];
1736 if (lastname && strequal(lastname,s->name)) {
1737 continue;
1739 lastname = s->name;
1740 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1741 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1742 i, s->name, s->type, s->comment, s->domain));
1743 count2--;
1747 *rparam_len = 8;
1748 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1749 if (!*rparam) {
1750 return False;
1752 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1753 SSVAL(*rparam,2,0);
1754 SSVAL(*rparam,4,counted);
1755 SSVAL(*rparam,6,counted+missed);
1757 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1758 domain,uLevel,first,first_name,
1759 first < total ? servers[first].name : "",
1760 counted,counted+missed));
1762 SAFE_FREE(servers);
1764 return True;
1767 /****************************************************************************
1768 command 0x34 - suspected of being a "Lookup Names" stub api
1769 ****************************************************************************/
1771 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1772 char *param, int tpscnt,
1773 char *data, int tdscnt,
1774 int mdrcnt, int mprcnt, char **rdata,
1775 char **rparam, int *rdata_len, int *rparam_len)
1777 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1778 char *str2 = skip_string(param,tpscnt,str1);
1779 char *p = skip_string(param,tpscnt,str2);
1780 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1781 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1782 int counted=0;
1783 int missed=0;
1785 if (!str1 || !str2 || !p) {
1786 return False;
1789 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1790 str1, str2, p, uLevel, buf_len));
1792 if (!prefix_ok(str1,"zWrLeh")) {
1793 return False;
1796 *rdata_len = 0;
1798 *rparam_len = 8;
1799 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1800 if (!*rparam) {
1801 return False;
1804 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1805 SSVAL(*rparam,2,0);
1806 SSVAL(*rparam,4,counted);
1807 SSVAL(*rparam,6,counted+missed);
1809 return True;
1812 /****************************************************************************
1813 get info about a share
1814 ****************************************************************************/
1816 static bool check_share_info(int uLevel, char* id)
1818 switch( uLevel ) {
1819 case 0:
1820 if (strcmp(id,"B13") != 0) {
1821 return False;
1823 break;
1824 case 1:
1825 /* Level-2 descriptor is allowed (and ignored) */
1826 if (strcmp(id,"B13BWz") != 0 &&
1827 strcmp(id,"B13BWzWWWzB9B") != 0) {
1828 return False;
1830 break;
1831 case 2:
1832 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1833 return False;
1835 break;
1836 case 91:
1837 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1838 return False;
1840 break;
1841 default:
1842 return False;
1844 return True;
1847 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1848 char** buf, int* buflen,
1849 char** stringbuf, int* stringspace, char* baseaddr)
1851 int struct_len;
1852 char* p;
1853 char* p2;
1854 int l2;
1855 int len;
1857 switch( uLevel ) {
1858 case 0:
1859 struct_len = 13;
1860 break;
1861 case 1:
1862 struct_len = 20;
1863 break;
1864 case 2:
1865 struct_len = 40;
1866 break;
1867 case 91:
1868 struct_len = 68;
1869 break;
1870 default:
1871 return -1;
1874 if (!buf) {
1875 len = 0;
1877 if (uLevel > 0) {
1878 len += StrlenExpanded(conn,snum,lp_comment(snum));
1880 if (uLevel > 1) {
1881 len += strlen(lp_pathname(snum)) + 1;
1883 if (buflen) {
1884 *buflen = struct_len;
1886 if (stringspace) {
1887 *stringspace = len;
1889 return struct_len + len;
1892 len = struct_len;
1893 p = *buf;
1894 if ((*buflen) < struct_len) {
1895 return -1;
1898 if (stringbuf) {
1899 p2 = *stringbuf;
1900 l2 = *stringspace;
1901 } else {
1902 p2 = p + struct_len;
1903 l2 = (*buflen) - struct_len;
1906 if (!baseaddr) {
1907 baseaddr = p;
1910 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1912 if (uLevel > 0) {
1913 int type;
1915 SCVAL(p,13,0);
1916 type = STYPE_DISKTREE;
1917 if (lp_print_ok(snum)) {
1918 type = STYPE_PRINTQ;
1920 if (strequal("IPC",lp_fstype(snum))) {
1921 type = STYPE_IPC;
1923 SSVAL(p,14,type); /* device type */
1924 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1925 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1928 if (uLevel > 1) {
1929 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1930 SSVALS(p,22,-1); /* max uses */
1931 SSVAL(p,24,1); /* current uses */
1932 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1933 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1934 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1937 if (uLevel > 2) {
1938 memset(p+40,0,SHPWLEN+2);
1939 SSVAL(p,50,0);
1940 SIVAL(p,52,0);
1941 SSVAL(p,56,0);
1942 SSVAL(p,58,0);
1943 SIVAL(p,60,0);
1944 SSVAL(p,64,0);
1945 SSVAL(p,66,0);
1948 if (stringbuf) {
1949 (*buf) = p + struct_len;
1950 (*buflen) -= struct_len;
1951 (*stringbuf) = p2;
1952 (*stringspace) = l2;
1953 } else {
1954 (*buf) = p2;
1955 (*buflen) -= len;
1958 return len;
1961 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1962 char *param, int tpscnt,
1963 char *data, int tdscnt,
1964 int mdrcnt,int mprcnt,
1965 char **rdata,char **rparam,
1966 int *rdata_len,int *rparam_len)
1968 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1969 char *str2 = skip_string(param,tpscnt,str1);
1970 char *netname = skip_string(param,tpscnt,str2);
1971 char *p = skip_string(param,tpscnt,netname);
1972 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1973 int snum;
1975 if (!str1 || !str2 || !netname || !p) {
1976 return False;
1979 snum = find_service(netname);
1980 if (snum < 0) {
1981 return False;
1984 /* check it's a supported varient */
1985 if (!prefix_ok(str1,"zWrLh")) {
1986 return False;
1988 if (!check_share_info(uLevel,str2)) {
1989 return False;
1992 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1993 if (!*rdata) {
1994 return False;
1996 p = *rdata;
1997 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1998 if (*rdata_len < 0) {
1999 return False;
2002 *rparam_len = 6;
2003 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2004 if (!*rparam) {
2005 return False;
2007 SSVAL(*rparam,0,NERR_Success);
2008 SSVAL(*rparam,2,0); /* converter word */
2009 SSVAL(*rparam,4,*rdata_len);
2011 return True;
2014 /****************************************************************************
2015 View the list of available shares.
2017 This function is the server side of the NetShareEnum() RAP call.
2018 It fills the return buffer with share names and share comments.
2019 Note that the return buffer normally (in all known cases) allows only
2020 twelve byte strings for share names (plus one for a nul terminator).
2021 Share names longer than 12 bytes must be skipped.
2022 ****************************************************************************/
2024 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
2025 char *param, int tpscnt,
2026 char *data, int tdscnt,
2027 int mdrcnt,
2028 int mprcnt,
2029 char **rdata,
2030 char **rparam,
2031 int *rdata_len,
2032 int *rparam_len )
2034 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2035 char *str2 = skip_string(param,tpscnt,str1);
2036 char *p = skip_string(param,tpscnt,str2);
2037 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2038 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
2039 char *p2;
2040 int count = 0;
2041 int total=0,counted=0;
2042 bool missed = False;
2043 int i;
2044 int data_len, fixed_len, string_len;
2045 int f_len = 0, s_len = 0;
2047 if (!str1 || !str2 || !p) {
2048 return False;
2051 if (!prefix_ok(str1,"WrLeh")) {
2052 return False;
2054 if (!check_share_info(uLevel,str2)) {
2055 return False;
2058 /* Ensure all the usershares are loaded. */
2059 become_root();
2060 load_registry_shares();
2061 count = load_usershare_shares();
2062 unbecome_root();
2064 data_len = fixed_len = string_len = 0;
2065 for (i=0;i<count;i++) {
2066 fstring servicename_dos;
2067 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2068 continue;
2070 push_ascii_fstring(servicename_dos, lp_servicename(i));
2071 /* Maximum name length = 13. */
2072 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
2073 total++;
2074 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
2075 if (data_len < buf_len) {
2076 counted++;
2077 fixed_len += f_len;
2078 string_len += s_len;
2079 } else {
2080 missed = True;
2085 *rdata_len = fixed_len + string_len;
2086 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2087 if (!*rdata) {
2088 return False;
2091 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
2092 p = *rdata;
2093 f_len = fixed_len;
2094 s_len = string_len;
2096 for( i = 0; i < count; i++ ) {
2097 fstring servicename_dos;
2098 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2099 continue;
2102 push_ascii_fstring(servicename_dos, lp_servicename(i));
2103 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2104 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2105 break;
2110 *rparam_len = 8;
2111 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2112 if (!*rparam) {
2113 return False;
2115 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2116 SSVAL(*rparam,2,0);
2117 SSVAL(*rparam,4,counted);
2118 SSVAL(*rparam,6,total);
2120 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2121 counted,total,uLevel,
2122 buf_len,*rdata_len,mdrcnt));
2124 return True;
2127 /****************************************************************************
2128 Add a share
2129 ****************************************************************************/
2131 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
2132 char *param, int tpscnt,
2133 char *data, int tdscnt,
2134 int mdrcnt,int mprcnt,
2135 char **rdata,char **rparam,
2136 int *rdata_len,int *rparam_len)
2138 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2139 char *str2 = skip_string(param,tpscnt,str1);
2140 char *p = skip_string(param,tpscnt,str2);
2141 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2142 fstring sharename;
2143 fstring comment;
2144 char *pathname = NULL;
2145 unsigned int offset;
2146 int res = ERRunsup;
2147 size_t converted_size;
2149 WERROR werr = WERR_OK;
2150 TALLOC_CTX *mem_ctx = talloc_tos();
2151 NTSTATUS status;
2152 struct rpc_pipe_client *cli = NULL;
2153 union srvsvc_NetShareInfo info;
2154 struct srvsvc_NetShareInfo2 info2;
2156 if (!str1 || !str2 || !p) {
2157 return False;
2160 /* check it's a supported varient */
2161 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2162 return False;
2164 if (!check_share_info(uLevel,str2)) {
2165 return False;
2167 if (uLevel != 2) {
2168 return False;
2171 /* Do we have a string ? */
2172 if (skip_string(data,mdrcnt,data) == NULL) {
2173 return False;
2175 pull_ascii_fstring(sharename,data);
2177 if (mdrcnt < 28) {
2178 return False;
2181 /* only support disk share adds */
2182 if (SVAL(data,14)!=STYPE_DISKTREE) {
2183 return False;
2186 offset = IVAL(data, 16);
2187 if (offset >= mdrcnt) {
2188 res = ERRinvalidparam;
2189 goto out;
2192 /* Do we have a string ? */
2193 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2194 return False;
2196 pull_ascii_fstring(comment, offset? (data+offset) : "");
2198 offset = IVAL(data, 26);
2200 if (offset >= mdrcnt) {
2201 res = ERRinvalidparam;
2202 goto out;
2205 /* Do we have a string ? */
2206 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2207 return False;
2210 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2211 offset ? (data+offset) : "", &converted_size))
2213 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
2214 strerror(errno)));
2217 if (!pathname) {
2218 return false;
2221 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_srvsvc.syntax_id,
2222 rpc_srvsvc_dispatch, conn->server_info,
2223 &cli);
2224 if (!NT_STATUS_IS_OK(status)) {
2225 DEBUG(0,("api_RNetShareAdd: could not connect to srvsvc: %s\n",
2226 nt_errstr(status)));
2227 res = W_ERROR_V(ntstatus_to_werror(status));
2228 goto out;
2231 info2.name = sharename;
2232 info2.type = STYPE_DISKTREE;
2233 info2.comment = comment;
2234 info2.permissions = 0;
2235 info2.max_users = 0;
2236 info2.current_users = 0;
2237 info2.path = pathname;
2238 info2.password = NULL;
2240 info.info2 = &info2;
2242 status = rpccli_srvsvc_NetShareAdd(cli, mem_ctx,
2243 cli->srv_name_slash,
2245 &info,
2246 NULL,
2247 &werr);
2248 if (!NT_STATUS_IS_OK(status)) {
2249 res = W_ERROR_V(ntstatus_to_werror(status));
2250 goto out;
2252 if (!W_ERROR_IS_OK(werr)) {
2253 res = W_ERROR_V(werr);
2254 goto out;
2257 *rparam_len = 6;
2258 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2259 if (!*rparam) {
2260 return False;
2262 SSVAL(*rparam,0,NERR_Success);
2263 SSVAL(*rparam,2,0); /* converter word */
2264 SSVAL(*rparam,4,*rdata_len);
2265 *rdata_len = 0;
2267 return True;
2269 out:
2271 *rparam_len = 4;
2272 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2273 if (!*rparam) {
2274 return False;
2276 *rdata_len = 0;
2277 SSVAL(*rparam,0,res);
2278 SSVAL(*rparam,2,0);
2279 return True;
2282 /****************************************************************************
2283 view list of groups available
2284 ****************************************************************************/
2286 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
2287 char *param, int tpscnt,
2288 char *data, int tdscnt,
2289 int mdrcnt,int mprcnt,
2290 char **rdata,char **rparam,
2291 int *rdata_len,int *rparam_len)
2293 int i;
2294 int errflags=0;
2295 int resume_context, cli_buf_size;
2296 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2297 char *str2 = skip_string(param,tpscnt,str1);
2298 char *p = skip_string(param,tpscnt,str2);
2300 uint32_t num_groups;
2301 uint32_t resume_handle;
2302 struct rpc_pipe_client *samr_pipe;
2303 struct policy_handle samr_handle, domain_handle;
2304 NTSTATUS status;
2306 if (!str1 || !str2 || !p) {
2307 return False;
2310 if (strcmp(str1,"WrLeh") != 0) {
2311 return False;
2314 /* parameters
2315 * W-> resume context (number of users to skip)
2316 * r -> return parameter pointer to receive buffer
2317 * L -> length of receive buffer
2318 * e -> return parameter number of entries
2319 * h -> return parameter total number of users
2322 if (strcmp("B21",str2) != 0) {
2323 return False;
2326 status = rpc_pipe_open_internal(
2327 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2328 conn->server_info, &samr_pipe);
2329 if (!NT_STATUS_IS_OK(status)) {
2330 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2331 nt_errstr(status)));
2332 return false;
2335 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2336 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2337 if (!NT_STATUS_IS_OK(status)) {
2338 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2339 nt_errstr(status)));
2340 return false;
2343 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2344 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2345 get_global_sam_sid(), &domain_handle);
2346 if (!NT_STATUS_IS_OK(status)) {
2347 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2348 nt_errstr(status)));
2349 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2350 return false;
2353 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2354 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2355 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2356 "%d\n", resume_context, cli_buf_size));
2358 *rdata_len = cli_buf_size;
2359 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2360 if (!*rdata) {
2361 return False;
2364 p = *rdata;
2366 errflags = NERR_Success;
2367 num_groups = 0;
2368 resume_handle = 0;
2370 while (true) {
2371 struct samr_SamArray *sam_entries;
2372 uint32_t num_entries;
2374 status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
2375 &domain_handle,
2376 &resume_handle,
2377 &sam_entries, 1,
2378 &num_entries);
2379 if (!NT_STATUS_IS_OK(status)) {
2380 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2381 "%s\n", nt_errstr(status)));
2382 break;
2385 if (num_entries == 0) {
2386 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2387 "no entries -- done\n"));
2388 break;
2391 for(i=0; i<num_entries; i++) {
2392 const char *name;
2394 name = sam_entries->entries[i].name.string;
2396 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2397 /* set overflow error */
2398 DEBUG(3,("overflow on entry %d group %s\n", i,
2399 name));
2400 errflags=234;
2401 break;
2404 /* truncate the name at 21 chars. */
2405 memset(p, 0, 21);
2406 strlcpy(p, name, 21);
2407 DEBUG(10,("adding entry %d group %s\n", i, p));
2408 p += 21;
2409 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2410 * idea why... */
2411 num_groups += 1;
2414 if (errflags != NERR_Success) {
2415 break;
2418 TALLOC_FREE(sam_entries);
2421 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2422 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2424 *rdata_len = PTR_DIFF(p,*rdata);
2426 *rparam_len = 8;
2427 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2428 if (!*rparam) {
2429 return False;
2431 SSVAL(*rparam, 0, errflags);
2432 SSVAL(*rparam, 2, 0); /* converter word */
2433 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2434 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2436 return(True);
2439 /*******************************************************************
2440 Get groups that a user is a member of.
2441 ******************************************************************/
2443 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2444 char *param, int tpscnt,
2445 char *data, int tdscnt,
2446 int mdrcnt,int mprcnt,
2447 char **rdata,char **rparam,
2448 int *rdata_len,int *rparam_len)
2450 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2451 char *str2 = skip_string(param,tpscnt,str1);
2452 char *UserName = skip_string(param,tpscnt,str2);
2453 char *p = skip_string(param,tpscnt,UserName);
2454 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2455 const char *level_string;
2456 int count=0;
2457 bool ret = False;
2458 uint32_t i;
2459 char *endp = NULL;
2461 struct rpc_pipe_client *samr_pipe;
2462 struct policy_handle samr_handle, domain_handle, user_handle;
2463 struct lsa_String name;
2464 struct lsa_Strings names;
2465 struct samr_Ids type, rid;
2466 struct samr_RidWithAttributeArray *rids;
2467 NTSTATUS status;
2469 if (!str1 || !str2 || !UserName || !p) {
2470 return False;
2473 *rparam_len = 8;
2474 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2475 if (!*rparam) {
2476 return False;
2479 /* check it's a supported varient */
2481 if ( strcmp(str1,"zWrLeh") != 0 )
2482 return False;
2484 switch( uLevel ) {
2485 case 0:
2486 level_string = "B21";
2487 break;
2488 default:
2489 return False;
2492 if (strcmp(level_string,str2) != 0)
2493 return False;
2495 *rdata_len = mdrcnt + 1024;
2496 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2497 if (!*rdata) {
2498 return False;
2501 SSVAL(*rparam,0,NERR_Success);
2502 SSVAL(*rparam,2,0); /* converter word */
2504 p = *rdata;
2505 endp = *rdata + *rdata_len;
2507 status = rpc_pipe_open_internal(
2508 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2509 conn->server_info, &samr_pipe);
2510 if (!NT_STATUS_IS_OK(status)) {
2511 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2512 nt_errstr(status)));
2513 return false;
2516 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2517 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2518 if (!NT_STATUS_IS_OK(status)) {
2519 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2520 nt_errstr(status)));
2521 return false;
2524 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2525 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2526 get_global_sam_sid(), &domain_handle);
2527 if (!NT_STATUS_IS_OK(status)) {
2528 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2529 nt_errstr(status)));
2530 goto close_sam;
2533 name.string = UserName;
2535 status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
2536 &domain_handle, 1, &name,
2537 &rid, &type);
2538 if (!NT_STATUS_IS_OK(status)) {
2539 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2540 nt_errstr(status)));
2541 goto close_domain;
2544 if (type.ids[0] != SID_NAME_USER) {
2545 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2546 sid_type_lookup(type.ids[0])));
2547 goto close_domain;
2550 status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
2551 &domain_handle,
2552 SAMR_USER_ACCESS_GET_GROUPS,
2553 rid.ids[0], &user_handle);
2554 if (!NT_STATUS_IS_OK(status)) {
2555 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2556 nt_errstr(status)));
2557 goto close_domain;
2560 status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
2561 &user_handle, &rids);
2562 if (!NT_STATUS_IS_OK(status)) {
2563 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2564 nt_errstr(status)));
2565 goto close_user;
2568 for (i=0; i<rids->count; i++) {
2570 status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
2571 &domain_handle,
2572 1, &rids->rids[i].rid,
2573 &names, &type);
2574 if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
2575 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2576 p += 21;
2577 count++;
2581 *rdata_len = PTR_DIFF(p,*rdata);
2583 SSVAL(*rparam,4,count); /* is this right?? */
2584 SSVAL(*rparam,6,count); /* is this right?? */
2586 ret = True;
2588 close_user:
2589 rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
2590 close_domain:
2591 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2592 close_sam:
2593 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2595 return ret;
2598 /*******************************************************************
2599 Get all users.
2600 ******************************************************************/
2602 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2603 char *param, int tpscnt,
2604 char *data, int tdscnt,
2605 int mdrcnt,int mprcnt,
2606 char **rdata,char **rparam,
2607 int *rdata_len,int *rparam_len)
2609 int count_sent=0;
2610 int num_users=0;
2611 int errflags=0;
2612 int i, resume_context, cli_buf_size;
2613 uint32_t resume_handle;
2615 struct rpc_pipe_client *samr_pipe;
2616 struct policy_handle samr_handle, domain_handle;
2617 NTSTATUS status;
2619 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2620 char *str2 = skip_string(param,tpscnt,str1);
2621 char *p = skip_string(param,tpscnt,str2);
2622 char *endp = NULL;
2624 if (!str1 || !str2 || !p) {
2625 return False;
2628 if (strcmp(str1,"WrLeh") != 0)
2629 return False;
2630 /* parameters
2631 * W-> resume context (number of users to skip)
2632 * r -> return parameter pointer to receive buffer
2633 * L -> length of receive buffer
2634 * e -> return parameter number of entries
2635 * h -> return parameter total number of users
2638 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2639 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2640 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2641 resume_context, cli_buf_size));
2643 *rparam_len = 8;
2644 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2645 if (!*rparam) {
2646 return False;
2649 /* check it's a supported varient */
2650 if (strcmp("B21",str2) != 0)
2651 return False;
2653 *rdata_len = cli_buf_size;
2654 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2655 if (!*rdata) {
2656 return False;
2659 p = *rdata;
2660 endp = *rdata + *rdata_len;
2662 status = rpc_pipe_open_internal(
2663 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2664 conn->server_info, &samr_pipe);
2665 if (!NT_STATUS_IS_OK(status)) {
2666 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2667 nt_errstr(status)));
2668 return false;
2671 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2672 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2673 if (!NT_STATUS_IS_OK(status)) {
2674 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2675 nt_errstr(status)));
2676 return false;
2679 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2680 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2681 get_global_sam_sid(), &domain_handle);
2682 if (!NT_STATUS_IS_OK(status)) {
2683 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2684 nt_errstr(status)));
2685 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2686 return false;
2689 errflags=NERR_Success;
2691 resume_handle = 0;
2693 while (true) {
2694 struct samr_SamArray *sam_entries;
2695 uint32_t num_entries;
2697 status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
2698 &domain_handle,
2699 &resume_handle,
2700 0, &sam_entries, 1,
2701 &num_entries);
2703 if (!NT_STATUS_IS_OK(status)) {
2704 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2705 "%s\n", nt_errstr(status)));
2706 break;
2709 if (num_entries == 0) {
2710 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2711 "no entries -- done\n"));
2712 break;
2715 for (i=0; i<num_entries; i++) {
2716 const char *name;
2718 name = sam_entries->entries[i].name.string;
2720 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2721 &&(strlen(name)<=21)) {
2722 strlcpy(p,name,PTR_DIFF(endp,p));
2723 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2724 "username %s\n",count_sent,p));
2725 p += 21;
2726 count_sent++;
2727 } else {
2728 /* set overflow error */
2729 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2730 "username %s\n",count_sent,name));
2731 errflags=234;
2732 break;
2736 if (errflags != NERR_Success) {
2737 break;
2740 TALLOC_FREE(sam_entries);
2743 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2744 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2746 *rdata_len = PTR_DIFF(p,*rdata);
2748 SSVAL(*rparam,0,errflags);
2749 SSVAL(*rparam,2,0); /* converter word */
2750 SSVAL(*rparam,4,count_sent); /* is this right?? */
2751 SSVAL(*rparam,6,num_users); /* is this right?? */
2753 return True;
2756 /****************************************************************************
2757 Get the time of day info.
2758 ****************************************************************************/
2760 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2761 char *param, int tpscnt,
2762 char *data, int tdscnt,
2763 int mdrcnt,int mprcnt,
2764 char **rdata,char **rparam,
2765 int *rdata_len,int *rparam_len)
2767 struct tm *t;
2768 time_t unixdate = time(NULL);
2769 char *p;
2771 *rparam_len = 4;
2772 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2773 if (!*rparam) {
2774 return False;
2777 *rdata_len = 21;
2778 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2779 if (!*rdata) {
2780 return False;
2783 SSVAL(*rparam,0,NERR_Success);
2784 SSVAL(*rparam,2,0); /* converter word */
2786 p = *rdata;
2788 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2789 by NT in a "net time" operation,
2790 it seems to ignore the one below */
2792 /* the client expects to get localtime, not GMT, in this bit
2793 (I think, this needs testing) */
2794 t = localtime(&unixdate);
2795 if (!t) {
2796 return False;
2799 SIVAL(p,4,0); /* msecs ? */
2800 SCVAL(p,8,t->tm_hour);
2801 SCVAL(p,9,t->tm_min);
2802 SCVAL(p,10,t->tm_sec);
2803 SCVAL(p,11,0); /* hundredths of seconds */
2804 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2805 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2806 SCVAL(p,16,t->tm_mday);
2807 SCVAL(p,17,t->tm_mon + 1);
2808 SSVAL(p,18,1900+t->tm_year);
2809 SCVAL(p,20,t->tm_wday);
2811 return True;
2814 /****************************************************************************
2815 Set the user password.
2816 *****************************************************************************/
2818 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2819 char *param, int tpscnt,
2820 char *data, int tdscnt,
2821 int mdrcnt,int mprcnt,
2822 char **rdata,char **rparam,
2823 int *rdata_len,int *rparam_len)
2825 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2826 char *p = NULL;
2827 fstring user;
2828 fstring pass1,pass2;
2830 /* Skip 2 strings. */
2831 p = skip_string(param,tpscnt,np);
2832 p = skip_string(param,tpscnt,p);
2834 if (!np || !p) {
2835 return False;
2838 /* Do we have a string ? */
2839 if (skip_string(param,tpscnt,p) == NULL) {
2840 return False;
2842 pull_ascii_fstring(user,p);
2844 p = skip_string(param,tpscnt,p);
2845 if (!p) {
2846 return False;
2849 memset(pass1,'\0',sizeof(pass1));
2850 memset(pass2,'\0',sizeof(pass2));
2852 * We use 31 here not 32 as we're checking
2853 * the last byte we want to access is safe.
2855 if (!is_offset_safe(param,tpscnt,p,31)) {
2856 return False;
2858 memcpy(pass1,p,16);
2859 memcpy(pass2,p+16,16);
2861 *rparam_len = 4;
2862 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2863 if (!*rparam) {
2864 return False;
2867 *rdata_len = 0;
2869 SSVAL(*rparam,0,NERR_badpass);
2870 SSVAL(*rparam,2,0); /* converter word */
2872 DEBUG(3,("Set password for <%s>\n",user));
2875 * Attempt to verify the old password against smbpasswd entries
2876 * Win98 clients send old and new password in plaintext for this call.
2880 struct auth_serversupplied_info *server_info = NULL;
2881 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2883 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2885 become_root();
2886 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2887 SSVAL(*rparam,0,NERR_Success);
2889 unbecome_root();
2891 TALLOC_FREE(server_info);
2893 data_blob_clear_free(&password);
2897 * If the plaintext change failed, attempt
2898 * the old encrypted method. NT will generate this
2899 * after trying the samr method. Note that this
2900 * method is done as a last resort as this
2901 * password change method loses the NT password hash
2902 * and cannot change the UNIX password as no plaintext
2903 * is received.
2906 if(SVAL(*rparam,0) != NERR_Success) {
2907 struct samu *hnd = NULL;
2909 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2910 become_root();
2911 if (change_lanman_password(hnd,(uchar *)pass2)) {
2912 SSVAL(*rparam,0,NERR_Success);
2914 unbecome_root();
2915 TALLOC_FREE(hnd);
2919 memset((char *)pass1,'\0',sizeof(fstring));
2920 memset((char *)pass2,'\0',sizeof(fstring));
2922 return(True);
2925 /****************************************************************************
2926 Set the user password (SamOEM version - gets plaintext).
2927 ****************************************************************************/
2929 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2930 char *param, int tpscnt,
2931 char *data, int tdscnt,
2932 int mdrcnt,int mprcnt,
2933 char **rdata,char **rparam,
2934 int *rdata_len,int *rparam_len)
2936 fstring user;
2937 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2939 TALLOC_CTX *mem_ctx = talloc_tos();
2940 NTSTATUS status;
2941 struct rpc_pipe_client *cli = NULL;
2942 struct lsa_AsciiString server, account;
2943 struct samr_CryptPassword password;
2944 struct samr_Password hash;
2945 int errcode = NERR_badpass;
2946 int bufsize;
2948 *rparam_len = 4;
2949 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2950 if (!*rparam) {
2951 return False;
2954 if (!p) {
2955 return False;
2957 *rdata_len = 0;
2959 SSVAL(*rparam,0,NERR_badpass);
2962 * Check the parameter definition is correct.
2965 /* Do we have a string ? */
2966 if (skip_string(param,tpscnt,p) == 0) {
2967 return False;
2969 if(!strequal(p, "zsT")) {
2970 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2971 return False;
2973 p = skip_string(param, tpscnt, p);
2974 if (!p) {
2975 return False;
2978 /* Do we have a string ? */
2979 if (skip_string(param,tpscnt,p) == 0) {
2980 return False;
2982 if(!strequal(p, "B516B16")) {
2983 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2984 return False;
2986 p = skip_string(param,tpscnt,p);
2987 if (!p) {
2988 return False;
2990 /* Do we have a string ? */
2991 if (skip_string(param,tpscnt,p) == 0) {
2992 return False;
2994 p += pull_ascii_fstring(user,p);
2996 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2998 if (tdscnt != 532) {
2999 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3000 goto out;
3003 bufsize = get_safe_SVAL(param,tpscnt,p,0,-1);
3004 if (bufsize != 532) {
3005 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3006 goto out;
3009 memcpy(password.data, data, 516);
3010 memcpy(hash.hash, data+516, 16);
3012 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_samr.syntax_id,
3013 rpc_samr_dispatch, conn->server_info,
3014 &cli);
3015 if (!NT_STATUS_IS_OK(status)) {
3016 DEBUG(0,("api_SamOEMChangePassword: could not connect to samr: %s\n",
3017 nt_errstr(status)));
3018 errcode = W_ERROR_V(ntstatus_to_werror(status));
3019 goto out;
3022 init_lsa_AsciiString(&server, global_myname());
3023 init_lsa_AsciiString(&account, user);
3025 status = rpccli_samr_OemChangePasswordUser2(cli, mem_ctx,
3026 &server,
3027 &account,
3028 &password,
3029 &hash);
3030 if (!NT_STATUS_IS_OK(status)) {
3031 errcode = W_ERROR_V(ntstatus_to_werror(status));
3032 goto out;
3035 errcode = NERR_Success;
3036 out:
3037 SSVAL(*rparam,0,errcode);
3038 SSVAL(*rparam,2,0); /* converter word */
3040 return(True);
3043 /****************************************************************************
3044 delete a print job
3045 Form: <W> <>
3046 ****************************************************************************/
3048 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
3049 char *param, int tpscnt,
3050 char *data, int tdscnt,
3051 int mdrcnt,int mprcnt,
3052 char **rdata,char **rparam,
3053 int *rdata_len,int *rparam_len)
3055 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3056 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3057 char *str2 = skip_string(param,tpscnt,str1);
3058 char *p = skip_string(param,tpscnt,str2);
3059 uint32 jobid;
3060 fstring sharename;
3061 int errcode;
3062 WERROR werr = WERR_OK;
3064 TALLOC_CTX *mem_ctx = talloc_tos();
3065 NTSTATUS status;
3066 struct rpc_pipe_client *cli = NULL;
3067 struct policy_handle handle;
3068 struct spoolss_DevmodeContainer devmode_ctr;
3069 enum spoolss_JobControl command;
3071 if (!str1 || !str2 || !p) {
3072 return False;
3075 * We use 1 here not 2 as we're checking
3076 * the last byte we want to access is safe.
3078 if (!is_offset_safe(param,tpscnt,p,1)) {
3079 return False;
3081 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3082 return False;
3084 /* check it's a supported varient */
3085 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
3086 return(False);
3088 *rparam_len = 4;
3089 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3090 if (!*rparam) {
3091 return False;
3093 *rdata_len = 0;
3095 ZERO_STRUCT(handle);
3097 status = rpc_connect_spoolss_pipe(conn, &cli);
3098 if (!NT_STATUS_IS_OK(status)) {
3099 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
3100 nt_errstr(status)));
3101 errcode = W_ERROR_V(ntstatus_to_werror(status));
3102 goto out;
3105 ZERO_STRUCT(devmode_ctr);
3107 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3108 sharename,
3109 "RAW",
3110 devmode_ctr,
3111 JOB_ACCESS_ADMINISTER,
3112 &handle,
3113 &werr);
3114 if (!NT_STATUS_IS_OK(status)) {
3115 errcode = W_ERROR_V(ntstatus_to_werror(status));
3116 goto out;
3118 if (!W_ERROR_IS_OK(werr)) {
3119 errcode = W_ERROR_V(werr);
3120 goto out;
3123 /* FIXME: formerly NERR_JobNotFound was returned if job did not exist
3124 * and NERR_DestNotFound if share did not exist */
3126 errcode = NERR_Success;
3128 switch (function) {
3129 case 81: /* delete */
3130 command = SPOOLSS_JOB_CONTROL_DELETE;
3131 break;
3132 case 82: /* pause */
3133 command = SPOOLSS_JOB_CONTROL_PAUSE;
3134 break;
3135 case 83: /* resume */
3136 command = SPOOLSS_JOB_CONTROL_RESUME;
3137 break;
3138 default:
3139 errcode = NERR_notsupported;
3140 goto out;
3143 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3144 &handle,
3145 jobid,
3146 NULL, /* unique ptr ctr */
3147 command,
3148 &werr);
3149 if (!NT_STATUS_IS_OK(status)) {
3150 errcode = W_ERROR_V(ntstatus_to_werror(status));
3151 goto out;
3153 if (!W_ERROR_IS_OK(werr)) {
3154 errcode = W_ERROR_V(werr);
3155 goto out;
3158 out:
3159 if (cli && is_valid_policy_hnd(&handle)) {
3160 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3163 SSVAL(*rparam,0,errcode);
3164 SSVAL(*rparam,2,0); /* converter word */
3166 return(True);
3169 /****************************************************************************
3170 Purge a print queue - or pause or resume it.
3171 ****************************************************************************/
3173 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
3174 char *param, int tpscnt,
3175 char *data, int tdscnt,
3176 int mdrcnt,int mprcnt,
3177 char **rdata,char **rparam,
3178 int *rdata_len,int *rparam_len)
3180 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3181 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3182 char *str2 = skip_string(param,tpscnt,str1);
3183 char *QueueName = skip_string(param,tpscnt,str2);
3184 int errcode = NERR_notsupported;
3185 WERROR werr = WERR_OK;
3186 NTSTATUS status;
3188 TALLOC_CTX *mem_ctx = talloc_tos();
3189 struct rpc_pipe_client *cli = NULL;
3190 struct policy_handle handle;
3191 struct spoolss_SetPrinterInfoCtr info_ctr;
3192 struct spoolss_DevmodeContainer devmode_ctr;
3193 struct sec_desc_buf secdesc_ctr;
3194 enum spoolss_PrinterControl command;
3196 if (!str1 || !str2 || !QueueName) {
3197 return False;
3200 /* check it's a supported varient */
3201 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3202 return(False);
3204 *rparam_len = 4;
3205 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3206 if (!*rparam) {
3207 return False;
3209 *rdata_len = 0;
3211 if (skip_string(param,tpscnt,QueueName) == NULL) {
3212 return False;
3215 ZERO_STRUCT(handle);
3217 status = rpc_connect_spoolss_pipe(conn, &cli);
3218 if (!NT_STATUS_IS_OK(status)) {
3219 DEBUG(0,("api_WPrintQueueCtrl: could not connect to spoolss: %s\n",
3220 nt_errstr(status)));
3221 errcode = W_ERROR_V(ntstatus_to_werror(status));
3222 goto out;
3225 ZERO_STRUCT(devmode_ctr);
3227 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3228 QueueName,
3229 NULL,
3230 devmode_ctr,
3231 SEC_FLAG_MAXIMUM_ALLOWED,
3232 &handle,
3233 &werr);
3234 if (!NT_STATUS_IS_OK(status)) {
3235 errcode = W_ERROR_V(ntstatus_to_werror(status));
3236 goto out;
3238 if (!W_ERROR_IS_OK(werr)) {
3239 errcode = W_ERROR_V(werr);
3240 goto out;
3243 switch (function) {
3244 case 74: /* Pause queue */
3245 command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3246 break;
3247 case 75: /* Resume queue */
3248 command = SPOOLSS_PRINTER_CONTROL_RESUME;
3249 break;
3250 case 103: /* Purge */
3251 command = SPOOLSS_PRINTER_CONTROL_PURGE;
3252 break;
3253 default:
3254 werr = WERR_NOT_SUPPORTED;
3255 break;
3258 if (!W_ERROR_IS_OK(werr)) {
3259 errcode = W_ERROR_V(werr);
3260 goto out;
3263 ZERO_STRUCT(info_ctr);
3264 ZERO_STRUCT(secdesc_ctr);
3266 status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
3267 &handle,
3268 &info_ctr,
3269 &devmode_ctr,
3270 &secdesc_ctr,
3271 command,
3272 &werr);
3273 if (!NT_STATUS_IS_OK(status)) {
3274 errcode = W_ERROR_V(ntstatus_to_werror(status));
3275 goto out;
3277 if (!W_ERROR_IS_OK(werr)) {
3278 errcode = W_ERROR_V(werr);
3279 goto out;
3282 errcode = W_ERROR_V(werr);
3284 out:
3286 if (cli && is_valid_policy_hnd(&handle)) {
3287 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3290 SSVAL(*rparam,0,errcode);
3291 SSVAL(*rparam,2,0); /* converter word */
3293 return(True);
3296 /****************************************************************************
3297 set the property of a print job (undocumented?)
3298 ? function = 0xb -> set name of print job
3299 ? function = 0x6 -> move print job up/down
3300 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3301 or <WWsTP> <WB21BB16B10zWWzDDz>
3302 ****************************************************************************/
3304 static int check_printjob_info(struct pack_desc* desc,
3305 int uLevel, char* id)
3307 desc->subformat = NULL;
3308 switch( uLevel ) {
3309 case 0: desc->format = "W"; break;
3310 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3311 case 2: desc->format = "WWzWWDDzz"; break;
3312 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3313 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3314 default:
3315 DEBUG(0,("check_printjob_info: invalid level %d\n",
3316 uLevel ));
3317 return False;
3319 if (id == NULL || strcmp(desc->format,id) != 0) {
3320 DEBUG(0,("check_printjob_info: invalid format %s\n",
3321 id ? id : "<NULL>" ));
3322 return False;
3324 return True;
3327 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
3328 char *param, int tpscnt,
3329 char *data, int tdscnt,
3330 int mdrcnt,int mprcnt,
3331 char **rdata,char **rparam,
3332 int *rdata_len,int *rparam_len)
3334 struct pack_desc desc;
3335 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3336 char *str2 = skip_string(param,tpscnt,str1);
3337 char *p = skip_string(param,tpscnt,str2);
3338 uint32 jobid;
3339 fstring sharename;
3340 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3341 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3342 int errcode;
3344 TALLOC_CTX *mem_ctx = talloc_tos();
3345 WERROR werr;
3346 NTSTATUS status;
3347 struct rpc_pipe_client *cli = NULL;
3348 struct policy_handle handle;
3349 struct spoolss_DevmodeContainer devmode_ctr;
3350 struct spoolss_JobInfoContainer ctr;
3351 union spoolss_JobInfo info;
3352 struct spoolss_SetJobInfo1 info1;
3354 if (!str1 || !str2 || !p) {
3355 return False;
3358 * We use 1 here not 2 as we're checking
3359 * the last byte we want to access is safe.
3361 if (!is_offset_safe(param,tpscnt,p,1)) {
3362 return False;
3364 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3365 return False;
3366 *rparam_len = 4;
3367 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3368 if (!*rparam) {
3369 return False;
3372 *rdata_len = 0;
3374 /* check it's a supported varient */
3375 if ((strcmp(str1,"WWsTP")) ||
3376 (!check_printjob_info(&desc,uLevel,str2)))
3377 return(False);
3379 errcode = NERR_notsupported;
3381 switch (function) {
3382 case 0xb:
3383 /* change print job name, data gives the name */
3384 break;
3385 default:
3386 goto out;
3389 ZERO_STRUCT(handle);
3391 status = rpc_connect_spoolss_pipe(conn, &cli);
3392 if (!NT_STATUS_IS_OK(status)) {
3393 DEBUG(0,("api_PrintJobInfo: could not connect to spoolss: %s\n",
3394 nt_errstr(status)));
3395 errcode = W_ERROR_V(ntstatus_to_werror(status));
3396 goto out;
3399 ZERO_STRUCT(devmode_ctr);
3401 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3402 sharename,
3403 "RAW",
3404 devmode_ctr,
3405 PRINTER_ACCESS_USE,
3406 &handle,
3407 &werr);
3408 if (!NT_STATUS_IS_OK(status)) {
3409 errcode = W_ERROR_V(ntstatus_to_werror(status));
3410 goto out;
3412 if (!W_ERROR_IS_OK(werr)) {
3413 errcode = W_ERROR_V(werr);
3414 goto out;
3417 werr = rpccli_spoolss_getjob(cli, mem_ctx,
3418 &handle,
3419 jobid,
3420 1, /* level */
3421 0, /* offered */
3422 &info);
3423 if (!W_ERROR_IS_OK(werr)) {
3424 errcode = W_ERROR_V(werr);
3425 goto out;
3428 ZERO_STRUCT(ctr);
3430 info1.job_id = info.info1.job_id;
3431 info1.printer_name = info.info1.printer_name;
3432 info1.user_name = info.info1.user_name;
3433 info1.document_name = data;
3434 info1.data_type = info.info1.data_type;
3435 info1.text_status = info.info1.text_status;
3436 info1.status = info.info1.status;
3437 info1.priority = info.info1.priority;
3438 info1.position = info.info1.position;
3439 info1.total_pages = info.info1.total_pages;
3440 info1.pages_printed = info.info1.pages_printed;
3441 info1.submitted = info.info1.submitted;
3443 ctr.level = 1;
3444 ctr.info.info1 = &info1;
3446 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3447 &handle,
3448 jobid,
3449 &ctr,
3451 &werr);
3452 if (!NT_STATUS_IS_OK(status)) {
3453 errcode = W_ERROR_V(ntstatus_to_werror(status));
3454 goto out;
3456 if (!W_ERROR_IS_OK(werr)) {
3457 errcode = W_ERROR_V(werr);
3458 goto out;
3461 errcode = NERR_Success;
3462 out:
3464 if (cli && is_valid_policy_hnd(&handle)) {
3465 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3468 SSVALS(*rparam,0,errcode);
3469 SSVAL(*rparam,2,0); /* converter word */
3471 return(True);
3475 /****************************************************************************
3476 Get info about the server.
3477 ****************************************************************************/
3479 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
3480 char *param, int tpscnt,
3481 char *data, int tdscnt,
3482 int mdrcnt,int mprcnt,
3483 char **rdata,char **rparam,
3484 int *rdata_len,int *rparam_len)
3486 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3487 char *str2 = skip_string(param,tpscnt,str1);
3488 char *p = skip_string(param,tpscnt,str2);
3489 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3490 char *p2;
3491 int struct_len;
3493 NTSTATUS status;
3494 WERROR werr;
3495 TALLOC_CTX *mem_ctx = talloc_tos();
3496 struct rpc_pipe_client *cli = NULL;
3497 union srvsvc_NetSrvInfo info;
3498 int errcode;
3500 if (!str1 || !str2 || !p) {
3501 return False;
3504 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3506 /* check it's a supported varient */
3507 if (!prefix_ok(str1,"WrLh")) {
3508 return False;
3511 switch( uLevel ) {
3512 case 0:
3513 if (strcmp(str2,"B16") != 0) {
3514 return False;
3516 struct_len = 16;
3517 break;
3518 case 1:
3519 if (strcmp(str2,"B16BBDz") != 0) {
3520 return False;
3522 struct_len = 26;
3523 break;
3524 case 2:
3525 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3526 return False;
3528 struct_len = 134;
3529 break;
3530 case 3:
3531 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3532 return False;
3534 struct_len = 144;
3535 break;
3536 case 20:
3537 if (strcmp(str2,"DN") != 0) {
3538 return False;
3540 struct_len = 6;
3541 break;
3542 case 50:
3543 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3544 return False;
3546 struct_len = 42;
3547 break;
3548 default:
3549 return False;
3552 *rdata_len = mdrcnt;
3553 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3554 if (!*rdata) {
3555 return False;
3558 p = *rdata;
3559 p2 = p + struct_len;
3561 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_srvsvc.syntax_id,
3562 rpc_srvsvc_dispatch, conn->server_info,
3563 &cli);
3564 if (!NT_STATUS_IS_OK(status)) {
3565 DEBUG(0,("api_RNetServerGetInfo: could not connect to srvsvc: %s\n",
3566 nt_errstr(status)));
3567 errcode = W_ERROR_V(ntstatus_to_werror(status));
3568 goto out;
3571 status = rpccli_srvsvc_NetSrvGetInfo(cli, mem_ctx,
3572 NULL,
3573 101,
3574 &info,
3575 &werr);
3576 if (!NT_STATUS_IS_OK(status)) {
3577 errcode = W_ERROR_V(ntstatus_to_werror(status));
3578 goto out;
3580 if (!W_ERROR_IS_OK(werr)) {
3581 errcode = W_ERROR_V(werr);
3582 goto out;
3585 if (info.info101 == NULL) {
3586 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3587 goto out;
3590 if (uLevel != 20) {
3591 srvstr_push(NULL, 0, p, info.info101->server_name, 16,
3592 STR_ASCII|STR_UPPER|STR_TERMINATE);
3594 p += 16;
3595 if (uLevel > 0) {
3596 SCVAL(p,0,info.info101->version_major);
3597 SCVAL(p,1,info.info101->version_minor);
3598 SIVAL(p,2,info.info101->server_type);
3600 if (mdrcnt == struct_len) {
3601 SIVAL(p,6,0);
3602 } else {
3603 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3604 if (mdrcnt - struct_len <= 0) {
3605 return false;
3607 push_ascii(p2,
3608 info.info101->comment,
3609 MIN(mdrcnt - struct_len,
3610 MAX_SERVER_STRING_LENGTH),
3611 STR_TERMINATE);
3612 p2 = skip_string(*rdata,*rdata_len,p2);
3613 if (!p2) {
3614 return False;
3619 if (uLevel > 1) {
3620 return False; /* not yet implemented */
3623 errcode = NERR_Success;
3625 out:
3627 *rdata_len = PTR_DIFF(p2,*rdata);
3629 *rparam_len = 6;
3630 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3631 if (!*rparam) {
3632 return False;
3634 SSVAL(*rparam,0,errcode);
3635 SSVAL(*rparam,2,0); /* converter word */
3636 SSVAL(*rparam,4,*rdata_len);
3638 return True;
3641 /****************************************************************************
3642 Get info about the server.
3643 ****************************************************************************/
3645 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3646 char *param, int tpscnt,
3647 char *data, int tdscnt,
3648 int mdrcnt,int mprcnt,
3649 char **rdata,char **rparam,
3650 int *rdata_len,int *rparam_len)
3652 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3653 char *str2 = skip_string(param,tpscnt,str1);
3654 char *p = skip_string(param,tpscnt,str2);
3655 char *p2;
3656 char *endp;
3657 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3659 if (!str1 || !str2 || !p) {
3660 return False;
3663 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3665 *rparam_len = 6;
3666 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3667 if (!*rparam) {
3668 return False;
3671 /* check it's a supported varient */
3672 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3673 return False;
3676 *rdata_len = mdrcnt + 1024;
3677 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3678 if (!*rdata) {
3679 return False;
3682 SSVAL(*rparam,0,NERR_Success);
3683 SSVAL(*rparam,2,0); /* converter word */
3685 p = *rdata;
3686 endp = *rdata + *rdata_len;
3688 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3689 if (!p2) {
3690 return False;
3693 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3694 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3695 strupper_m(p2);
3696 p2 = skip_string(*rdata,*rdata_len,p2);
3697 if (!p2) {
3698 return False;
3700 p += 4;
3702 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3703 strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3704 p2 = skip_string(*rdata,*rdata_len,p2);
3705 if (!p2) {
3706 return False;
3708 p += 4;
3710 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3711 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3712 strupper_m(p2);
3713 p2 = skip_string(*rdata,*rdata_len,p2);
3714 if (!p2) {
3715 return False;
3717 p += 4;
3719 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3720 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3721 p += 2;
3723 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3724 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3725 p2 = skip_string(*rdata,*rdata_len,p2);
3726 if (!p2) {
3727 return False;
3729 p += 4;
3731 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3732 strlcpy(p2,"",PTR_DIFF(endp,p2));
3733 p2 = skip_string(*rdata,*rdata_len,p2);
3734 if (!p2) {
3735 return False;
3737 p += 4;
3739 *rdata_len = PTR_DIFF(p2,*rdata);
3741 SSVAL(*rparam,4,*rdata_len);
3743 return True;
3746 /****************************************************************************
3747 get info about a user
3749 struct user_info_11 {
3750 char usri11_name[21]; 0-20
3751 char usri11_pad; 21
3752 char *usri11_comment; 22-25
3753 char *usri11_usr_comment; 26-29
3754 unsigned short usri11_priv; 30-31
3755 unsigned long usri11_auth_flags; 32-35
3756 long usri11_password_age; 36-39
3757 char *usri11_homedir; 40-43
3758 char *usri11_parms; 44-47
3759 long usri11_last_logon; 48-51
3760 long usri11_last_logoff; 52-55
3761 unsigned short usri11_bad_pw_count; 56-57
3762 unsigned short usri11_num_logons; 58-59
3763 char *usri11_logon_server; 60-63
3764 unsigned short usri11_country_code; 64-65
3765 char *usri11_workstations; 66-69
3766 unsigned long usri11_max_storage; 70-73
3767 unsigned short usri11_units_per_week; 74-75
3768 unsigned char *usri11_logon_hours; 76-79
3769 unsigned short usri11_code_page; 80-81
3772 where:
3774 usri11_name specifies the user name for which information is retrieved
3776 usri11_pad aligns the next data structure element to a word boundary
3778 usri11_comment is a null terminated ASCII comment
3780 usri11_user_comment is a null terminated ASCII comment about the user
3782 usri11_priv specifies the level of the privilege assigned to the user.
3783 The possible values are:
3785 Name Value Description
3786 USER_PRIV_GUEST 0 Guest privilege
3787 USER_PRIV_USER 1 User privilege
3788 USER_PRV_ADMIN 2 Administrator privilege
3790 usri11_auth_flags specifies the account operator privileges. The
3791 possible values are:
3793 Name Value Description
3794 AF_OP_PRINT 0 Print operator
3797 Leach, Naik [Page 28]
3801 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3804 AF_OP_COMM 1 Communications operator
3805 AF_OP_SERVER 2 Server operator
3806 AF_OP_ACCOUNTS 3 Accounts operator
3809 usri11_password_age specifies how many seconds have elapsed since the
3810 password was last changed.
3812 usri11_home_dir points to a null terminated ASCII string that contains
3813 the path name of the user's home directory.
3815 usri11_parms points to a null terminated ASCII string that is set
3816 aside for use by applications.
3818 usri11_last_logon specifies the time when the user last logged on.
3819 This value is stored as the number of seconds elapsed since
3820 00:00:00, January 1, 1970.
3822 usri11_last_logoff specifies the time when the user last logged off.
3823 This value is stored as the number of seconds elapsed since
3824 00:00:00, January 1, 1970. A value of 0 means the last logoff
3825 time is unknown.
3827 usri11_bad_pw_count specifies the number of incorrect passwords
3828 entered since the last successful logon.
3830 usri11_log1_num_logons specifies the number of times this user has
3831 logged on. A value of -1 means the number of logons is unknown.
3833 usri11_logon_server points to a null terminated ASCII string that
3834 contains the name of the server to which logon requests are sent.
3835 A null string indicates logon requests should be sent to the
3836 domain controller.
3838 usri11_country_code specifies the country code for the user's language
3839 of choice.
3841 usri11_workstations points to a null terminated ASCII string that
3842 contains the names of workstations the user may log on from.
3843 There may be up to 8 workstations, with the names separated by
3844 commas. A null strings indicates there are no restrictions.
3846 usri11_max_storage specifies the maximum amount of disk space the user
3847 can occupy. A value of 0xffffffff indicates there are no
3848 restrictions.
3850 usri11_units_per_week specifies the equal number of time units into
3851 which a week is divided. This value must be equal to 168.
3853 usri11_logon_hours points to a 21 byte (168 bits) string that
3854 specifies the time during which the user can log on. Each bit
3855 represents one unique hour in a week. The first bit (bit 0, word
3856 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3860 Leach, Naik [Page 29]
3864 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3867 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3868 are no restrictions.
3870 usri11_code_page specifies the code page for the user's language of
3871 choice
3873 All of the pointers in this data structure need to be treated
3874 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3875 to be ignored. The converter word returned in the parameters section
3876 needs to be subtracted from the lower 16 bits to calculate an offset
3877 into the return buffer where this ASCII string resides.
3879 There is no auxiliary data in the response.
3881 ****************************************************************************/
3883 #define usri11_name 0
3884 #define usri11_pad 21
3885 #define usri11_comment 22
3886 #define usri11_usr_comment 26
3887 #define usri11_full_name 30
3888 #define usri11_priv 34
3889 #define usri11_auth_flags 36
3890 #define usri11_password_age 40
3891 #define usri11_homedir 44
3892 #define usri11_parms 48
3893 #define usri11_last_logon 52
3894 #define usri11_last_logoff 56
3895 #define usri11_bad_pw_count 60
3896 #define usri11_num_logons 62
3897 #define usri11_logon_server 64
3898 #define usri11_country_code 68
3899 #define usri11_workstations 70
3900 #define usri11_max_storage 74
3901 #define usri11_units_per_week 78
3902 #define usri11_logon_hours 80
3903 #define usri11_code_page 84
3904 #define usri11_end 86
3906 #define USER_PRIV_GUEST 0
3907 #define USER_PRIV_USER 1
3908 #define USER_PRIV_ADMIN 2
3910 #define AF_OP_PRINT 0
3911 #define AF_OP_COMM 1
3912 #define AF_OP_SERVER 2
3913 #define AF_OP_ACCOUNTS 3
3916 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3917 char *param, int tpscnt,
3918 char *data, int tdscnt,
3919 int mdrcnt,int mprcnt,
3920 char **rdata,char **rparam,
3921 int *rdata_len,int *rparam_len)
3923 struct smbd_server_connection *sconn = smbd_server_conn;
3924 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3925 char *str2 = skip_string(param,tpscnt,str1);
3926 char *UserName = skip_string(param,tpscnt,str2);
3927 char *p = skip_string(param,tpscnt,UserName);
3928 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3929 char *p2;
3930 char *endp;
3931 const char *level_string;
3933 /* get NIS home of a previously validated user - simeon */
3934 /* With share level security vuid will always be zero.
3935 Don't depend on vuser being non-null !!. JRA */
3936 user_struct *vuser = get_valid_user_struct(sconn, vuid);
3937 if(vuser != NULL) {
3938 DEBUG(3,(" Username of UID %d is %s\n",
3939 (int)vuser->server_info->utok.uid,
3940 vuser->server_info->unix_name));
3943 if (!str1 || !str2 || !UserName || !p) {
3944 return False;
3947 *rparam_len = 6;
3948 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3949 if (!*rparam) {
3950 return False;
3953 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3955 /* check it's a supported variant */
3956 if (strcmp(str1,"zWrLh") != 0) {
3957 return False;
3959 switch( uLevel ) {
3960 case 0: level_string = "B21"; break;
3961 case 1: level_string = "B21BB16DWzzWz"; break;
3962 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3963 case 10: level_string = "B21Bzzz"; break;
3964 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3965 default: return False;
3968 if (strcmp(level_string,str2) != 0) {
3969 return False;
3972 *rdata_len = mdrcnt + 1024;
3973 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3974 if (!*rdata) {
3975 return False;
3978 SSVAL(*rparam,0,NERR_Success);
3979 SSVAL(*rparam,2,0); /* converter word */
3981 p = *rdata;
3982 endp = *rdata + *rdata_len;
3983 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3984 if (!p2) {
3985 return False;
3988 memset(p,0,21);
3989 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3991 if (uLevel > 0) {
3992 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3993 *p2 = 0;
3996 if (uLevel >= 10) {
3997 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3998 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
3999 p2 = skip_string(*rdata,*rdata_len,p2);
4000 if (!p2) {
4001 return False;
4004 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
4005 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
4006 p2 = skip_string(*rdata,*rdata_len,p2);
4007 if (!p2) {
4008 return False;
4011 /* EEK! the cifsrap.txt doesn't have this in!!!! */
4012 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
4013 strlcpy(p2,((vuser != NULL)
4014 ? pdb_get_fullname(vuser->server_info->sam_account)
4015 : UserName),PTR_DIFF(endp,p2));
4016 p2 = skip_string(*rdata,*rdata_len,p2);
4017 if (!p2) {
4018 return False;
4022 if (uLevel == 11) {
4023 const char *homedir = "";
4024 if (vuser != NULL) {
4025 homedir = pdb_get_homedir(
4026 vuser->server_info->sam_account);
4028 /* modelled after NTAS 3.51 reply */
4029 SSVAL(p,usri11_priv,
4030 (get_current_uid(conn) == sec_initial_uid())?
4031 USER_PRIV_ADMIN:USER_PRIV_USER);
4032 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
4033 SIVALS(p,usri11_password_age,-1); /* password age */
4034 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
4035 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
4036 p2 = skip_string(*rdata,*rdata_len,p2);
4037 if (!p2) {
4038 return False;
4040 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
4041 strlcpy(p2,"",PTR_DIFF(endp,p2));
4042 p2 = skip_string(*rdata,*rdata_len,p2);
4043 if (!p2) {
4044 return False;
4046 SIVAL(p,usri11_last_logon,0); /* last logon */
4047 SIVAL(p,usri11_last_logoff,0); /* last logoff */
4048 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
4049 SSVALS(p,usri11_num_logons,-1); /* num logons */
4050 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
4051 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
4052 p2 = skip_string(*rdata,*rdata_len,p2);
4053 if (!p2) {
4054 return False;
4056 SSVAL(p,usri11_country_code,0); /* country code */
4058 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
4059 strlcpy(p2,"",PTR_DIFF(endp,p2));
4060 p2 = skip_string(*rdata,*rdata_len,p2);
4061 if (!p2) {
4062 return False;
4065 SIVALS(p,usri11_max_storage,-1); /* max storage */
4066 SSVAL(p,usri11_units_per_week,168); /* units per week */
4067 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
4069 /* a simple way to get logon hours at all times. */
4070 memset(p2,0xff,21);
4071 SCVAL(p2,21,0); /* fix zero termination */
4072 p2 = skip_string(*rdata,*rdata_len,p2);
4073 if (!p2) {
4074 return False;
4077 SSVAL(p,usri11_code_page,0); /* code page */
4080 if (uLevel == 1 || uLevel == 2) {
4081 memset(p+22,' ',16); /* password */
4082 SIVALS(p,38,-1); /* password age */
4083 SSVAL(p,42,
4084 (get_current_uid(conn) == sec_initial_uid())?
4085 USER_PRIV_ADMIN:USER_PRIV_USER);
4086 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
4087 strlcpy(p2, vuser ? pdb_get_homedir(
4088 vuser->server_info->sam_account) : "",
4089 PTR_DIFF(endp,p2));
4090 p2 = skip_string(*rdata,*rdata_len,p2);
4091 if (!p2) {
4092 return False;
4094 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
4095 *p2++ = 0;
4096 SSVAL(p,52,0); /* flags */
4097 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
4098 strlcpy(p2, vuser ? pdb_get_logon_script(
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 if (uLevel == 2) {
4106 SIVAL(p,60,0); /* auth_flags */
4107 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
4108 strlcpy(p2,((vuser != NULL)
4109 ? pdb_get_fullname(vuser->server_info->sam_account)
4110 : UserName),PTR_DIFF(endp,p2));
4111 p2 = skip_string(*rdata,*rdata_len,p2);
4112 if (!p2) {
4113 return False;
4115 SIVAL(p,68,0); /* urs_comment */
4116 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
4117 strlcpy(p2,"",PTR_DIFF(endp,p2));
4118 p2 = skip_string(*rdata,*rdata_len,p2);
4119 if (!p2) {
4120 return False;
4122 SIVAL(p,76,0); /* workstations */
4123 SIVAL(p,80,0); /* last_logon */
4124 SIVAL(p,84,0); /* last_logoff */
4125 SIVALS(p,88,-1); /* acct_expires */
4126 SIVALS(p,92,-1); /* max_storage */
4127 SSVAL(p,96,168); /* units_per_week */
4128 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
4129 memset(p2,-1,21);
4130 p2 += 21;
4131 SSVALS(p,102,-1); /* bad_pw_count */
4132 SSVALS(p,104,-1); /* num_logons */
4133 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
4135 TALLOC_CTX *ctx = talloc_tos();
4136 int space_rem = *rdata_len - (p2 - *rdata);
4137 char *tmp;
4139 if (space_rem <= 0) {
4140 return false;
4142 tmp = talloc_strdup(ctx, "\\\\%L");
4143 if (!tmp) {
4144 return false;
4146 tmp = talloc_sub_basic(ctx,
4149 tmp);
4150 if (!tmp) {
4151 return false;
4154 push_ascii(p2,
4155 tmp,
4156 space_rem,
4157 STR_TERMINATE);
4159 p2 = skip_string(*rdata,*rdata_len,p2);
4160 if (!p2) {
4161 return False;
4163 SSVAL(p,110,49); /* country_code */
4164 SSVAL(p,112,860); /* code page */
4168 *rdata_len = PTR_DIFF(p2,*rdata);
4170 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
4172 return(True);
4175 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
4176 char *param, int tpscnt,
4177 char *data, int tdscnt,
4178 int mdrcnt,int mprcnt,
4179 char **rdata,char **rparam,
4180 int *rdata_len,int *rparam_len)
4182 struct smbd_server_connection *sconn = smbd_server_conn;
4183 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4184 char *str2 = skip_string(param,tpscnt,str1);
4185 char *p = skip_string(param,tpscnt,str2);
4186 int uLevel;
4187 struct pack_desc desc;
4188 char* name;
4189 /* With share level security vuid will always be zero.
4190 Don't depend on vuser being non-null !!. JRA */
4191 user_struct *vuser = get_valid_user_struct(sconn, vuid);
4193 if (!str1 || !str2 || !p) {
4194 return False;
4197 if(vuser != NULL) {
4198 DEBUG(3,(" Username of UID %d is %s\n",
4199 (int)vuser->server_info->utok.uid,
4200 vuser->server_info->unix_name));
4203 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4204 name = get_safe_str_ptr(param,tpscnt,p,2);
4205 if (!name) {
4206 return False;
4209 memset((char *)&desc,'\0',sizeof(desc));
4211 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
4213 /* check it's a supported varient */
4214 if (strcmp(str1,"OOWb54WrLh") != 0) {
4215 return False;
4217 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
4218 return False;
4220 if (mdrcnt > 0) {
4221 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4222 if (!*rdata) {
4223 return False;
4227 desc.base = *rdata;
4228 desc.buflen = mdrcnt;
4229 desc.subformat = NULL;
4230 desc.format = str2;
4232 if (init_package(&desc,1,0)) {
4233 PACKI(&desc,"W",0); /* code */
4234 PACKS(&desc,"B21",name); /* eff. name */
4235 PACKS(&desc,"B",""); /* pad */
4236 PACKI(&desc,"W",
4237 (get_current_uid(conn) == sec_initial_uid())?
4238 USER_PRIV_ADMIN:USER_PRIV_USER);
4239 PACKI(&desc,"D",0); /* auth flags XXX */
4240 PACKI(&desc,"W",0); /* num logons */
4241 PACKI(&desc,"W",0); /* bad pw count */
4242 PACKI(&desc,"D",0); /* last logon */
4243 PACKI(&desc,"D",-1); /* last logoff */
4244 PACKI(&desc,"D",-1); /* logoff time */
4245 PACKI(&desc,"D",-1); /* kickoff time */
4246 PACKI(&desc,"D",0); /* password age */
4247 PACKI(&desc,"D",0); /* password can change */
4248 PACKI(&desc,"D",-1); /* password must change */
4251 fstring mypath;
4252 fstrcpy(mypath,"\\\\");
4253 fstrcat(mypath,get_local_machine_name());
4254 strupper_m(mypath);
4255 PACKS(&desc,"z",mypath); /* computer */
4258 PACKS(&desc,"z",lp_workgroup());/* domain */
4259 PACKS(&desc,"z", vuser ? pdb_get_logon_script(
4260 vuser->server_info->sam_account) : ""); /* script path */
4261 PACKI(&desc,"D",0x00000000); /* reserved */
4264 *rdata_len = desc.usedlen;
4265 *rparam_len = 6;
4266 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4267 if (!*rparam) {
4268 return False;
4270 SSVALS(*rparam,0,desc.errcode);
4271 SSVAL(*rparam,2,0);
4272 SSVAL(*rparam,4,desc.neededlen);
4274 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4276 return True;
4279 /****************************************************************************
4280 api_WAccessGetUserPerms
4281 ****************************************************************************/
4283 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
4284 char *param, int tpscnt,
4285 char *data, int tdscnt,
4286 int mdrcnt,int mprcnt,
4287 char **rdata,char **rparam,
4288 int *rdata_len,int *rparam_len)
4290 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4291 char *str2 = skip_string(param,tpscnt,str1);
4292 char *user = skip_string(param,tpscnt,str2);
4293 char *resource = skip_string(param,tpscnt,user);
4295 if (!str1 || !str2 || !user || !resource) {
4296 return False;
4299 if (skip_string(param,tpscnt,resource) == NULL) {
4300 return False;
4302 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4304 /* check it's a supported varient */
4305 if (strcmp(str1,"zzh") != 0) {
4306 return False;
4308 if (strcmp(str2,"") != 0) {
4309 return False;
4312 *rparam_len = 6;
4313 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4314 if (!*rparam) {
4315 return False;
4317 SSVALS(*rparam,0,0); /* errorcode */
4318 SSVAL(*rparam,2,0); /* converter word */
4319 SSVAL(*rparam,4,0x7f); /* permission flags */
4321 return True;
4324 /****************************************************************************
4325 api_WPrintJobEnumerate
4326 ****************************************************************************/
4328 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
4329 char *param, int tpscnt,
4330 char *data, int tdscnt,
4331 int mdrcnt,int mprcnt,
4332 char **rdata,char **rparam,
4333 int *rdata_len,int *rparam_len)
4335 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4336 char *str2 = skip_string(param,tpscnt,str1);
4337 char *p = skip_string(param,tpscnt,str2);
4338 int uLevel;
4339 fstring sharename;
4340 uint32 jobid;
4341 struct pack_desc desc;
4342 char *tmpdata=NULL;
4344 TALLOC_CTX *mem_ctx = talloc_tos();
4345 WERROR werr;
4346 NTSTATUS status;
4347 struct rpc_pipe_client *cli = NULL;
4348 struct policy_handle handle;
4349 struct spoolss_DevmodeContainer devmode_ctr;
4350 union spoolss_JobInfo info;
4352 if (!str1 || !str2 || !p) {
4353 return False;
4356 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4358 memset((char *)&desc,'\0',sizeof(desc));
4359 memset((char *)&status,'\0',sizeof(status));
4361 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4363 /* check it's a supported varient */
4364 if (strcmp(str1,"WWrLh") != 0) {
4365 return False;
4367 if (!check_printjob_info(&desc,uLevel,str2)) {
4368 return False;
4371 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4372 return False;
4375 ZERO_STRUCT(handle);
4377 status = rpc_connect_spoolss_pipe(conn, &cli);
4378 if (!NT_STATUS_IS_OK(status)) {
4379 DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n",
4380 nt_errstr(status)));
4381 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4382 goto out;
4385 ZERO_STRUCT(devmode_ctr);
4387 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4388 sharename,
4389 "RAW",
4390 devmode_ctr,
4391 PRINTER_ACCESS_USE,
4392 &handle,
4393 &werr);
4394 if (!NT_STATUS_IS_OK(status)) {
4395 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4396 goto out;
4398 if (!W_ERROR_IS_OK(werr)) {
4399 desc.errcode = W_ERROR_V(werr);
4400 goto out;
4403 werr = rpccli_spoolss_getjob(cli, mem_ctx,
4404 &handle,
4405 jobid,
4406 2, /* level */
4407 0, /* offered */
4408 &info);
4409 if (!W_ERROR_IS_OK(werr)) {
4410 desc.errcode = W_ERROR_V(werr);
4411 goto out;
4414 if (mdrcnt > 0) {
4415 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4416 if (!*rdata) {
4417 return False;
4419 desc.base = *rdata;
4420 desc.buflen = mdrcnt;
4421 } else {
4423 * Don't return data but need to get correct length
4424 * init_package will return wrong size if buflen=0
4426 desc.buflen = getlen(desc.format);
4427 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4430 if (init_package(&desc,1,0)) {
4431 fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position);
4432 *rdata_len = desc.usedlen;
4433 } else {
4434 desc.errcode = NERR_JobNotFound;
4435 *rdata_len = 0;
4437 out:
4438 if (cli && is_valid_policy_hnd(&handle)) {
4439 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4442 *rparam_len = 6;
4443 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4444 if (!*rparam) {
4445 return False;
4447 SSVALS(*rparam,0,desc.errcode);
4448 SSVAL(*rparam,2,0);
4449 SSVAL(*rparam,4,desc.neededlen);
4451 SAFE_FREE(tmpdata);
4453 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4455 return True;
4458 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
4459 char *param, int tpscnt,
4460 char *data, int tdscnt,
4461 int mdrcnt,int mprcnt,
4462 char **rdata,char **rparam,
4463 int *rdata_len,int *rparam_len)
4465 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4466 char *str2 = skip_string(param,tpscnt,str1);
4467 char *p = skip_string(param,tpscnt,str2);
4468 char *name = p;
4469 int uLevel;
4470 int i, succnt=0;
4471 struct pack_desc desc;
4473 TALLOC_CTX *mem_ctx = talloc_tos();
4474 WERROR werr;
4475 NTSTATUS status;
4476 struct rpc_pipe_client *cli = NULL;
4477 struct policy_handle handle;
4478 struct spoolss_DevmodeContainer devmode_ctr;
4479 uint32_t count;
4480 union spoolss_JobInfo *info;
4482 if (!str1 || !str2 || !p) {
4483 return False;
4486 memset((char *)&desc,'\0',sizeof(desc));
4488 p = skip_string(param,tpscnt,p);
4489 if (!p) {
4490 return False;
4492 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4494 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4496 /* check it's a supported variant */
4497 if (strcmp(str1,"zWrLeh") != 0) {
4498 return False;
4501 if (uLevel > 2) {
4502 return False; /* defined only for uLevel 0,1,2 */
4505 if (!check_printjob_info(&desc,uLevel,str2)) {
4506 return False;
4509 ZERO_STRUCT(handle);
4511 status = rpc_connect_spoolss_pipe(conn, &cli);
4512 if (!NT_STATUS_IS_OK(status)) {
4513 DEBUG(0,("api_WPrintJobEnumerate: could not connect to spoolss: %s\n",
4514 nt_errstr(status)));
4515 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4516 goto out;
4519 ZERO_STRUCT(devmode_ctr);
4521 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4522 name,
4523 NULL,
4524 devmode_ctr,
4525 SEC_FLAG_MAXIMUM_ALLOWED,
4526 &handle,
4527 &werr);
4528 if (!NT_STATUS_IS_OK(status)) {
4529 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4530 goto out;
4532 if (!W_ERROR_IS_OK(werr)) {
4533 desc.errcode = W_ERROR_V(werr);
4534 goto out;
4537 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
4538 &handle,
4539 0, /* firstjob */
4540 0xff, /* numjobs */
4541 2, /* level */
4542 0, /* offered */
4543 &count,
4544 &info);
4545 if (!W_ERROR_IS_OK(werr)) {
4546 desc.errcode = W_ERROR_V(werr);
4547 goto out;
4550 if (mdrcnt > 0) {
4551 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4552 if (!*rdata) {
4553 return False;
4556 desc.base = *rdata;
4557 desc.buflen = mdrcnt;
4559 if (init_package(&desc,count,0)) {
4560 succnt = 0;
4561 for (i = 0; i < count; i++) {
4562 fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i);
4563 if (desc.errcode == NERR_Success) {
4564 succnt = i+1;
4568 out:
4569 if (cli && is_valid_policy_hnd(&handle)) {
4570 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4573 *rdata_len = desc.usedlen;
4575 *rparam_len = 8;
4576 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4577 if (!*rparam) {
4578 return False;
4580 SSVALS(*rparam,0,desc.errcode);
4581 SSVAL(*rparam,2,0);
4582 SSVAL(*rparam,4,succnt);
4583 SSVAL(*rparam,6,count);
4585 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4587 return True;
4590 static int check_printdest_info(struct pack_desc* desc,
4591 int uLevel, char* id)
4593 desc->subformat = NULL;
4594 switch( uLevel ) {
4595 case 0:
4596 desc->format = "B9";
4597 break;
4598 case 1:
4599 desc->format = "B9B21WWzW";
4600 break;
4601 case 2:
4602 desc->format = "z";
4603 break;
4604 case 3:
4605 desc->format = "zzzWWzzzWW";
4606 break;
4607 default:
4608 DEBUG(0,("check_printdest_info: invalid level %d\n",
4609 uLevel));
4610 return False;
4612 if (id == NULL || strcmp(desc->format,id) != 0) {
4613 DEBUG(0,("check_printdest_info: invalid string %s\n",
4614 id ? id : "<NULL>" ));
4615 return False;
4617 return True;
4620 static void fill_printdest_info(struct spoolss_PrinterInfo2 *info2, int uLevel,
4621 struct pack_desc* desc)
4623 char buf[100];
4625 strncpy(buf, info2->printername, sizeof(buf)-1);
4626 buf[sizeof(buf)-1] = 0;
4627 strupper_m(buf);
4629 if (uLevel <= 1) {
4630 PACKS(desc,"B9",buf); /* szName */
4631 if (uLevel == 1) {
4632 PACKS(desc,"B21",""); /* szUserName */
4633 PACKI(desc,"W",0); /* uJobId */
4634 PACKI(desc,"W",0); /* fsStatus */
4635 PACKS(desc,"z",""); /* pszStatus */
4636 PACKI(desc,"W",0); /* time */
4640 if (uLevel == 2 || uLevel == 3) {
4641 PACKS(desc,"z",buf); /* pszPrinterName */
4642 if (uLevel == 3) {
4643 PACKS(desc,"z",""); /* pszUserName */
4644 PACKS(desc,"z",""); /* pszLogAddr */
4645 PACKI(desc,"W",0); /* uJobId */
4646 PACKI(desc,"W",0); /* fsStatus */
4647 PACKS(desc,"z",""); /* pszStatus */
4648 PACKS(desc,"z",""); /* pszComment */
4649 PACKS(desc,"z","NULL"); /* pszDrivers */
4650 PACKI(desc,"W",0); /* time */
4651 PACKI(desc,"W",0); /* pad1 */
4656 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
4657 char *param, int tpscnt,
4658 char *data, int tdscnt,
4659 int mdrcnt,int mprcnt,
4660 char **rdata,char **rparam,
4661 int *rdata_len,int *rparam_len)
4663 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4664 char *str2 = skip_string(param,tpscnt,str1);
4665 char *p = skip_string(param,tpscnt,str2);
4666 char* PrinterName = p;
4667 int uLevel;
4668 struct pack_desc desc;
4669 char *tmpdata=NULL;
4671 TALLOC_CTX *mem_ctx = talloc_tos();
4672 WERROR werr;
4673 NTSTATUS status;
4674 struct rpc_pipe_client *cli = NULL;
4675 struct policy_handle handle;
4676 struct spoolss_DevmodeContainer devmode_ctr;
4677 union spoolss_PrinterInfo info;
4679 if (!str1 || !str2 || !p) {
4680 return False;
4683 memset((char *)&desc,'\0',sizeof(desc));
4685 p = skip_string(param,tpscnt,p);
4686 if (!p) {
4687 return False;
4689 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4691 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4693 /* check it's a supported varient */
4694 if (strcmp(str1,"zWrLh") != 0) {
4695 return False;
4697 if (!check_printdest_info(&desc,uLevel,str2)) {
4698 return False;
4701 ZERO_STRUCT(handle);
4703 status = rpc_connect_spoolss_pipe(conn, &cli);
4704 if (!NT_STATUS_IS_OK(status)) {
4705 DEBUG(0,("api_WPrintDestGetInfo: could not connect to spoolss: %s\n",
4706 nt_errstr(status)));
4707 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4708 goto out;
4711 ZERO_STRUCT(devmode_ctr);
4713 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4714 PrinterName,
4715 NULL,
4716 devmode_ctr,
4717 SEC_FLAG_MAXIMUM_ALLOWED,
4718 &handle,
4719 &werr);
4720 if (!NT_STATUS_IS_OK(status)) {
4721 *rdata_len = 0;
4722 desc.errcode = NERR_DestNotFound;
4723 desc.neededlen = 0;
4724 goto out;
4726 if (!W_ERROR_IS_OK(werr)) {
4727 *rdata_len = 0;
4728 desc.errcode = NERR_DestNotFound;
4729 desc.neededlen = 0;
4730 goto out;
4733 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
4734 &handle,
4737 &info);
4738 if (!W_ERROR_IS_OK(werr)) {
4739 *rdata_len = 0;
4740 desc.errcode = NERR_DestNotFound;
4741 desc.neededlen = 0;
4742 goto out;
4745 if (mdrcnt > 0) {
4746 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4747 if (!*rdata) {
4748 return False;
4750 desc.base = *rdata;
4751 desc.buflen = mdrcnt;
4752 } else {
4754 * Don't return data but need to get correct length
4755 * init_package will return wrong size if buflen=0
4757 desc.buflen = getlen(desc.format);
4758 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4760 if (init_package(&desc,1,0)) {
4761 fill_printdest_info(&info.info2, uLevel,&desc);
4764 out:
4765 if (cli && is_valid_policy_hnd(&handle)) {
4766 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4769 *rdata_len = desc.usedlen;
4771 *rparam_len = 6;
4772 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4773 if (!*rparam) {
4774 return False;
4776 SSVALS(*rparam,0,desc.errcode);
4777 SSVAL(*rparam,2,0);
4778 SSVAL(*rparam,4,desc.neededlen);
4780 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4781 SAFE_FREE(tmpdata);
4783 return True;
4786 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4787 char *param, int tpscnt,
4788 char *data, int tdscnt,
4789 int mdrcnt,int mprcnt,
4790 char **rdata,char **rparam,
4791 int *rdata_len,int *rparam_len)
4793 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4794 char *str2 = skip_string(param,tpscnt,str1);
4795 char *p = skip_string(param,tpscnt,str2);
4796 int uLevel;
4797 int queuecnt;
4798 int i, n, succnt=0;
4799 struct pack_desc desc;
4801 TALLOC_CTX *mem_ctx = talloc_tos();
4802 WERROR werr;
4803 NTSTATUS status;
4804 struct rpc_pipe_client *cli = NULL;
4805 union spoolss_PrinterInfo *info;
4806 uint32_t count;
4808 if (!str1 || !str2 || !p) {
4809 return False;
4812 memset((char *)&desc,'\0',sizeof(desc));
4814 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4816 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4818 /* check it's a supported varient */
4819 if (strcmp(str1,"WrLeh") != 0) {
4820 return False;
4822 if (!check_printdest_info(&desc,uLevel,str2)) {
4823 return False;
4826 queuecnt = 0;
4828 status = rpc_connect_spoolss_pipe(conn, &cli);
4829 if (!NT_STATUS_IS_OK(status)) {
4830 DEBUG(0,("api_WPrintDestEnum: could not connect to spoolss: %s\n",
4831 nt_errstr(status)));
4832 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4833 goto out;
4836 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
4837 PRINTER_ENUM_LOCAL,
4838 cli->srv_name_slash,
4841 &count,
4842 &info);
4843 if (!W_ERROR_IS_OK(werr)) {
4844 desc.errcode = W_ERROR_V(werr);
4845 *rdata_len = 0;
4846 desc.errcode = NERR_DestNotFound;
4847 desc.neededlen = 0;
4848 goto out;
4851 queuecnt = count;
4853 if (mdrcnt > 0) {
4854 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4855 if (!*rdata) {
4856 return False;
4860 desc.base = *rdata;
4861 desc.buflen = mdrcnt;
4862 if (init_package(&desc,queuecnt,0)) {
4863 succnt = 0;
4864 n = 0;
4865 for (i = 0; i < count; i++) {
4866 fill_printdest_info(&info[i].info2, uLevel,&desc);
4867 n++;
4868 if (desc.errcode == NERR_Success) {
4869 succnt = n;
4873 out:
4874 *rdata_len = desc.usedlen;
4876 *rparam_len = 8;
4877 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4878 if (!*rparam) {
4879 return False;
4881 SSVALS(*rparam,0,desc.errcode);
4882 SSVAL(*rparam,2,0);
4883 SSVAL(*rparam,4,succnt);
4884 SSVAL(*rparam,6,queuecnt);
4886 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4888 return True;
4891 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4892 char *param, int tpscnt,
4893 char *data, int tdscnt,
4894 int mdrcnt,int mprcnt,
4895 char **rdata,char **rparam,
4896 int *rdata_len,int *rparam_len)
4898 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4899 char *str2 = skip_string(param,tpscnt,str1);
4900 char *p = skip_string(param,tpscnt,str2);
4901 int uLevel;
4902 int succnt;
4903 struct pack_desc desc;
4905 if (!str1 || !str2 || !p) {
4906 return False;
4909 memset((char *)&desc,'\0',sizeof(desc));
4911 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4913 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4915 /* check it's a supported varient */
4916 if (strcmp(str1,"WrLeh") != 0) {
4917 return False;
4919 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4920 return False;
4923 if (mdrcnt > 0) {
4924 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4925 if (!*rdata) {
4926 return False;
4929 desc.base = *rdata;
4930 desc.buflen = mdrcnt;
4931 if (init_package(&desc,1,0)) {
4932 PACKS(&desc,"B41","NULL");
4935 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4937 *rdata_len = desc.usedlen;
4939 *rparam_len = 8;
4940 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4941 if (!*rparam) {
4942 return False;
4944 SSVALS(*rparam,0,desc.errcode);
4945 SSVAL(*rparam,2,0);
4946 SSVAL(*rparam,4,succnt);
4947 SSVAL(*rparam,6,1);
4949 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4951 return True;
4954 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4955 char *param, int tpscnt,
4956 char *data, int tdscnt,
4957 int mdrcnt,int mprcnt,
4958 char **rdata,char **rparam,
4959 int *rdata_len,int *rparam_len)
4961 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4962 char *str2 = skip_string(param,tpscnt,str1);
4963 char *p = skip_string(param,tpscnt,str2);
4964 int uLevel;
4965 int succnt;
4966 struct pack_desc desc;
4968 if (!str1 || !str2 || !p) {
4969 return False;
4971 memset((char *)&desc,'\0',sizeof(desc));
4973 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4975 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4977 /* check it's a supported varient */
4978 if (strcmp(str1,"WrLeh") != 0) {
4979 return False;
4981 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4982 return False;
4985 if (mdrcnt > 0) {
4986 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4987 if (!*rdata) {
4988 return False;
4991 desc.base = *rdata;
4992 desc.buflen = mdrcnt;
4993 desc.format = str2;
4994 if (init_package(&desc,1,0)) {
4995 PACKS(&desc,"B13","lpd");
4998 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5000 *rdata_len = desc.usedlen;
5002 *rparam_len = 8;
5003 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5004 if (!*rparam) {
5005 return False;
5007 SSVALS(*rparam,0,desc.errcode);
5008 SSVAL(*rparam,2,0);
5009 SSVAL(*rparam,4,succnt);
5010 SSVAL(*rparam,6,1);
5012 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
5014 return True;
5017 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
5018 char *param, int tpscnt,
5019 char *data, int tdscnt,
5020 int mdrcnt,int mprcnt,
5021 char **rdata,char **rparam,
5022 int *rdata_len,int *rparam_len)
5024 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5025 char *str2 = skip_string(param,tpscnt,str1);
5026 char *p = skip_string(param,tpscnt,str2);
5027 int uLevel;
5028 int succnt;
5029 struct pack_desc desc;
5031 if (!str1 || !str2 || !p) {
5032 return False;
5035 memset((char *)&desc,'\0',sizeof(desc));
5037 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5039 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
5041 /* check it's a supported varient */
5042 if (strcmp(str1,"WrLeh") != 0) {
5043 return False;
5045 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
5046 return False;
5049 if (mdrcnt > 0) {
5050 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5051 if (!*rdata) {
5052 return False;
5055 memset((char *)&desc,'\0',sizeof(desc));
5056 desc.base = *rdata;
5057 desc.buflen = mdrcnt;
5058 desc.format = str2;
5059 if (init_package(&desc,1,0)) {
5060 PACKS(&desc,"B13","lp0");
5063 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5065 *rdata_len = desc.usedlen;
5067 *rparam_len = 8;
5068 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5069 if (!*rparam) {
5070 return False;
5072 SSVALS(*rparam,0,desc.errcode);
5073 SSVAL(*rparam,2,0);
5074 SSVAL(*rparam,4,succnt);
5075 SSVAL(*rparam,6,1);
5077 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
5079 return True;
5082 /****************************************************************************
5083 List open sessions
5084 ****************************************************************************/
5086 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
5087 char *param, int tpscnt,
5088 char *data, int tdscnt,
5089 int mdrcnt,int mprcnt,
5090 char **rdata,char **rparam,
5091 int *rdata_len,int *rparam_len)
5094 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5095 char *str2 = skip_string(param,tpscnt,str1);
5096 char *p = skip_string(param,tpscnt,str2);
5097 int uLevel;
5098 struct pack_desc desc;
5099 struct sessionid *session_list;
5100 int i, num_sessions;
5102 if (!str1 || !str2 || !p) {
5103 return False;
5106 memset((char *)&desc,'\0',sizeof(desc));
5108 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5110 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
5111 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
5112 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
5114 /* check it's a supported varient */
5115 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
5116 return False;
5118 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
5119 return False;
5122 num_sessions = list_sessions(talloc_tos(), &session_list);
5124 if (mdrcnt > 0) {
5125 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5126 if (!*rdata) {
5127 return False;
5130 memset((char *)&desc,'\0',sizeof(desc));
5131 desc.base = *rdata;
5132 desc.buflen = mdrcnt;
5133 desc.format = str2;
5134 if (!init_package(&desc,num_sessions,0)) {
5135 return False;
5138 for(i=0; i<num_sessions; i++) {
5139 PACKS(&desc, "z", session_list[i].remote_machine);
5140 PACKS(&desc, "z", session_list[i].username);
5141 PACKI(&desc, "W", 1); /* num conns */
5142 PACKI(&desc, "W", 0); /* num opens */
5143 PACKI(&desc, "W", 1); /* num users */
5144 PACKI(&desc, "D", 0); /* session time */
5145 PACKI(&desc, "D", 0); /* idle time */
5146 PACKI(&desc, "D", 0); /* flags */
5147 PACKS(&desc, "z", "Unknown Client"); /* client type string */
5150 *rdata_len = desc.usedlen;
5152 *rparam_len = 8;
5153 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5154 if (!*rparam) {
5155 return False;
5157 SSVALS(*rparam,0,desc.errcode);
5158 SSVAL(*rparam,2,0); /* converter */
5159 SSVAL(*rparam,4,num_sessions); /* count */
5161 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
5163 return True;
5167 /****************************************************************************
5168 The buffer was too small.
5169 ****************************************************************************/
5171 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
5172 int mdrcnt, int mprcnt,
5173 char **rdata, char **rparam,
5174 int *rdata_len, int *rparam_len)
5176 *rparam_len = MIN(*rparam_len,mprcnt);
5177 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5178 if (!*rparam) {
5179 return False;
5182 *rdata_len = 0;
5184 SSVAL(*rparam,0,NERR_BufTooSmall);
5186 DEBUG(3,("Supplied buffer too small in API command\n"));
5188 return True;
5191 /****************************************************************************
5192 The request is not supported.
5193 ****************************************************************************/
5195 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
5196 char *param, int tpscnt,
5197 char *data, int tdscnt,
5198 int mdrcnt, int mprcnt,
5199 char **rdata, char **rparam,
5200 int *rdata_len, int *rparam_len)
5202 *rparam_len = 4;
5203 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5204 if (!*rparam) {
5205 return False;
5208 *rdata_len = 0;
5210 SSVAL(*rparam,0,NERR_notsupported);
5211 SSVAL(*rparam,2,0); /* converter word */
5213 DEBUG(3,("Unsupported API command\n"));
5215 return True;
5218 static const struct {
5219 const char *name;
5220 int id;
5221 bool (*fn)(connection_struct *, uint16,
5222 char *, int,
5223 char *, int,
5224 int,int,char **,char **,int *,int *);
5225 bool auth_user; /* Deny anonymous access? */
5226 } api_commands[] = {
5227 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
5228 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
5229 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
5230 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
5231 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
5232 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
5233 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
5234 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
5235 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
5236 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
5237 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
5238 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
5239 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
5240 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
5241 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
5242 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
5243 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
5244 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
5245 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
5246 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
5247 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
5248 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
5249 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
5250 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
5251 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
5252 {"NetServerEnum3", RAP_NetServerEnum3, api_RNetServerEnum3}, /* anon OK */
5253 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
5254 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
5255 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
5256 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
5257 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
5258 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
5259 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
5260 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
5261 {NULL, -1, api_Unsupported}
5262 /* The following RAP calls are not implemented by Samba:
5264 RAP_WFileEnum2 - anon not OK
5269 /****************************************************************************
5270 Handle remote api calls.
5271 ****************************************************************************/
5273 void api_reply(connection_struct *conn, uint16 vuid,
5274 struct smb_request *req,
5275 char *data, char *params,
5276 int tdscnt, int tpscnt,
5277 int mdrcnt, int mprcnt)
5279 struct smbd_server_connection *sconn = smbd_server_conn;
5280 int api_command;
5281 char *rdata = NULL;
5282 char *rparam = NULL;
5283 const char *name1 = NULL;
5284 const char *name2 = NULL;
5285 int rdata_len = 0;
5286 int rparam_len = 0;
5287 bool reply=False;
5288 int i;
5290 if (!params) {
5291 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
5292 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5293 return;
5296 if (tpscnt < 2) {
5297 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5298 return;
5300 api_command = SVAL(params,0);
5301 /* Is there a string at position params+2 ? */
5302 if (skip_string(params,tpscnt,params+2)) {
5303 name1 = params + 2;
5304 } else {
5305 name1 = "";
5307 name2 = skip_string(params,tpscnt,params+2);
5308 if (!name2) {
5309 name2 = "";
5312 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
5313 api_command,
5314 name1,
5315 name2,
5316 tdscnt,tpscnt,mdrcnt,mprcnt));
5318 for (i=0;api_commands[i].name;i++) {
5319 if (api_commands[i].id == api_command && api_commands[i].fn) {
5320 DEBUG(3,("Doing %s\n",api_commands[i].name));
5321 break;
5325 /* Check whether this api call can be done anonymously */
5327 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
5328 user_struct *user = get_valid_user_struct(sconn, vuid);
5330 if (!user || user->server_info->guest) {
5331 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5332 return;
5336 rdata = (char *)SMB_MALLOC(1024);
5337 if (rdata) {
5338 memset(rdata,'\0',1024);
5341 rparam = (char *)SMB_MALLOC(1024);
5342 if (rparam) {
5343 memset(rparam,'\0',1024);
5346 if(!rdata || !rparam) {
5347 DEBUG(0,("api_reply: malloc fail !\n"));
5348 SAFE_FREE(rdata);
5349 SAFE_FREE(rparam);
5350 reply_nterror(req, NT_STATUS_NO_MEMORY);
5351 return;
5354 reply = api_commands[i].fn(conn,
5355 vuid,
5356 params,tpscnt, /* params + length */
5357 data,tdscnt, /* data + length */
5358 mdrcnt,mprcnt,
5359 &rdata,&rparam,&rdata_len,&rparam_len);
5362 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
5363 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
5364 &rdata,&rparam,&rdata_len,&rparam_len);
5367 /* if we get False back then it's actually unsupported */
5368 if (!reply) {
5369 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
5370 &rdata,&rparam,&rdata_len,&rparam_len);
5373 /* If api_Unsupported returns false we can't return anything. */
5374 if (reply) {
5375 send_trans_reply(conn, req, rparam, rparam_len,
5376 rdata, rdata_len, False);
5379 SAFE_FREE(rdata);
5380 SAFE_FREE(rparam);
5381 return;