VERSION: Disable git snapshots for the 4.1.4 release.
[Samba.git] / source3 / smbd / lanman.c
blobe6b9530410cc4e269cdc04a228dafd9120dc1b07
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/smbd.h"
30 #include "smbd/globals.h"
31 #include "rpc_client/rpc_client.h"
32 #include "../librpc/gen_ndr/ndr_samr_c.h"
33 #include "../librpc/gen_ndr/ndr_spoolss_c.h"
34 #include "rpc_client/cli_spoolss.h"
35 #include "rpc_client/init_spoolss.h"
36 #include "../librpc/gen_ndr/ndr_srvsvc_c.h"
37 #include "../librpc/gen_ndr/rap.h"
38 #include "../lib/util/binsearch.h"
39 #include "../libcli/auth/libcli_auth.h"
40 #include "rpc_client/init_lsa.h"
41 #include "../libcli/security/security.h"
42 #include "printing.h"
43 #include "passdb/machine_sid.h"
44 #include "auth.h"
45 #include "rpc_server/rpc_ncacn_np.h"
47 #ifdef CHECK_TYPES
48 #undef CHECK_TYPES
49 #endif
50 #define CHECK_TYPES 0
52 #define NERR_Success 0
53 #define NERR_badpass 86
54 #define NERR_notsupported 50
56 #define NERR_BASE (2100)
57 #define NERR_BufTooSmall (NERR_BASE+23)
58 #define NERR_JobNotFound (NERR_BASE+51)
59 #define NERR_DestNotFound (NERR_BASE+52)
61 #define ACCESS_READ 0x01
62 #define ACCESS_WRITE 0x02
63 #define ACCESS_CREATE 0x04
65 #define SHPWLEN 8 /* share password length */
67 /* Limit size of ipc replies */
69 static char *smb_realloc_limit(void *ptr, size_t size)
71 char *val;
73 size = MAX((size),4*1024);
74 val = (char *)SMB_REALLOC(ptr,size);
75 if (val) {
76 memset(val,'\0',size);
78 return val;
81 static bool api_Unsupported(struct smbd_server_connection *sconn,
82 connection_struct *conn, uint64_t vuid,
83 char *param, int tpscnt,
84 char *data, int tdscnt,
85 int mdrcnt, int mprcnt,
86 char **rdata, char **rparam,
87 int *rdata_len, int *rparam_len);
89 static bool api_TooSmall(struct smbd_server_connection *sconn,
90 connection_struct *conn, uint64_t vuid, char *param, char *data,
91 int mdrcnt, int mprcnt,
92 char **rdata, char **rparam,
93 int *rdata_len, int *rparam_len);
96 static int CopyExpanded(connection_struct *conn,
97 int snum, char **dst, char *src, int *p_space_remaining)
99 TALLOC_CTX *ctx = talloc_tos();
100 char *buf = NULL;
101 int l;
103 if (!src || !dst || !p_space_remaining || !(*dst) ||
104 *p_space_remaining <= 0) {
105 return 0;
108 buf = talloc_strdup(ctx, src);
109 if (!buf) {
110 *p_space_remaining = 0;
111 return 0;
113 buf = talloc_string_sub(ctx, buf,"%S", lp_servicename(ctx, snum));
114 if (!buf) {
115 *p_space_remaining = 0;
116 return 0;
118 buf = talloc_sub_advanced(ctx,
119 lp_servicename(ctx, SNUM(conn)),
120 conn->session_info->unix_info->unix_name,
121 conn->connectpath,
122 conn->session_info->unix_token->gid,
123 conn->session_info->unix_info->sanitized_username,
124 conn->session_info->info->domain_name,
125 buf);
126 if (!buf) {
127 *p_space_remaining = 0;
128 return 0;
130 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
131 if (l == -1) {
132 return 0;
134 (*dst) += l;
135 (*p_space_remaining) -= l;
136 return l;
139 static int CopyAndAdvance(char **dst, char *src, int *n)
141 int l;
142 if (!src || !dst || !n || !(*dst)) {
143 return 0;
145 l = push_ascii(*dst,src,*n, STR_TERMINATE);
146 if (l == -1) {
147 return 0;
149 (*dst) += l;
150 (*n) -= l;
151 return l;
154 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
156 TALLOC_CTX *ctx = talloc_tos();
157 char *buf = NULL;
158 if (!s) {
159 return 0;
161 buf = talloc_strdup(ctx,s);
162 if (!buf) {
163 return 0;
165 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(ctx, snum));
166 if (!buf) {
167 return 0;
169 buf = talloc_sub_advanced(ctx,
170 lp_servicename(ctx, SNUM(conn)),
171 conn->session_info->unix_info->unix_name,
172 conn->connectpath,
173 conn->session_info->unix_token->gid,
174 conn->session_info->unix_info->sanitized_username,
175 conn->session_info->info->domain_name,
176 buf);
177 if (!buf) {
178 return 0;
180 return strlen(buf) + 1;
183 /*******************************************************************
184 Check a API string for validity when we only need to check the prefix.
185 ******************************************************************/
187 static bool prefix_ok(const char *str, const char *prefix)
189 return(strncmp(str,prefix,strlen(prefix)) == 0);
192 struct pack_desc {
193 const char *format; /* formatstring for structure */
194 const char *subformat; /* subformat for structure */
195 char *base; /* baseaddress of buffer */
196 int buflen; /* remaining size for fixed part; on init: length of base */
197 int subcount; /* count of substructures */
198 char *structbuf; /* pointer into buffer for remaining fixed part */
199 int stringlen; /* remaining size for variable part */
200 char *stringbuf; /* pointer into buffer for remaining variable part */
201 int neededlen; /* total needed size */
202 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
203 const char *curpos; /* current position; pointer into format or subformat */
204 int errcode;
207 static int get_counter(const char **p)
209 int i, n;
210 if (!p || !(*p)) {
211 return 1;
213 if (!isdigit((int)**p)) {
214 return 1;
216 for (n = 0;;) {
217 i = **p;
218 if (isdigit(i)) {
219 n = 10 * n + (i - '0');
220 } else {
221 return n;
223 (*p)++;
227 static int getlen(const char *p)
229 int n = 0;
230 if (!p) {
231 return 0;
234 while (*p) {
235 switch( *p++ ) {
236 case 'W': /* word (2 byte) */
237 n += 2;
238 break;
239 case 'K': /* status word? (2 byte) */
240 n += 2;
241 break;
242 case 'N': /* count of substructures (word) at end */
243 n += 2;
244 break;
245 case 'D': /* double word (4 byte) */
246 case 'z': /* offset to zero terminated string (4 byte) */
247 case 'l': /* offset to user data (4 byte) */
248 n += 4;
249 break;
250 case 'b': /* offset to data (with counter) (4 byte) */
251 n += 4;
252 get_counter(&p);
253 break;
254 case 'B': /* byte (with optional counter) */
255 n += get_counter(&p);
256 break;
259 return n;
262 static bool init_package(struct pack_desc *p, int count, int subcount)
264 int n = p->buflen;
265 int i;
267 if (!p->format || !p->base) {
268 return False;
271 i = count * getlen(p->format);
272 if (p->subformat) {
273 i += subcount * getlen(p->subformat);
275 p->structbuf = p->base;
276 p->neededlen = 0;
277 p->usedlen = 0;
278 p->subcount = 0;
279 p->curpos = p->format;
280 if (i > n) {
281 p->neededlen = i;
282 i = n = 0;
283 #if 0
285 * This is the old error code we used. Aparently
286 * WinNT/2k systems return ERRbuftoosmall (2123) and
287 * OS/2 needs this. I'm leaving this here so we can revert
288 * if needed. JRA.
290 p->errcode = ERRmoredata;
291 #else
292 p->errcode = ERRbuftoosmall;
293 #endif
294 } else {
295 p->errcode = NERR_Success;
297 p->buflen = i;
298 n -= i;
299 p->stringbuf = p->base + i;
300 p->stringlen = n;
301 return (p->errcode == NERR_Success);
304 static int package(struct pack_desc *p, ...)
306 va_list args;
307 int needed=0, stringneeded;
308 const char *str=NULL;
309 int is_string=0, stringused;
310 int32 temp;
312 va_start(args,p);
314 if (!*p->curpos) {
315 if (!p->subcount) {
316 p->curpos = p->format;
317 } else {
318 p->curpos = p->subformat;
319 p->subcount--;
322 #if CHECK_TYPES
323 str = va_arg(args,char*);
324 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
325 #endif
326 stringneeded = -1;
328 if (!p->curpos) {
329 va_end(args);
330 return 0;
333 switch( *p->curpos++ ) {
334 case 'W': /* word (2 byte) */
335 needed = 2;
336 temp = va_arg(args,int);
337 if (p->buflen >= needed) {
338 SSVAL(p->structbuf,0,temp);
340 break;
341 case 'K': /* status word? (2 byte) */
342 needed = 2;
343 temp = va_arg(args,int);
344 if (p->buflen >= needed) {
345 SSVAL(p->structbuf,0,temp);
347 break;
348 case 'N': /* count of substructures (word) at end */
349 needed = 2;
350 p->subcount = va_arg(args,int);
351 if (p->buflen >= needed) {
352 SSVAL(p->structbuf,0,p->subcount);
354 break;
355 case 'D': /* double word (4 byte) */
356 needed = 4;
357 temp = va_arg(args,int);
358 if (p->buflen >= needed) {
359 SIVAL(p->structbuf,0,temp);
361 break;
362 case 'B': /* byte (with optional counter) */
363 needed = get_counter(&p->curpos);
365 char *s = va_arg(args,char*);
366 if (p->buflen >= needed) {
367 StrnCpy(p->structbuf,s?s:"",needed-1);
370 break;
371 case 'z': /* offset to zero terminated string (4 byte) */
372 str = va_arg(args,char*);
373 stringneeded = (str ? strlen(str)+1 : 0);
374 is_string = 1;
375 break;
376 case 'l': /* offset to user data (4 byte) */
377 str = va_arg(args,char*);
378 stringneeded = va_arg(args,int);
379 is_string = 0;
380 break;
381 case 'b': /* offset to data (with counter) (4 byte) */
382 str = va_arg(args,char*);
383 stringneeded = get_counter(&p->curpos);
384 is_string = 0;
385 break;
388 va_end(args);
389 if (stringneeded >= 0) {
390 needed = 4;
391 if (p->buflen >= needed) {
392 stringused = stringneeded;
393 if (stringused > p->stringlen) {
394 stringused = (is_string ? p->stringlen : 0);
395 if (p->errcode == NERR_Success) {
396 p->errcode = ERRmoredata;
399 if (!stringused) {
400 SIVAL(p->structbuf,0,0);
401 } else {
402 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
403 memcpy(p->stringbuf,str?str:"",stringused);
404 if (is_string) {
405 p->stringbuf[stringused-1] = '\0';
407 p->stringbuf += stringused;
408 p->stringlen -= stringused;
409 p->usedlen += stringused;
412 p->neededlen += stringneeded;
415 p->neededlen += needed;
416 if (p->buflen >= needed) {
417 p->structbuf += needed;
418 p->buflen -= needed;
419 p->usedlen += needed;
420 } else {
421 if (p->errcode == NERR_Success) {
422 p->errcode = ERRmoredata;
425 return 1;
428 #if CHECK_TYPES
429 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
430 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
431 #else
432 #define PACK(desc,t,v) package(desc,v)
433 #define PACKl(desc,t,v,l) package(desc,v,l)
434 #endif
436 static void PACKI(struct pack_desc* desc, const char *t,int v)
438 PACK(desc,t,v);
441 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
443 PACK(desc,t,v);
446 /****************************************************************************
447 Get a print queue.
448 ****************************************************************************/
450 static void PackDriverData(struct pack_desc* desc)
452 char drivdata[4+4+32];
453 SIVAL(drivdata,0,sizeof drivdata); /* cb */
454 SIVAL(drivdata,4,1000); /* lVersion */
455 memset(drivdata+8,0,32); /* szDeviceName */
456 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
457 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
460 static int check_printq_info(struct pack_desc* desc,
461 unsigned int uLevel, char *id1, char *id2)
463 desc->subformat = NULL;
464 switch( uLevel ) {
465 case 0:
466 desc->format = "B13";
467 break;
468 case 1:
469 desc->format = "B13BWWWzzzzzWW";
470 break;
471 case 2:
472 desc->format = "B13BWWWzzzzzWN";
473 desc->subformat = "WB21BB16B10zWWzDDz";
474 break;
475 case 3:
476 desc->format = "zWWWWzzzzWWzzl";
477 break;
478 case 4:
479 desc->format = "zWWWWzzzzWNzzl";
480 desc->subformat = "WWzWWDDzz";
481 break;
482 case 5:
483 desc->format = "z";
484 break;
485 case 51:
486 desc->format = "K";
487 break;
488 case 52:
489 desc->format = "WzzzzzzzzN";
490 desc->subformat = "z";
491 break;
492 default:
493 DEBUG(0,("check_printq_info: invalid level %d\n",
494 uLevel ));
495 return False;
497 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
498 DEBUG(0,("check_printq_info: invalid format %s\n",
499 id1 ? id1 : "<NULL>" ));
500 return False;
502 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
503 DEBUG(0,("check_printq_info: invalid subformat %s\n",
504 id2 ? id2 : "<NULL>" ));
505 return False;
507 return True;
511 #define RAP_JOB_STATUS_QUEUED 0
512 #define RAP_JOB_STATUS_PAUSED 1
513 #define RAP_JOB_STATUS_SPOOLING 2
514 #define RAP_JOB_STATUS_PRINTING 3
515 #define RAP_JOB_STATUS_PRINTED 4
517 #define RAP_QUEUE_STATUS_PAUSED 1
518 #define RAP_QUEUE_STATUS_ERROR 2
520 /* turn a print job status into a on the wire status
522 static int printj_spoolss_status(int v)
524 if (v == JOB_STATUS_QUEUED)
525 return RAP_JOB_STATUS_QUEUED;
526 if (v & JOB_STATUS_PAUSED)
527 return RAP_JOB_STATUS_PAUSED;
528 if (v & JOB_STATUS_SPOOLING)
529 return RAP_JOB_STATUS_SPOOLING;
530 if (v & JOB_STATUS_PRINTING)
531 return RAP_JOB_STATUS_PRINTING;
532 return 0;
535 /* turn a print queue status into a on the wire status
537 static int printq_spoolss_status(int v)
539 if (v == PRINTER_STATUS_OK)
540 return 0;
541 if (v & PRINTER_STATUS_PAUSED)
542 return RAP_QUEUE_STATUS_PAUSED;
543 return RAP_QUEUE_STATUS_ERROR;
546 static void fill_spoolss_printjob_info(int uLevel,
547 struct pack_desc *desc,
548 struct spoolss_JobInfo2 *info2,
549 int n)
551 time_t t = spoolss_Time_to_time_t(&info2->submitted);
553 /* the client expects localtime */
554 t -= get_time_zone(t);
556 PACKI(desc,"W",pjobid_to_rap(info2->printer_name, info2->job_id)); /* uJobId */
557 if (uLevel == 1) {
558 PACKS(desc,"B21", info2->user_name); /* szUserName */
559 PACKS(desc,"B",""); /* pad */
560 PACKS(desc,"B16",""); /* szNotifyName */
561 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
562 PACKS(desc,"z",""); /* pszParms */
563 PACKI(desc,"W",n+1); /* uPosition */
564 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
565 PACKS(desc,"z",""); /* pszStatus */
566 PACKI(desc,"D", t); /* ulSubmitted */
567 PACKI(desc,"D", info2->size); /* ulSize */
568 PACKS(desc,"z", info2->document_name); /* pszComment */
570 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
571 PACKI(desc,"W", info2->priority); /* uPriority */
572 PACKS(desc,"z", info2->user_name); /* pszUserName */
573 PACKI(desc,"W",n+1); /* uPosition */
574 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
575 PACKI(desc,"D",t); /* ulSubmitted */
576 PACKI(desc,"D", info2->size); /* ulSize */
577 PACKS(desc,"z","Samba"); /* pszComment */
578 PACKS(desc,"z", info2->document_name); /* pszDocument */
579 if (uLevel == 3) {
580 PACKS(desc,"z",""); /* pszNotifyName */
581 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
582 PACKS(desc,"z",""); /* pszParms */
583 PACKS(desc,"z",""); /* pszStatus */
584 PACKS(desc,"z", info2->printer_name); /* pszQueue */
585 PACKS(desc,"z","lpd"); /* pszQProcName */
586 PACKS(desc,"z",""); /* pszQProcParms */
587 PACKS(desc,"z","NULL"); /* pszDriverName */
588 PackDriverData(desc); /* pDriverData */
589 PACKS(desc,"z",""); /* pszPrinterName */
590 } else if (uLevel == 4) { /* OS2 */
591 PACKS(desc,"z",""); /* pszSpoolFileName */
592 PACKS(desc,"z",""); /* pszPortName */
593 PACKS(desc,"z",""); /* pszStatus */
594 PACKI(desc,"D",0); /* ulPagesSpooled */
595 PACKI(desc,"D",0); /* ulPagesSent */
596 PACKI(desc,"D",0); /* ulPagesPrinted */
597 PACKI(desc,"D",0); /* ulTimePrinted */
598 PACKI(desc,"D",0); /* ulExtendJobStatus */
599 PACKI(desc,"D",0); /* ulStartPage */
600 PACKI(desc,"D",0); /* ulEndPage */
605 /********************************************************************
606 Respond to the DosPrintQInfo command with a level of 52
607 This is used to get printer driver information for Win9x clients
608 ********************************************************************/
609 static void fill_printq_info_52(struct spoolss_DriverInfo3 *driver,
610 struct pack_desc* desc, int count,
611 const char *printer_name)
613 int i;
614 fstring location;
615 trim_string(discard_const_p(char, driver->driver_path), "\\print$\\WIN40\\0\\", 0);
616 trim_string(discard_const_p(char, driver->data_file), "\\print$\\WIN40\\0\\", 0);
617 trim_string(discard_const_p(char, driver->help_file), "\\print$\\WIN40\\0\\", 0);
619 PACKI(desc, "W", 0x0400); /* don't know */
620 PACKS(desc, "z", driver->driver_name); /* long printer name */
621 PACKS(desc, "z", driver->driver_path); /* Driverfile Name */
622 PACKS(desc, "z", driver->data_file); /* Datafile name */
623 PACKS(desc, "z", driver->monitor_name); /* language monitor */
625 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
626 standard_sub_basic( "", "", location, sizeof(location)-1 );
627 PACKS(desc,"z", location); /* share to retrieve files */
629 PACKS(desc,"z", driver->default_datatype); /* default data type */
630 PACKS(desc,"z", driver->help_file); /* helpfile name */
631 PACKS(desc,"z", driver->driver_path); /* driver name */
633 DEBUG(3,("Printer Driver Name: %s:\n",driver->driver_name));
634 DEBUG(3,("Driver: %s:\n",driver->driver_path));
635 DEBUG(3,("Data File: %s:\n",driver->data_file));
636 DEBUG(3,("Language Monitor: %s:\n",driver->monitor_name));
637 DEBUG(3,("Driver Location: %s:\n",location));
638 DEBUG(3,("Data Type: %s:\n",driver->default_datatype));
639 DEBUG(3,("Help File: %s:\n",driver->help_file));
640 PACKI(desc,"N",count); /* number of files to copy */
642 for ( i=0; i<count && driver->dependent_files && *driver->dependent_files[i]; i++)
644 trim_string(discard_const_p(char, driver->dependent_files[i]), "\\print$\\WIN40\\0\\", 0);
645 PACKS(desc,"z",driver->dependent_files[i]); /* driver files to copy */
646 DEBUG(3,("Dependent File: %s:\n", driver->dependent_files[i]));
649 /* sanity check */
650 if ( i != count )
651 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
652 count, i));
654 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", printer_name, i));
656 desc->errcode=NERR_Success;
660 static const char *strip_unc(const char *unc)
662 char *p;
664 if (unc == NULL) {
665 return NULL;
668 if ((p = strrchr(unc, '\\')) != NULL) {
669 return p+1;
672 return unc;
675 static void fill_printq_info(int uLevel,
676 struct pack_desc* desc,
677 int count,
678 union spoolss_JobInfo *job_info,
679 struct spoolss_DriverInfo3 *driver_info,
680 struct spoolss_PrinterInfo2 *printer_info)
682 switch (uLevel) {
683 case 0:
684 case 1:
685 case 2:
686 PACKS(desc,"B13", strip_unc(printer_info->printername));
687 break;
688 case 3:
689 case 4:
690 case 5:
691 PACKS(desc,"z", strip_unc(printer_info->printername));
692 break;
693 case 51:
694 PACKI(desc,"K", printq_spoolss_status(printer_info->status));
695 break;
698 if (uLevel == 1 || uLevel == 2) {
699 PACKS(desc,"B",""); /* alignment */
700 PACKI(desc,"W",5); /* priority */
701 PACKI(desc,"W",0); /* start time */
702 PACKI(desc,"W",0); /* until time */
703 PACKS(desc,"z",""); /* pSepFile */
704 PACKS(desc,"z","lpd"); /* pPrProc */
705 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pDestinations */
706 PACKS(desc,"z",""); /* pParms */
707 if (printer_info->printername == NULL) {
708 PACKS(desc,"z","UNKNOWN PRINTER");
709 PACKI(desc,"W",LPSTAT_ERROR);
710 } else {
711 PACKS(desc,"z", printer_info->comment);
712 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* status */
714 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
717 if (uLevel == 3 || uLevel == 4) {
718 PACKI(desc,"W",5); /* uPriority */
719 PACKI(desc,"W",0); /* uStarttime */
720 PACKI(desc,"W",0); /* uUntiltime */
721 PACKI(desc,"W",5); /* pad1 */
722 PACKS(desc,"z",""); /* pszSepFile */
723 PACKS(desc,"z","WinPrint"); /* pszPrProc */
724 PACKS(desc,"z",NULL); /* pszParms */
725 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
726 /* "don't ask" that it's done this way to fix corrupted
727 Win9X/ME printer comments. */
728 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* fsStatus */
729 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
730 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pszPrinters */
731 PACKS(desc,"z", printer_info->drivername); /* pszDriverName */
732 PackDriverData(desc); /* pDriverData */
735 if (uLevel == 2 || uLevel == 4) {
736 int i;
737 for (i = 0; i < count; i++) {
738 fill_spoolss_printjob_info(uLevel == 2 ? 1 : 2, desc, &job_info[i].info2, i);
742 if (uLevel==52)
743 fill_printq_info_52(driver_info, desc, count, printer_info->printername);
746 /* This function returns the number of files for a given driver */
747 static int get_printerdrivernumber(const struct spoolss_DriverInfo3 *driver)
749 int result = 0;
751 /* count the number of files */
752 while (driver->dependent_files && *driver->dependent_files[result])
753 result++;
755 return result;
758 static bool api_DosPrintQGetInfo(struct smbd_server_connection *sconn,
759 connection_struct *conn, uint64_t vuid,
760 char *param, int tpscnt,
761 char *data, int tdscnt,
762 int mdrcnt,int mprcnt,
763 char **rdata,char **rparam,
764 int *rdata_len,int *rparam_len)
766 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
767 char *str2 = skip_string(param,tpscnt,str1);
768 char *p = skip_string(param,tpscnt,str2);
769 char *QueueName = p;
770 unsigned int uLevel;
771 uint32_t count = 0;
772 char *str3;
773 struct pack_desc desc;
774 char* tmpdata=NULL;
776 WERROR werr = WERR_OK;
777 TALLOC_CTX *mem_ctx = talloc_tos();
778 NTSTATUS status;
779 struct rpc_pipe_client *cli = NULL;
780 struct dcerpc_binding_handle *b = NULL;
781 struct policy_handle handle;
782 struct spoolss_DevmodeContainer devmode_ctr;
783 union spoolss_DriverInfo driver_info;
784 union spoolss_JobInfo *job_info = NULL;
785 union spoolss_PrinterInfo printer_info;
787 if (!str1 || !str2 || !p) {
788 return False;
790 memset((char *)&desc,'\0',sizeof(desc));
792 p = skip_string(param,tpscnt,p);
793 if (!p) {
794 return False;
796 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
797 str3 = get_safe_str_ptr(param,tpscnt,p,4);
798 /* str3 may be null here and is checked in check_printq_info(). */
800 /* remove any trailing username */
801 if ((p = strchr_m(QueueName,'%')))
802 *p = 0;
804 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
806 /* check it's a supported varient */
807 if (!prefix_ok(str1,"zWrLh"))
808 return False;
809 if (!check_printq_info(&desc,uLevel,str2,str3)) {
811 * Patch from Scott Moomaw <scott@bridgewater.edu>
812 * to return the 'invalid info level' error if an
813 * unknown level was requested.
815 *rdata_len = 0;
816 *rparam_len = 6;
817 *rparam = smb_realloc_limit(*rparam,*rparam_len);
818 if (!*rparam) {
819 return False;
821 SSVALS(*rparam,0,ERRunknownlevel);
822 SSVAL(*rparam,2,0);
823 SSVAL(*rparam,4,0);
824 return(True);
827 ZERO_STRUCT(handle);
829 if (QueueName == NULL || (strlen(QueueName) < 1)) {
830 desc.errcode = W_ERROR_V(WERR_INVALID_PARAM);
831 goto out;
834 status = rpc_pipe_open_interface(conn,
835 &ndr_table_spoolss.syntax_id,
836 conn->session_info,
837 conn->sconn->remote_address,
838 conn->sconn->msg_ctx,
839 &cli);
840 if (!NT_STATUS_IS_OK(status)) {
841 DEBUG(0,("api_DosPrintQGetInfo: could not connect to spoolss: %s\n",
842 nt_errstr(status)));
843 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
844 goto out;
846 b = cli->binding_handle;
848 ZERO_STRUCT(devmode_ctr);
850 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
851 QueueName,
852 "RAW",
853 devmode_ctr,
854 PRINTER_ACCESS_USE,
855 &handle,
856 &werr);
857 if (!NT_STATUS_IS_OK(status)) {
858 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
859 goto out;
861 if (!W_ERROR_IS_OK(werr)) {
862 desc.errcode = W_ERROR_V(werr);
863 goto out;
866 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
867 &handle,
870 &printer_info);
871 if (!W_ERROR_IS_OK(werr)) {
872 desc.errcode = W_ERROR_V(werr);
873 goto out;
876 if (uLevel==52) {
877 uint32_t server_major_version;
878 uint32_t server_minor_version;
880 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
881 &handle,
882 "Windows 4.0",
883 3, /* level */
885 0, /* version */
887 &driver_info,
888 &server_major_version,
889 &server_minor_version);
890 if (!W_ERROR_IS_OK(werr)) {
891 desc.errcode = W_ERROR_V(werr);
892 goto out;
895 count = get_printerdrivernumber(&driver_info.info3);
896 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
897 } else {
898 uint32_t num_jobs;
899 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
900 &handle,
901 0, /* firstjob */
902 0xff, /* numjobs */
903 2, /* level */
904 0, /* offered */
905 &num_jobs,
906 &job_info);
907 if (!W_ERROR_IS_OK(werr)) {
908 desc.errcode = W_ERROR_V(werr);
909 goto out;
912 count = num_jobs;
915 if (mdrcnt > 0) {
916 *rdata = smb_realloc_limit(*rdata,mdrcnt);
917 if (!*rdata) {
918 return False;
920 desc.base = *rdata;
921 desc.buflen = mdrcnt;
922 } else {
924 * Don't return data but need to get correct length
925 * init_package will return wrong size if buflen=0
927 desc.buflen = getlen(desc.format);
928 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
931 if (init_package(&desc,1,count)) {
932 desc.subcount = count;
933 fill_printq_info(uLevel,&desc,count, job_info, &driver_info.info3, &printer_info.info2);
936 *rdata_len = desc.usedlen;
939 * We must set the return code to ERRbuftoosmall
940 * in order to support lanman style printing with Win NT/2k
941 * clients --jerry
943 if (!mdrcnt && lp_disable_spoolss())
944 desc.errcode = ERRbuftoosmall;
946 out:
947 if (b && is_valid_policy_hnd(&handle)) {
948 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
951 *rdata_len = desc.usedlen;
952 *rparam_len = 6;
953 *rparam = smb_realloc_limit(*rparam,*rparam_len);
954 if (!*rparam) {
955 SAFE_FREE(tmpdata);
956 return False;
958 SSVALS(*rparam,0,desc.errcode);
959 SSVAL(*rparam,2,0);
960 SSVAL(*rparam,4,desc.neededlen);
962 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
964 SAFE_FREE(tmpdata);
966 return(True);
969 /****************************************************************************
970 View list of all print jobs on all queues.
971 ****************************************************************************/
973 static bool api_DosPrintQEnum(struct smbd_server_connection *sconn,
974 connection_struct *conn, uint64_t vuid,
975 char *param, int tpscnt,
976 char *data, int tdscnt,
977 int mdrcnt, int mprcnt,
978 char **rdata, char** rparam,
979 int *rdata_len, int *rparam_len)
981 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
982 char *output_format1 = skip_string(param,tpscnt,param_format);
983 char *p = skip_string(param,tpscnt,output_format1);
984 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
985 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
986 int i;
987 struct pack_desc desc;
988 int *subcntarr = NULL;
989 int queuecnt = 0, subcnt = 0, succnt = 0;
991 WERROR werr = WERR_OK;
992 TALLOC_CTX *mem_ctx = talloc_tos();
993 NTSTATUS status;
994 struct rpc_pipe_client *cli = NULL;
995 struct dcerpc_binding_handle *b = NULL;
996 struct spoolss_DevmodeContainer devmode_ctr;
997 uint32_t num_printers;
998 union spoolss_PrinterInfo *printer_info;
999 union spoolss_DriverInfo *driver_info;
1000 union spoolss_JobInfo **job_info;
1002 if (!param_format || !output_format1 || !p) {
1003 return False;
1006 memset((char *)&desc,'\0',sizeof(desc));
1008 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
1010 if (!prefix_ok(param_format,"WrLeh")) {
1011 return False;
1013 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
1015 * Patch from Scott Moomaw <scott@bridgewater.edu>
1016 * to return the 'invalid info level' error if an
1017 * unknown level was requested.
1019 *rdata_len = 0;
1020 *rparam_len = 6;
1021 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1022 if (!*rparam) {
1023 return False;
1025 SSVALS(*rparam,0,ERRunknownlevel);
1026 SSVAL(*rparam,2,0);
1027 SSVAL(*rparam,4,0);
1028 return(True);
1031 status = rpc_pipe_open_interface(conn,
1032 &ndr_table_spoolss.syntax_id,
1033 conn->session_info,
1034 conn->sconn->remote_address,
1035 conn->sconn->msg_ctx,
1036 &cli);
1037 if (!NT_STATUS_IS_OK(status)) {
1038 DEBUG(0,("api_DosPrintQEnum: could not connect to spoolss: %s\n",
1039 nt_errstr(status)));
1040 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1041 goto out;
1043 b = cli->binding_handle;
1045 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
1046 PRINTER_ENUM_LOCAL,
1047 cli->srv_name_slash,
1050 &num_printers,
1051 &printer_info);
1052 if (!W_ERROR_IS_OK(werr)) {
1053 desc.errcode = W_ERROR_V(werr);
1054 goto out;
1057 queuecnt = num_printers;
1059 job_info = talloc_array(mem_ctx, union spoolss_JobInfo *, num_printers);
1060 if (job_info == NULL) {
1061 goto err;
1064 driver_info = talloc_array(mem_ctx, union spoolss_DriverInfo, num_printers);
1065 if (driver_info == NULL) {
1066 goto err;
1069 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1070 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1071 goto err;
1074 if (mdrcnt > 0) {
1075 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1076 if (!*rdata) {
1077 goto err;
1080 desc.base = *rdata;
1081 desc.buflen = mdrcnt;
1083 subcnt = 0;
1084 for (i = 0; i < num_printers; i++) {
1086 uint32_t num_jobs;
1087 struct policy_handle handle;
1088 const char *printername;
1090 printername = talloc_strdup(mem_ctx, printer_info[i].info2.printername);
1091 if (printername == NULL) {
1092 goto err;
1095 ZERO_STRUCT(handle);
1096 ZERO_STRUCT(devmode_ctr);
1098 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
1099 printername,
1100 "RAW",
1101 devmode_ctr,
1102 PRINTER_ACCESS_USE,
1103 &handle,
1104 &werr);
1105 if (!NT_STATUS_IS_OK(status)) {
1106 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1107 goto out;
1109 if (!W_ERROR_IS_OK(werr)) {
1110 desc.errcode = W_ERROR_V(werr);
1111 goto out;
1114 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
1115 &handle,
1116 0, /* firstjob */
1117 0xff, /* numjobs */
1118 2, /* level */
1119 0, /* offered */
1120 &num_jobs,
1121 &job_info[i]);
1122 if (!W_ERROR_IS_OK(werr)) {
1123 desc.errcode = W_ERROR_V(werr);
1124 goto out;
1127 if (uLevel==52) {
1128 uint32_t server_major_version;
1129 uint32_t server_minor_version;
1131 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1132 &handle,
1133 "Windows 4.0",
1134 3, /* level */
1136 0, /* version */
1138 &driver_info[i],
1139 &server_major_version,
1140 &server_minor_version);
1141 if (!W_ERROR_IS_OK(werr)) {
1142 desc.errcode = W_ERROR_V(werr);
1143 goto out;
1147 subcntarr[i] = num_jobs;
1148 subcnt += subcntarr[i];
1150 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
1153 if (init_package(&desc,queuecnt,subcnt)) {
1154 for (i = 0; i < num_printers; i++) {
1155 fill_printq_info(uLevel,&desc,subcntarr[i], job_info[i], &driver_info[i].info3, &printer_info[i].info2);
1156 if (desc.errcode == NERR_Success) {
1157 succnt = i;
1162 out:
1163 SAFE_FREE(subcntarr);
1164 *rdata_len = desc.usedlen;
1165 *rparam_len = 8;
1166 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1167 if (!*rparam) {
1168 goto err;
1170 SSVALS(*rparam,0,desc.errcode);
1171 SSVAL(*rparam,2,0);
1172 SSVAL(*rparam,4,succnt);
1173 SSVAL(*rparam,6,queuecnt);
1175 return True;
1177 err:
1179 SAFE_FREE(subcntarr);
1181 return False;
1184 /****************************************************************************
1185 Get info level for a server list query.
1186 ****************************************************************************/
1188 static bool check_session_info(int uLevel, char* id)
1190 switch( uLevel ) {
1191 case 0:
1192 if (strcmp(id,"B16") != 0) {
1193 return False;
1195 break;
1196 case 1:
1197 if (strcmp(id,"B16BBDz") != 0) {
1198 return False;
1200 break;
1201 default:
1202 return False;
1204 return True;
1207 struct srv_info_struct {
1208 fstring name;
1209 uint32 type;
1210 fstring comment;
1211 fstring domain;
1212 bool server_added;
1215 /*******************************************************************
1216 Get server info lists from the files saved by nmbd. Return the
1217 number of entries.
1218 ******************************************************************/
1220 static int get_session_info(uint32 servertype,
1221 struct srv_info_struct **servers,
1222 const char *domain)
1224 int count=0;
1225 int alloced=0;
1226 char **lines;
1227 bool local_list_only;
1228 int i;
1230 lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
1231 if (!lines) {
1232 DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
1233 return 0;
1236 /* request for everything is code for request all servers */
1237 if (servertype == SV_TYPE_ALL) {
1238 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1241 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1243 DEBUG(4,("Servertype search: %8x\n",servertype));
1245 for (i=0;lines[i];i++) {
1246 fstring stype;
1247 struct srv_info_struct *s;
1248 const char *ptr = lines[i];
1249 bool ok = True;
1250 TALLOC_CTX *frame = NULL;
1251 char *p;
1253 if (!*ptr) {
1254 continue;
1257 if (count == alloced) {
1258 alloced += 10;
1259 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1260 if (!*servers) {
1261 DEBUG(0,("get_session_info: failed to enlarge servers info struct!\n"));
1262 TALLOC_FREE(lines);
1263 return 0;
1265 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1267 s = &(*servers)[count];
1269 frame = talloc_stackframe();
1270 s->name[0] = '\0';
1271 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1272 TALLOC_FREE(frame);
1273 continue;
1275 fstrcpy(s->name, p);
1277 stype[0] = '\0';
1278 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1279 TALLOC_FREE(frame);
1280 continue;
1282 fstrcpy(stype, p);
1284 s->comment[0] = '\0';
1285 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1286 TALLOC_FREE(frame);
1287 continue;
1289 fstrcpy(s->comment, p);
1290 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1292 s->domain[0] = '\0';
1293 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1294 /* this allows us to cope with an old nmbd */
1295 fstrcpy(s->domain,lp_workgroup());
1296 } else {
1297 fstrcpy(s->domain, p);
1299 TALLOC_FREE(frame);
1301 if (sscanf(stype,"%X",&s->type) != 1) {
1302 DEBUG(4,("r:host file "));
1303 ok = False;
1306 /* Filter the servers/domains we return based on what was asked for. */
1308 /* Check to see if we are being asked for a local list only. */
1309 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1310 DEBUG(4,("r: local list only"));
1311 ok = False;
1314 /* doesn't match up: don't want it */
1315 if (!(servertype & s->type)) {
1316 DEBUG(4,("r:serv type "));
1317 ok = False;
1320 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1321 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1322 DEBUG(4,("s: dom mismatch "));
1323 ok = False;
1326 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1327 ok = False;
1330 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1331 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1333 if (ok) {
1334 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1335 s->name, s->type, s->comment, s->domain));
1336 s->server_added = True;
1337 count++;
1338 } else {
1339 DEBUG(4,("%20s %8x %25s %15s\n",
1340 s->name, s->type, s->comment, s->domain));
1344 TALLOC_FREE(lines);
1345 return count;
1348 /*******************************************************************
1349 Fill in a server info structure.
1350 ******************************************************************/
1352 static int fill_srv_info(struct srv_info_struct *service,
1353 int uLevel, char **buf, int *buflen,
1354 char **stringbuf, int *stringspace, char *baseaddr)
1356 int struct_len;
1357 char* p;
1358 char* p2;
1359 int l2;
1360 int len;
1362 switch (uLevel) {
1363 case 0:
1364 struct_len = 16;
1365 break;
1366 case 1:
1367 struct_len = 26;
1368 break;
1369 default:
1370 return -1;
1373 if (!buf) {
1374 len = 0;
1375 switch (uLevel) {
1376 case 1:
1377 len = strlen(service->comment)+1;
1378 break;
1381 *buflen = struct_len;
1382 *stringspace = len;
1383 return struct_len + len;
1386 len = struct_len;
1387 p = *buf;
1388 if (*buflen < struct_len) {
1389 return -1;
1391 if (stringbuf) {
1392 p2 = *stringbuf;
1393 l2 = *stringspace;
1394 } else {
1395 p2 = p + struct_len;
1396 l2 = *buflen - struct_len;
1398 if (!baseaddr) {
1399 baseaddr = p;
1402 switch (uLevel) {
1403 case 0:
1404 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1405 break;
1407 case 1:
1408 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1409 SIVAL(p,18,service->type);
1410 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1411 len += CopyAndAdvance(&p2,service->comment,&l2);
1412 break;
1415 if (stringbuf) {
1416 *buf = p + struct_len;
1417 *buflen -= struct_len;
1418 *stringbuf = p2;
1419 *stringspace = l2;
1420 } else {
1421 *buf = p2;
1422 *buflen -= len;
1424 return len;
1428 static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1430 return strcasecmp_m(s1->name,s2->name);
1433 /****************************************************************************
1434 View list of servers available (or possibly domains). The info is
1435 extracted from lists saved by nmbd on the local host.
1436 ****************************************************************************/
1438 static bool api_RNetServerEnum2(struct smbd_server_connection *sconn,
1439 connection_struct *conn, uint64_t vuid,
1440 char *param, int tpscnt,
1441 char *data, int tdscnt,
1442 int mdrcnt, int mprcnt, char **rdata,
1443 char **rparam, int *rdata_len, int *rparam_len)
1445 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1446 char *str2 = skip_string(param,tpscnt,str1);
1447 char *p = skip_string(param,tpscnt,str2);
1448 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1449 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1450 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1451 char *p2;
1452 int data_len, fixed_len, string_len;
1453 int f_len = 0, s_len = 0;
1454 struct srv_info_struct *servers=NULL;
1455 int counted=0,total=0;
1456 int i,missed;
1457 fstring domain;
1458 bool domain_request;
1459 bool local_request;
1461 if (!str1 || !str2 || !p) {
1462 return False;
1465 /* If someone sets all the bits they don't really mean to set
1466 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1467 known servers. */
1469 if (servertype == SV_TYPE_ALL) {
1470 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1473 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1474 any other bit (they may just set this bit on its own) they
1475 want all the locally seen servers. However this bit can be
1476 set on its own so set the requested servers to be
1477 ALL - DOMAIN_ENUM. */
1479 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1480 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1483 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1484 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1486 p += 8;
1488 if (!prefix_ok(str1,"WrLehD")) {
1489 return False;
1491 if (!check_session_info(uLevel,str2)) {
1492 return False;
1495 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1496 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1497 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1499 if (strcmp(str1, "WrLehDz") == 0) {
1500 if (skip_string(param,tpscnt,p) == NULL) {
1501 return False;
1503 pull_ascii_fstring(domain, p);
1504 } else {
1505 fstrcpy(domain, lp_workgroup());
1508 DEBUG(4, ("domain [%s]\n", domain));
1510 if (lp_browse_list()) {
1511 total = get_session_info(servertype,&servers,domain);
1514 data_len = fixed_len = string_len = 0;
1515 missed = 0;
1517 TYPESAFE_QSORT(servers, total, srv_comp);
1520 char *lastname=NULL;
1522 for (i=0;i<total;i++) {
1523 struct srv_info_struct *s = &servers[i];
1525 if (lastname && strequal(lastname,s->name)) {
1526 continue;
1528 lastname = s->name;
1529 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1530 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1531 i, s->name, s->type, s->comment, s->domain));
1533 if (data_len < buf_len) {
1534 counted++;
1535 fixed_len += f_len;
1536 string_len += s_len;
1537 } else {
1538 missed++;
1543 *rdata_len = fixed_len + string_len;
1544 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1545 if (!*rdata) {
1546 return False;
1549 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1550 p = *rdata;
1551 f_len = fixed_len;
1552 s_len = string_len;
1555 char *lastname=NULL;
1556 int count2 = counted;
1558 for (i = 0; i < total && count2;i++) {
1559 struct srv_info_struct *s = &servers[i];
1561 if (lastname && strequal(lastname,s->name)) {
1562 continue;
1564 lastname = s->name;
1565 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1566 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1567 i, s->name, s->type, s->comment, s->domain));
1568 count2--;
1572 *rparam_len = 8;
1573 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1574 if (!*rparam) {
1575 return False;
1577 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1578 SSVAL(*rparam,2,0);
1579 SSVAL(*rparam,4,counted);
1580 SSVAL(*rparam,6,counted+missed);
1582 SAFE_FREE(servers);
1584 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1585 domain,uLevel,counted,counted+missed));
1587 return True;
1590 static int srv_name_match(const char *n1, const char *n2)
1593 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1595 * In Windows, FirstNameToReturn need not be an exact match:
1596 * the server will return a list of servers that exist on
1597 * the network greater than or equal to the FirstNameToReturn.
1599 int ret = strcasecmp_m(n1, n2);
1601 if (ret <= 0) {
1602 return 0;
1605 return ret;
1608 static bool api_RNetServerEnum3(struct smbd_server_connection *sconn,
1609 connection_struct *conn, uint64_t vuid,
1610 char *param, int tpscnt,
1611 char *data, int tdscnt,
1612 int mdrcnt, int mprcnt, char **rdata,
1613 char **rparam, int *rdata_len, int *rparam_len)
1615 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1616 char *str2 = skip_string(param,tpscnt,str1);
1617 char *p = skip_string(param,tpscnt,str2);
1618 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1619 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1620 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1621 char *p2;
1622 int data_len, fixed_len, string_len;
1623 int f_len = 0, s_len = 0;
1624 struct srv_info_struct *servers=NULL;
1625 int counted=0,first=0,total=0;
1626 int i,missed;
1627 fstring domain;
1628 fstring first_name;
1629 bool domain_request;
1630 bool local_request;
1632 if (!str1 || !str2 || !p) {
1633 return False;
1636 /* If someone sets all the bits they don't really mean to set
1637 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1638 known servers. */
1640 if (servertype == SV_TYPE_ALL) {
1641 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1644 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1645 any other bit (they may just set this bit on its own) they
1646 want all the locally seen servers. However this bit can be
1647 set on its own so set the requested servers to be
1648 ALL - DOMAIN_ENUM. */
1650 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1651 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1654 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1655 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1657 p += 8;
1659 if (strcmp(str1, "WrLehDzz") != 0) {
1660 return false;
1662 if (!check_session_info(uLevel,str2)) {
1663 return False;
1666 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1667 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1668 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1670 if (skip_string(param,tpscnt,p) == NULL) {
1671 return False;
1673 pull_ascii_fstring(domain, p);
1674 if (domain[0] == '\0') {
1675 fstrcpy(domain, lp_workgroup());
1677 p = skip_string(param,tpscnt,p);
1678 if (skip_string(param,tpscnt,p) == NULL) {
1679 return False;
1681 pull_ascii_fstring(first_name, p);
1683 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1684 domain, first_name));
1686 if (lp_browse_list()) {
1687 total = get_session_info(servertype,&servers,domain);
1690 data_len = fixed_len = string_len = 0;
1691 missed = 0;
1693 TYPESAFE_QSORT(servers, total, srv_comp);
1695 if (first_name[0] != '\0') {
1696 struct srv_info_struct *first_server = NULL;
1698 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1699 srv_name_match, first_server);
1700 if (first_server) {
1701 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1703 * The binary search may not find the exact match
1704 * so we need to search backward to find the first match
1706 * This implements the strange matching windows
1707 * implements. (see the comment in srv_name_match().
1709 for (;first > 0;) {
1710 int ret;
1711 ret = strcasecmp_m(first_name,
1712 servers[first-1].name);
1713 if (ret > 0) {
1714 break;
1716 first--;
1718 } else {
1719 /* we should return no entries */
1720 first = total;
1725 char *lastname=NULL;
1727 for (i=first;i<total;i++) {
1728 struct srv_info_struct *s = &servers[i];
1730 if (lastname && strequal(lastname,s->name)) {
1731 continue;
1733 lastname = s->name;
1734 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1735 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1736 i, s->name, s->type, s->comment, s->domain));
1738 if (data_len < buf_len) {
1739 counted++;
1740 fixed_len += f_len;
1741 string_len += s_len;
1742 } else {
1743 missed++;
1748 *rdata_len = fixed_len + string_len;
1749 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1750 if (!*rdata) {
1751 return False;
1754 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1755 p = *rdata;
1756 f_len = fixed_len;
1757 s_len = string_len;
1760 char *lastname=NULL;
1761 int count2 = counted;
1763 for (i = first; i < total && count2;i++) {
1764 struct srv_info_struct *s = &servers[i];
1766 if (lastname && strequal(lastname,s->name)) {
1767 continue;
1769 lastname = s->name;
1770 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1771 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1772 i, s->name, s->type, s->comment, s->domain));
1773 count2--;
1777 *rparam_len = 8;
1778 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1779 if (!*rparam) {
1780 return False;
1782 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1783 SSVAL(*rparam,2,0);
1784 SSVAL(*rparam,4,counted);
1785 SSVAL(*rparam,6,counted+missed);
1787 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1788 domain,uLevel,first,first_name,
1789 first < total ? servers[first].name : "",
1790 counted,counted+missed));
1792 SAFE_FREE(servers);
1794 return True;
1797 /****************************************************************************
1798 command 0x34 - suspected of being a "Lookup Names" stub api
1799 ****************************************************************************/
1801 static bool api_RNetGroupGetUsers(struct smbd_server_connection *sconn,
1802 connection_struct *conn, uint64_t vuid,
1803 char *param, int tpscnt,
1804 char *data, int tdscnt,
1805 int mdrcnt, int mprcnt, char **rdata,
1806 char **rparam, int *rdata_len, int *rparam_len)
1808 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1809 char *str2 = skip_string(param,tpscnt,str1);
1810 char *p = skip_string(param,tpscnt,str2);
1811 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1812 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1813 int counted=0;
1814 int missed=0;
1816 if (!str1 || !str2 || !p) {
1817 return False;
1820 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1821 str1, str2, p, uLevel, buf_len));
1823 if (!prefix_ok(str1,"zWrLeh")) {
1824 return False;
1827 *rdata_len = 0;
1829 *rparam_len = 8;
1830 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1831 if (!*rparam) {
1832 return False;
1835 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1836 SSVAL(*rparam,2,0);
1837 SSVAL(*rparam,4,counted);
1838 SSVAL(*rparam,6,counted+missed);
1840 return True;
1843 /****************************************************************************
1844 get info about a share
1845 ****************************************************************************/
1847 static bool check_share_info(int uLevel, char* id)
1849 switch( uLevel ) {
1850 case 0:
1851 if (strcmp(id,"B13") != 0) {
1852 return False;
1854 break;
1855 case 1:
1856 /* Level-2 descriptor is allowed (and ignored) */
1857 if (strcmp(id,"B13BWz") != 0 &&
1858 strcmp(id,"B13BWzWWWzB9B") != 0) {
1859 return False;
1861 break;
1862 case 2:
1863 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1864 return False;
1866 break;
1867 case 91:
1868 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1869 return False;
1871 break;
1872 default:
1873 return False;
1875 return True;
1878 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1879 char** buf, int* buflen,
1880 char** stringbuf, int* stringspace, char* baseaddr)
1882 int struct_len;
1883 char* p;
1884 char* p2;
1885 int l2;
1886 int len;
1888 switch( uLevel ) {
1889 case 0:
1890 struct_len = 13;
1891 break;
1892 case 1:
1893 struct_len = 20;
1894 break;
1895 case 2:
1896 struct_len = 40;
1897 break;
1898 case 91:
1899 struct_len = 68;
1900 break;
1901 default:
1902 return -1;
1905 if (!buf) {
1906 len = 0;
1908 if (uLevel > 0) {
1909 len += StrlenExpanded(conn,snum,lp_comment(talloc_tos(), snum));
1911 if (uLevel > 1) {
1912 len += strlen(lp_pathname(talloc_tos(), snum)) + 1;
1914 if (buflen) {
1915 *buflen = struct_len;
1917 if (stringspace) {
1918 *stringspace = len;
1920 return struct_len + len;
1923 len = struct_len;
1924 p = *buf;
1925 if ((*buflen) < struct_len) {
1926 return -1;
1929 if (stringbuf) {
1930 p2 = *stringbuf;
1931 l2 = *stringspace;
1932 } else {
1933 p2 = p + struct_len;
1934 l2 = (*buflen) - struct_len;
1937 if (!baseaddr) {
1938 baseaddr = p;
1941 push_ascii(p,lp_servicename(talloc_tos(), snum),13, STR_TERMINATE);
1943 if (uLevel > 0) {
1944 int type;
1946 SCVAL(p,13,0);
1947 type = STYPE_DISKTREE;
1948 if (lp_print_ok(snum)) {
1949 type = STYPE_PRINTQ;
1951 if (strequal("IPC",lp_fstype(talloc_tos(),snum))) {
1952 type = STYPE_IPC;
1954 SSVAL(p,14,type); /* device type */
1955 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1956 len += CopyExpanded(conn,snum,&p2,lp_comment(talloc_tos(),snum),&l2);
1959 if (uLevel > 1) {
1960 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1961 SSVALS(p,22,-1); /* max uses */
1962 SSVAL(p,24,1); /* current uses */
1963 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1964 len += CopyAndAdvance(&p2,lp_pathname(talloc_tos(),snum),&l2);
1965 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1968 if (uLevel > 2) {
1969 memset(p+40,0,SHPWLEN+2);
1970 SSVAL(p,50,0);
1971 SIVAL(p,52,0);
1972 SSVAL(p,56,0);
1973 SSVAL(p,58,0);
1974 SIVAL(p,60,0);
1975 SSVAL(p,64,0);
1976 SSVAL(p,66,0);
1979 if (stringbuf) {
1980 (*buf) = p + struct_len;
1981 (*buflen) -= struct_len;
1982 (*stringbuf) = p2;
1983 (*stringspace) = l2;
1984 } else {
1985 (*buf) = p2;
1986 (*buflen) -= len;
1989 return len;
1992 static bool api_RNetShareGetInfo(struct smbd_server_connection *sconn,
1993 connection_struct *conn,uint64_t vuid,
1994 char *param, int tpscnt,
1995 char *data, int tdscnt,
1996 int mdrcnt,int mprcnt,
1997 char **rdata,char **rparam,
1998 int *rdata_len,int *rparam_len)
2000 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2001 char *str2 = skip_string(param,tpscnt,str1);
2002 char *netname_in = skip_string(param,tpscnt,str2);
2003 char *netname = NULL;
2004 char *p = skip_string(param,tpscnt,netname);
2005 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2006 int snum;
2008 if (!str1 || !str2 || !netname_in || !p) {
2009 return False;
2012 snum = find_service(talloc_tos(), netname_in, &netname);
2013 if (snum < 0 || !netname) {
2014 return False;
2017 /* check it's a supported varient */
2018 if (!prefix_ok(str1,"zWrLh")) {
2019 return False;
2021 if (!check_share_info(uLevel,str2)) {
2022 return False;
2025 *rdata = smb_realloc_limit(*rdata,mdrcnt);
2026 if (!*rdata) {
2027 return False;
2029 p = *rdata;
2030 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
2031 if (*rdata_len < 0) {
2032 return False;
2035 *rparam_len = 6;
2036 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2037 if (!*rparam) {
2038 return False;
2040 SSVAL(*rparam,0,NERR_Success);
2041 SSVAL(*rparam,2,0); /* converter word */
2042 SSVAL(*rparam,4,*rdata_len);
2044 return True;
2047 /****************************************************************************
2048 View the list of available shares.
2050 This function is the server side of the NetShareEnum() RAP call.
2051 It fills the return buffer with share names and share comments.
2052 Note that the return buffer normally (in all known cases) allows only
2053 twelve byte strings for share names (plus one for a nul terminator).
2054 Share names longer than 12 bytes must be skipped.
2055 ****************************************************************************/
2057 static bool api_RNetShareEnum(struct smbd_server_connection *sconn,
2058 connection_struct *conn, uint64_t vuid,
2059 char *param, int tpscnt,
2060 char *data, int tdscnt,
2061 int mdrcnt,
2062 int mprcnt,
2063 char **rdata,
2064 char **rparam,
2065 int *rdata_len,
2066 int *rparam_len )
2068 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2069 char *str2 = skip_string(param,tpscnt,str1);
2070 char *p = skip_string(param,tpscnt,str2);
2071 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2072 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
2073 char *p2;
2074 int count = 0;
2075 int total=0,counted=0;
2076 bool missed = False;
2077 int i;
2078 int data_len, fixed_len, string_len;
2079 int f_len = 0, s_len = 0;
2081 if (!str1 || !str2 || !p) {
2082 return False;
2085 if (!prefix_ok(str1,"WrLeh")) {
2086 return False;
2088 if (!check_share_info(uLevel,str2)) {
2089 return False;
2092 /* Ensure all the usershares are loaded. */
2093 become_root();
2094 load_registry_shares();
2095 count = load_usershare_shares(NULL, connections_snum_used);
2096 unbecome_root();
2098 data_len = fixed_len = string_len = 0;
2099 for (i=0;i<count;i++) {
2100 fstring servicename_dos;
2101 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2102 continue;
2104 push_ascii_fstring(servicename_dos, lp_servicename(talloc_tos(), i));
2105 /* Maximum name length = 13. */
2106 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
2107 total++;
2108 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
2109 if (data_len < buf_len) {
2110 counted++;
2111 fixed_len += f_len;
2112 string_len += s_len;
2113 } else {
2114 missed = True;
2119 *rdata_len = fixed_len + string_len;
2120 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2121 if (!*rdata) {
2122 return False;
2125 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
2126 p = *rdata;
2127 f_len = fixed_len;
2128 s_len = string_len;
2130 for( i = 0; i < count; i++ ) {
2131 fstring servicename_dos;
2132 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2133 continue;
2136 push_ascii_fstring(servicename_dos,
2137 lp_servicename(talloc_tos(), i));
2138 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2139 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2140 break;
2145 *rparam_len = 8;
2146 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2147 if (!*rparam) {
2148 return False;
2150 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2151 SSVAL(*rparam,2,0);
2152 SSVAL(*rparam,4,counted);
2153 SSVAL(*rparam,6,total);
2155 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2156 counted,total,uLevel,
2157 buf_len,*rdata_len,mdrcnt));
2159 return True;
2162 /****************************************************************************
2163 Add a share
2164 ****************************************************************************/
2166 static bool api_RNetShareAdd(struct smbd_server_connection *sconn,
2167 connection_struct *conn,uint64_t vuid,
2168 char *param, int tpscnt,
2169 char *data, int tdscnt,
2170 int mdrcnt,int mprcnt,
2171 char **rdata,char **rparam,
2172 int *rdata_len,int *rparam_len)
2174 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2175 char *str2 = skip_string(param,tpscnt,str1);
2176 char *p = skip_string(param,tpscnt,str2);
2177 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2178 fstring sharename;
2179 fstring comment;
2180 char *pathname = NULL;
2181 unsigned int offset;
2182 int res = ERRunsup;
2183 size_t converted_size;
2185 WERROR werr = WERR_OK;
2186 TALLOC_CTX *mem_ctx = talloc_tos();
2187 NTSTATUS status;
2188 struct rpc_pipe_client *cli = NULL;
2189 union srvsvc_NetShareInfo info;
2190 struct srvsvc_NetShareInfo2 info2;
2191 struct dcerpc_binding_handle *b;
2193 if (!str1 || !str2 || !p) {
2194 return False;
2197 /* check it's a supported varient */
2198 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2199 return False;
2201 if (!check_share_info(uLevel,str2)) {
2202 return False;
2204 if (uLevel != 2) {
2205 return False;
2208 /* Do we have a string ? */
2209 if (skip_string(data,mdrcnt,data) == NULL) {
2210 return False;
2212 pull_ascii_fstring(sharename,data);
2214 if (mdrcnt < 28) {
2215 return False;
2218 /* only support disk share adds */
2219 if (SVAL(data,14)!=STYPE_DISKTREE) {
2220 return False;
2223 offset = IVAL(data, 16);
2224 if (offset >= mdrcnt) {
2225 res = ERRinvalidparam;
2226 goto out;
2229 /* Do we have a string ? */
2230 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2231 return False;
2233 pull_ascii_fstring(comment, offset? (data+offset) : "");
2235 offset = IVAL(data, 26);
2237 if (offset >= mdrcnt) {
2238 res = ERRinvalidparam;
2239 goto out;
2242 /* Do we have a string ? */
2243 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2244 return False;
2247 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2248 offset ? (data+offset) : "", &converted_size))
2250 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
2251 strerror(errno)));
2254 if (!pathname) {
2255 return false;
2258 status = rpc_pipe_open_interface(mem_ctx, &ndr_table_srvsvc.syntax_id,
2259 conn->session_info,
2260 conn->sconn->remote_address,
2261 conn->sconn->msg_ctx,
2262 &cli);
2263 if (!NT_STATUS_IS_OK(status)) {
2264 DEBUG(0,("api_RNetShareAdd: could not connect to srvsvc: %s\n",
2265 nt_errstr(status)));
2266 res = W_ERROR_V(ntstatus_to_werror(status));
2267 goto out;
2270 b = cli->binding_handle;
2272 info2.name = sharename;
2273 info2.type = STYPE_DISKTREE;
2274 info2.comment = comment;
2275 info2.permissions = 0;
2276 info2.max_users = 0;
2277 info2.current_users = 0;
2278 info2.path = pathname;
2279 info2.password = NULL;
2281 info.info2 = &info2;
2283 status = dcerpc_srvsvc_NetShareAdd(b, mem_ctx,
2284 cli->srv_name_slash,
2286 &info,
2287 NULL,
2288 &werr);
2289 if (!NT_STATUS_IS_OK(status)) {
2290 res = W_ERROR_V(ntstatus_to_werror(status));
2291 goto out;
2293 if (!W_ERROR_IS_OK(werr)) {
2294 res = W_ERROR_V(werr);
2295 goto out;
2298 *rparam_len = 6;
2299 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2300 if (!*rparam) {
2301 return False;
2303 SSVAL(*rparam,0,NERR_Success);
2304 SSVAL(*rparam,2,0); /* converter word */
2305 SSVAL(*rparam,4,*rdata_len);
2306 *rdata_len = 0;
2308 return True;
2310 out:
2312 *rparam_len = 4;
2313 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2314 if (!*rparam) {
2315 return False;
2317 *rdata_len = 0;
2318 SSVAL(*rparam,0,res);
2319 SSVAL(*rparam,2,0);
2320 return True;
2323 /****************************************************************************
2324 view list of groups available
2325 ****************************************************************************/
2327 static bool api_RNetGroupEnum(struct smbd_server_connection *sconn,
2328 connection_struct *conn,uint64_t vuid,
2329 char *param, int tpscnt,
2330 char *data, int tdscnt,
2331 int mdrcnt,int mprcnt,
2332 char **rdata,char **rparam,
2333 int *rdata_len,int *rparam_len)
2335 int i;
2336 int errflags=0;
2337 int resume_context, cli_buf_size;
2338 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2339 char *str2 = skip_string(param,tpscnt,str1);
2340 char *p = skip_string(param,tpscnt,str2);
2342 uint32_t num_groups;
2343 uint32_t resume_handle;
2344 struct rpc_pipe_client *samr_pipe;
2345 struct policy_handle samr_handle, domain_handle;
2346 NTSTATUS status, result;
2347 struct dcerpc_binding_handle *b;
2349 if (!str1 || !str2 || !p) {
2350 return False;
2353 if (strcmp(str1,"WrLeh") != 0) {
2354 return False;
2357 /* parameters
2358 * W-> resume context (number of users to skip)
2359 * r -> return parameter pointer to receive buffer
2360 * L -> length of receive buffer
2361 * e -> return parameter number of entries
2362 * h -> return parameter total number of users
2365 if (strcmp("B21",str2) != 0) {
2366 return False;
2369 status = rpc_pipe_open_interface(
2370 talloc_tos(), &ndr_table_samr.syntax_id,
2371 conn->session_info, conn->sconn->remote_address,
2372 conn->sconn->msg_ctx, &samr_pipe);
2373 if (!NT_STATUS_IS_OK(status)) {
2374 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2375 nt_errstr(status)));
2376 return false;
2379 b = samr_pipe->binding_handle;
2381 status = dcerpc_samr_Connect2(b, talloc_tos(), lp_netbios_name(),
2382 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle,
2383 &result);
2384 if (!NT_STATUS_IS_OK(status)) {
2385 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2386 nt_errstr(status)));
2387 return false;
2389 if (!NT_STATUS_IS_OK(result)) {
2390 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2391 nt_errstr(result)));
2392 return false;
2395 status = dcerpc_samr_OpenDomain(b, talloc_tos(), &samr_handle,
2396 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2397 get_global_sam_sid(), &domain_handle,
2398 &result);
2399 if (!NT_STATUS_IS_OK(status)) {
2400 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2401 nt_errstr(status)));
2402 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2403 return false;
2405 if (!NT_STATUS_IS_OK(result)) {
2406 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2407 nt_errstr(result)));
2408 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2409 return false;
2412 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2413 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2414 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2415 "%d\n", resume_context, cli_buf_size));
2417 *rdata_len = cli_buf_size;
2418 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2419 if (!*rdata) {
2420 return False;
2423 p = *rdata;
2425 errflags = NERR_Success;
2426 num_groups = 0;
2427 resume_handle = 0;
2429 while (true) {
2430 struct samr_SamArray *sam_entries;
2431 uint32_t num_entries;
2433 status = dcerpc_samr_EnumDomainGroups(b, talloc_tos(),
2434 &domain_handle,
2435 &resume_handle,
2436 &sam_entries, 1,
2437 &num_entries,
2438 &result);
2439 if (!NT_STATUS_IS_OK(status)) {
2440 DEBUG(10, ("dcerpc_samr_EnumDomainGroups returned "
2441 "%s\n", nt_errstr(status)));
2442 break;
2444 if (!NT_STATUS_IS_OK(result)) {
2445 status = result;
2446 DEBUG(10, ("dcerpc_samr_EnumDomainGroups returned "
2447 "%s\n", nt_errstr(result)));
2448 break;
2451 if (num_entries == 0) {
2452 DEBUG(10, ("dcerpc_samr_EnumDomainGroups returned "
2453 "no entries -- done\n"));
2454 break;
2457 for(i=0; i<num_entries; i++) {
2458 const char *name;
2460 name = sam_entries->entries[i].name.string;
2462 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2463 /* set overflow error */
2464 DEBUG(3,("overflow on entry %d group %s\n", i,
2465 name));
2466 errflags=234;
2467 break;
2470 /* truncate the name at 21 chars. */
2471 memset(p, 0, 21);
2472 strlcpy(p, name, 21);
2473 DEBUG(10,("adding entry %d group %s\n", i, p));
2474 p += 21;
2475 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2476 * idea why... */
2477 num_groups += 1;
2480 if (errflags != NERR_Success) {
2481 break;
2484 TALLOC_FREE(sam_entries);
2487 dcerpc_samr_Close(b, talloc_tos(), &domain_handle, &result);
2488 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2490 *rdata_len = PTR_DIFF(p,*rdata);
2492 *rparam_len = 8;
2493 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2494 if (!*rparam) {
2495 return False;
2497 SSVAL(*rparam, 0, errflags);
2498 SSVAL(*rparam, 2, 0); /* converter word */
2499 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2500 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2502 return(True);
2505 /*******************************************************************
2506 Get groups that a user is a member of.
2507 ******************************************************************/
2509 static bool api_NetUserGetGroups(struct smbd_server_connection *sconn,
2510 connection_struct *conn,uint64_t vuid,
2511 char *param, int tpscnt,
2512 char *data, int tdscnt,
2513 int mdrcnt,int mprcnt,
2514 char **rdata,char **rparam,
2515 int *rdata_len,int *rparam_len)
2517 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2518 char *str2 = skip_string(param,tpscnt,str1);
2519 char *UserName = skip_string(param,tpscnt,str2);
2520 char *p = skip_string(param,tpscnt,UserName);
2521 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2522 const char *level_string;
2523 int count=0;
2524 bool ret = False;
2525 uint32_t i;
2526 char *endp = NULL;
2528 struct rpc_pipe_client *samr_pipe;
2529 struct policy_handle samr_handle, domain_handle, user_handle;
2530 struct lsa_String name;
2531 struct lsa_Strings names;
2532 struct samr_Ids type, rid;
2533 struct samr_RidWithAttributeArray *rids;
2534 NTSTATUS status, result;
2535 struct dcerpc_binding_handle *b;
2537 if (!str1 || !str2 || !UserName || !p) {
2538 return False;
2541 *rparam_len = 8;
2542 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2543 if (!*rparam) {
2544 return False;
2547 /* check it's a supported varient */
2549 if ( strcmp(str1,"zWrLeh") != 0 )
2550 return False;
2552 switch( uLevel ) {
2553 case 0:
2554 level_string = "B21";
2555 break;
2556 default:
2557 return False;
2560 if (strcmp(level_string,str2) != 0)
2561 return False;
2563 *rdata_len = mdrcnt + 1024;
2564 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2565 if (!*rdata) {
2566 return False;
2569 SSVAL(*rparam,0,NERR_Success);
2570 SSVAL(*rparam,2,0); /* converter word */
2572 p = *rdata;
2573 endp = *rdata + *rdata_len;
2575 status = rpc_pipe_open_interface(
2576 talloc_tos(), &ndr_table_samr.syntax_id,
2577 conn->session_info, conn->sconn->remote_address,
2578 conn->sconn->msg_ctx, &samr_pipe);
2579 if (!NT_STATUS_IS_OK(status)) {
2580 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2581 nt_errstr(status)));
2582 return false;
2585 b = samr_pipe->binding_handle;
2587 status = dcerpc_samr_Connect2(b, talloc_tos(), lp_netbios_name(),
2588 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle,
2589 &result);
2590 if (!NT_STATUS_IS_OK(status)) {
2591 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2592 nt_errstr(status)));
2593 return false;
2595 if (!NT_STATUS_IS_OK(result)) {
2596 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2597 nt_errstr(result)));
2598 return false;
2601 status = dcerpc_samr_OpenDomain(b, talloc_tos(), &samr_handle,
2602 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2603 get_global_sam_sid(), &domain_handle,
2604 &result);
2605 if (!NT_STATUS_IS_OK(status)) {
2606 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2607 nt_errstr(status)));
2608 goto close_sam;
2610 if (!NT_STATUS_IS_OK(result)) {
2611 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2612 nt_errstr(result)));
2613 goto close_sam;
2616 name.string = UserName;
2618 status = dcerpc_samr_LookupNames(b, talloc_tos(),
2619 &domain_handle, 1, &name,
2620 &rid, &type,
2621 &result);
2622 if (!NT_STATUS_IS_OK(status)) {
2623 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2624 nt_errstr(status)));
2625 goto close_domain;
2627 if (!NT_STATUS_IS_OK(result)) {
2628 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2629 nt_errstr(result)));
2630 goto close_domain;
2632 if (rid.count != 1) {
2633 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2634 goto close_domain;
2636 if (type.count != 1) {
2637 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2638 goto close_domain;
2641 if (type.ids[0] != SID_NAME_USER) {
2642 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2643 sid_type_lookup(type.ids[0])));
2644 goto close_domain;
2647 status = dcerpc_samr_OpenUser(b, talloc_tos(),
2648 &domain_handle,
2649 SAMR_USER_ACCESS_GET_GROUPS,
2650 rid.ids[0], &user_handle,
2651 &result);
2652 if (!NT_STATUS_IS_OK(status)) {
2653 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2654 nt_errstr(status)));
2655 goto close_domain;
2657 if (!NT_STATUS_IS_OK(result)) {
2658 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2659 nt_errstr(result)));
2660 goto close_domain;
2663 status = dcerpc_samr_GetGroupsForUser(b, talloc_tos(),
2664 &user_handle, &rids,
2665 &result);
2666 if (!NT_STATUS_IS_OK(status)) {
2667 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2668 nt_errstr(status)));
2669 goto close_user;
2671 if (!NT_STATUS_IS_OK(result)) {
2672 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2673 nt_errstr(result)));
2674 goto close_user;
2677 for (i=0; i<rids->count; i++) {
2679 status = dcerpc_samr_LookupRids(b, talloc_tos(),
2680 &domain_handle,
2681 1, &rids->rids[i].rid,
2682 &names, &type,
2683 &result);
2684 if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result) && (names.count == 1)) {
2685 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2686 p += 21;
2687 count++;
2691 *rdata_len = PTR_DIFF(p,*rdata);
2693 SSVAL(*rparam,4,count); /* is this right?? */
2694 SSVAL(*rparam,6,count); /* is this right?? */
2696 ret = True;
2698 close_user:
2699 dcerpc_samr_Close(b, talloc_tos(), &user_handle, &result);
2700 close_domain:
2701 dcerpc_samr_Close(b, talloc_tos(), &domain_handle, &result);
2702 close_sam:
2703 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2705 return ret;
2708 /*******************************************************************
2709 Get all users.
2710 ******************************************************************/
2712 static bool api_RNetUserEnum(struct smbd_server_connection *sconn,
2713 connection_struct *conn, uint64_t vuid,
2714 char *param, int tpscnt,
2715 char *data, int tdscnt,
2716 int mdrcnt,int mprcnt,
2717 char **rdata,char **rparam,
2718 int *rdata_len,int *rparam_len)
2720 int count_sent=0;
2721 int num_users=0;
2722 int errflags=0;
2723 int i, resume_context, cli_buf_size;
2724 uint32_t resume_handle;
2726 struct rpc_pipe_client *samr_pipe;
2727 struct policy_handle samr_handle, domain_handle;
2728 NTSTATUS status, result;
2730 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2731 char *str2 = skip_string(param,tpscnt,str1);
2732 char *p = skip_string(param,tpscnt,str2);
2733 char *endp = NULL;
2735 struct dcerpc_binding_handle *b;
2737 if (!str1 || !str2 || !p) {
2738 return False;
2741 if (strcmp(str1,"WrLeh") != 0)
2742 return False;
2743 /* parameters
2744 * W-> resume context (number of users to skip)
2745 * r -> return parameter pointer to receive buffer
2746 * L -> length of receive buffer
2747 * e -> return parameter number of entries
2748 * h -> return parameter total number of users
2751 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2752 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2753 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2754 resume_context, cli_buf_size));
2756 *rparam_len = 8;
2757 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2758 if (!*rparam) {
2759 return False;
2762 /* check it's a supported varient */
2763 if (strcmp("B21",str2) != 0)
2764 return False;
2766 *rdata_len = cli_buf_size;
2767 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2768 if (!*rdata) {
2769 return False;
2772 p = *rdata;
2773 endp = *rdata + *rdata_len;
2775 status = rpc_pipe_open_interface(
2776 talloc_tos(), &ndr_table_samr.syntax_id,
2777 conn->session_info, conn->sconn->remote_address,
2778 conn->sconn->msg_ctx, &samr_pipe);
2779 if (!NT_STATUS_IS_OK(status)) {
2780 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2781 nt_errstr(status)));
2782 return false;
2785 b = samr_pipe->binding_handle;
2787 status = dcerpc_samr_Connect2(b, talloc_tos(), lp_netbios_name(),
2788 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle,
2789 &result);
2790 if (!NT_STATUS_IS_OK(status)) {
2791 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2792 nt_errstr(status)));
2793 return false;
2795 if (!NT_STATUS_IS_OK(result)) {
2796 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2797 nt_errstr(result)));
2798 return false;
2801 status = dcerpc_samr_OpenDomain(b, talloc_tos(), &samr_handle,
2802 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2803 get_global_sam_sid(), &domain_handle,
2804 &result);
2805 if (!NT_STATUS_IS_OK(status)) {
2806 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2807 nt_errstr(status)));
2808 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2809 return false;
2811 if (!NT_STATUS_IS_OK(result)) {
2812 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2813 nt_errstr(result)));
2814 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2815 return false;
2818 errflags=NERR_Success;
2820 resume_handle = 0;
2822 while (true) {
2823 struct samr_SamArray *sam_entries;
2824 uint32_t num_entries;
2826 status = dcerpc_samr_EnumDomainUsers(b, talloc_tos(),
2827 &domain_handle,
2828 &resume_handle,
2829 0, &sam_entries, 1,
2830 &num_entries,
2831 &result);
2833 if (!NT_STATUS_IS_OK(status)) {
2834 DEBUG(10, ("dcerpc_samr_EnumDomainUsers returned "
2835 "%s\n", nt_errstr(status)));
2836 break;
2838 if (!NT_STATUS_IS_OK(result)) {
2839 DEBUG(10, ("dcerpc_samr_EnumDomainUsers returned "
2840 "%s\n", nt_errstr(result)));
2841 break;
2844 if (num_entries == 0) {
2845 DEBUG(10, ("dcerpc_samr_EnumDomainUsers returned "
2846 "no entries -- done\n"));
2847 break;
2850 for (i=0; i<num_entries; i++) {
2851 const char *name;
2853 name = sam_entries->entries[i].name.string;
2855 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2856 &&(strlen(name)<=21)) {
2857 strlcpy(p,name,PTR_DIFF(endp,p));
2858 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2859 "username %s\n",count_sent,p));
2860 p += 21;
2861 count_sent++;
2862 } else {
2863 /* set overflow error */
2864 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2865 "username %s\n",count_sent,name));
2866 errflags=234;
2867 break;
2871 if (errflags != NERR_Success) {
2872 break;
2875 TALLOC_FREE(sam_entries);
2878 dcerpc_samr_Close(b, talloc_tos(), &domain_handle, &result);
2879 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2881 *rdata_len = PTR_DIFF(p,*rdata);
2883 SSVAL(*rparam,0,errflags);
2884 SSVAL(*rparam,2,0); /* converter word */
2885 SSVAL(*rparam,4,count_sent); /* is this right?? */
2886 SSVAL(*rparam,6,num_users); /* is this right?? */
2888 return True;
2891 /****************************************************************************
2892 Get the time of day info.
2893 ****************************************************************************/
2895 static bool api_NetRemoteTOD(struct smbd_server_connection *sconn,
2896 connection_struct *conn,uint64_t vuid,
2897 char *param, int tpscnt,
2898 char *data, int tdscnt,
2899 int mdrcnt,int mprcnt,
2900 char **rdata,char **rparam,
2901 int *rdata_len,int *rparam_len)
2903 struct tm *t;
2904 time_t unixdate = time(NULL);
2905 char *p;
2907 *rparam_len = 4;
2908 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2909 if (!*rparam) {
2910 return False;
2913 *rdata_len = 21;
2914 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2915 if (!*rdata) {
2916 return False;
2919 SSVAL(*rparam,0,NERR_Success);
2920 SSVAL(*rparam,2,0); /* converter word */
2922 p = *rdata;
2924 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2925 by NT in a "net time" operation,
2926 it seems to ignore the one below */
2928 /* the client expects to get localtime, not GMT, in this bit
2929 (I think, this needs testing) */
2930 t = localtime(&unixdate);
2931 if (!t) {
2932 return False;
2935 SIVAL(p,4,0); /* msecs ? */
2936 SCVAL(p,8,t->tm_hour);
2937 SCVAL(p,9,t->tm_min);
2938 SCVAL(p,10,t->tm_sec);
2939 SCVAL(p,11,0); /* hundredths of seconds */
2940 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2941 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2942 SCVAL(p,16,t->tm_mday);
2943 SCVAL(p,17,t->tm_mon + 1);
2944 SSVAL(p,18,1900+t->tm_year);
2945 SCVAL(p,20,t->tm_wday);
2947 return True;
2950 /****************************************************************************
2951 Set the user password.
2952 *****************************************************************************/
2954 static bool api_SetUserPassword(struct smbd_server_connection *sconn,
2955 connection_struct *conn,uint64_t vuid,
2956 char *param, int tpscnt,
2957 char *data, int tdscnt,
2958 int mdrcnt,int mprcnt,
2959 char **rdata,char **rparam,
2960 int *rdata_len,int *rparam_len)
2962 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2963 char *p = NULL;
2964 fstring user;
2965 fstring pass1,pass2;
2966 TALLOC_CTX *mem_ctx = talloc_tos();
2967 NTSTATUS status, result;
2968 struct rpc_pipe_client *cli = NULL;
2969 struct policy_handle connect_handle, domain_handle, user_handle;
2970 struct lsa_String domain_name;
2971 struct dom_sid2 *domain_sid;
2972 struct lsa_String names;
2973 struct samr_Ids rids;
2974 struct samr_Ids types;
2975 struct samr_Password old_lm_hash;
2976 struct samr_Password new_lm_hash;
2977 int errcode = NERR_badpass;
2978 uint32_t rid;
2979 int encrypted;
2980 int min_pwd_length;
2981 struct dcerpc_binding_handle *b = NULL;
2983 /* Skip 2 strings. */
2984 p = skip_string(param,tpscnt,np);
2985 p = skip_string(param,tpscnt,p);
2987 if (!np || !p) {
2988 return False;
2991 /* Do we have a string ? */
2992 if (skip_string(param,tpscnt,p) == NULL) {
2993 return False;
2995 pull_ascii_fstring(user,p);
2997 p = skip_string(param,tpscnt,p);
2998 if (!p) {
2999 return False;
3002 memset(pass1,'\0',sizeof(pass1));
3003 memset(pass2,'\0',sizeof(pass2));
3005 * We use 31 here not 32 as we're checking
3006 * the last byte we want to access is safe.
3008 if (!is_offset_safe(param,tpscnt,p,31)) {
3009 return False;
3011 memcpy(pass1,p,16);
3012 memcpy(pass2,p+16,16);
3014 encrypted = get_safe_SVAL(param,tpscnt,p+32,0,-1);
3015 if (encrypted == -1) {
3016 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3017 goto out;
3020 min_pwd_length = get_safe_SVAL(param,tpscnt,p+34,0,-1);
3021 if (min_pwd_length == -1) {
3022 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3023 goto out;
3026 *rparam_len = 4;
3027 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3028 if (!*rparam) {
3029 return False;
3032 *rdata_len = 0;
3034 DEBUG(3,("Set password for <%s> (encrypted: %d, min_pwd_length: %d)\n",
3035 user, encrypted, min_pwd_length));
3037 ZERO_STRUCT(connect_handle);
3038 ZERO_STRUCT(domain_handle);
3039 ZERO_STRUCT(user_handle);
3041 status = rpc_pipe_open_interface(mem_ctx, &ndr_table_samr.syntax_id,
3042 conn->session_info,
3043 conn->sconn->remote_address,
3044 conn->sconn->msg_ctx,
3045 &cli);
3046 if (!NT_STATUS_IS_OK(status)) {
3047 DEBUG(0,("api_SetUserPassword: could not connect to samr: %s\n",
3048 nt_errstr(status)));
3049 errcode = W_ERROR_V(ntstatus_to_werror(status));
3050 goto out;
3053 b = cli->binding_handle;
3055 status = dcerpc_samr_Connect2(b, mem_ctx,
3056 lp_netbios_name(),
3057 SAMR_ACCESS_CONNECT_TO_SERVER |
3058 SAMR_ACCESS_ENUM_DOMAINS |
3059 SAMR_ACCESS_LOOKUP_DOMAIN,
3060 &connect_handle,
3061 &result);
3062 if (!NT_STATUS_IS_OK(status)) {
3063 errcode = W_ERROR_V(ntstatus_to_werror(status));
3064 goto out;
3066 if (!NT_STATUS_IS_OK(result)) {
3067 errcode = W_ERROR_V(ntstatus_to_werror(result));
3068 goto out;
3071 init_lsa_String(&domain_name, get_global_sam_name());
3073 status = dcerpc_samr_LookupDomain(b, mem_ctx,
3074 &connect_handle,
3075 &domain_name,
3076 &domain_sid,
3077 &result);
3078 if (!NT_STATUS_IS_OK(status)) {
3079 errcode = W_ERROR_V(ntstatus_to_werror(status));
3080 goto out;
3082 if (!NT_STATUS_IS_OK(result)) {
3083 errcode = W_ERROR_V(ntstatus_to_werror(result));
3084 goto out;
3087 status = dcerpc_samr_OpenDomain(b, mem_ctx,
3088 &connect_handle,
3089 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
3090 domain_sid,
3091 &domain_handle,
3092 &result);
3093 if (!NT_STATUS_IS_OK(status)) {
3094 errcode = W_ERROR_V(ntstatus_to_werror(status));
3095 goto out;
3097 if (!NT_STATUS_IS_OK(result)) {
3098 errcode = W_ERROR_V(ntstatus_to_werror(result));
3099 goto out;
3102 init_lsa_String(&names, user);
3104 status = dcerpc_samr_LookupNames(b, mem_ctx,
3105 &domain_handle,
3107 &names,
3108 &rids,
3109 &types,
3110 &result);
3111 if (!NT_STATUS_IS_OK(status)) {
3112 errcode = W_ERROR_V(ntstatus_to_werror(status));
3113 goto out;
3115 if (!NT_STATUS_IS_OK(result)) {
3116 errcode = W_ERROR_V(ntstatus_to_werror(result));
3117 goto out;
3120 if (rids.count != 1) {
3121 errcode = W_ERROR_V(WERR_NO_SUCH_USER);
3122 goto out;
3124 if (rids.count != types.count) {
3125 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3126 goto out;
3128 if (types.ids[0] != SID_NAME_USER) {
3129 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3130 goto out;
3133 rid = rids.ids[0];
3135 status = dcerpc_samr_OpenUser(b, mem_ctx,
3136 &domain_handle,
3137 SAMR_USER_ACCESS_CHANGE_PASSWORD,
3138 rid,
3139 &user_handle,
3140 &result);
3141 if (!NT_STATUS_IS_OK(status)) {
3142 errcode = W_ERROR_V(ntstatus_to_werror(status));
3143 goto out;
3145 if (!NT_STATUS_IS_OK(result)) {
3146 errcode = W_ERROR_V(ntstatus_to_werror(result));
3147 goto out;
3150 if (encrypted == 0) {
3151 E_deshash(pass1, old_lm_hash.hash);
3152 E_deshash(pass2, new_lm_hash.hash);
3153 } else {
3154 ZERO_STRUCT(old_lm_hash);
3155 ZERO_STRUCT(new_lm_hash);
3156 memcpy(old_lm_hash.hash, pass1, MIN(strlen(pass1), 16));
3157 memcpy(new_lm_hash.hash, pass2, MIN(strlen(pass2), 16));
3160 status = dcerpc_samr_ChangePasswordUser(b, mem_ctx,
3161 &user_handle,
3162 true, /* lm_present */
3163 &old_lm_hash,
3164 &new_lm_hash,
3165 false, /* nt_present */
3166 NULL, /* old_nt_crypted */
3167 NULL, /* new_nt_crypted */
3168 false, /* cross1_present */
3169 NULL, /* nt_cross */
3170 false, /* cross2_present */
3171 NULL, /* lm_cross */
3172 &result);
3173 if (!NT_STATUS_IS_OK(status)) {
3174 errcode = W_ERROR_V(ntstatus_to_werror(status));
3175 goto out;
3177 if (!NT_STATUS_IS_OK(result)) {
3178 errcode = W_ERROR_V(ntstatus_to_werror(result));
3179 goto out;
3182 errcode = NERR_Success;
3183 out:
3185 if (b && is_valid_policy_hnd(&user_handle)) {
3186 dcerpc_samr_Close(b, mem_ctx, &user_handle, &result);
3188 if (b && is_valid_policy_hnd(&domain_handle)) {
3189 dcerpc_samr_Close(b, mem_ctx, &domain_handle, &result);
3191 if (b && is_valid_policy_hnd(&connect_handle)) {
3192 dcerpc_samr_Close(b, mem_ctx, &connect_handle, &result);
3195 memset((char *)pass1,'\0',sizeof(fstring));
3196 memset((char *)pass2,'\0',sizeof(fstring));
3198 SSVAL(*rparam,0,errcode);
3199 SSVAL(*rparam,2,0); /* converter word */
3200 return(True);
3203 /****************************************************************************
3204 Set the user password (SamOEM version - gets plaintext).
3205 ****************************************************************************/
3207 static bool api_SamOEMChangePassword(struct smbd_server_connection *sconn,
3208 connection_struct *conn,uint64_t vuid,
3209 char *param, int tpscnt,
3210 char *data, int tdscnt,
3211 int mdrcnt,int mprcnt,
3212 char **rdata,char **rparam,
3213 int *rdata_len,int *rparam_len)
3215 fstring user;
3216 char *p = get_safe_str_ptr(param,tpscnt,param,2);
3218 TALLOC_CTX *mem_ctx = talloc_tos();
3219 NTSTATUS status, result;
3220 struct rpc_pipe_client *cli = NULL;
3221 struct lsa_AsciiString server, account;
3222 struct samr_CryptPassword password;
3223 struct samr_Password hash;
3224 int errcode = NERR_badpass;
3225 int bufsize;
3226 struct dcerpc_binding_handle *b;
3228 *rparam_len = 4;
3229 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3230 if (!*rparam) {
3231 return False;
3234 if (!p) {
3235 return False;
3237 *rdata_len = 0;
3239 SSVAL(*rparam,0,NERR_badpass);
3242 * Check the parameter definition is correct.
3245 /* Do we have a string ? */
3246 if (skip_string(param,tpscnt,p) == 0) {
3247 return False;
3249 if(!strequal(p, "zsT")) {
3250 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
3251 return False;
3253 p = skip_string(param, tpscnt, p);
3254 if (!p) {
3255 return False;
3258 /* Do we have a string ? */
3259 if (skip_string(param,tpscnt,p) == 0) {
3260 return False;
3262 if(!strequal(p, "B516B16")) {
3263 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
3264 return False;
3266 p = skip_string(param,tpscnt,p);
3267 if (!p) {
3268 return False;
3270 /* Do we have a string ? */
3271 if (skip_string(param,tpscnt,p) == 0) {
3272 return False;
3274 p += pull_ascii_fstring(user,p);
3276 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
3278 if (tdscnt != 532) {
3279 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3280 goto out;
3283 bufsize = get_safe_SVAL(param,tpscnt,p,0,-1);
3284 if (bufsize != 532) {
3285 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3286 goto out;
3289 memcpy(password.data, data, 516);
3290 memcpy(hash.hash, data+516, 16);
3292 status = rpc_pipe_open_interface(mem_ctx, &ndr_table_samr.syntax_id,
3293 conn->session_info,
3294 conn->sconn->remote_address,
3295 conn->sconn->msg_ctx,
3296 &cli);
3297 if (!NT_STATUS_IS_OK(status)) {
3298 DEBUG(0,("api_SamOEMChangePassword: could not connect to samr: %s\n",
3299 nt_errstr(status)));
3300 errcode = W_ERROR_V(ntstatus_to_werror(status));
3301 goto out;
3304 b = cli->binding_handle;
3306 init_lsa_AsciiString(&server, lp_netbios_name());
3307 init_lsa_AsciiString(&account, user);
3309 status = dcerpc_samr_OemChangePasswordUser2(b, mem_ctx,
3310 &server,
3311 &account,
3312 &password,
3313 &hash,
3314 &result);
3315 if (!NT_STATUS_IS_OK(status)) {
3316 errcode = W_ERROR_V(ntstatus_to_werror(status));
3317 goto out;
3319 if (!NT_STATUS_IS_OK(result)) {
3320 errcode = W_ERROR_V(ntstatus_to_werror(result));
3321 goto out;
3324 errcode = NERR_Success;
3325 out:
3326 SSVAL(*rparam,0,errcode);
3327 SSVAL(*rparam,2,0); /* converter word */
3329 return(True);
3332 /****************************************************************************
3333 delete a print job
3334 Form: <W> <>
3335 ****************************************************************************/
3337 static bool api_RDosPrintJobDel(struct smbd_server_connection *sconn,
3338 connection_struct *conn,uint64_t vuid,
3339 char *param, int tpscnt,
3340 char *data, int tdscnt,
3341 int mdrcnt,int mprcnt,
3342 char **rdata,char **rparam,
3343 int *rdata_len,int *rparam_len)
3345 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3346 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3347 char *str2 = skip_string(param,tpscnt,str1);
3348 char *p = skip_string(param,tpscnt,str2);
3349 uint32 jobid;
3350 fstring sharename;
3351 int errcode;
3352 WERROR werr = WERR_OK;
3354 TALLOC_CTX *mem_ctx = talloc_tos();
3355 NTSTATUS status;
3356 struct rpc_pipe_client *cli = NULL;
3357 struct dcerpc_binding_handle *b = NULL;
3358 struct policy_handle handle;
3359 struct spoolss_DevmodeContainer devmode_ctr;
3360 enum spoolss_JobControl command;
3362 if (!str1 || !str2 || !p) {
3363 return False;
3366 * We use 1 here not 2 as we're checking
3367 * the last byte we want to access is safe.
3369 if (!is_offset_safe(param,tpscnt,p,1)) {
3370 return False;
3372 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3373 return False;
3375 /* check it's a supported varient */
3376 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
3377 return(False);
3379 *rparam_len = 4;
3380 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3381 if (!*rparam) {
3382 return False;
3384 *rdata_len = 0;
3386 ZERO_STRUCT(handle);
3388 status = rpc_pipe_open_interface(conn,
3389 &ndr_table_spoolss.syntax_id,
3390 conn->session_info,
3391 conn->sconn->remote_address,
3392 conn->sconn->msg_ctx,
3393 &cli);
3394 if (!NT_STATUS_IS_OK(status)) {
3395 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
3396 nt_errstr(status)));
3397 errcode = W_ERROR_V(ntstatus_to_werror(status));
3398 goto out;
3400 b = cli->binding_handle;
3402 ZERO_STRUCT(devmode_ctr);
3404 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
3405 sharename,
3406 "RAW",
3407 devmode_ctr,
3408 JOB_ACCESS_ADMINISTER,
3409 &handle,
3410 &werr);
3411 if (!NT_STATUS_IS_OK(status)) {
3412 errcode = W_ERROR_V(ntstatus_to_werror(status));
3413 goto out;
3415 if (!W_ERROR_IS_OK(werr)) {
3416 errcode = W_ERROR_V(werr);
3417 goto out;
3420 /* FIXME: formerly NERR_JobNotFound was returned if job did not exist
3421 * and NERR_DestNotFound if share did not exist */
3423 errcode = NERR_Success;
3425 switch (function) {
3426 case 81: /* delete */
3427 command = SPOOLSS_JOB_CONTROL_DELETE;
3428 break;
3429 case 82: /* pause */
3430 command = SPOOLSS_JOB_CONTROL_PAUSE;
3431 break;
3432 case 83: /* resume */
3433 command = SPOOLSS_JOB_CONTROL_RESUME;
3434 break;
3435 default:
3436 errcode = NERR_notsupported;
3437 goto out;
3440 status = dcerpc_spoolss_SetJob(b, mem_ctx,
3441 &handle,
3442 jobid,
3443 NULL, /* unique ptr ctr */
3444 command,
3445 &werr);
3446 if (!NT_STATUS_IS_OK(status)) {
3447 errcode = W_ERROR_V(ntstatus_to_werror(status));
3448 goto out;
3450 if (!W_ERROR_IS_OK(werr)) {
3451 errcode = W_ERROR_V(werr);
3452 goto out;
3455 out:
3456 if (b && is_valid_policy_hnd(&handle)) {
3457 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
3460 SSVAL(*rparam,0,errcode);
3461 SSVAL(*rparam,2,0); /* converter word */
3463 return(True);
3466 /****************************************************************************
3467 Purge a print queue - or pause or resume it.
3468 ****************************************************************************/
3470 static bool api_WPrintQueueCtrl(struct smbd_server_connection *sconn,
3471 connection_struct *conn,uint64_t vuid,
3472 char *param, int tpscnt,
3473 char *data, int tdscnt,
3474 int mdrcnt,int mprcnt,
3475 char **rdata,char **rparam,
3476 int *rdata_len,int *rparam_len)
3478 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3479 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3480 char *str2 = skip_string(param,tpscnt,str1);
3481 char *QueueName = skip_string(param,tpscnt,str2);
3482 int errcode = NERR_notsupported;
3483 WERROR werr = WERR_OK;
3484 NTSTATUS status;
3486 TALLOC_CTX *mem_ctx = talloc_tos();
3487 struct rpc_pipe_client *cli = NULL;
3488 struct dcerpc_binding_handle *b = NULL;
3489 struct policy_handle handle;
3490 struct spoolss_SetPrinterInfoCtr info_ctr;
3491 struct spoolss_DevmodeContainer devmode_ctr;
3492 struct sec_desc_buf secdesc_ctr;
3493 enum spoolss_PrinterControl command;
3495 if (!str1 || !str2 || !QueueName) {
3496 return False;
3499 /* check it's a supported varient */
3500 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3501 return(False);
3503 *rparam_len = 4;
3504 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3505 if (!*rparam) {
3506 return False;
3508 *rdata_len = 0;
3510 if (skip_string(param,tpscnt,QueueName) == NULL) {
3511 return False;
3514 ZERO_STRUCT(handle);
3516 status = rpc_pipe_open_interface(conn,
3517 &ndr_table_spoolss.syntax_id,
3518 conn->session_info,
3519 conn->sconn->remote_address,
3520 conn->sconn->msg_ctx,
3521 &cli);
3522 if (!NT_STATUS_IS_OK(status)) {
3523 DEBUG(0,("api_WPrintQueueCtrl: could not connect to spoolss: %s\n",
3524 nt_errstr(status)));
3525 errcode = W_ERROR_V(ntstatus_to_werror(status));
3526 goto out;
3528 b = cli->binding_handle;
3530 ZERO_STRUCT(devmode_ctr);
3532 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
3533 QueueName,
3534 NULL,
3535 devmode_ctr,
3536 PRINTER_ACCESS_ADMINISTER,
3537 &handle,
3538 &werr);
3539 if (!NT_STATUS_IS_OK(status)) {
3540 errcode = W_ERROR_V(ntstatus_to_werror(status));
3541 goto out;
3543 if (!W_ERROR_IS_OK(werr)) {
3544 errcode = W_ERROR_V(werr);
3545 goto out;
3548 switch (function) {
3549 case 74: /* Pause queue */
3550 command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3551 break;
3552 case 75: /* Resume queue */
3553 command = SPOOLSS_PRINTER_CONTROL_RESUME;
3554 break;
3555 case 103: /* Purge */
3556 command = SPOOLSS_PRINTER_CONTROL_PURGE;
3557 break;
3558 default:
3559 werr = WERR_NOT_SUPPORTED;
3560 break;
3563 if (!W_ERROR_IS_OK(werr)) {
3564 errcode = W_ERROR_V(werr);
3565 goto out;
3568 ZERO_STRUCT(info_ctr);
3569 ZERO_STRUCT(secdesc_ctr);
3571 status = dcerpc_spoolss_SetPrinter(b, mem_ctx,
3572 &handle,
3573 &info_ctr,
3574 &devmode_ctr,
3575 &secdesc_ctr,
3576 command,
3577 &werr);
3578 if (!NT_STATUS_IS_OK(status)) {
3579 errcode = W_ERROR_V(ntstatus_to_werror(status));
3580 goto out;
3582 if (!W_ERROR_IS_OK(werr)) {
3583 errcode = W_ERROR_V(werr);
3584 goto out;
3587 errcode = W_ERROR_V(werr);
3589 out:
3591 if (b && is_valid_policy_hnd(&handle)) {
3592 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
3595 SSVAL(*rparam,0,errcode);
3596 SSVAL(*rparam,2,0); /* converter word */
3598 return(True);
3601 /****************************************************************************
3602 set the property of a print job (undocumented?)
3603 ? function = 0xb -> set name of print job
3604 ? function = 0x6 -> move print job up/down
3605 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3606 or <WWsTP> <WB21BB16B10zWWzDDz>
3607 ****************************************************************************/
3609 static int check_printjob_info(struct pack_desc* desc,
3610 int uLevel, char* id)
3612 desc->subformat = NULL;
3613 switch( uLevel ) {
3614 case 0: desc->format = "W"; break;
3615 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3616 case 2: desc->format = "WWzWWDDzz"; break;
3617 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3618 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3619 default:
3620 DEBUG(0,("check_printjob_info: invalid level %d\n",
3621 uLevel ));
3622 return False;
3624 if (id == NULL || strcmp(desc->format,id) != 0) {
3625 DEBUG(0,("check_printjob_info: invalid format %s\n",
3626 id ? id : "<NULL>" ));
3627 return False;
3629 return True;
3632 static bool api_PrintJobInfo(struct smbd_server_connection *sconn,
3633 connection_struct *conn, uint64_t vuid,
3634 char *param, int tpscnt,
3635 char *data, int tdscnt,
3636 int mdrcnt,int mprcnt,
3637 char **rdata,char **rparam,
3638 int *rdata_len,int *rparam_len)
3640 struct pack_desc desc;
3641 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3642 char *str2 = skip_string(param,tpscnt,str1);
3643 char *p = skip_string(param,tpscnt,str2);
3644 uint32 jobid;
3645 fstring sharename;
3646 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3647 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3648 int errcode;
3650 TALLOC_CTX *mem_ctx = talloc_tos();
3651 WERROR werr;
3652 NTSTATUS status;
3653 struct rpc_pipe_client *cli = NULL;
3654 struct dcerpc_binding_handle *b = NULL;
3655 struct policy_handle handle;
3656 struct spoolss_DevmodeContainer devmode_ctr;
3657 struct spoolss_JobInfoContainer ctr;
3658 union spoolss_JobInfo info;
3659 struct spoolss_SetJobInfo1 info1;
3661 if (!str1 || !str2 || !p) {
3662 return False;
3665 * We use 1 here not 2 as we're checking
3666 * the last byte we want to access is safe.
3668 if (!is_offset_safe(param,tpscnt,p,1)) {
3669 return False;
3671 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3672 return False;
3673 *rparam_len = 4;
3674 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3675 if (!*rparam) {
3676 return False;
3679 *rdata_len = 0;
3681 /* check it's a supported varient */
3682 if ((strcmp(str1,"WWsTP")) ||
3683 (!check_printjob_info(&desc,uLevel,str2)))
3684 return(False);
3686 errcode = NERR_notsupported;
3688 switch (function) {
3689 case 0xb:
3690 /* change print job name, data gives the name */
3691 break;
3692 default:
3693 goto out;
3696 ZERO_STRUCT(handle);
3698 status = rpc_pipe_open_interface(conn,
3699 &ndr_table_spoolss.syntax_id,
3700 conn->session_info,
3701 conn->sconn->remote_address,
3702 conn->sconn->msg_ctx,
3703 &cli);
3704 if (!NT_STATUS_IS_OK(status)) {
3705 DEBUG(0,("api_PrintJobInfo: could not connect to spoolss: %s\n",
3706 nt_errstr(status)));
3707 errcode = W_ERROR_V(ntstatus_to_werror(status));
3708 goto out;
3710 b = cli->binding_handle;
3712 ZERO_STRUCT(devmode_ctr);
3714 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
3715 sharename,
3716 "RAW",
3717 devmode_ctr,
3718 PRINTER_ACCESS_USE,
3719 &handle,
3720 &werr);
3721 if (!NT_STATUS_IS_OK(status)) {
3722 errcode = W_ERROR_V(ntstatus_to_werror(status));
3723 goto out;
3725 if (!W_ERROR_IS_OK(werr)) {
3726 errcode = W_ERROR_V(werr);
3727 goto out;
3730 werr = rpccli_spoolss_getjob(cli, mem_ctx,
3731 &handle,
3732 jobid,
3733 1, /* level */
3734 0, /* offered */
3735 &info);
3736 if (!W_ERROR_IS_OK(werr)) {
3737 errcode = W_ERROR_V(werr);
3738 goto out;
3741 ZERO_STRUCT(ctr);
3743 info1.job_id = info.info1.job_id;
3744 info1.printer_name = info.info1.printer_name;
3745 info1.user_name = info.info1.user_name;
3746 info1.document_name = data;
3747 info1.data_type = info.info1.data_type;
3748 info1.text_status = info.info1.text_status;
3749 info1.status = info.info1.status;
3750 info1.priority = info.info1.priority;
3751 info1.position = info.info1.position;
3752 info1.total_pages = info.info1.total_pages;
3753 info1.pages_printed = info.info1.pages_printed;
3754 info1.submitted = info.info1.submitted;
3756 ctr.level = 1;
3757 ctr.info.info1 = &info1;
3759 status = dcerpc_spoolss_SetJob(b, mem_ctx,
3760 &handle,
3761 jobid,
3762 &ctr,
3764 &werr);
3765 if (!NT_STATUS_IS_OK(status)) {
3766 errcode = W_ERROR_V(ntstatus_to_werror(status));
3767 goto out;
3769 if (!W_ERROR_IS_OK(werr)) {
3770 errcode = W_ERROR_V(werr);
3771 goto out;
3774 errcode = NERR_Success;
3775 out:
3777 if (b && is_valid_policy_hnd(&handle)) {
3778 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
3781 SSVALS(*rparam,0,errcode);
3782 SSVAL(*rparam,2,0); /* converter word */
3784 return(True);
3788 /****************************************************************************
3789 Get info about the server.
3790 ****************************************************************************/
3792 static bool api_RNetServerGetInfo(struct smbd_server_connection *sconn,
3793 connection_struct *conn,uint64_t vuid,
3794 char *param, int tpscnt,
3795 char *data, int tdscnt,
3796 int mdrcnt,int mprcnt,
3797 char **rdata,char **rparam,
3798 int *rdata_len,int *rparam_len)
3800 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3801 char *str2 = skip_string(param,tpscnt,str1);
3802 char *p = skip_string(param,tpscnt,str2);
3803 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3804 char *p2;
3805 int struct_len;
3807 NTSTATUS status;
3808 WERROR werr;
3809 TALLOC_CTX *mem_ctx = talloc_tos();
3810 struct rpc_pipe_client *cli = NULL;
3811 union srvsvc_NetSrvInfo info;
3812 int errcode;
3813 struct dcerpc_binding_handle *b;
3815 if (!str1 || !str2 || !p) {
3816 return False;
3819 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3821 /* check it's a supported varient */
3822 if (!prefix_ok(str1,"WrLh")) {
3823 return False;
3826 switch( uLevel ) {
3827 case 0:
3828 if (strcmp(str2,"B16") != 0) {
3829 return False;
3831 struct_len = 16;
3832 break;
3833 case 1:
3834 if (strcmp(str2,"B16BBDz") != 0) {
3835 return False;
3837 struct_len = 26;
3838 break;
3839 case 2:
3840 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3841 return False;
3843 struct_len = 134;
3844 break;
3845 case 3:
3846 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3847 return False;
3849 struct_len = 144;
3850 break;
3851 case 20:
3852 if (strcmp(str2,"DN") != 0) {
3853 return False;
3855 struct_len = 6;
3856 break;
3857 case 50:
3858 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3859 return False;
3861 struct_len = 42;
3862 break;
3863 default:
3864 return False;
3867 *rdata_len = mdrcnt;
3868 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3869 if (!*rdata) {
3870 return False;
3873 p = *rdata;
3874 p2 = p + struct_len;
3876 status = rpc_pipe_open_interface(mem_ctx, &ndr_table_srvsvc.syntax_id,
3877 conn->session_info,
3878 conn->sconn->remote_address,
3879 conn->sconn->msg_ctx,
3880 &cli);
3881 if (!NT_STATUS_IS_OK(status)) {
3882 DEBUG(0,("api_RNetServerGetInfo: could not connect to srvsvc: %s\n",
3883 nt_errstr(status)));
3884 errcode = W_ERROR_V(ntstatus_to_werror(status));
3885 goto out;
3888 b = cli->binding_handle;
3890 status = dcerpc_srvsvc_NetSrvGetInfo(b, mem_ctx,
3891 NULL,
3892 101,
3893 &info,
3894 &werr);
3895 if (!NT_STATUS_IS_OK(status)) {
3896 errcode = W_ERROR_V(ntstatus_to_werror(status));
3897 goto out;
3899 if (!W_ERROR_IS_OK(werr)) {
3900 errcode = W_ERROR_V(werr);
3901 goto out;
3904 if (info.info101 == NULL) {
3905 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3906 goto out;
3909 if (uLevel != 20) {
3910 srvstr_push(NULL, 0, p, info.info101->server_name, 16,
3911 STR_ASCII|STR_UPPER|STR_TERMINATE);
3913 p += 16;
3914 if (uLevel > 0) {
3915 SCVAL(p,0,info.info101->version_major);
3916 SCVAL(p,1,info.info101->version_minor);
3917 SIVAL(p,2,info.info101->server_type);
3919 if (mdrcnt == struct_len) {
3920 SIVAL(p,6,0);
3921 } else {
3922 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3923 if (mdrcnt - struct_len <= 0) {
3924 return false;
3926 push_ascii(p2,
3927 info.info101->comment,
3928 MIN(mdrcnt - struct_len,
3929 MAX_SERVER_STRING_LENGTH),
3930 STR_TERMINATE);
3931 p2 = skip_string(*rdata,*rdata_len,p2);
3932 if (!p2) {
3933 return False;
3938 if (uLevel > 1) {
3939 return False; /* not yet implemented */
3942 errcode = NERR_Success;
3944 out:
3946 *rdata_len = PTR_DIFF(p2,*rdata);
3948 *rparam_len = 6;
3949 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3950 if (!*rparam) {
3951 return False;
3953 SSVAL(*rparam,0,errcode);
3954 SSVAL(*rparam,2,0); /* converter word */
3955 SSVAL(*rparam,4,*rdata_len);
3957 return True;
3960 /****************************************************************************
3961 Get info about the server.
3962 ****************************************************************************/
3964 static bool api_NetWkstaGetInfo(struct smbd_server_connection *sconn,
3965 connection_struct *conn,uint64_t vuid,
3966 char *param, int tpscnt,
3967 char *data, int tdscnt,
3968 int mdrcnt,int mprcnt,
3969 char **rdata,char **rparam,
3970 int *rdata_len,int *rparam_len)
3972 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3973 char *str2 = skip_string(param,tpscnt,str1);
3974 char *p = skip_string(param,tpscnt,str2);
3975 char *p2;
3976 char *endp;
3977 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3979 if (!str1 || !str2 || !p) {
3980 return False;
3983 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3985 *rparam_len = 6;
3986 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3987 if (!*rparam) {
3988 return False;
3991 /* check it's a supported varient */
3992 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3993 return False;
3996 *rdata_len = mdrcnt + 1024;
3997 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3998 if (!*rdata) {
3999 return False;
4002 SSVAL(*rparam,0,NERR_Success);
4003 SSVAL(*rparam,2,0); /* converter word */
4005 p = *rdata;
4006 endp = *rdata + *rdata_len;
4008 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
4009 if (!p2) {
4010 return False;
4013 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
4014 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
4015 if (!strupper_m(p2)) {
4016 return false;
4018 p2 = skip_string(*rdata,*rdata_len,p2);
4019 if (!p2) {
4020 return False;
4022 p += 4;
4024 SIVAL(p,0,PTR_DIFF(p2,*rdata));
4025 strlcpy(p2,conn->session_info->unix_info->sanitized_username,PTR_DIFF(endp,p2));
4026 p2 = skip_string(*rdata,*rdata_len,p2);
4027 if (!p2) {
4028 return False;
4030 p += 4;
4032 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
4033 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
4034 if (!strupper_m(p2)) {
4035 return false;
4037 p2 = skip_string(*rdata,*rdata_len,p2);
4038 if (!p2) {
4039 return False;
4041 p += 4;
4043 SCVAL(p,0,SAMBA_MAJOR_NBT_ANNOUNCE_VERSION); /* system version - e.g 4 in 4.1 */
4044 SCVAL(p,1,SAMBA_MINOR_NBT_ANNOUNCE_VERSION); /* system version - e.g .1 in 4.1 */
4045 p += 2;
4047 SIVAL(p,0,PTR_DIFF(p2,*rdata));
4048 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
4049 p2 = skip_string(*rdata,*rdata_len,p2);
4050 if (!p2) {
4051 return False;
4053 p += 4;
4055 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
4056 strlcpy(p2,"",PTR_DIFF(endp,p2));
4057 p2 = skip_string(*rdata,*rdata_len,p2);
4058 if (!p2) {
4059 return False;
4061 p += 4;
4063 *rdata_len = PTR_DIFF(p2,*rdata);
4065 SSVAL(*rparam,4,*rdata_len);
4067 return True;
4070 /****************************************************************************
4071 get info about a user
4073 struct user_info_11 {
4074 char usri11_name[21]; 0-20
4075 char usri11_pad; 21
4076 char *usri11_comment; 22-25
4077 char *usri11_usr_comment; 26-29
4078 unsigned short usri11_priv; 30-31
4079 unsigned long usri11_auth_flags; 32-35
4080 long usri11_password_age; 36-39
4081 char *usri11_homedir; 40-43
4082 char *usri11_parms; 44-47
4083 long usri11_last_logon; 48-51
4084 long usri11_last_logoff; 52-55
4085 unsigned short usri11_bad_pw_count; 56-57
4086 unsigned short usri11_num_logons; 58-59
4087 char *usri11_logon_server; 60-63
4088 unsigned short usri11_country_code; 64-65
4089 char *usri11_workstations; 66-69
4090 unsigned long usri11_max_storage; 70-73
4091 unsigned short usri11_units_per_week; 74-75
4092 unsigned char *usri11_logon_hours; 76-79
4093 unsigned short usri11_code_page; 80-81
4096 where:
4098 usri11_name specifies the user name for which information is retrieved
4100 usri11_pad aligns the next data structure element to a word boundary
4102 usri11_comment is a null terminated ASCII comment
4104 usri11_user_comment is a null terminated ASCII comment about the user
4106 usri11_priv specifies the level of the privilege assigned to the user.
4107 The possible values are:
4109 Name Value Description
4110 USER_PRIV_GUEST 0 Guest privilege
4111 USER_PRIV_USER 1 User privilege
4112 USER_PRV_ADMIN 2 Administrator privilege
4114 usri11_auth_flags specifies the account operator privileges. The
4115 possible values are:
4117 Name Value Description
4118 AF_OP_PRINT 0 Print operator
4121 Leach, Naik [Page 28]
4125 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
4128 AF_OP_COMM 1 Communications operator
4129 AF_OP_SERVER 2 Server operator
4130 AF_OP_ACCOUNTS 3 Accounts operator
4133 usri11_password_age specifies how many seconds have elapsed since the
4134 password was last changed.
4136 usri11_home_dir points to a null terminated ASCII string that contains
4137 the path name of the user's home directory.
4139 usri11_parms points to a null terminated ASCII string that is set
4140 aside for use by applications.
4142 usri11_last_logon specifies the time when the user last logged on.
4143 This value is stored as the number of seconds elapsed since
4144 00:00:00, January 1, 1970.
4146 usri11_last_logoff specifies the time when the user last logged off.
4147 This value is stored as the number of seconds elapsed since
4148 00:00:00, January 1, 1970. A value of 0 means the last logoff
4149 time is unknown.
4151 usri11_bad_pw_count specifies the number of incorrect passwords
4152 entered since the last successful logon.
4154 usri11_log1_num_logons specifies the number of times this user has
4155 logged on. A value of -1 means the number of logons is unknown.
4157 usri11_logon_server points to a null terminated ASCII string that
4158 contains the name of the server to which logon requests are sent.
4159 A null string indicates logon requests should be sent to the
4160 domain controller.
4162 usri11_country_code specifies the country code for the user's language
4163 of choice.
4165 usri11_workstations points to a null terminated ASCII string that
4166 contains the names of workstations the user may log on from.
4167 There may be up to 8 workstations, with the names separated by
4168 commas. A null strings indicates there are no restrictions.
4170 usri11_max_storage specifies the maximum amount of disk space the user
4171 can occupy. A value of 0xffffffff indicates there are no
4172 restrictions.
4174 usri11_units_per_week specifies the equal number of time units into
4175 which a week is divided. This value must be equal to 168.
4177 usri11_logon_hours points to a 21 byte (168 bits) string that
4178 specifies the time during which the user can log on. Each bit
4179 represents one unique hour in a week. The first bit (bit 0, word
4180 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
4184 Leach, Naik [Page 29]
4188 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
4191 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
4192 are no restrictions.
4194 usri11_code_page specifies the code page for the user's language of
4195 choice
4197 All of the pointers in this data structure need to be treated
4198 specially. The pointer is a 32 bit pointer. The higher 16 bits need
4199 to be ignored. The converter word returned in the parameters section
4200 needs to be subtracted from the lower 16 bits to calculate an offset
4201 into the return buffer where this ASCII string resides.
4203 There is no auxiliary data in the response.
4205 ****************************************************************************/
4207 #define usri11_name 0
4208 #define usri11_pad 21
4209 #define usri11_comment 22
4210 #define usri11_usr_comment 26
4211 #define usri11_full_name 30
4212 #define usri11_priv 34
4213 #define usri11_auth_flags 36
4214 #define usri11_password_age 40
4215 #define usri11_homedir 44
4216 #define usri11_parms 48
4217 #define usri11_last_logon 52
4218 #define usri11_last_logoff 56
4219 #define usri11_bad_pw_count 60
4220 #define usri11_num_logons 62
4221 #define usri11_logon_server 64
4222 #define usri11_country_code 68
4223 #define usri11_workstations 70
4224 #define usri11_max_storage 74
4225 #define usri11_units_per_week 78
4226 #define usri11_logon_hours 80
4227 #define usri11_code_page 84
4228 #define usri11_end 86
4230 static bool api_RNetUserGetInfo(struct smbd_server_connection *sconn,
4231 connection_struct *conn, uint64_t vuid,
4232 char *param, int tpscnt,
4233 char *data, int tdscnt,
4234 int mdrcnt,int mprcnt,
4235 char **rdata,char **rparam,
4236 int *rdata_len,int *rparam_len)
4238 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4239 char *str2 = skip_string(param,tpscnt,str1);
4240 char *UserName = skip_string(param,tpscnt,str2);
4241 char *p = skip_string(param,tpscnt,UserName);
4242 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4243 char *p2;
4244 char *endp;
4245 const char *level_string;
4247 TALLOC_CTX *mem_ctx = talloc_tos();
4248 NTSTATUS status, result;
4249 struct rpc_pipe_client *cli = NULL;
4250 struct policy_handle connect_handle, domain_handle, user_handle;
4251 struct lsa_String domain_name;
4252 struct dom_sid2 *domain_sid;
4253 struct lsa_String names;
4254 struct samr_Ids rids;
4255 struct samr_Ids types;
4256 int errcode = W_ERROR_V(WERR_USER_NOT_FOUND);
4257 uint32_t rid;
4258 union samr_UserInfo *info;
4259 struct dcerpc_binding_handle *b = NULL;
4261 if (!str1 || !str2 || !UserName || !p) {
4262 return False;
4265 *rparam_len = 6;
4266 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4267 if (!*rparam) {
4268 return False;
4271 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
4273 /* check it's a supported variant */
4274 if (strcmp(str1,"zWrLh") != 0) {
4275 return False;
4277 switch( uLevel ) {
4278 case 0: level_string = "B21"; break;
4279 case 1: level_string = "B21BB16DWzzWz"; break;
4280 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
4281 case 10: level_string = "B21Bzzz"; break;
4282 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
4283 default: return False;
4286 if (strcmp(level_string,str2) != 0) {
4287 return False;
4290 *rdata_len = mdrcnt + 1024;
4291 *rdata = smb_realloc_limit(*rdata,*rdata_len);
4292 if (!*rdata) {
4293 return False;
4296 p = *rdata;
4297 endp = *rdata + *rdata_len;
4298 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
4299 if (!p2) {
4300 return False;
4303 ZERO_STRUCT(connect_handle);
4304 ZERO_STRUCT(domain_handle);
4305 ZERO_STRUCT(user_handle);
4307 status = rpc_pipe_open_interface(mem_ctx, &ndr_table_samr.syntax_id,
4308 conn->session_info,
4309 conn->sconn->remote_address,
4310 conn->sconn->msg_ctx,
4311 &cli);
4312 if (!NT_STATUS_IS_OK(status)) {
4313 DEBUG(0,("api_RNetUserGetInfo: could not connect to samr: %s\n",
4314 nt_errstr(status)));
4315 errcode = W_ERROR_V(ntstatus_to_werror(status));
4316 goto out;
4319 b = cli->binding_handle;
4321 status = dcerpc_samr_Connect2(b, mem_ctx,
4322 lp_netbios_name(),
4323 SAMR_ACCESS_CONNECT_TO_SERVER |
4324 SAMR_ACCESS_ENUM_DOMAINS |
4325 SAMR_ACCESS_LOOKUP_DOMAIN,
4326 &connect_handle,
4327 &result);
4328 if (!NT_STATUS_IS_OK(status)) {
4329 errcode = W_ERROR_V(ntstatus_to_werror(status));
4330 goto out;
4332 if (!NT_STATUS_IS_OK(result)) {
4333 errcode = W_ERROR_V(ntstatus_to_werror(result));
4334 goto out;
4337 init_lsa_String(&domain_name, get_global_sam_name());
4339 status = dcerpc_samr_LookupDomain(b, mem_ctx,
4340 &connect_handle,
4341 &domain_name,
4342 &domain_sid,
4343 &result);
4344 if (!NT_STATUS_IS_OK(status)) {
4345 errcode = W_ERROR_V(ntstatus_to_werror(status));
4346 goto out;
4348 if (!NT_STATUS_IS_OK(result)) {
4349 errcode = W_ERROR_V(ntstatus_to_werror(result));
4350 goto out;
4353 status = dcerpc_samr_OpenDomain(b, mem_ctx,
4354 &connect_handle,
4355 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
4356 domain_sid,
4357 &domain_handle,
4358 &result);
4359 if (!NT_STATUS_IS_OK(status)) {
4360 errcode = W_ERROR_V(ntstatus_to_werror(status));
4361 goto out;
4363 if (!NT_STATUS_IS_OK(result)) {
4364 errcode = W_ERROR_V(ntstatus_to_werror(result));
4365 goto out;
4368 init_lsa_String(&names, UserName);
4370 status = dcerpc_samr_LookupNames(b, mem_ctx,
4371 &domain_handle,
4373 &names,
4374 &rids,
4375 &types,
4376 &result);
4377 if (!NT_STATUS_IS_OK(status)) {
4378 errcode = W_ERROR_V(ntstatus_to_werror(status));
4379 goto out;
4381 if (!NT_STATUS_IS_OK(result)) {
4382 errcode = W_ERROR_V(ntstatus_to_werror(result));
4383 goto out;
4386 if (rids.count != 1) {
4387 errcode = W_ERROR_V(WERR_NO_SUCH_USER);
4388 goto out;
4390 if (rids.count != types.count) {
4391 errcode = W_ERROR_V(WERR_INVALID_PARAM);
4392 goto out;
4394 if (types.ids[0] != SID_NAME_USER) {
4395 errcode = W_ERROR_V(WERR_INVALID_PARAM);
4396 goto out;
4399 rid = rids.ids[0];
4401 status = dcerpc_samr_OpenUser(b, mem_ctx,
4402 &domain_handle,
4403 SAMR_USER_ACCESS_GET_LOCALE |
4404 SAMR_USER_ACCESS_GET_LOGONINFO |
4405 SAMR_USER_ACCESS_GET_ATTRIBUTES |
4406 SAMR_USER_ACCESS_GET_GROUPS |
4407 SAMR_USER_ACCESS_GET_GROUP_MEMBERSHIP |
4408 SEC_STD_READ_CONTROL,
4409 rid,
4410 &user_handle,
4411 &result);
4412 if (!NT_STATUS_IS_OK(status)) {
4413 errcode = W_ERROR_V(ntstatus_to_werror(status));
4414 goto out;
4416 if (!NT_STATUS_IS_OK(result)) {
4417 errcode = W_ERROR_V(ntstatus_to_werror(result));
4418 goto out;
4421 status = dcerpc_samr_QueryUserInfo2(b, mem_ctx,
4422 &user_handle,
4423 UserAllInformation,
4424 &info,
4425 &result);
4426 if (!NT_STATUS_IS_OK(status)) {
4427 errcode = W_ERROR_V(ntstatus_to_werror(status));
4428 goto out;
4430 if (!NT_STATUS_IS_OK(result)) {
4431 errcode = W_ERROR_V(ntstatus_to_werror(result));
4432 goto out;
4435 memset(p,0,21);
4436 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
4438 if (uLevel > 0) {
4439 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
4440 *p2 = 0;
4443 if (uLevel >= 10) {
4444 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
4445 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
4446 p2 = skip_string(*rdata,*rdata_len,p2);
4447 if (!p2) {
4448 return False;
4451 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
4452 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
4453 p2 = skip_string(*rdata,*rdata_len,p2);
4454 if (!p2) {
4455 return False;
4458 /* EEK! the cifsrap.txt doesn't have this in!!!! */
4459 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
4460 strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4461 p2 = skip_string(*rdata,*rdata_len,p2);
4462 if (!p2) {
4463 return False;
4467 if (uLevel == 11) {
4468 const char *homedir = info->info21.home_directory.string;
4469 /* modelled after NTAS 3.51 reply */
4470 SSVAL(p,usri11_priv,
4471 (get_current_uid(conn) == sec_initial_uid())?
4472 USER_PRIV_ADMIN:USER_PRIV_USER);
4473 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
4474 SIVALS(p,usri11_password_age,-1); /* password age */
4475 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
4476 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
4477 p2 = skip_string(*rdata,*rdata_len,p2);
4478 if (!p2) {
4479 return False;
4481 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
4482 strlcpy(p2,"",PTR_DIFF(endp,p2));
4483 p2 = skip_string(*rdata,*rdata_len,p2);
4484 if (!p2) {
4485 return False;
4487 SIVAL(p,usri11_last_logon,0); /* last logon */
4488 SIVAL(p,usri11_last_logoff,0); /* last logoff */
4489 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
4490 SSVALS(p,usri11_num_logons,-1); /* num logons */
4491 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
4492 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
4493 p2 = skip_string(*rdata,*rdata_len,p2);
4494 if (!p2) {
4495 return False;
4497 SSVAL(p,usri11_country_code,0); /* country code */
4499 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
4500 strlcpy(p2,"",PTR_DIFF(endp,p2));
4501 p2 = skip_string(*rdata,*rdata_len,p2);
4502 if (!p2) {
4503 return False;
4506 SIVALS(p,usri11_max_storage,-1); /* max storage */
4507 SSVAL(p,usri11_units_per_week,168); /* units per week */
4508 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
4510 /* a simple way to get logon hours at all times. */
4511 memset(p2,0xff,21);
4512 SCVAL(p2,21,0); /* fix zero termination */
4513 p2 = skip_string(*rdata,*rdata_len,p2);
4514 if (!p2) {
4515 return False;
4518 SSVAL(p,usri11_code_page,0); /* code page */
4521 if (uLevel == 1 || uLevel == 2) {
4522 memset(p+22,' ',16); /* password */
4523 SIVALS(p,38,-1); /* password age */
4524 SSVAL(p,42,
4525 (get_current_uid(conn) == sec_initial_uid())?
4526 USER_PRIV_ADMIN:USER_PRIV_USER);
4527 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
4528 strlcpy(p2, info->info21.home_directory.string,
4529 PTR_DIFF(endp,p2));
4530 p2 = skip_string(*rdata,*rdata_len,p2);
4531 if (!p2) {
4532 return False;
4534 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
4535 *p2++ = 0;
4536 SSVAL(p,52,0); /* flags */
4537 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
4538 strlcpy(p2, info->info21.logon_script.string,
4539 PTR_DIFF(endp,p2));
4540 p2 = skip_string(*rdata,*rdata_len,p2);
4541 if (!p2) {
4542 return False;
4544 if (uLevel == 2) {
4545 SIVAL(p,58,0); /* auth_flags */
4546 SIVAL(p,62,PTR_DIFF(p2,*rdata)); /* full_name */
4547 strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4548 p2 = skip_string(*rdata,*rdata_len,p2);
4549 if (!p2) {
4550 return False;
4552 SIVAL(p,66,0); /* urs_comment */
4553 SIVAL(p,70,PTR_DIFF(p2,*rdata)); /* parms */
4554 strlcpy(p2,"",PTR_DIFF(endp,p2));
4555 p2 = skip_string(*rdata,*rdata_len,p2);
4556 if (!p2) {
4557 return False;
4559 SIVAL(p,74,0); /* workstations */
4560 SIVAL(p,78,0); /* last_logon */
4561 SIVAL(p,82,0); /* last_logoff */
4562 SIVALS(p,86,-1); /* acct_expires */
4563 SIVALS(p,90,-1); /* max_storage */
4564 SSVAL(p,94,168); /* units_per_week */
4565 SIVAL(p,96,PTR_DIFF(p2,*rdata)); /* logon_hours */
4566 memset(p2,-1,21);
4567 p2 += 21;
4568 SSVALS(p,100,-1); /* bad_pw_count */
4569 SSVALS(p,102,-1); /* num_logons */
4570 SIVAL(p,104,PTR_DIFF(p2,*rdata)); /* logon_server */
4572 TALLOC_CTX *ctx = talloc_tos();
4573 int space_rem = *rdata_len - (p2 - *rdata);
4574 char *tmp;
4576 if (space_rem <= 0) {
4577 return false;
4579 tmp = talloc_strdup(ctx, "\\\\%L");
4580 if (!tmp) {
4581 return false;
4583 tmp = talloc_sub_basic(ctx,
4586 tmp);
4587 if (!tmp) {
4588 return false;
4591 push_ascii(p2,
4592 tmp,
4593 space_rem,
4594 STR_TERMINATE);
4596 p2 = skip_string(*rdata,*rdata_len,p2);
4597 if (!p2) {
4598 return False;
4600 SSVAL(p,108,49); /* country_code */
4601 SSVAL(p,110,860); /* code page */
4605 errcode = NERR_Success;
4607 out:
4608 *rdata_len = PTR_DIFF(p2,*rdata);
4610 if (b && is_valid_policy_hnd(&user_handle)) {
4611 dcerpc_samr_Close(b, mem_ctx, &user_handle, &result);
4613 if (b && is_valid_policy_hnd(&domain_handle)) {
4614 dcerpc_samr_Close(b, mem_ctx, &domain_handle, &result);
4616 if (b && is_valid_policy_hnd(&connect_handle)) {
4617 dcerpc_samr_Close(b, mem_ctx, &connect_handle, &result);
4620 SSVAL(*rparam,0,errcode);
4621 SSVAL(*rparam,2,0); /* converter word */
4622 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
4624 return(True);
4627 static bool api_WWkstaUserLogon(struct smbd_server_connection *sconn,
4628 connection_struct *conn,uint64_t vuid,
4629 char *param, int tpscnt,
4630 char *data, int tdscnt,
4631 int mdrcnt,int mprcnt,
4632 char **rdata,char **rparam,
4633 int *rdata_len,int *rparam_len)
4635 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4636 char *str2 = skip_string(param,tpscnt,str1);
4637 char *p = skip_string(param,tpscnt,str2);
4638 int uLevel;
4639 struct pack_desc desc;
4640 char* name;
4641 /* With share level security vuid will always be zero.
4642 Don't depend on vuser being non-null !!. JRA */
4643 struct user_struct *vuser = get_valid_user_struct(sconn, vuid);
4645 if (!str1 || !str2 || !p) {
4646 return False;
4649 if(vuser != NULL) {
4650 DEBUG(3,(" Username of UID %d is %s\n",
4651 (int)vuser->session_info->unix_token->uid,
4652 vuser->session_info->unix_info->unix_name));
4655 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4656 name = get_safe_str_ptr(param,tpscnt,p,2);
4657 if (!name) {
4658 return False;
4661 memset((char *)&desc,'\0',sizeof(desc));
4663 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
4665 /* check it's a supported varient */
4666 if (strcmp(str1,"OOWb54WrLh") != 0) {
4667 return False;
4669 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
4670 return False;
4672 if (mdrcnt > 0) {
4673 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4674 if (!*rdata) {
4675 return False;
4679 desc.base = *rdata;
4680 desc.buflen = mdrcnt;
4681 desc.subformat = NULL;
4682 desc.format = str2;
4684 if (init_package(&desc,1,0)) {
4685 PACKI(&desc,"W",0); /* code */
4686 PACKS(&desc,"B21",name); /* eff. name */
4687 PACKS(&desc,"B",""); /* pad */
4688 PACKI(&desc,"W",
4689 (get_current_uid(conn) == sec_initial_uid())?
4690 USER_PRIV_ADMIN:USER_PRIV_USER);
4691 PACKI(&desc,"D",0); /* auth flags XXX */
4692 PACKI(&desc,"W",0); /* num logons */
4693 PACKI(&desc,"W",0); /* bad pw count */
4694 PACKI(&desc,"D",0); /* last logon */
4695 PACKI(&desc,"D",-1); /* last logoff */
4696 PACKI(&desc,"D",-1); /* logoff time */
4697 PACKI(&desc,"D",-1); /* kickoff time */
4698 PACKI(&desc,"D",0); /* password age */
4699 PACKI(&desc,"D",0); /* password can change */
4700 PACKI(&desc,"D",-1); /* password must change */
4703 fstring mypath;
4704 fstrcpy(mypath,"\\\\");
4705 fstrcat(mypath,get_local_machine_name());
4706 if (!strupper_m(mypath)) {
4707 return false;
4709 PACKS(&desc,"z",mypath); /* computer */
4712 PACKS(&desc,"z",lp_workgroup());/* domain */
4713 PACKS(&desc,"z", vuser ?
4714 vuser->session_info->info->logon_script
4715 : ""); /* script path */
4716 PACKI(&desc,"D",0x00000000); /* reserved */
4719 *rdata_len = desc.usedlen;
4720 *rparam_len = 6;
4721 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4722 if (!*rparam) {
4723 return False;
4725 SSVALS(*rparam,0,desc.errcode);
4726 SSVAL(*rparam,2,0);
4727 SSVAL(*rparam,4,desc.neededlen);
4729 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4731 return True;
4734 /****************************************************************************
4735 api_WAccessGetUserPerms
4736 ****************************************************************************/
4738 static bool api_WAccessGetUserPerms(struct smbd_server_connection *sconn,
4739 connection_struct *conn,uint64_t vuid,
4740 char *param, int tpscnt,
4741 char *data, int tdscnt,
4742 int mdrcnt,int mprcnt,
4743 char **rdata,char **rparam,
4744 int *rdata_len,int *rparam_len)
4746 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4747 char *str2 = skip_string(param,tpscnt,str1);
4748 char *user = skip_string(param,tpscnt,str2);
4749 char *resource = skip_string(param,tpscnt,user);
4751 if (!str1 || !str2 || !user || !resource) {
4752 return False;
4755 if (skip_string(param,tpscnt,resource) == NULL) {
4756 return False;
4758 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4760 /* check it's a supported varient */
4761 if (strcmp(str1,"zzh") != 0) {
4762 return False;
4764 if (strcmp(str2,"") != 0) {
4765 return False;
4768 *rparam_len = 6;
4769 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4770 if (!*rparam) {
4771 return False;
4773 SSVALS(*rparam,0,0); /* errorcode */
4774 SSVAL(*rparam,2,0); /* converter word */
4775 SSVAL(*rparam,4,0x7f); /* permission flags */
4777 return True;
4780 /****************************************************************************
4781 api_WPrintJobEnumerate
4782 ****************************************************************************/
4784 static bool api_WPrintJobGetInfo(struct smbd_server_connection *sconn,
4785 connection_struct *conn, uint64_t vuid,
4786 char *param, int tpscnt,
4787 char *data, int tdscnt,
4788 int mdrcnt,int mprcnt,
4789 char **rdata,char **rparam,
4790 int *rdata_len,int *rparam_len)
4792 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4793 char *str2 = skip_string(param,tpscnt,str1);
4794 char *p = skip_string(param,tpscnt,str2);
4795 int uLevel;
4796 fstring sharename;
4797 uint32 jobid;
4798 struct pack_desc desc;
4799 char *tmpdata=NULL;
4801 TALLOC_CTX *mem_ctx = talloc_tos();
4802 WERROR werr;
4803 NTSTATUS status;
4804 struct rpc_pipe_client *cli = NULL;
4805 struct dcerpc_binding_handle *b = NULL;
4806 struct policy_handle handle;
4807 struct spoolss_DevmodeContainer devmode_ctr;
4808 union spoolss_JobInfo info;
4810 if (!str1 || !str2 || !p) {
4811 return False;
4814 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4816 memset((char *)&desc,'\0',sizeof(desc));
4817 memset((char *)&status,'\0',sizeof(status));
4819 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4821 /* check it's a supported varient */
4822 if (strcmp(str1,"WWrLh") != 0) {
4823 return False;
4825 if (!check_printjob_info(&desc,uLevel,str2)) {
4826 return False;
4829 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4830 return False;
4833 ZERO_STRUCT(handle);
4835 status = rpc_pipe_open_interface(conn,
4836 &ndr_table_spoolss.syntax_id,
4837 conn->session_info,
4838 conn->sconn->remote_address,
4839 conn->sconn->msg_ctx,
4840 &cli);
4841 if (!NT_STATUS_IS_OK(status)) {
4842 DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n",
4843 nt_errstr(status)));
4844 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4845 goto out;
4847 b = cli->binding_handle;
4849 ZERO_STRUCT(devmode_ctr);
4851 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
4852 sharename,
4853 "RAW",
4854 devmode_ctr,
4855 PRINTER_ACCESS_USE,
4856 &handle,
4857 &werr);
4858 if (!NT_STATUS_IS_OK(status)) {
4859 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4860 goto out;
4862 if (!W_ERROR_IS_OK(werr)) {
4863 desc.errcode = W_ERROR_V(werr);
4864 goto out;
4867 werr = rpccli_spoolss_getjob(cli, mem_ctx,
4868 &handle,
4869 jobid,
4870 2, /* level */
4871 0, /* offered */
4872 &info);
4873 if (!W_ERROR_IS_OK(werr)) {
4874 desc.errcode = W_ERROR_V(werr);
4875 goto out;
4878 if (mdrcnt > 0) {
4879 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4880 if (!*rdata) {
4881 return False;
4883 desc.base = *rdata;
4884 desc.buflen = mdrcnt;
4885 } else {
4887 * Don't return data but need to get correct length
4888 * init_package will return wrong size if buflen=0
4890 desc.buflen = getlen(desc.format);
4891 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4894 if (init_package(&desc,1,0)) {
4895 fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position);
4896 *rdata_len = desc.usedlen;
4897 } else {
4898 desc.errcode = NERR_JobNotFound;
4899 *rdata_len = 0;
4901 out:
4902 if (b && is_valid_policy_hnd(&handle)) {
4903 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
4906 *rparam_len = 6;
4907 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4908 if (!*rparam) {
4909 return False;
4911 SSVALS(*rparam,0,desc.errcode);
4912 SSVAL(*rparam,2,0);
4913 SSVAL(*rparam,4,desc.neededlen);
4915 SAFE_FREE(tmpdata);
4917 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4919 return True;
4922 static bool api_WPrintJobEnumerate(struct smbd_server_connection *sconn,
4923 connection_struct *conn, uint64_t vuid,
4924 char *param, int tpscnt,
4925 char *data, int tdscnt,
4926 int mdrcnt,int mprcnt,
4927 char **rdata,char **rparam,
4928 int *rdata_len,int *rparam_len)
4930 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4931 char *str2 = skip_string(param,tpscnt,str1);
4932 char *p = skip_string(param,tpscnt,str2);
4933 char *name = p;
4934 int uLevel;
4935 int i, succnt=0;
4936 struct pack_desc desc;
4938 TALLOC_CTX *mem_ctx = talloc_tos();
4939 WERROR werr;
4940 NTSTATUS status;
4941 struct rpc_pipe_client *cli = NULL;
4942 struct dcerpc_binding_handle *b = NULL;
4943 struct policy_handle handle;
4944 struct spoolss_DevmodeContainer devmode_ctr;
4945 uint32_t count = 0;
4946 union spoolss_JobInfo *info;
4948 if (!str1 || !str2 || !p) {
4949 return False;
4952 memset((char *)&desc,'\0',sizeof(desc));
4954 p = skip_string(param,tpscnt,p);
4955 if (!p) {
4956 return False;
4958 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4960 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4962 /* check it's a supported variant */
4963 if (strcmp(str1,"zWrLeh") != 0) {
4964 return False;
4967 if (uLevel > 2) {
4968 return False; /* defined only for uLevel 0,1,2 */
4971 if (!check_printjob_info(&desc,uLevel,str2)) {
4972 return False;
4975 ZERO_STRUCT(handle);
4977 status = rpc_pipe_open_interface(conn,
4978 &ndr_table_spoolss.syntax_id,
4979 conn->session_info,
4980 conn->sconn->remote_address,
4981 conn->sconn->msg_ctx,
4982 &cli);
4983 if (!NT_STATUS_IS_OK(status)) {
4984 DEBUG(0,("api_WPrintJobEnumerate: could not connect to spoolss: %s\n",
4985 nt_errstr(status)));
4986 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4987 goto out;
4989 b = cli->binding_handle;
4991 ZERO_STRUCT(devmode_ctr);
4993 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
4994 name,
4995 NULL,
4996 devmode_ctr,
4997 PRINTER_ACCESS_USE,
4998 &handle,
4999 &werr);
5000 if (!NT_STATUS_IS_OK(status)) {
5001 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5002 goto out;
5004 if (!W_ERROR_IS_OK(werr)) {
5005 desc.errcode = W_ERROR_V(werr);
5006 goto out;
5009 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
5010 &handle,
5011 0, /* firstjob */
5012 0xff, /* numjobs */
5013 2, /* level */
5014 0, /* offered */
5015 &count,
5016 &info);
5017 if (!W_ERROR_IS_OK(werr)) {
5018 desc.errcode = W_ERROR_V(werr);
5019 goto out;
5022 if (mdrcnt > 0) {
5023 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5024 if (!*rdata) {
5025 return False;
5028 desc.base = *rdata;
5029 desc.buflen = mdrcnt;
5031 if (init_package(&desc,count,0)) {
5032 succnt = 0;
5033 for (i = 0; i < count; i++) {
5034 fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i);
5035 if (desc.errcode == NERR_Success) {
5036 succnt = i+1;
5040 out:
5041 if (b && is_valid_policy_hnd(&handle)) {
5042 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5045 *rdata_len = desc.usedlen;
5047 *rparam_len = 8;
5048 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5049 if (!*rparam) {
5050 return False;
5052 SSVALS(*rparam,0,desc.errcode);
5053 SSVAL(*rparam,2,0);
5054 SSVAL(*rparam,4,succnt);
5055 SSVAL(*rparam,6,count);
5057 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
5059 return True;
5062 static int check_printdest_info(struct pack_desc* desc,
5063 int uLevel, char* id)
5065 desc->subformat = NULL;
5066 switch( uLevel ) {
5067 case 0:
5068 desc->format = "B9";
5069 break;
5070 case 1:
5071 desc->format = "B9B21WWzW";
5072 break;
5073 case 2:
5074 desc->format = "z";
5075 break;
5076 case 3:
5077 desc->format = "zzzWWzzzWW";
5078 break;
5079 default:
5080 DEBUG(0,("check_printdest_info: invalid level %d\n",
5081 uLevel));
5082 return False;
5084 if (id == NULL || strcmp(desc->format,id) != 0) {
5085 DEBUG(0,("check_printdest_info: invalid string %s\n",
5086 id ? id : "<NULL>" ));
5087 return False;
5089 return True;
5092 static void fill_printdest_info(struct spoolss_PrinterInfo2 *info2, int uLevel,
5093 struct pack_desc* desc)
5095 char buf[100];
5097 strncpy(buf, info2->printername, sizeof(buf)-1);
5098 buf[sizeof(buf)-1] = 0;
5099 (void)strupper_m(buf);
5101 if (uLevel <= 1) {
5102 PACKS(desc,"B9",buf); /* szName */
5103 if (uLevel == 1) {
5104 PACKS(desc,"B21",""); /* szUserName */
5105 PACKI(desc,"W",0); /* uJobId */
5106 PACKI(desc,"W",0); /* fsStatus */
5107 PACKS(desc,"z",""); /* pszStatus */
5108 PACKI(desc,"W",0); /* time */
5112 if (uLevel == 2 || uLevel == 3) {
5113 PACKS(desc,"z",buf); /* pszPrinterName */
5114 if (uLevel == 3) {
5115 PACKS(desc,"z",""); /* pszUserName */
5116 PACKS(desc,"z",""); /* pszLogAddr */
5117 PACKI(desc,"W",0); /* uJobId */
5118 PACKI(desc,"W",0); /* fsStatus */
5119 PACKS(desc,"z",""); /* pszStatus */
5120 PACKS(desc,"z",""); /* pszComment */
5121 PACKS(desc,"z","NULL"); /* pszDrivers */
5122 PACKI(desc,"W",0); /* time */
5123 PACKI(desc,"W",0); /* pad1 */
5128 static bool api_WPrintDestGetInfo(struct smbd_server_connection *sconn,
5129 connection_struct *conn, uint64_t vuid,
5130 char *param, int tpscnt,
5131 char *data, int tdscnt,
5132 int mdrcnt,int mprcnt,
5133 char **rdata,char **rparam,
5134 int *rdata_len,int *rparam_len)
5136 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5137 char *str2 = skip_string(param,tpscnt,str1);
5138 char *p = skip_string(param,tpscnt,str2);
5139 char* PrinterName = p;
5140 int uLevel;
5141 struct pack_desc desc;
5142 char *tmpdata=NULL;
5144 TALLOC_CTX *mem_ctx = talloc_tos();
5145 WERROR werr;
5146 NTSTATUS status;
5147 struct rpc_pipe_client *cli = NULL;
5148 struct dcerpc_binding_handle *b = NULL;
5149 struct policy_handle handle;
5150 struct spoolss_DevmodeContainer devmode_ctr;
5151 union spoolss_PrinterInfo info;
5153 if (!str1 || !str2 || !p) {
5154 return False;
5157 memset((char *)&desc,'\0',sizeof(desc));
5159 p = skip_string(param,tpscnt,p);
5160 if (!p) {
5161 return False;
5163 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5165 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
5167 /* check it's a supported varient */
5168 if (strcmp(str1,"zWrLh") != 0) {
5169 return False;
5171 if (!check_printdest_info(&desc,uLevel,str2)) {
5172 return False;
5175 ZERO_STRUCT(handle);
5177 status = rpc_pipe_open_interface(conn,
5178 &ndr_table_spoolss.syntax_id,
5179 conn->session_info,
5180 conn->sconn->remote_address,
5181 conn->sconn->msg_ctx,
5182 &cli);
5183 if (!NT_STATUS_IS_OK(status)) {
5184 DEBUG(0,("api_WPrintDestGetInfo: could not connect to spoolss: %s\n",
5185 nt_errstr(status)));
5186 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5187 goto out;
5189 b = cli->binding_handle;
5191 ZERO_STRUCT(devmode_ctr);
5193 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5194 PrinterName,
5195 NULL,
5196 devmode_ctr,
5197 PRINTER_ACCESS_USE,
5198 &handle,
5199 &werr);
5200 if (!NT_STATUS_IS_OK(status)) {
5201 *rdata_len = 0;
5202 desc.errcode = NERR_DestNotFound;
5203 desc.neededlen = 0;
5204 goto out;
5206 if (!W_ERROR_IS_OK(werr)) {
5207 *rdata_len = 0;
5208 desc.errcode = NERR_DestNotFound;
5209 desc.neededlen = 0;
5210 goto out;
5213 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
5214 &handle,
5217 &info);
5218 if (!W_ERROR_IS_OK(werr)) {
5219 *rdata_len = 0;
5220 desc.errcode = NERR_DestNotFound;
5221 desc.neededlen = 0;
5222 goto out;
5225 if (mdrcnt > 0) {
5226 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5227 if (!*rdata) {
5228 return False;
5230 desc.base = *rdata;
5231 desc.buflen = mdrcnt;
5232 } else {
5234 * Don't return data but need to get correct length
5235 * init_package will return wrong size if buflen=0
5237 desc.buflen = getlen(desc.format);
5238 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
5240 if (init_package(&desc,1,0)) {
5241 fill_printdest_info(&info.info2, uLevel,&desc);
5244 out:
5245 if (b && is_valid_policy_hnd(&handle)) {
5246 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5249 *rdata_len = desc.usedlen;
5251 *rparam_len = 6;
5252 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5253 if (!*rparam) {
5254 return False;
5256 SSVALS(*rparam,0,desc.errcode);
5257 SSVAL(*rparam,2,0);
5258 SSVAL(*rparam,4,desc.neededlen);
5260 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
5261 SAFE_FREE(tmpdata);
5263 return True;
5266 static bool api_WPrintDestEnum(struct smbd_server_connection *sconn,
5267 connection_struct *conn, uint64_t vuid,
5268 char *param, int tpscnt,
5269 char *data, int tdscnt,
5270 int mdrcnt,int mprcnt,
5271 char **rdata,char **rparam,
5272 int *rdata_len,int *rparam_len)
5274 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5275 char *str2 = skip_string(param,tpscnt,str1);
5276 char *p = skip_string(param,tpscnt,str2);
5277 int uLevel;
5278 int queuecnt;
5279 int i, n, succnt=0;
5280 struct pack_desc desc;
5282 TALLOC_CTX *mem_ctx = talloc_tos();
5283 WERROR werr;
5284 NTSTATUS status;
5285 struct rpc_pipe_client *cli = NULL;
5286 union spoolss_PrinterInfo *info;
5287 uint32_t count;
5289 if (!str1 || !str2 || !p) {
5290 return False;
5293 memset((char *)&desc,'\0',sizeof(desc));
5295 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5297 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
5299 /* check it's a supported varient */
5300 if (strcmp(str1,"WrLeh") != 0) {
5301 return False;
5303 if (!check_printdest_info(&desc,uLevel,str2)) {
5304 return False;
5307 queuecnt = 0;
5309 status = rpc_pipe_open_interface(conn,
5310 &ndr_table_spoolss.syntax_id,
5311 conn->session_info,
5312 conn->sconn->remote_address,
5313 conn->sconn->msg_ctx,
5314 &cli);
5315 if (!NT_STATUS_IS_OK(status)) {
5316 DEBUG(0,("api_WPrintDestEnum: could not connect to spoolss: %s\n",
5317 nt_errstr(status)));
5318 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5319 goto out;
5322 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
5323 PRINTER_ENUM_LOCAL,
5324 cli->srv_name_slash,
5327 &count,
5328 &info);
5329 if (!W_ERROR_IS_OK(werr)) {
5330 desc.errcode = W_ERROR_V(werr);
5331 *rdata_len = 0;
5332 desc.errcode = NERR_DestNotFound;
5333 desc.neededlen = 0;
5334 goto out;
5337 queuecnt = count;
5339 if (mdrcnt > 0) {
5340 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5341 if (!*rdata) {
5342 return False;
5346 desc.base = *rdata;
5347 desc.buflen = mdrcnt;
5348 if (init_package(&desc,queuecnt,0)) {
5349 succnt = 0;
5350 n = 0;
5351 for (i = 0; i < count; i++) {
5352 fill_printdest_info(&info[i].info2, uLevel,&desc);
5353 n++;
5354 if (desc.errcode == NERR_Success) {
5355 succnt = n;
5359 out:
5360 *rdata_len = desc.usedlen;
5362 *rparam_len = 8;
5363 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5364 if (!*rparam) {
5365 return False;
5367 SSVALS(*rparam,0,desc.errcode);
5368 SSVAL(*rparam,2,0);
5369 SSVAL(*rparam,4,succnt);
5370 SSVAL(*rparam,6,queuecnt);
5372 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
5374 return True;
5377 static bool api_WPrintDriverEnum(struct smbd_server_connection *sconn,
5378 connection_struct *conn, uint64_t vuid,
5379 char *param, int tpscnt,
5380 char *data, int tdscnt,
5381 int mdrcnt,int mprcnt,
5382 char **rdata,char **rparam,
5383 int *rdata_len,int *rparam_len)
5385 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5386 char *str2 = skip_string(param,tpscnt,str1);
5387 char *p = skip_string(param,tpscnt,str2);
5388 int uLevel;
5389 int succnt;
5390 struct pack_desc desc;
5392 if (!str1 || !str2 || !p) {
5393 return False;
5396 memset((char *)&desc,'\0',sizeof(desc));
5398 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5400 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
5402 /* check it's a supported varient */
5403 if (strcmp(str1,"WrLeh") != 0) {
5404 return False;
5406 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
5407 return False;
5410 if (mdrcnt > 0) {
5411 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5412 if (!*rdata) {
5413 return False;
5416 desc.base = *rdata;
5417 desc.buflen = mdrcnt;
5418 if (init_package(&desc,1,0)) {
5419 PACKS(&desc,"B41","NULL");
5422 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5424 *rdata_len = desc.usedlen;
5426 *rparam_len = 8;
5427 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5428 if (!*rparam) {
5429 return False;
5431 SSVALS(*rparam,0,desc.errcode);
5432 SSVAL(*rparam,2,0);
5433 SSVAL(*rparam,4,succnt);
5434 SSVAL(*rparam,6,1);
5436 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
5438 return True;
5441 static bool api_WPrintQProcEnum(struct smbd_server_connection *sconn,
5442 connection_struct *conn, uint64_t vuid,
5443 char *param, int tpscnt,
5444 char *data, int tdscnt,
5445 int mdrcnt,int mprcnt,
5446 char **rdata,char **rparam,
5447 int *rdata_len,int *rparam_len)
5449 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5450 char *str2 = skip_string(param,tpscnt,str1);
5451 char *p = skip_string(param,tpscnt,str2);
5452 int uLevel;
5453 int succnt;
5454 struct pack_desc desc;
5456 if (!str1 || !str2 || !p) {
5457 return False;
5459 memset((char *)&desc,'\0',sizeof(desc));
5461 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5463 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
5465 /* check it's a supported varient */
5466 if (strcmp(str1,"WrLeh") != 0) {
5467 return False;
5469 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
5470 return False;
5473 if (mdrcnt > 0) {
5474 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5475 if (!*rdata) {
5476 return False;
5479 desc.base = *rdata;
5480 desc.buflen = mdrcnt;
5481 desc.format = str2;
5482 if (init_package(&desc,1,0)) {
5483 PACKS(&desc,"B13","lpd");
5486 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5488 *rdata_len = desc.usedlen;
5490 *rparam_len = 8;
5491 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5492 if (!*rparam) {
5493 return False;
5495 SSVALS(*rparam,0,desc.errcode);
5496 SSVAL(*rparam,2,0);
5497 SSVAL(*rparam,4,succnt);
5498 SSVAL(*rparam,6,1);
5500 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
5502 return True;
5505 static bool api_WPrintPortEnum(struct smbd_server_connection *sconn,
5506 connection_struct *conn, uint64_t vuid,
5507 char *param, int tpscnt,
5508 char *data, int tdscnt,
5509 int mdrcnt,int mprcnt,
5510 char **rdata,char **rparam,
5511 int *rdata_len,int *rparam_len)
5513 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5514 char *str2 = skip_string(param,tpscnt,str1);
5515 char *p = skip_string(param,tpscnt,str2);
5516 int uLevel;
5517 int succnt;
5518 struct pack_desc desc;
5520 if (!str1 || !str2 || !p) {
5521 return False;
5524 memset((char *)&desc,'\0',sizeof(desc));
5526 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5528 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
5530 /* check it's a supported varient */
5531 if (strcmp(str1,"WrLeh") != 0) {
5532 return False;
5534 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
5535 return False;
5538 if (mdrcnt > 0) {
5539 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5540 if (!*rdata) {
5541 return False;
5544 memset((char *)&desc,'\0',sizeof(desc));
5545 desc.base = *rdata;
5546 desc.buflen = mdrcnt;
5547 desc.format = str2;
5548 if (init_package(&desc,1,0)) {
5549 PACKS(&desc,"B13","lp0");
5552 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5554 *rdata_len = desc.usedlen;
5556 *rparam_len = 8;
5557 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5558 if (!*rparam) {
5559 return False;
5561 SSVALS(*rparam,0,desc.errcode);
5562 SSVAL(*rparam,2,0);
5563 SSVAL(*rparam,4,succnt);
5564 SSVAL(*rparam,6,1);
5566 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
5568 return True;
5571 /****************************************************************************
5572 List open sessions
5573 ****************************************************************************/
5575 static bool api_RNetSessionEnum(struct smbd_server_connection *sconn,
5576 connection_struct *conn, uint64_t vuid,
5577 char *param, int tpscnt,
5578 char *data, int tdscnt,
5579 int mdrcnt,int mprcnt,
5580 char **rdata,char **rparam,
5581 int *rdata_len,int *rparam_len)
5584 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5585 char *str2 = skip_string(param,tpscnt,str1);
5586 char *p = skip_string(param,tpscnt,str2);
5587 int uLevel;
5588 struct pack_desc desc;
5589 int i;
5591 TALLOC_CTX *mem_ctx = talloc_tos();
5592 WERROR werr;
5593 NTSTATUS status;
5594 struct rpc_pipe_client *cli = NULL;
5595 struct dcerpc_binding_handle *b = NULL;
5596 struct srvsvc_NetSessInfoCtr info_ctr;
5597 uint32_t totalentries, resume_handle = 0;
5598 uint32_t count = 0;
5600 if (!str1 || !str2 || !p) {
5601 return False;
5604 ZERO_STRUCT(desc);
5606 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5608 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
5609 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
5610 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
5612 /* check it's a supported varient */
5613 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
5614 return False;
5616 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
5617 return False;
5620 status = rpc_pipe_open_interface(conn,
5621 &ndr_table_srvsvc.syntax_id,
5622 conn->session_info,
5623 conn->sconn->remote_address,
5624 conn->sconn->msg_ctx,
5625 &cli);
5626 if (!NT_STATUS_IS_OK(status)) {
5627 DEBUG(0,("RNetSessionEnum: could not connect to srvsvc: %s\n",
5628 nt_errstr(status)));
5629 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5630 goto out;
5632 b = cli->binding_handle;
5634 info_ctr.level = 1;
5635 info_ctr.ctr.ctr1 = talloc_zero(talloc_tos(), struct srvsvc_NetSessCtr1);
5636 if (info_ctr.ctr.ctr1 == NULL) {
5637 desc.errcode = W_ERROR_V(WERR_NOMEM);
5638 goto out;
5641 status = dcerpc_srvsvc_NetSessEnum(b, mem_ctx,
5642 cli->srv_name_slash,
5643 NULL, /* client */
5644 NULL, /* user */
5645 &info_ctr,
5646 (uint32_t)-1, /* max_buffer */
5647 &totalentries,
5648 &resume_handle,
5649 &werr);
5650 if (!NT_STATUS_IS_OK(status)) {
5651 DEBUG(0,("RNetSessionEnum: dcerpc_srvsvc_NetSessEnum failed: %s\n",
5652 nt_errstr(status)));
5653 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5654 goto out;
5657 if (!W_ERROR_IS_OK(werr)) {
5658 DEBUG(0,("RNetSessionEnum: dcerpc_srvsvc_NetSessEnum failed: %s\n",
5659 win_errstr(werr)));
5660 desc.errcode = W_ERROR_V(werr);
5661 goto out;
5664 count = info_ctr.ctr.ctr1->count;
5666 out:
5667 if (mdrcnt > 0) {
5668 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5669 if (!*rdata) {
5670 return False;
5674 desc.base = *rdata;
5675 desc.buflen = mdrcnt;
5676 desc.format = str2;
5677 if (!init_package(&desc, count,0)) {
5678 return False;
5681 for(i=0; i < count; i++) {
5682 PACKS(&desc, "z", info_ctr.ctr.ctr1->array[i].client);
5683 PACKS(&desc, "z", info_ctr.ctr.ctr1->array[i].user);
5684 PACKI(&desc, "W", 1); /* num conns */
5685 PACKI(&desc, "W", info_ctr.ctr.ctr1->array[i].num_open);
5686 PACKI(&desc, "W", 1); /* num users */
5687 PACKI(&desc, "D", 0); /* session time */
5688 PACKI(&desc, "D", 0); /* idle time */
5689 PACKI(&desc, "D", 0); /* flags */
5690 PACKS(&desc, "z", "Unknown Client"); /* client type string */
5693 *rdata_len = desc.usedlen;
5695 *rparam_len = 8;
5696 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5697 if (!*rparam) {
5698 return False;
5700 SSVALS(*rparam,0,desc.errcode);
5701 SSVAL(*rparam,2,0); /* converter */
5702 SSVAL(*rparam,4, count); /* count */
5704 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
5706 return True;
5710 /****************************************************************************
5711 The buffer was too small.
5712 ****************************************************************************/
5714 static bool api_TooSmall(struct smbd_server_connection *sconn,
5715 connection_struct *conn,uint64_t vuid, char *param, char *data,
5716 int mdrcnt, int mprcnt,
5717 char **rdata, char **rparam,
5718 int *rdata_len, int *rparam_len)
5720 *rparam_len = MIN(*rparam_len,mprcnt);
5721 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5722 if (!*rparam) {
5723 return False;
5726 *rdata_len = 0;
5728 SSVAL(*rparam,0,NERR_BufTooSmall);
5730 DEBUG(3,("Supplied buffer too small in API command\n"));
5732 return True;
5735 /****************************************************************************
5736 The request is not supported.
5737 ****************************************************************************/
5739 static bool api_Unsupported(struct smbd_server_connection *sconn,
5740 connection_struct *conn, uint64_t vuid,
5741 char *param, int tpscnt,
5742 char *data, int tdscnt,
5743 int mdrcnt, int mprcnt,
5744 char **rdata, char **rparam,
5745 int *rdata_len, int *rparam_len)
5747 *rparam_len = 4;
5748 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5749 if (!*rparam) {
5750 return False;
5753 *rdata_len = 0;
5755 SSVAL(*rparam,0,NERR_notsupported);
5756 SSVAL(*rparam,2,0); /* converter word */
5758 DEBUG(3,("Unsupported API command\n"));
5760 return True;
5763 static const struct {
5764 const char *name;
5765 int id;
5766 bool (*fn)(struct smbd_server_connection *sconn,
5767 connection_struct *, uint64_t,
5768 char *, int,
5769 char *, int,
5770 int,int,char **,char **,int *,int *);
5771 bool auth_user; /* Deny anonymous access? */
5772 } api_commands[] = {
5773 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
5774 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
5775 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
5776 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
5777 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
5778 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
5779 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
5780 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
5781 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
5782 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
5783 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
5784 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
5785 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
5786 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
5787 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
5788 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
5789 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
5790 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
5791 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
5792 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
5793 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
5794 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
5795 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
5796 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
5797 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
5798 {"NetServerEnum3", RAP_NetServerEnum3, api_RNetServerEnum3}, /* anon OK */
5799 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
5800 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
5801 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
5802 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
5803 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
5804 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
5805 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
5806 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
5807 {NULL, -1, api_Unsupported}
5808 /* The following RAP calls are not implemented by Samba:
5810 RAP_WFileEnum2 - anon not OK
5815 /****************************************************************************
5816 Handle remote api calls.
5817 ****************************************************************************/
5819 void api_reply(connection_struct *conn, uint64_t vuid,
5820 struct smb_request *req,
5821 char *data, char *params,
5822 int tdscnt, int tpscnt,
5823 int mdrcnt, int mprcnt)
5825 int api_command;
5826 char *rdata = NULL;
5827 char *rparam = NULL;
5828 const char *name1 = NULL;
5829 const char *name2 = NULL;
5830 int rdata_len = 0;
5831 int rparam_len = 0;
5832 bool reply=False;
5833 int i;
5835 if (!params) {
5836 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
5837 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5838 return;
5841 if (tpscnt < 2) {
5842 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5843 return;
5845 api_command = SVAL(params,0);
5846 /* Is there a string at position params+2 ? */
5847 if (skip_string(params,tpscnt,params+2)) {
5848 name1 = params + 2;
5849 } else {
5850 name1 = "";
5852 name2 = skip_string(params,tpscnt,params+2);
5853 if (!name2) {
5854 name2 = "";
5857 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
5858 api_command,
5859 name1,
5860 name2,
5861 tdscnt,tpscnt,mdrcnt,mprcnt));
5863 for (i=0;api_commands[i].name;i++) {
5864 if (api_commands[i].id == api_command && api_commands[i].fn) {
5865 DEBUG(3,("Doing %s\n",api_commands[i].name));
5866 break;
5870 /* Check whether this api call can be done anonymously */
5872 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
5873 struct user_struct *user = get_valid_user_struct(req->sconn, vuid);
5875 if (!user || security_session_user_level(user->session_info, NULL) < SECURITY_USER) {
5876 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5877 return;
5881 rdata = (char *)SMB_MALLOC(1024);
5882 if (rdata) {
5883 memset(rdata,'\0',1024);
5886 rparam = (char *)SMB_MALLOC(1024);
5887 if (rparam) {
5888 memset(rparam,'\0',1024);
5891 if(!rdata || !rparam) {
5892 DEBUG(0,("api_reply: malloc fail !\n"));
5893 SAFE_FREE(rdata);
5894 SAFE_FREE(rparam);
5895 reply_nterror(req, NT_STATUS_NO_MEMORY);
5896 return;
5899 reply = api_commands[i].fn(req->sconn, conn,
5900 vuid,
5901 params,tpscnt, /* params + length */
5902 data,tdscnt, /* data + length */
5903 mdrcnt,mprcnt,
5904 &rdata,&rparam,&rdata_len,&rparam_len);
5907 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
5908 reply = api_TooSmall(req->sconn,conn,vuid,params,data,
5909 mdrcnt,mprcnt,
5910 &rdata,&rparam,&rdata_len,&rparam_len);
5913 /* if we get False back then it's actually unsupported */
5914 if (!reply) {
5915 reply = api_Unsupported(req->sconn,conn,vuid,params,tpscnt,
5916 data,
5917 tdscnt,mdrcnt,mprcnt,
5918 &rdata,&rparam,&rdata_len,&rparam_len);
5921 /* If api_Unsupported returns false we can't return anything. */
5922 if (reply) {
5923 send_trans_reply(conn, req, rparam, rparam_len,
5924 rdata, rdata_len, False);
5927 SAFE_FREE(rdata);
5928 SAFE_FREE(rparam);
5929 return;