nfs4acls: Use talloc_realloc()
[Samba.git] / source3 / smbd / lanman.c
blob53e2724805c35e073e58de106f139965b5c5db9d
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 == 0) {
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 == 0) {
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_t 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,
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,
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_t 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_t 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;
1229 char *slist_cache_path = cache_path(SERVER_LIST);
1230 if (slist_cache_path == NULL) {
1231 return 0;
1234 lines = file_lines_load(slist_cache_path, NULL, 0, NULL);
1235 if (!lines) {
1236 DEBUG(4, ("Can't open %s - %s\n",
1237 slist_cache_path, strerror(errno)));
1238 TALLOC_FREE(slist_cache_path);
1239 return 0;
1241 TALLOC_FREE(slist_cache_path);
1243 /* request for everything is code for request all servers */
1244 if (servertype == SV_TYPE_ALL) {
1245 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1248 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1250 DEBUG(4,("Servertype search: %8x\n",servertype));
1252 for (i=0;lines[i];i++) {
1253 fstring stype;
1254 struct srv_info_struct *s;
1255 const char *ptr = lines[i];
1256 bool ok = True;
1257 TALLOC_CTX *frame = NULL;
1258 char *p;
1260 if (!*ptr) {
1261 continue;
1264 if (count == alloced) {
1265 alloced += 10;
1266 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1267 if (!*servers) {
1268 DEBUG(0,("get_session_info: failed to enlarge servers info struct!\n"));
1269 TALLOC_FREE(lines);
1270 return 0;
1272 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1274 s = &(*servers)[count];
1276 frame = talloc_stackframe();
1277 s->name[0] = '\0';
1278 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1279 TALLOC_FREE(frame);
1280 continue;
1282 fstrcpy(s->name, p);
1284 stype[0] = '\0';
1285 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1286 TALLOC_FREE(frame);
1287 continue;
1289 fstrcpy(stype, p);
1291 s->comment[0] = '\0';
1292 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1293 TALLOC_FREE(frame);
1294 continue;
1296 fstrcpy(s->comment, p);
1297 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1299 s->domain[0] = '\0';
1300 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1301 /* this allows us to cope with an old nmbd */
1302 fstrcpy(s->domain,lp_workgroup());
1303 } else {
1304 fstrcpy(s->domain, p);
1306 TALLOC_FREE(frame);
1308 if (sscanf(stype,"%X",&s->type) != 1) {
1309 DEBUG(4,("r:host file "));
1310 ok = False;
1313 /* Filter the servers/domains we return based on what was asked for. */
1315 /* Check to see if we are being asked for a local list only. */
1316 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1317 DEBUG(4,("r: local list only"));
1318 ok = False;
1321 /* doesn't match up: don't want it */
1322 if (!(servertype & s->type)) {
1323 DEBUG(4,("r:serv type "));
1324 ok = False;
1327 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1328 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1329 DEBUG(4,("s: dom mismatch "));
1330 ok = False;
1333 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1334 ok = False;
1337 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1338 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1340 if (ok) {
1341 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1342 s->name, s->type, s->comment, s->domain));
1343 s->server_added = True;
1344 count++;
1345 } else {
1346 DEBUG(4,("%20s %8x %25s %15s\n",
1347 s->name, s->type, s->comment, s->domain));
1351 TALLOC_FREE(lines);
1352 return count;
1355 /*******************************************************************
1356 Fill in a server info structure.
1357 ******************************************************************/
1359 static int fill_srv_info(struct srv_info_struct *service,
1360 int uLevel, char **buf, int *buflen,
1361 char **stringbuf, int *stringspace, char *baseaddr)
1363 int struct_len;
1364 char* p;
1365 char* p2;
1366 int l2;
1367 int len;
1369 switch (uLevel) {
1370 case 0:
1371 struct_len = 16;
1372 break;
1373 case 1:
1374 struct_len = 26;
1375 break;
1376 default:
1377 return -1;
1380 if (!buf) {
1381 len = 0;
1382 switch (uLevel) {
1383 case 1:
1384 len = strlen(service->comment)+1;
1385 break;
1388 *buflen = struct_len;
1389 *stringspace = len;
1390 return struct_len + len;
1393 len = struct_len;
1394 p = *buf;
1395 if (*buflen < struct_len) {
1396 return -1;
1398 if (stringbuf) {
1399 p2 = *stringbuf;
1400 l2 = *stringspace;
1401 } else {
1402 p2 = p + struct_len;
1403 l2 = *buflen - struct_len;
1405 if (!baseaddr) {
1406 baseaddr = p;
1409 switch (uLevel) {
1410 case 0:
1411 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1412 break;
1414 case 1:
1415 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1416 SIVAL(p,18,service->type);
1417 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1418 len += CopyAndAdvance(&p2,service->comment,&l2);
1419 break;
1422 if (stringbuf) {
1423 *buf = p + struct_len;
1424 *buflen -= struct_len;
1425 *stringbuf = p2;
1426 *stringspace = l2;
1427 } else {
1428 *buf = p2;
1429 *buflen -= len;
1431 return len;
1435 static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1437 return strcasecmp_m(s1->name,s2->name);
1440 /****************************************************************************
1441 View list of servers available (or possibly domains). The info is
1442 extracted from lists saved by nmbd on the local host.
1443 ****************************************************************************/
1445 static bool api_RNetServerEnum2(struct smbd_server_connection *sconn,
1446 connection_struct *conn, uint64_t vuid,
1447 char *param, int tpscnt,
1448 char *data, int tdscnt,
1449 int mdrcnt, int mprcnt, char **rdata,
1450 char **rparam, int *rdata_len, int *rparam_len)
1452 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1453 char *str2 = skip_string(param,tpscnt,str1);
1454 char *p = skip_string(param,tpscnt,str2);
1455 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1456 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1457 uint32_t servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1458 char *p2;
1459 int data_len, fixed_len, string_len;
1460 int f_len = 0, s_len = 0;
1461 struct srv_info_struct *servers=NULL;
1462 int counted=0,total=0;
1463 int i,missed;
1464 fstring domain;
1465 bool domain_request;
1466 bool local_request;
1468 if (!str1 || !str2 || !p) {
1469 return False;
1472 /* If someone sets all the bits they don't really mean to set
1473 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1474 known servers. */
1476 if (servertype == SV_TYPE_ALL) {
1477 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1480 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1481 any other bit (they may just set this bit on its own) they
1482 want all the locally seen servers. However this bit can be
1483 set on its own so set the requested servers to be
1484 ALL - DOMAIN_ENUM. */
1486 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1487 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1490 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1491 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1493 p += 8;
1495 if (!prefix_ok(str1,"WrLehD")) {
1496 return False;
1498 if (!check_session_info(uLevel,str2)) {
1499 return False;
1502 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1503 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1504 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1506 if (strcmp(str1, "WrLehDz") == 0) {
1507 if (skip_string(param,tpscnt,p) == NULL) {
1508 return False;
1510 pull_ascii_fstring(domain, p);
1511 } else {
1512 fstrcpy(domain, lp_workgroup());
1515 DEBUG(4, ("domain [%s]\n", domain));
1517 if (lp_browse_list()) {
1518 total = get_session_info(servertype,&servers,domain);
1521 data_len = fixed_len = string_len = 0;
1522 missed = 0;
1524 TYPESAFE_QSORT(servers, total, srv_comp);
1527 char *lastname=NULL;
1529 for (i=0;i<total;i++) {
1530 struct srv_info_struct *s = &servers[i];
1532 if (lastname && strequal(lastname,s->name)) {
1533 continue;
1535 lastname = s->name;
1536 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1537 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1538 i, s->name, s->type, s->comment, s->domain));
1540 if (data_len < buf_len) {
1541 counted++;
1542 fixed_len += f_len;
1543 string_len += s_len;
1544 } else {
1545 missed++;
1550 *rdata_len = fixed_len + string_len;
1551 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1552 if (!*rdata) {
1553 return False;
1556 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1557 p = *rdata;
1558 f_len = fixed_len;
1559 s_len = string_len;
1562 char *lastname=NULL;
1563 int count2 = counted;
1565 for (i = 0; i < total && count2;i++) {
1566 struct srv_info_struct *s = &servers[i];
1568 if (lastname && strequal(lastname,s->name)) {
1569 continue;
1571 lastname = s->name;
1572 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1573 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1574 i, s->name, s->type, s->comment, s->domain));
1575 count2--;
1579 *rparam_len = 8;
1580 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1581 if (!*rparam) {
1582 return False;
1584 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1585 SSVAL(*rparam,2,0);
1586 SSVAL(*rparam,4,counted);
1587 SSVAL(*rparam,6,counted+missed);
1589 SAFE_FREE(servers);
1591 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1592 domain,uLevel,counted,counted+missed));
1594 return True;
1597 static int srv_name_match(const char *n1, const char *n2)
1600 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1602 * In Windows, FirstNameToReturn need not be an exact match:
1603 * the server will return a list of servers that exist on
1604 * the network greater than or equal to the FirstNameToReturn.
1606 int ret = strcasecmp_m(n1, n2);
1608 if (ret <= 0) {
1609 return 0;
1612 return ret;
1615 static bool api_RNetServerEnum3(struct smbd_server_connection *sconn,
1616 connection_struct *conn, uint64_t vuid,
1617 char *param, int tpscnt,
1618 char *data, int tdscnt,
1619 int mdrcnt, int mprcnt, char **rdata,
1620 char **rparam, int *rdata_len, int *rparam_len)
1622 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1623 char *str2 = skip_string(param,tpscnt,str1);
1624 char *p = skip_string(param,tpscnt,str2);
1625 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1626 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1627 uint32_t servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1628 char *p2;
1629 int data_len, fixed_len, string_len;
1630 int f_len = 0, s_len = 0;
1631 struct srv_info_struct *servers=NULL;
1632 int counted=0,first=0,total=0;
1633 int i,missed;
1634 fstring domain;
1635 fstring first_name;
1636 bool domain_request;
1637 bool local_request;
1639 if (!str1 || !str2 || !p) {
1640 return False;
1643 /* If someone sets all the bits they don't really mean to set
1644 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1645 known servers. */
1647 if (servertype == SV_TYPE_ALL) {
1648 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1651 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1652 any other bit (they may just set this bit on its own) they
1653 want all the locally seen servers. However this bit can be
1654 set on its own so set the requested servers to be
1655 ALL - DOMAIN_ENUM. */
1657 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1658 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1661 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1662 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1664 p += 8;
1666 if (strcmp(str1, "WrLehDzz") != 0) {
1667 return false;
1669 if (!check_session_info(uLevel,str2)) {
1670 return False;
1673 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1674 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1675 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1677 if (skip_string(param,tpscnt,p) == NULL) {
1678 return False;
1680 pull_ascii_fstring(domain, p);
1681 if (domain[0] == '\0') {
1682 fstrcpy(domain, lp_workgroup());
1684 p = skip_string(param,tpscnt,p);
1685 if (skip_string(param,tpscnt,p) == NULL) {
1686 return False;
1688 pull_ascii_fstring(first_name, p);
1690 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1691 domain, first_name));
1693 if (lp_browse_list()) {
1694 total = get_session_info(servertype,&servers,domain);
1697 data_len = fixed_len = string_len = 0;
1698 missed = 0;
1700 TYPESAFE_QSORT(servers, total, srv_comp);
1702 if (first_name[0] != '\0') {
1703 struct srv_info_struct *first_server = NULL;
1705 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1706 srv_name_match, first_server);
1707 if (first_server) {
1708 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1710 * The binary search may not find the exact match
1711 * so we need to search backward to find the first match
1713 * This implements the strange matching windows
1714 * implements. (see the comment in srv_name_match().
1716 for (;first > 0;) {
1717 int ret;
1718 ret = strcasecmp_m(first_name,
1719 servers[first-1].name);
1720 if (ret > 0) {
1721 break;
1723 first--;
1725 } else {
1726 /* we should return no entries */
1727 first = total;
1732 char *lastname=NULL;
1734 for (i=first;i<total;i++) {
1735 struct srv_info_struct *s = &servers[i];
1737 if (lastname && strequal(lastname,s->name)) {
1738 continue;
1740 lastname = s->name;
1741 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1742 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1743 i, s->name, s->type, s->comment, s->domain));
1745 if (data_len < buf_len) {
1746 counted++;
1747 fixed_len += f_len;
1748 string_len += s_len;
1749 } else {
1750 missed++;
1755 *rdata_len = fixed_len + string_len;
1756 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1757 if (!*rdata) {
1758 return False;
1761 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1762 p = *rdata;
1763 f_len = fixed_len;
1764 s_len = string_len;
1767 char *lastname=NULL;
1768 int count2 = counted;
1770 for (i = first; i < total && count2;i++) {
1771 struct srv_info_struct *s = &servers[i];
1773 if (lastname && strequal(lastname,s->name)) {
1774 continue;
1776 lastname = s->name;
1777 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1778 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1779 i, s->name, s->type, s->comment, s->domain));
1780 count2--;
1784 *rparam_len = 8;
1785 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1786 if (!*rparam) {
1787 return False;
1789 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1790 SSVAL(*rparam,2,0);
1791 SSVAL(*rparam,4,counted);
1792 SSVAL(*rparam,6,counted+missed);
1794 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1795 domain,uLevel,first,first_name,
1796 first < total ? servers[first].name : "",
1797 counted,counted+missed));
1799 SAFE_FREE(servers);
1801 return True;
1804 /****************************************************************************
1805 command 0x34 - suspected of being a "Lookup Names" stub api
1806 ****************************************************************************/
1808 static bool api_RNetGroupGetUsers(struct smbd_server_connection *sconn,
1809 connection_struct *conn, uint64_t vuid,
1810 char *param, int tpscnt,
1811 char *data, int tdscnt,
1812 int mdrcnt, int mprcnt, char **rdata,
1813 char **rparam, int *rdata_len, int *rparam_len)
1815 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1816 char *str2 = skip_string(param,tpscnt,str1);
1817 char *p = skip_string(param,tpscnt,str2);
1818 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1819 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1820 int counted=0;
1821 int missed=0;
1823 if (!str1 || !str2 || !p) {
1824 return False;
1827 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1828 str1, str2, p, uLevel, buf_len));
1830 if (!prefix_ok(str1,"zWrLeh")) {
1831 return False;
1834 *rdata_len = 0;
1836 *rparam_len = 8;
1837 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1838 if (!*rparam) {
1839 return False;
1842 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1843 SSVAL(*rparam,2,0);
1844 SSVAL(*rparam,4,counted);
1845 SSVAL(*rparam,6,counted+missed);
1847 return True;
1850 /****************************************************************************
1851 get info about a share
1852 ****************************************************************************/
1854 static bool check_share_info(int uLevel, char* id)
1856 switch( uLevel ) {
1857 case 0:
1858 if (strcmp(id,"B13") != 0) {
1859 return False;
1861 break;
1862 case 1:
1863 /* Level-2 descriptor is allowed (and ignored) */
1864 if (strcmp(id,"B13BWz") != 0 &&
1865 strcmp(id,"B13BWzWWWzB9B") != 0) {
1866 return False;
1868 break;
1869 case 2:
1870 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1871 return False;
1873 break;
1874 case 91:
1875 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1876 return False;
1878 break;
1879 default:
1880 return False;
1882 return True;
1885 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1886 char** buf, int* buflen,
1887 char** stringbuf, int* stringspace, char* baseaddr)
1889 int struct_len;
1890 char* p;
1891 char* p2;
1892 int l2;
1893 int len;
1895 switch( uLevel ) {
1896 case 0:
1897 struct_len = 13;
1898 break;
1899 case 1:
1900 struct_len = 20;
1901 break;
1902 case 2:
1903 struct_len = 40;
1904 break;
1905 case 91:
1906 struct_len = 68;
1907 break;
1908 default:
1909 return -1;
1912 if (!buf) {
1913 len = 0;
1915 if (uLevel > 0) {
1916 len += StrlenExpanded(conn,snum,lp_comment(talloc_tos(), snum));
1918 if (uLevel > 1) {
1919 len += strlen(lp_path(talloc_tos(), snum)) + 1;
1921 if (buflen) {
1922 *buflen = struct_len;
1924 if (stringspace) {
1925 *stringspace = len;
1927 return struct_len + len;
1930 len = struct_len;
1931 p = *buf;
1932 if ((*buflen) < struct_len) {
1933 return -1;
1936 if (stringbuf) {
1937 p2 = *stringbuf;
1938 l2 = *stringspace;
1939 } else {
1940 p2 = p + struct_len;
1941 l2 = (*buflen) - struct_len;
1944 if (!baseaddr) {
1945 baseaddr = p;
1948 push_ascii(p,lp_servicename(talloc_tos(), snum),13, STR_TERMINATE);
1950 if (uLevel > 0) {
1951 int type;
1953 SCVAL(p,13,0);
1954 type = STYPE_DISKTREE;
1955 if (lp_printable(snum)) {
1956 type = STYPE_PRINTQ;
1958 if (strequal("IPC",lp_fstype(snum))) {
1959 type = STYPE_IPC;
1961 SSVAL(p,14,type); /* device type */
1962 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1963 len += CopyExpanded(conn,snum,&p2,lp_comment(talloc_tos(),snum),&l2);
1966 if (uLevel > 1) {
1967 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1968 SSVALS(p,22,-1); /* max uses */
1969 SSVAL(p,24,1); /* current uses */
1970 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1971 len += CopyAndAdvance(&p2,lp_path(talloc_tos(),snum),&l2);
1972 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1975 if (uLevel > 2) {
1976 memset(p+40,0,SHPWLEN+2);
1977 SSVAL(p,50,0);
1978 SIVAL(p,52,0);
1979 SSVAL(p,56,0);
1980 SSVAL(p,58,0);
1981 SIVAL(p,60,0);
1982 SSVAL(p,64,0);
1983 SSVAL(p,66,0);
1986 if (stringbuf) {
1987 (*buf) = p + struct_len;
1988 (*buflen) -= struct_len;
1989 (*stringbuf) = p2;
1990 (*stringspace) = l2;
1991 } else {
1992 (*buf) = p2;
1993 (*buflen) -= len;
1996 return len;
1999 static bool api_RNetShareGetInfo(struct smbd_server_connection *sconn,
2000 connection_struct *conn,uint64_t vuid,
2001 char *param, int tpscnt,
2002 char *data, int tdscnt,
2003 int mdrcnt,int mprcnt,
2004 char **rdata,char **rparam,
2005 int *rdata_len,int *rparam_len)
2007 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2008 char *str2 = skip_string(param,tpscnt,str1);
2009 char *netname_in = skip_string(param,tpscnt,str2);
2010 char *netname = NULL;
2011 char *p = skip_string(param,tpscnt,netname);
2012 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2013 int snum;
2015 if (!str1 || !str2 || !netname_in || !p) {
2016 return False;
2019 snum = find_service(talloc_tos(), netname_in, &netname);
2020 if (snum < 0 || !netname) {
2021 return False;
2024 /* check it's a supported varient */
2025 if (!prefix_ok(str1,"zWrLh")) {
2026 return False;
2028 if (!check_share_info(uLevel,str2)) {
2029 return False;
2032 *rdata = smb_realloc_limit(*rdata,mdrcnt);
2033 if (!*rdata) {
2034 return False;
2036 p = *rdata;
2037 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
2038 if (*rdata_len < 0) {
2039 return False;
2042 *rparam_len = 6;
2043 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2044 if (!*rparam) {
2045 return False;
2047 SSVAL(*rparam,0,NERR_Success);
2048 SSVAL(*rparam,2,0); /* converter word */
2049 SSVAL(*rparam,4,*rdata_len);
2051 return True;
2054 /****************************************************************************
2055 View the list of available shares.
2057 This function is the server side of the NetShareEnum() RAP call.
2058 It fills the return buffer with share names and share comments.
2059 Note that the return buffer normally (in all known cases) allows only
2060 twelve byte strings for share names (plus one for a nul terminator).
2061 Share names longer than 12 bytes must be skipped.
2062 ****************************************************************************/
2064 static bool api_RNetShareEnum(struct smbd_server_connection *sconn,
2065 connection_struct *conn, uint64_t vuid,
2066 char *param, int tpscnt,
2067 char *data, int tdscnt,
2068 int mdrcnt,
2069 int mprcnt,
2070 char **rdata,
2071 char **rparam,
2072 int *rdata_len,
2073 int *rparam_len )
2075 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2076 char *str2 = skip_string(param,tpscnt,str1);
2077 char *p = skip_string(param,tpscnt,str2);
2078 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2079 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
2080 char *p2;
2081 int count = 0;
2082 int total=0,counted=0;
2083 bool missed = False;
2084 int i;
2085 int data_len, fixed_len, string_len;
2086 int f_len = 0, s_len = 0;
2088 if (!str1 || !str2 || !p) {
2089 return False;
2092 if (!prefix_ok(str1,"WrLeh")) {
2093 return False;
2095 if (!check_share_info(uLevel,str2)) {
2096 return False;
2099 /* Ensure all the usershares are loaded. */
2100 become_root();
2101 delete_and_reload_printers(sconn->ev_ctx, sconn->msg_ctx);
2102 load_registry_shares();
2103 count = load_usershare_shares(NULL, connections_snum_used);
2104 unbecome_root();
2106 data_len = fixed_len = string_len = 0;
2107 for (i=0;i<count;i++) {
2108 fstring servicename_dos;
2109 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2110 continue;
2112 push_ascii_fstring(servicename_dos, lp_servicename(talloc_tos(), i));
2113 /* Maximum name length = 13. */
2114 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
2115 total++;
2116 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
2117 if (data_len < buf_len) {
2118 counted++;
2119 fixed_len += f_len;
2120 string_len += s_len;
2121 } else {
2122 missed = True;
2127 *rdata_len = fixed_len + string_len;
2128 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2129 if (!*rdata) {
2130 return False;
2133 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
2134 p = *rdata;
2135 f_len = fixed_len;
2136 s_len = string_len;
2138 for( i = 0; i < count; i++ ) {
2139 fstring servicename_dos;
2140 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2141 continue;
2144 push_ascii_fstring(servicename_dos,
2145 lp_servicename(talloc_tos(), i));
2146 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2147 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2148 break;
2153 *rparam_len = 8;
2154 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2155 if (!*rparam) {
2156 return False;
2158 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2159 SSVAL(*rparam,2,0);
2160 SSVAL(*rparam,4,counted);
2161 SSVAL(*rparam,6,total);
2163 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2164 counted,total,uLevel,
2165 buf_len,*rdata_len,mdrcnt));
2167 return True;
2170 /****************************************************************************
2171 Add a share
2172 ****************************************************************************/
2174 static bool api_RNetShareAdd(struct smbd_server_connection *sconn,
2175 connection_struct *conn,uint64_t vuid,
2176 char *param, int tpscnt,
2177 char *data, int tdscnt,
2178 int mdrcnt,int mprcnt,
2179 char **rdata,char **rparam,
2180 int *rdata_len,int *rparam_len)
2182 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2183 char *str2 = skip_string(param,tpscnt,str1);
2184 char *p = skip_string(param,tpscnt,str2);
2185 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2186 fstring sharename;
2187 fstring comment;
2188 char *pathname = NULL;
2189 unsigned int offset;
2190 int res = ERRunsup;
2191 size_t converted_size;
2193 WERROR werr = WERR_OK;
2194 TALLOC_CTX *mem_ctx = talloc_tos();
2195 NTSTATUS status;
2196 struct rpc_pipe_client *cli = NULL;
2197 union srvsvc_NetShareInfo info;
2198 struct srvsvc_NetShareInfo2 info2;
2199 struct dcerpc_binding_handle *b;
2201 if (!str1 || !str2 || !p) {
2202 return False;
2205 /* check it's a supported varient */
2206 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2207 return False;
2209 if (!check_share_info(uLevel,str2)) {
2210 return False;
2212 if (uLevel != 2) {
2213 return False;
2216 /* Do we have a string ? */
2217 if (skip_string(data,mdrcnt,data) == NULL) {
2218 return False;
2220 pull_ascii_fstring(sharename,data);
2222 if (mdrcnt < 28) {
2223 return False;
2226 /* only support disk share adds */
2227 if (SVAL(data,14)!=STYPE_DISKTREE) {
2228 return False;
2231 offset = IVAL(data, 16);
2232 if (offset >= mdrcnt) {
2233 res = ERRinvalidparam;
2234 goto out;
2237 /* Do we have a string ? */
2238 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2239 return False;
2241 pull_ascii_fstring(comment, offset? (data+offset) : "");
2243 offset = IVAL(data, 26);
2245 if (offset >= mdrcnt) {
2246 res = ERRinvalidparam;
2247 goto out;
2250 /* Do we have a string ? */
2251 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2252 return False;
2255 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2256 offset ? (data+offset) : "", &converted_size))
2258 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
2259 strerror(errno)));
2262 if (!pathname) {
2263 return false;
2266 status = rpc_pipe_open_interface(mem_ctx, &ndr_table_srvsvc,
2267 conn->session_info,
2268 conn->sconn->remote_address,
2269 conn->sconn->msg_ctx,
2270 &cli);
2271 if (!NT_STATUS_IS_OK(status)) {
2272 DEBUG(0,("api_RNetShareAdd: could not connect to srvsvc: %s\n",
2273 nt_errstr(status)));
2274 res = W_ERROR_V(ntstatus_to_werror(status));
2275 goto out;
2278 b = cli->binding_handle;
2280 info2.name = sharename;
2281 info2.type = STYPE_DISKTREE;
2282 info2.comment = comment;
2283 info2.permissions = 0;
2284 info2.max_users = 0;
2285 info2.current_users = 0;
2286 info2.path = pathname;
2287 info2.password = NULL;
2289 info.info2 = &info2;
2291 status = dcerpc_srvsvc_NetShareAdd(b, mem_ctx,
2292 cli->srv_name_slash,
2294 &info,
2295 NULL,
2296 &werr);
2297 if (!NT_STATUS_IS_OK(status)) {
2298 res = W_ERROR_V(ntstatus_to_werror(status));
2299 goto out;
2301 if (!W_ERROR_IS_OK(werr)) {
2302 res = W_ERROR_V(werr);
2303 goto out;
2306 *rparam_len = 6;
2307 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2308 if (!*rparam) {
2309 return False;
2311 SSVAL(*rparam,0,NERR_Success);
2312 SSVAL(*rparam,2,0); /* converter word */
2313 SSVAL(*rparam,4,*rdata_len);
2314 *rdata_len = 0;
2316 return True;
2318 out:
2320 *rparam_len = 4;
2321 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2322 if (!*rparam) {
2323 return False;
2325 *rdata_len = 0;
2326 SSVAL(*rparam,0,res);
2327 SSVAL(*rparam,2,0);
2328 return True;
2331 /****************************************************************************
2332 view list of groups available
2333 ****************************************************************************/
2335 static bool api_RNetGroupEnum(struct smbd_server_connection *sconn,
2336 connection_struct *conn,uint64_t vuid,
2337 char *param, int tpscnt,
2338 char *data, int tdscnt,
2339 int mdrcnt,int mprcnt,
2340 char **rdata,char **rparam,
2341 int *rdata_len,int *rparam_len)
2343 int i;
2344 int errflags=0;
2345 int resume_context, cli_buf_size;
2346 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2347 char *str2 = skip_string(param,tpscnt,str1);
2348 char *p = skip_string(param,tpscnt,str2);
2350 uint32_t num_groups;
2351 uint32_t resume_handle;
2352 struct rpc_pipe_client *samr_pipe = NULL;
2353 struct policy_handle samr_handle, domain_handle;
2354 NTSTATUS status, result;
2355 struct dcerpc_binding_handle *b;
2357 if (!str1 || !str2 || !p) {
2358 return False;
2361 if (strcmp(str1,"WrLeh") != 0) {
2362 return False;
2365 /* parameters
2366 * W-> resume context (number of users to skip)
2367 * r -> return parameter pointer to receive buffer
2368 * L -> length of receive buffer
2369 * e -> return parameter number of entries
2370 * h -> return parameter total number of users
2373 if (strcmp("B21",str2) != 0) {
2374 return False;
2377 status = rpc_pipe_open_interface(
2378 talloc_tos(), &ndr_table_samr,
2379 conn->session_info, conn->sconn->remote_address,
2380 conn->sconn->msg_ctx, &samr_pipe);
2381 if (!NT_STATUS_IS_OK(status)) {
2382 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2383 nt_errstr(status)));
2384 return false;
2387 b = samr_pipe->binding_handle;
2389 status = dcerpc_samr_Connect2(b, talloc_tos(), lp_netbios_name(),
2390 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle,
2391 &result);
2392 if (!NT_STATUS_IS_OK(status)) {
2393 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2394 nt_errstr(status)));
2395 return false;
2397 if (!NT_STATUS_IS_OK(result)) {
2398 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2399 nt_errstr(result)));
2400 return false;
2403 status = dcerpc_samr_OpenDomain(b, talloc_tos(), &samr_handle,
2404 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2405 get_global_sam_sid(), &domain_handle,
2406 &result);
2407 if (!NT_STATUS_IS_OK(status)) {
2408 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2409 nt_errstr(status)));
2410 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2411 return false;
2413 if (!NT_STATUS_IS_OK(result)) {
2414 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2415 nt_errstr(result)));
2416 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2417 return false;
2420 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2421 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2422 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2423 "%d\n", resume_context, cli_buf_size));
2425 *rdata_len = cli_buf_size;
2426 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2427 if (!*rdata) {
2428 return False;
2431 p = *rdata;
2433 errflags = NERR_Success;
2434 num_groups = 0;
2435 resume_handle = 0;
2437 while (true) {
2438 struct samr_SamArray *sam_entries;
2439 uint32_t num_entries;
2441 status = dcerpc_samr_EnumDomainGroups(b, talloc_tos(),
2442 &domain_handle,
2443 &resume_handle,
2444 &sam_entries, 1,
2445 &num_entries,
2446 &result);
2447 if (!NT_STATUS_IS_OK(status)) {
2448 DEBUG(10, ("dcerpc_samr_EnumDomainGroups returned "
2449 "%s\n", nt_errstr(status)));
2450 break;
2452 if (!NT_STATUS_IS_OK(result)) {
2453 status = result;
2454 DEBUG(10, ("dcerpc_samr_EnumDomainGroups returned "
2455 "%s\n", nt_errstr(result)));
2456 break;
2459 if (num_entries == 0) {
2460 DEBUG(10, ("dcerpc_samr_EnumDomainGroups returned "
2461 "no entries -- done\n"));
2462 break;
2465 for(i=0; i<num_entries; i++) {
2466 const char *name;
2468 name = sam_entries->entries[i].name.string;
2470 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2471 /* set overflow error */
2472 DEBUG(3,("overflow on entry %d group %s\n", i,
2473 name));
2474 errflags=234;
2475 break;
2478 /* truncate the name at 21 chars. */
2479 memset(p, 0, 21);
2480 strlcpy(p, name, 21);
2481 DEBUG(10,("adding entry %d group %s\n", i, p));
2482 p += 21;
2483 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2484 * idea why... */
2485 num_groups += 1;
2488 if (errflags != NERR_Success) {
2489 break;
2492 TALLOC_FREE(sam_entries);
2495 dcerpc_samr_Close(b, talloc_tos(), &domain_handle, &result);
2496 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2498 *rdata_len = PTR_DIFF(p,*rdata);
2500 *rparam_len = 8;
2501 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2502 if (!*rparam) {
2503 return False;
2505 SSVAL(*rparam, 0, errflags);
2506 SSVAL(*rparam, 2, 0); /* converter word */
2507 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2508 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2510 return(True);
2513 /*******************************************************************
2514 Get groups that a user is a member of.
2515 ******************************************************************/
2517 static bool api_NetUserGetGroups(struct smbd_server_connection *sconn,
2518 connection_struct *conn,uint64_t vuid,
2519 char *param, int tpscnt,
2520 char *data, int tdscnt,
2521 int mdrcnt,int mprcnt,
2522 char **rdata,char **rparam,
2523 int *rdata_len,int *rparam_len)
2525 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2526 char *str2 = skip_string(param,tpscnt,str1);
2527 char *UserName = skip_string(param,tpscnt,str2);
2528 char *p = skip_string(param,tpscnt,UserName);
2529 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2530 const char *level_string;
2531 int count=0;
2532 bool ret = False;
2533 uint32_t i;
2534 char *endp = NULL;
2536 struct rpc_pipe_client *samr_pipe = NULL;
2537 struct policy_handle samr_handle, domain_handle, user_handle;
2538 struct lsa_String name;
2539 struct lsa_Strings names;
2540 struct samr_Ids type, rid;
2541 struct samr_RidWithAttributeArray *rids;
2542 NTSTATUS status, result;
2543 struct dcerpc_binding_handle *b;
2545 if (!str1 || !str2 || !UserName || !p) {
2546 return False;
2549 *rparam_len = 8;
2550 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2551 if (!*rparam) {
2552 return False;
2555 /* check it's a supported varient */
2557 if ( strcmp(str1,"zWrLeh") != 0 )
2558 return False;
2560 switch( uLevel ) {
2561 case 0:
2562 level_string = "B21";
2563 break;
2564 default:
2565 return False;
2568 if (strcmp(level_string,str2) != 0)
2569 return False;
2571 *rdata_len = mdrcnt + 1024;
2572 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2573 if (!*rdata) {
2574 return False;
2577 SSVAL(*rparam,0,NERR_Success);
2578 SSVAL(*rparam,2,0); /* converter word */
2580 p = *rdata;
2581 endp = *rdata + *rdata_len;
2583 status = rpc_pipe_open_interface(
2584 talloc_tos(), &ndr_table_samr,
2585 conn->session_info, conn->sconn->remote_address,
2586 conn->sconn->msg_ctx, &samr_pipe);
2587 if (!NT_STATUS_IS_OK(status)) {
2588 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2589 nt_errstr(status)));
2590 return false;
2593 b = samr_pipe->binding_handle;
2595 status = dcerpc_samr_Connect2(b, talloc_tos(), lp_netbios_name(),
2596 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle,
2597 &result);
2598 if (!NT_STATUS_IS_OK(status)) {
2599 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2600 nt_errstr(status)));
2601 return false;
2603 if (!NT_STATUS_IS_OK(result)) {
2604 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2605 nt_errstr(result)));
2606 return false;
2609 status = dcerpc_samr_OpenDomain(b, talloc_tos(), &samr_handle,
2610 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2611 get_global_sam_sid(), &domain_handle,
2612 &result);
2613 if (!NT_STATUS_IS_OK(status)) {
2614 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2615 nt_errstr(status)));
2616 goto close_sam;
2618 if (!NT_STATUS_IS_OK(result)) {
2619 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2620 nt_errstr(result)));
2621 goto close_sam;
2624 name.string = UserName;
2626 status = dcerpc_samr_LookupNames(b, talloc_tos(),
2627 &domain_handle, 1, &name,
2628 &rid, &type,
2629 &result);
2630 if (!NT_STATUS_IS_OK(status)) {
2631 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2632 nt_errstr(status)));
2633 goto close_domain;
2635 if (!NT_STATUS_IS_OK(result)) {
2636 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2637 nt_errstr(result)));
2638 goto close_domain;
2640 if (rid.count != 1) {
2641 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2642 goto close_domain;
2644 if (type.count != 1) {
2645 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2646 goto close_domain;
2649 if (type.ids[0] != SID_NAME_USER) {
2650 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2651 sid_type_lookup(type.ids[0])));
2652 goto close_domain;
2655 status = dcerpc_samr_OpenUser(b, talloc_tos(),
2656 &domain_handle,
2657 SAMR_USER_ACCESS_GET_GROUPS,
2658 rid.ids[0], &user_handle,
2659 &result);
2660 if (!NT_STATUS_IS_OK(status)) {
2661 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2662 nt_errstr(status)));
2663 goto close_domain;
2665 if (!NT_STATUS_IS_OK(result)) {
2666 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2667 nt_errstr(result)));
2668 goto close_domain;
2671 status = dcerpc_samr_GetGroupsForUser(b, talloc_tos(),
2672 &user_handle, &rids,
2673 &result);
2674 if (!NT_STATUS_IS_OK(status)) {
2675 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2676 nt_errstr(status)));
2677 goto close_user;
2679 if (!NT_STATUS_IS_OK(result)) {
2680 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2681 nt_errstr(result)));
2682 goto close_user;
2685 for (i=0; i<rids->count; i++) {
2687 status = dcerpc_samr_LookupRids(b, talloc_tos(),
2688 &domain_handle,
2689 1, &rids->rids[i].rid,
2690 &names, &type,
2691 &result);
2692 if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result) && (names.count == 1)) {
2693 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2694 p += 21;
2695 count++;
2699 *rdata_len = PTR_DIFF(p,*rdata);
2701 SSVAL(*rparam,4,count); /* is this right?? */
2702 SSVAL(*rparam,6,count); /* is this right?? */
2704 ret = True;
2706 close_user:
2707 dcerpc_samr_Close(b, talloc_tos(), &user_handle, &result);
2708 close_domain:
2709 dcerpc_samr_Close(b, talloc_tos(), &domain_handle, &result);
2710 close_sam:
2711 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2713 return ret;
2716 /*******************************************************************
2717 Get all users.
2718 ******************************************************************/
2720 static bool api_RNetUserEnum(struct smbd_server_connection *sconn,
2721 connection_struct *conn, uint64_t vuid,
2722 char *param, int tpscnt,
2723 char *data, int tdscnt,
2724 int mdrcnt,int mprcnt,
2725 char **rdata,char **rparam,
2726 int *rdata_len,int *rparam_len)
2728 int count_sent=0;
2729 int num_users=0;
2730 int errflags=0;
2731 int i, resume_context, cli_buf_size;
2732 uint32_t resume_handle;
2734 struct rpc_pipe_client *samr_pipe = NULL;
2735 struct policy_handle samr_handle, domain_handle;
2736 NTSTATUS status, result;
2738 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2739 char *str2 = skip_string(param,tpscnt,str1);
2740 char *p = skip_string(param,tpscnt,str2);
2741 char *endp = NULL;
2743 struct dcerpc_binding_handle *b;
2745 if (!str1 || !str2 || !p) {
2746 return False;
2749 if (strcmp(str1,"WrLeh") != 0)
2750 return False;
2751 /* parameters
2752 * W-> resume context (number of users to skip)
2753 * r -> return parameter pointer to receive buffer
2754 * L -> length of receive buffer
2755 * e -> return parameter number of entries
2756 * h -> return parameter total number of users
2759 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2760 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2761 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2762 resume_context, cli_buf_size));
2764 *rparam_len = 8;
2765 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2766 if (!*rparam) {
2767 return False;
2770 /* check it's a supported varient */
2771 if (strcmp("B21",str2) != 0)
2772 return False;
2774 *rdata_len = cli_buf_size;
2775 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2776 if (!*rdata) {
2777 return False;
2780 p = *rdata;
2781 endp = *rdata + *rdata_len;
2783 status = rpc_pipe_open_interface(
2784 talloc_tos(), &ndr_table_samr,
2785 conn->session_info, conn->sconn->remote_address,
2786 conn->sconn->msg_ctx, &samr_pipe);
2787 if (!NT_STATUS_IS_OK(status)) {
2788 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2789 nt_errstr(status)));
2790 return false;
2793 b = samr_pipe->binding_handle;
2795 status = dcerpc_samr_Connect2(b, talloc_tos(), lp_netbios_name(),
2796 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle,
2797 &result);
2798 if (!NT_STATUS_IS_OK(status)) {
2799 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2800 nt_errstr(status)));
2801 return false;
2803 if (!NT_STATUS_IS_OK(result)) {
2804 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2805 nt_errstr(result)));
2806 return false;
2809 status = dcerpc_samr_OpenDomain(b, talloc_tos(), &samr_handle,
2810 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2811 get_global_sam_sid(), &domain_handle,
2812 &result);
2813 if (!NT_STATUS_IS_OK(status)) {
2814 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2815 nt_errstr(status)));
2816 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2817 return false;
2819 if (!NT_STATUS_IS_OK(result)) {
2820 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2821 nt_errstr(result)));
2822 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2823 return false;
2826 errflags=NERR_Success;
2828 resume_handle = 0;
2830 while (true) {
2831 struct samr_SamArray *sam_entries;
2832 uint32_t num_entries;
2834 status = dcerpc_samr_EnumDomainUsers(b, talloc_tos(),
2835 &domain_handle,
2836 &resume_handle,
2837 0, &sam_entries, 1,
2838 &num_entries,
2839 &result);
2841 if (!NT_STATUS_IS_OK(status)) {
2842 DEBUG(10, ("dcerpc_samr_EnumDomainUsers returned "
2843 "%s\n", nt_errstr(status)));
2844 break;
2846 if (!NT_STATUS_IS_OK(result)) {
2847 DEBUG(10, ("dcerpc_samr_EnumDomainUsers returned "
2848 "%s\n", nt_errstr(result)));
2849 break;
2852 if (num_entries == 0) {
2853 DEBUG(10, ("dcerpc_samr_EnumDomainUsers returned "
2854 "no entries -- done\n"));
2855 break;
2858 for (i=0; i<num_entries; i++) {
2859 const char *name;
2861 name = sam_entries->entries[i].name.string;
2863 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2864 &&(strlen(name)<=21)) {
2865 strlcpy(p,name,PTR_DIFF(endp,p));
2866 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2867 "username %s\n",count_sent,p));
2868 p += 21;
2869 count_sent++;
2870 } else {
2871 /* set overflow error */
2872 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2873 "username %s\n",count_sent,name));
2874 errflags=234;
2875 break;
2879 if (errflags != NERR_Success) {
2880 break;
2883 TALLOC_FREE(sam_entries);
2886 dcerpc_samr_Close(b, talloc_tos(), &domain_handle, &result);
2887 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2889 *rdata_len = PTR_DIFF(p,*rdata);
2891 SSVAL(*rparam,0,errflags);
2892 SSVAL(*rparam,2,0); /* converter word */
2893 SSVAL(*rparam,4,count_sent); /* is this right?? */
2894 SSVAL(*rparam,6,num_users); /* is this right?? */
2896 return True;
2899 /****************************************************************************
2900 Get the time of day info.
2901 ****************************************************************************/
2903 static bool api_NetRemoteTOD(struct smbd_server_connection *sconn,
2904 connection_struct *conn,uint64_t vuid,
2905 char *param, int tpscnt,
2906 char *data, int tdscnt,
2907 int mdrcnt,int mprcnt,
2908 char **rdata,char **rparam,
2909 int *rdata_len,int *rparam_len)
2911 struct tm *t;
2912 time_t unixdate = time(NULL);
2913 char *p;
2915 *rparam_len = 4;
2916 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2917 if (!*rparam) {
2918 return False;
2921 *rdata_len = 21;
2922 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2923 if (!*rdata) {
2924 return False;
2927 SSVAL(*rparam,0,NERR_Success);
2928 SSVAL(*rparam,2,0); /* converter word */
2930 p = *rdata;
2932 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2933 by NT in a "net time" operation,
2934 it seems to ignore the one below */
2936 /* the client expects to get localtime, not GMT, in this bit
2937 (I think, this needs testing) */
2938 t = localtime(&unixdate);
2939 if (!t) {
2940 return False;
2943 SIVAL(p,4,0); /* msecs ? */
2944 SCVAL(p,8,t->tm_hour);
2945 SCVAL(p,9,t->tm_min);
2946 SCVAL(p,10,t->tm_sec);
2947 SCVAL(p,11,0); /* hundredths of seconds */
2948 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2949 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2950 SCVAL(p,16,t->tm_mday);
2951 SCVAL(p,17,t->tm_mon + 1);
2952 SSVAL(p,18,1900+t->tm_year);
2953 SCVAL(p,20,t->tm_wday);
2955 return True;
2958 /****************************************************************************
2959 Set the user password (SamOEM version - gets plaintext).
2960 ****************************************************************************/
2962 static bool api_SamOEMChangePassword(struct smbd_server_connection *sconn,
2963 connection_struct *conn,uint64_t vuid,
2964 char *param, int tpscnt,
2965 char *data, int tdscnt,
2966 int mdrcnt,int mprcnt,
2967 char **rdata,char **rparam,
2968 int *rdata_len,int *rparam_len)
2970 fstring user;
2971 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2973 TALLOC_CTX *mem_ctx = talloc_tos();
2974 NTSTATUS status, result;
2975 struct rpc_pipe_client *cli = NULL;
2976 struct lsa_AsciiString server, account;
2977 struct samr_CryptPassword password;
2978 struct samr_Password hash;
2979 int errcode = NERR_badpass;
2980 int bufsize;
2981 struct dcerpc_binding_handle *b;
2983 *rparam_len = 4;
2984 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2985 if (!*rparam) {
2986 return False;
2989 if (!p) {
2990 return False;
2992 *rdata_len = 0;
2994 SSVAL(*rparam,0,NERR_badpass);
2997 * Check the parameter definition is correct.
3000 /* Do we have a string ? */
3001 if (skip_string(param,tpscnt,p) == 0) {
3002 return False;
3004 if(!strequal(p, "zsT")) {
3005 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
3006 return False;
3008 p = skip_string(param, tpscnt, p);
3009 if (!p) {
3010 return False;
3013 /* Do we have a string ? */
3014 if (skip_string(param,tpscnt,p) == 0) {
3015 return False;
3017 if(!strequal(p, "B516B16")) {
3018 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
3019 return False;
3021 p = skip_string(param,tpscnt,p);
3022 if (!p) {
3023 return False;
3025 /* Do we have a string ? */
3026 if (skip_string(param,tpscnt,p) == 0) {
3027 return False;
3029 p += pull_ascii_fstring(user,p);
3031 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
3033 if (tdscnt != 532) {
3034 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3035 goto out;
3038 bufsize = get_safe_SVAL(param,tpscnt,p,0,-1);
3039 if (bufsize != 532) {
3040 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3041 goto out;
3044 memcpy(password.data, data, 516);
3045 memcpy(hash.hash, data+516, 16);
3047 status = rpc_pipe_open_interface(mem_ctx, &ndr_table_samr,
3048 conn->session_info,
3049 conn->sconn->remote_address,
3050 conn->sconn->msg_ctx,
3051 &cli);
3052 if (!NT_STATUS_IS_OK(status)) {
3053 DEBUG(0,("api_SamOEMChangePassword: could not connect to samr: %s\n",
3054 nt_errstr(status)));
3055 errcode = W_ERROR_V(ntstatus_to_werror(status));
3056 goto out;
3059 b = cli->binding_handle;
3061 init_lsa_AsciiString(&server, lp_netbios_name());
3062 init_lsa_AsciiString(&account, user);
3064 status = dcerpc_samr_OemChangePasswordUser2(b, mem_ctx,
3065 &server,
3066 &account,
3067 &password,
3068 &hash,
3069 &result);
3070 if (!NT_STATUS_IS_OK(status)) {
3071 errcode = W_ERROR_V(ntstatus_to_werror(status));
3072 goto out;
3074 if (!NT_STATUS_IS_OK(result)) {
3075 errcode = W_ERROR_V(ntstatus_to_werror(result));
3076 goto out;
3079 errcode = NERR_Success;
3080 out:
3081 SSVAL(*rparam,0,errcode);
3082 SSVAL(*rparam,2,0); /* converter word */
3084 return(True);
3087 /****************************************************************************
3088 delete a print job
3089 Form: <W> <>
3090 ****************************************************************************/
3092 static bool api_RDosPrintJobDel(struct smbd_server_connection *sconn,
3093 connection_struct *conn,uint64_t vuid,
3094 char *param, int tpscnt,
3095 char *data, int tdscnt,
3096 int mdrcnt,int mprcnt,
3097 char **rdata,char **rparam,
3098 int *rdata_len,int *rparam_len)
3100 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3101 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3102 char *str2 = skip_string(param,tpscnt,str1);
3103 char *p = skip_string(param,tpscnt,str2);
3104 uint32_t jobid;
3105 fstring sharename;
3106 int errcode;
3107 WERROR werr = WERR_OK;
3109 TALLOC_CTX *mem_ctx = talloc_tos();
3110 NTSTATUS status;
3111 struct rpc_pipe_client *cli = NULL;
3112 struct dcerpc_binding_handle *b = NULL;
3113 struct policy_handle handle;
3114 struct spoolss_DevmodeContainer devmode_ctr;
3115 enum spoolss_JobControl command;
3117 if (!str1 || !str2 || !p) {
3118 return False;
3121 * We use 1 here not 2 as we're checking
3122 * the last byte we want to access is safe.
3124 if (!is_offset_safe(param,tpscnt,p,1)) {
3125 return False;
3127 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3128 return False;
3130 /* check it's a supported varient */
3131 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
3132 return(False);
3134 *rparam_len = 4;
3135 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3136 if (!*rparam) {
3137 return False;
3139 *rdata_len = 0;
3141 ZERO_STRUCT(handle);
3143 status = rpc_pipe_open_interface(conn,
3144 &ndr_table_spoolss,
3145 conn->session_info,
3146 conn->sconn->remote_address,
3147 conn->sconn->msg_ctx,
3148 &cli);
3149 if (!NT_STATUS_IS_OK(status)) {
3150 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
3151 nt_errstr(status)));
3152 errcode = W_ERROR_V(ntstatus_to_werror(status));
3153 goto out;
3155 b = cli->binding_handle;
3157 ZERO_STRUCT(devmode_ctr);
3159 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
3160 sharename,
3161 "RAW",
3162 devmode_ctr,
3163 JOB_ACCESS_ADMINISTER,
3164 &handle,
3165 &werr);
3166 if (!NT_STATUS_IS_OK(status)) {
3167 errcode = W_ERROR_V(ntstatus_to_werror(status));
3168 goto out;
3170 if (!W_ERROR_IS_OK(werr)) {
3171 errcode = W_ERROR_V(werr);
3172 goto out;
3175 /* FIXME: formerly NERR_JobNotFound was returned if job did not exist
3176 * and NERR_DestNotFound if share did not exist */
3178 errcode = NERR_Success;
3180 switch (function) {
3181 case 81: /* delete */
3182 command = SPOOLSS_JOB_CONTROL_DELETE;
3183 break;
3184 case 82: /* pause */
3185 command = SPOOLSS_JOB_CONTROL_PAUSE;
3186 break;
3187 case 83: /* resume */
3188 command = SPOOLSS_JOB_CONTROL_RESUME;
3189 break;
3190 default:
3191 errcode = NERR_notsupported;
3192 goto out;
3195 status = dcerpc_spoolss_SetJob(b, mem_ctx,
3196 &handle,
3197 jobid,
3198 NULL, /* unique ptr ctr */
3199 command,
3200 &werr);
3201 if (!NT_STATUS_IS_OK(status)) {
3202 errcode = W_ERROR_V(ntstatus_to_werror(status));
3203 goto out;
3205 if (!W_ERROR_IS_OK(werr)) {
3206 errcode = W_ERROR_V(werr);
3207 goto out;
3210 out:
3211 if (b && is_valid_policy_hnd(&handle)) {
3212 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
3215 SSVAL(*rparam,0,errcode);
3216 SSVAL(*rparam,2,0); /* converter word */
3218 return(True);
3221 /****************************************************************************
3222 Purge a print queue - or pause or resume it.
3223 ****************************************************************************/
3225 static bool api_WPrintQueueCtrl(struct smbd_server_connection *sconn,
3226 connection_struct *conn,uint64_t vuid,
3227 char *param, int tpscnt,
3228 char *data, int tdscnt,
3229 int mdrcnt,int mprcnt,
3230 char **rdata,char **rparam,
3231 int *rdata_len,int *rparam_len)
3233 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3234 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3235 char *str2 = skip_string(param,tpscnt,str1);
3236 char *QueueName = skip_string(param,tpscnt,str2);
3237 int errcode = NERR_notsupported;
3238 WERROR werr = WERR_OK;
3239 NTSTATUS status;
3241 TALLOC_CTX *mem_ctx = talloc_tos();
3242 struct rpc_pipe_client *cli = NULL;
3243 struct dcerpc_binding_handle *b = NULL;
3244 struct policy_handle handle;
3245 struct spoolss_SetPrinterInfoCtr info_ctr;
3246 struct spoolss_DevmodeContainer devmode_ctr;
3247 struct sec_desc_buf secdesc_ctr;
3248 enum spoolss_PrinterControl command;
3250 if (!str1 || !str2 || !QueueName) {
3251 return False;
3254 /* check it's a supported varient */
3255 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3256 return(False);
3258 *rparam_len = 4;
3259 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3260 if (!*rparam) {
3261 return False;
3263 *rdata_len = 0;
3265 if (skip_string(param,tpscnt,QueueName) == NULL) {
3266 return False;
3269 ZERO_STRUCT(handle);
3271 status = rpc_pipe_open_interface(conn,
3272 &ndr_table_spoolss,
3273 conn->session_info,
3274 conn->sconn->remote_address,
3275 conn->sconn->msg_ctx,
3276 &cli);
3277 if (!NT_STATUS_IS_OK(status)) {
3278 DEBUG(0,("api_WPrintQueueCtrl: could not connect to spoolss: %s\n",
3279 nt_errstr(status)));
3280 errcode = W_ERROR_V(ntstatus_to_werror(status));
3281 goto out;
3283 b = cli->binding_handle;
3285 ZERO_STRUCT(devmode_ctr);
3287 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
3288 QueueName,
3289 NULL,
3290 devmode_ctr,
3291 PRINTER_ACCESS_ADMINISTER,
3292 &handle,
3293 &werr);
3294 if (!NT_STATUS_IS_OK(status)) {
3295 errcode = W_ERROR_V(ntstatus_to_werror(status));
3296 goto out;
3298 if (!W_ERROR_IS_OK(werr)) {
3299 errcode = W_ERROR_V(werr);
3300 goto out;
3303 switch (function) {
3304 case 74: /* Pause queue */
3305 command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3306 break;
3307 case 75: /* Resume queue */
3308 command = SPOOLSS_PRINTER_CONTROL_RESUME;
3309 break;
3310 case 103: /* Purge */
3311 command = SPOOLSS_PRINTER_CONTROL_PURGE;
3312 break;
3313 default:
3314 werr = WERR_NOT_SUPPORTED;
3315 break;
3318 if (!W_ERROR_IS_OK(werr)) {
3319 errcode = W_ERROR_V(werr);
3320 goto out;
3323 ZERO_STRUCT(info_ctr);
3324 ZERO_STRUCT(secdesc_ctr);
3326 status = dcerpc_spoolss_SetPrinter(b, mem_ctx,
3327 &handle,
3328 &info_ctr,
3329 &devmode_ctr,
3330 &secdesc_ctr,
3331 command,
3332 &werr);
3333 if (!NT_STATUS_IS_OK(status)) {
3334 errcode = W_ERROR_V(ntstatus_to_werror(status));
3335 goto out;
3337 if (!W_ERROR_IS_OK(werr)) {
3338 errcode = W_ERROR_V(werr);
3339 goto out;
3342 errcode = W_ERROR_V(werr);
3344 out:
3346 if (b && is_valid_policy_hnd(&handle)) {
3347 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
3350 SSVAL(*rparam,0,errcode);
3351 SSVAL(*rparam,2,0); /* converter word */
3353 return(True);
3356 /****************************************************************************
3357 set the property of a print job (undocumented?)
3358 ? function = 0xb -> set name of print job
3359 ? function = 0x6 -> move print job up/down
3360 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3361 or <WWsTP> <WB21BB16B10zWWzDDz>
3362 ****************************************************************************/
3364 static int check_printjob_info(struct pack_desc* desc,
3365 int uLevel, char* id)
3367 desc->subformat = NULL;
3368 switch( uLevel ) {
3369 case 0: desc->format = "W"; break;
3370 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3371 case 2: desc->format = "WWzWWDDzz"; break;
3372 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3373 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3374 default:
3375 DEBUG(0,("check_printjob_info: invalid level %d\n",
3376 uLevel ));
3377 return False;
3379 if (id == NULL || strcmp(desc->format,id) != 0) {
3380 DEBUG(0,("check_printjob_info: invalid format %s\n",
3381 id ? id : "<NULL>" ));
3382 return False;
3384 return True;
3387 static bool api_PrintJobInfo(struct smbd_server_connection *sconn,
3388 connection_struct *conn, uint64_t vuid,
3389 char *param, int tpscnt,
3390 char *data, int tdscnt,
3391 int mdrcnt,int mprcnt,
3392 char **rdata,char **rparam,
3393 int *rdata_len,int *rparam_len)
3395 struct pack_desc desc;
3396 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3397 char *str2 = skip_string(param,tpscnt,str1);
3398 char *p = skip_string(param,tpscnt,str2);
3399 uint32_t jobid;
3400 fstring sharename;
3401 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3402 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3403 int errcode;
3405 TALLOC_CTX *mem_ctx = talloc_tos();
3406 WERROR werr;
3407 NTSTATUS status;
3408 struct rpc_pipe_client *cli = NULL;
3409 struct dcerpc_binding_handle *b = NULL;
3410 struct policy_handle handle;
3411 struct spoolss_DevmodeContainer devmode_ctr;
3412 struct spoolss_JobInfoContainer ctr;
3413 union spoolss_JobInfo info;
3414 struct spoolss_SetJobInfo1 info1;
3416 if (!str1 || !str2 || !p) {
3417 return False;
3420 * We use 1 here not 2 as we're checking
3421 * the last byte we want to access is safe.
3423 if (!is_offset_safe(param,tpscnt,p,1)) {
3424 return False;
3426 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3427 return False;
3428 *rparam_len = 4;
3429 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3430 if (!*rparam) {
3431 return False;
3434 *rdata_len = 0;
3436 /* check it's a supported varient */
3437 if ((strcmp(str1,"WWsTP")) ||
3438 (!check_printjob_info(&desc,uLevel,str2)))
3439 return(False);
3441 errcode = NERR_notsupported;
3443 switch (function) {
3444 case 0xb:
3445 /* change print job name, data gives the name */
3446 break;
3447 default:
3448 goto out;
3451 ZERO_STRUCT(handle);
3453 status = rpc_pipe_open_interface(conn,
3454 &ndr_table_spoolss,
3455 conn->session_info,
3456 conn->sconn->remote_address,
3457 conn->sconn->msg_ctx,
3458 &cli);
3459 if (!NT_STATUS_IS_OK(status)) {
3460 DEBUG(0,("api_PrintJobInfo: could not connect to spoolss: %s\n",
3461 nt_errstr(status)));
3462 errcode = W_ERROR_V(ntstatus_to_werror(status));
3463 goto out;
3465 b = cli->binding_handle;
3467 ZERO_STRUCT(devmode_ctr);
3469 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
3470 sharename,
3471 "RAW",
3472 devmode_ctr,
3473 PRINTER_ACCESS_USE,
3474 &handle,
3475 &werr);
3476 if (!NT_STATUS_IS_OK(status)) {
3477 errcode = W_ERROR_V(ntstatus_to_werror(status));
3478 goto out;
3480 if (!W_ERROR_IS_OK(werr)) {
3481 errcode = W_ERROR_V(werr);
3482 goto out;
3485 werr = rpccli_spoolss_getjob(cli, mem_ctx,
3486 &handle,
3487 jobid,
3488 1, /* level */
3489 0, /* offered */
3490 &info);
3491 if (!W_ERROR_IS_OK(werr)) {
3492 errcode = W_ERROR_V(werr);
3493 goto out;
3496 ZERO_STRUCT(ctr);
3498 info1.job_id = info.info1.job_id;
3499 info1.printer_name = info.info1.printer_name;
3500 info1.user_name = info.info1.user_name;
3501 info1.document_name = data;
3502 info1.data_type = info.info1.data_type;
3503 info1.text_status = info.info1.text_status;
3504 info1.status = info.info1.status;
3505 info1.priority = info.info1.priority;
3506 info1.position = info.info1.position;
3507 info1.total_pages = info.info1.total_pages;
3508 info1.pages_printed = info.info1.pages_printed;
3509 info1.submitted = info.info1.submitted;
3511 ctr.level = 1;
3512 ctr.info.info1 = &info1;
3514 status = dcerpc_spoolss_SetJob(b, mem_ctx,
3515 &handle,
3516 jobid,
3517 &ctr,
3519 &werr);
3520 if (!NT_STATUS_IS_OK(status)) {
3521 errcode = W_ERROR_V(ntstatus_to_werror(status));
3522 goto out;
3524 if (!W_ERROR_IS_OK(werr)) {
3525 errcode = W_ERROR_V(werr);
3526 goto out;
3529 errcode = NERR_Success;
3530 out:
3532 if (b && is_valid_policy_hnd(&handle)) {
3533 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
3536 SSVALS(*rparam,0,errcode);
3537 SSVAL(*rparam,2,0); /* converter word */
3539 return(True);
3543 /****************************************************************************
3544 Get info about the server.
3545 ****************************************************************************/
3547 static bool api_RNetServerGetInfo(struct smbd_server_connection *sconn,
3548 connection_struct *conn,uint64_t vuid,
3549 char *param, int tpscnt,
3550 char *data, int tdscnt,
3551 int mdrcnt,int mprcnt,
3552 char **rdata,char **rparam,
3553 int *rdata_len,int *rparam_len)
3555 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3556 char *str2 = skip_string(param,tpscnt,str1);
3557 char *p = skip_string(param,tpscnt,str2);
3558 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3559 char *p2;
3560 int struct_len;
3562 NTSTATUS status;
3563 WERROR werr;
3564 TALLOC_CTX *mem_ctx = talloc_tos();
3565 struct rpc_pipe_client *cli = NULL;
3566 union srvsvc_NetSrvInfo info;
3567 int errcode;
3568 struct dcerpc_binding_handle *b;
3570 if (!str1 || !str2 || !p) {
3571 return False;
3574 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3576 /* check it's a supported varient */
3577 if (!prefix_ok(str1,"WrLh")) {
3578 return False;
3581 switch( uLevel ) {
3582 case 0:
3583 if (strcmp(str2,"B16") != 0) {
3584 return False;
3586 struct_len = 16;
3587 break;
3588 case 1:
3589 if (strcmp(str2,"B16BBDz") != 0) {
3590 return False;
3592 struct_len = 26;
3593 break;
3594 case 2:
3595 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3596 return False;
3598 struct_len = 134;
3599 break;
3600 case 3:
3601 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3602 return False;
3604 struct_len = 144;
3605 break;
3606 case 20:
3607 if (strcmp(str2,"DN") != 0) {
3608 return False;
3610 struct_len = 6;
3611 break;
3612 case 50:
3613 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3614 return False;
3616 struct_len = 42;
3617 break;
3618 default:
3619 return False;
3622 *rdata_len = mdrcnt;
3623 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3624 if (!*rdata) {
3625 return False;
3628 p = *rdata;
3629 p2 = p + struct_len;
3631 status = rpc_pipe_open_interface(mem_ctx, &ndr_table_srvsvc,
3632 conn->session_info,
3633 conn->sconn->remote_address,
3634 conn->sconn->msg_ctx,
3635 &cli);
3636 if (!NT_STATUS_IS_OK(status)) {
3637 DEBUG(0,("api_RNetServerGetInfo: could not connect to srvsvc: %s\n",
3638 nt_errstr(status)));
3639 errcode = W_ERROR_V(ntstatus_to_werror(status));
3640 goto out;
3643 b = cli->binding_handle;
3645 status = dcerpc_srvsvc_NetSrvGetInfo(b, mem_ctx,
3646 NULL,
3647 101,
3648 &info,
3649 &werr);
3650 if (!NT_STATUS_IS_OK(status)) {
3651 errcode = W_ERROR_V(ntstatus_to_werror(status));
3652 goto out;
3654 if (!W_ERROR_IS_OK(werr)) {
3655 errcode = W_ERROR_V(werr);
3656 goto out;
3659 if (info.info101 == NULL) {
3660 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3661 goto out;
3664 if (uLevel != 20) {
3665 size_t len = 0;
3666 status = srvstr_push(NULL, 0, p, info.info101->server_name, 16,
3667 STR_ASCII|STR_UPPER|STR_TERMINATE, &len);
3668 if (!NT_STATUS_IS_OK(status)) {
3669 errcode = W_ERROR_V(ntstatus_to_werror(status));
3670 goto out;
3673 p += 16;
3674 if (uLevel > 0) {
3675 SCVAL(p,0,info.info101->version_major);
3676 SCVAL(p,1,info.info101->version_minor);
3677 SIVAL(p,2,info.info101->server_type);
3679 if (mdrcnt == struct_len) {
3680 SIVAL(p,6,0);
3681 } else {
3682 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3683 if (mdrcnt - struct_len <= 0) {
3684 return false;
3686 push_ascii(p2,
3687 info.info101->comment,
3688 MIN(mdrcnt - struct_len,
3689 MAX_SERVER_STRING_LENGTH),
3690 STR_TERMINATE);
3691 p2 = skip_string(*rdata,*rdata_len,p2);
3692 if (!p2) {
3693 return False;
3698 if (uLevel > 1) {
3699 return False; /* not yet implemented */
3702 errcode = NERR_Success;
3704 out:
3706 *rdata_len = PTR_DIFF(p2,*rdata);
3708 *rparam_len = 6;
3709 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3710 if (!*rparam) {
3711 return False;
3713 SSVAL(*rparam,0,errcode);
3714 SSVAL(*rparam,2,0); /* converter word */
3715 SSVAL(*rparam,4,*rdata_len);
3717 return True;
3720 /****************************************************************************
3721 Get info about the server.
3722 ****************************************************************************/
3724 static bool api_NetWkstaGetInfo(struct smbd_server_connection *sconn,
3725 connection_struct *conn,uint64_t vuid,
3726 char *param, int tpscnt,
3727 char *data, int tdscnt,
3728 int mdrcnt,int mprcnt,
3729 char **rdata,char **rparam,
3730 int *rdata_len,int *rparam_len)
3732 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3733 char *str2 = skip_string(param,tpscnt,str1);
3734 char *p = skip_string(param,tpscnt,str2);
3735 char *p2;
3736 char *endp;
3737 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3739 if (!str1 || !str2 || !p) {
3740 return False;
3743 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3745 *rparam_len = 6;
3746 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3747 if (!*rparam) {
3748 return False;
3751 /* check it's a supported varient */
3752 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3753 return False;
3756 *rdata_len = mdrcnt + 1024;
3757 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3758 if (!*rdata) {
3759 return False;
3762 SSVAL(*rparam,0,NERR_Success);
3763 SSVAL(*rparam,2,0); /* converter word */
3765 p = *rdata;
3766 endp = *rdata + *rdata_len;
3768 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3769 if (!p2) {
3770 return False;
3773 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3774 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3775 if (!strupper_m(p2)) {
3776 return false;
3778 p2 = skip_string(*rdata,*rdata_len,p2);
3779 if (!p2) {
3780 return False;
3782 p += 4;
3784 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3785 strlcpy(p2,conn->session_info->unix_info->sanitized_username,PTR_DIFF(endp,p2));
3786 p2 = skip_string(*rdata,*rdata_len,p2);
3787 if (!p2) {
3788 return False;
3790 p += 4;
3792 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3793 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3794 if (!strupper_m(p2)) {
3795 return false;
3797 p2 = skip_string(*rdata,*rdata_len,p2);
3798 if (!p2) {
3799 return False;
3801 p += 4;
3803 SCVAL(p,0,SAMBA_MAJOR_NBT_ANNOUNCE_VERSION); /* system version - e.g 4 in 4.1 */
3804 SCVAL(p,1,SAMBA_MINOR_NBT_ANNOUNCE_VERSION); /* system version - e.g .1 in 4.1 */
3805 p += 2;
3807 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3808 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3809 p2 = skip_string(*rdata,*rdata_len,p2);
3810 if (!p2) {
3811 return False;
3813 p += 4;
3815 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3816 strlcpy(p2,"",PTR_DIFF(endp,p2));
3817 p2 = skip_string(*rdata,*rdata_len,p2);
3818 if (!p2) {
3819 return False;
3821 p += 4;
3823 *rdata_len = PTR_DIFF(p2,*rdata);
3825 SSVAL(*rparam,4,*rdata_len);
3827 return True;
3830 /****************************************************************************
3831 get info about a user
3833 struct user_info_11 {
3834 char usri11_name[21]; 0-20
3835 char usri11_pad; 21
3836 char *usri11_comment; 22-25
3837 char *usri11_usr_comment; 26-29
3838 unsigned short usri11_priv; 30-31
3839 unsigned long usri11_auth_flags; 32-35
3840 long usri11_password_age; 36-39
3841 char *usri11_homedir; 40-43
3842 char *usri11_parms; 44-47
3843 long usri11_last_logon; 48-51
3844 long usri11_last_logoff; 52-55
3845 unsigned short usri11_bad_pw_count; 56-57
3846 unsigned short usri11_num_logons; 58-59
3847 char *usri11_logon_server; 60-63
3848 unsigned short usri11_country_code; 64-65
3849 char *usri11_workstations; 66-69
3850 unsigned long usri11_max_storage; 70-73
3851 unsigned short usri11_units_per_week; 74-75
3852 unsigned char *usri11_logon_hours; 76-79
3853 unsigned short usri11_code_page; 80-81
3856 where:
3858 usri11_name specifies the user name for which information is retrieved
3860 usri11_pad aligns the next data structure element to a word boundary
3862 usri11_comment is a null terminated ASCII comment
3864 usri11_user_comment is a null terminated ASCII comment about the user
3866 usri11_priv specifies the level of the privilege assigned to the user.
3867 The possible values are:
3869 Name Value Description
3870 USER_PRIV_GUEST 0 Guest privilege
3871 USER_PRIV_USER 1 User privilege
3872 USER_PRV_ADMIN 2 Administrator privilege
3874 usri11_auth_flags specifies the account operator privileges. The
3875 possible values are:
3877 Name Value Description
3878 AF_OP_PRINT 0 Print operator
3881 Leach, Naik [Page 28]
3885 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3888 AF_OP_COMM 1 Communications operator
3889 AF_OP_SERVER 2 Server operator
3890 AF_OP_ACCOUNTS 3 Accounts operator
3893 usri11_password_age specifies how many seconds have elapsed since the
3894 password was last changed.
3896 usri11_home_dir points to a null terminated ASCII string that contains
3897 the path name of the user's home directory.
3899 usri11_parms points to a null terminated ASCII string that is set
3900 aside for use by applications.
3902 usri11_last_logon specifies the time when the user last logged on.
3903 This value is stored as the number of seconds elapsed since
3904 00:00:00, January 1, 1970.
3906 usri11_last_logoff specifies the time when the user last logged off.
3907 This value is stored as the number of seconds elapsed since
3908 00:00:00, January 1, 1970. A value of 0 means the last logoff
3909 time is unknown.
3911 usri11_bad_pw_count specifies the number of incorrect passwords
3912 entered since the last successful logon.
3914 usri11_log1_num_logons specifies the number of times this user has
3915 logged on. A value of -1 means the number of logons is unknown.
3917 usri11_logon_server points to a null terminated ASCII string that
3918 contains the name of the server to which logon requests are sent.
3919 A null string indicates logon requests should be sent to the
3920 domain controller.
3922 usri11_country_code specifies the country code for the user's language
3923 of choice.
3925 usri11_workstations points to a null terminated ASCII string that
3926 contains the names of workstations the user may log on from.
3927 There may be up to 8 workstations, with the names separated by
3928 commas. A null strings indicates there are no restrictions.
3930 usri11_max_storage specifies the maximum amount of disk space the user
3931 can occupy. A value of 0xffffffff indicates there are no
3932 restrictions.
3934 usri11_units_per_week specifies the equal number of time units into
3935 which a week is divided. This value must be equal to 168.
3937 usri11_logon_hours points to a 21 byte (168 bits) string that
3938 specifies the time during which the user can log on. Each bit
3939 represents one unique hour in a week. The first bit (bit 0, word
3940 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3944 Leach, Naik [Page 29]
3948 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3951 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3952 are no restrictions.
3954 usri11_code_page specifies the code page for the user's language of
3955 choice
3957 All of the pointers in this data structure need to be treated
3958 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3959 to be ignored. The converter word returned in the parameters section
3960 needs to be subtracted from the lower 16 bits to calculate an offset
3961 into the return buffer where this ASCII string resides.
3963 There is no auxiliary data in the response.
3965 ****************************************************************************/
3967 #define usri11_name 0
3968 #define usri11_pad 21
3969 #define usri11_comment 22
3970 #define usri11_usr_comment 26
3971 #define usri11_full_name 30
3972 #define usri11_priv 34
3973 #define usri11_auth_flags 36
3974 #define usri11_password_age 40
3975 #define usri11_homedir 44
3976 #define usri11_parms 48
3977 #define usri11_last_logon 52
3978 #define usri11_last_logoff 56
3979 #define usri11_bad_pw_count 60
3980 #define usri11_num_logons 62
3981 #define usri11_logon_server 64
3982 #define usri11_country_code 68
3983 #define usri11_workstations 70
3984 #define usri11_max_storage 74
3985 #define usri11_units_per_week 78
3986 #define usri11_logon_hours 80
3987 #define usri11_code_page 84
3988 #define usri11_end 86
3990 static bool api_RNetUserGetInfo(struct smbd_server_connection *sconn,
3991 connection_struct *conn, uint64_t vuid,
3992 char *param, int tpscnt,
3993 char *data, int tdscnt,
3994 int mdrcnt,int mprcnt,
3995 char **rdata,char **rparam,
3996 int *rdata_len,int *rparam_len)
3998 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3999 char *str2 = skip_string(param,tpscnt,str1);
4000 char *UserName = skip_string(param,tpscnt,str2);
4001 char *p = skip_string(param,tpscnt,UserName);
4002 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4003 char *p2;
4004 char *endp;
4005 const char *level_string;
4007 TALLOC_CTX *mem_ctx = talloc_tos();
4008 NTSTATUS status, result;
4009 struct rpc_pipe_client *cli = NULL;
4010 struct policy_handle connect_handle, domain_handle, user_handle;
4011 struct lsa_String domain_name;
4012 struct dom_sid2 *domain_sid;
4013 struct lsa_String names;
4014 struct samr_Ids rids;
4015 struct samr_Ids types;
4016 int errcode = W_ERROR_V(WERR_USER_NOT_FOUND);
4017 uint32_t rid;
4018 union samr_UserInfo *info;
4019 struct dcerpc_binding_handle *b = NULL;
4021 if (!str1 || !str2 || !UserName || !p) {
4022 return False;
4025 *rparam_len = 6;
4026 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4027 if (!*rparam) {
4028 return False;
4031 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
4033 /* check it's a supported variant */
4034 if (strcmp(str1,"zWrLh") != 0) {
4035 return False;
4037 switch( uLevel ) {
4038 case 0: level_string = "B21"; break;
4039 case 1: level_string = "B21BB16DWzzWz"; break;
4040 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
4041 case 10: level_string = "B21Bzzz"; break;
4042 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
4043 default: return False;
4046 if (strcmp(level_string,str2) != 0) {
4047 return False;
4050 *rdata_len = mdrcnt + 1024;
4051 *rdata = smb_realloc_limit(*rdata,*rdata_len);
4052 if (!*rdata) {
4053 return False;
4056 p = *rdata;
4057 endp = *rdata + *rdata_len;
4058 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
4059 if (!p2) {
4060 return False;
4063 ZERO_STRUCT(connect_handle);
4064 ZERO_STRUCT(domain_handle);
4065 ZERO_STRUCT(user_handle);
4067 status = rpc_pipe_open_interface(mem_ctx, &ndr_table_samr,
4068 conn->session_info,
4069 conn->sconn->remote_address,
4070 conn->sconn->msg_ctx,
4071 &cli);
4072 if (!NT_STATUS_IS_OK(status)) {
4073 DEBUG(0,("api_RNetUserGetInfo: could not connect to samr: %s\n",
4074 nt_errstr(status)));
4075 errcode = W_ERROR_V(ntstatus_to_werror(status));
4076 goto out;
4079 b = cli->binding_handle;
4081 status = dcerpc_samr_Connect2(b, mem_ctx,
4082 lp_netbios_name(),
4083 SAMR_ACCESS_CONNECT_TO_SERVER |
4084 SAMR_ACCESS_ENUM_DOMAINS |
4085 SAMR_ACCESS_LOOKUP_DOMAIN,
4086 &connect_handle,
4087 &result);
4088 if (!NT_STATUS_IS_OK(status)) {
4089 errcode = W_ERROR_V(ntstatus_to_werror(status));
4090 goto out;
4092 if (!NT_STATUS_IS_OK(result)) {
4093 errcode = W_ERROR_V(ntstatus_to_werror(result));
4094 goto out;
4097 init_lsa_String(&domain_name, get_global_sam_name());
4099 status = dcerpc_samr_LookupDomain(b, mem_ctx,
4100 &connect_handle,
4101 &domain_name,
4102 &domain_sid,
4103 &result);
4104 if (!NT_STATUS_IS_OK(status)) {
4105 errcode = W_ERROR_V(ntstatus_to_werror(status));
4106 goto out;
4108 if (!NT_STATUS_IS_OK(result)) {
4109 errcode = W_ERROR_V(ntstatus_to_werror(result));
4110 goto out;
4113 status = dcerpc_samr_OpenDomain(b, mem_ctx,
4114 &connect_handle,
4115 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
4116 domain_sid,
4117 &domain_handle,
4118 &result);
4119 if (!NT_STATUS_IS_OK(status)) {
4120 errcode = W_ERROR_V(ntstatus_to_werror(status));
4121 goto out;
4123 if (!NT_STATUS_IS_OK(result)) {
4124 errcode = W_ERROR_V(ntstatus_to_werror(result));
4125 goto out;
4128 init_lsa_String(&names, UserName);
4130 status = dcerpc_samr_LookupNames(b, mem_ctx,
4131 &domain_handle,
4133 &names,
4134 &rids,
4135 &types,
4136 &result);
4137 if (!NT_STATUS_IS_OK(status)) {
4138 errcode = W_ERROR_V(ntstatus_to_werror(status));
4139 goto out;
4141 if (!NT_STATUS_IS_OK(result)) {
4142 errcode = W_ERROR_V(ntstatus_to_werror(result));
4143 goto out;
4146 if (rids.count != 1) {
4147 errcode = W_ERROR_V(WERR_NO_SUCH_USER);
4148 goto out;
4150 if (rids.count != types.count) {
4151 errcode = W_ERROR_V(WERR_INVALID_PARAM);
4152 goto out;
4154 if (types.ids[0] != SID_NAME_USER) {
4155 errcode = W_ERROR_V(WERR_INVALID_PARAM);
4156 goto out;
4159 rid = rids.ids[0];
4161 status = dcerpc_samr_OpenUser(b, mem_ctx,
4162 &domain_handle,
4163 SAMR_USER_ACCESS_GET_LOCALE |
4164 SAMR_USER_ACCESS_GET_LOGONINFO |
4165 SAMR_USER_ACCESS_GET_ATTRIBUTES |
4166 SAMR_USER_ACCESS_GET_GROUPS |
4167 SAMR_USER_ACCESS_GET_GROUP_MEMBERSHIP |
4168 SEC_STD_READ_CONTROL,
4169 rid,
4170 &user_handle,
4171 &result);
4172 if (!NT_STATUS_IS_OK(status)) {
4173 errcode = W_ERROR_V(ntstatus_to_werror(status));
4174 goto out;
4176 if (!NT_STATUS_IS_OK(result)) {
4177 errcode = W_ERROR_V(ntstatus_to_werror(result));
4178 goto out;
4181 status = dcerpc_samr_QueryUserInfo2(b, mem_ctx,
4182 &user_handle,
4183 UserAllInformation,
4184 &info,
4185 &result);
4186 if (!NT_STATUS_IS_OK(status)) {
4187 errcode = W_ERROR_V(ntstatus_to_werror(status));
4188 goto out;
4190 if (!NT_STATUS_IS_OK(result)) {
4191 errcode = W_ERROR_V(ntstatus_to_werror(result));
4192 goto out;
4195 memset(p,0,21);
4196 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
4198 if (uLevel > 0) {
4199 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
4200 *p2 = 0;
4203 if (uLevel >= 10) {
4204 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
4205 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
4206 p2 = skip_string(*rdata,*rdata_len,p2);
4207 if (!p2) {
4208 return False;
4211 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
4212 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
4213 p2 = skip_string(*rdata,*rdata_len,p2);
4214 if (!p2) {
4215 return False;
4218 /* EEK! the cifsrap.txt doesn't have this in!!!! */
4219 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
4220 strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4221 p2 = skip_string(*rdata,*rdata_len,p2);
4222 if (!p2) {
4223 return False;
4227 if (uLevel == 11) {
4228 const char *homedir = info->info21.home_directory.string;
4229 /* modelled after NTAS 3.51 reply */
4230 SSVAL(p,usri11_priv,
4231 (get_current_uid(conn) == sec_initial_uid())?
4232 USER_PRIV_ADMIN:USER_PRIV_USER);
4233 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
4234 SIVALS(p,usri11_password_age,-1); /* password age */
4235 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
4236 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
4237 p2 = skip_string(*rdata,*rdata_len,p2);
4238 if (!p2) {
4239 return False;
4241 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
4242 strlcpy(p2,"",PTR_DIFF(endp,p2));
4243 p2 = skip_string(*rdata,*rdata_len,p2);
4244 if (!p2) {
4245 return False;
4247 SIVAL(p,usri11_last_logon,0); /* last logon */
4248 SIVAL(p,usri11_last_logoff,0); /* last logoff */
4249 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
4250 SSVALS(p,usri11_num_logons,-1); /* num logons */
4251 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
4252 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
4253 p2 = skip_string(*rdata,*rdata_len,p2);
4254 if (!p2) {
4255 return False;
4257 SSVAL(p,usri11_country_code,0); /* country code */
4259 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
4260 strlcpy(p2,"",PTR_DIFF(endp,p2));
4261 p2 = skip_string(*rdata,*rdata_len,p2);
4262 if (!p2) {
4263 return False;
4266 SIVALS(p,usri11_max_storage,-1); /* max storage */
4267 SSVAL(p,usri11_units_per_week,168); /* units per week */
4268 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
4270 /* a simple way to get logon hours at all times. */
4271 memset(p2,0xff,21);
4272 SCVAL(p2,21,0); /* fix zero termination */
4273 p2 = skip_string(*rdata,*rdata_len,p2);
4274 if (!p2) {
4275 return False;
4278 SSVAL(p,usri11_code_page,0); /* code page */
4281 if (uLevel == 1 || uLevel == 2) {
4282 memset(p+22,' ',16); /* password */
4283 SIVALS(p,38,-1); /* password age */
4284 SSVAL(p,42,
4285 (get_current_uid(conn) == sec_initial_uid())?
4286 USER_PRIV_ADMIN:USER_PRIV_USER);
4287 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
4288 strlcpy(p2, info->info21.home_directory.string,
4289 PTR_DIFF(endp,p2));
4290 p2 = skip_string(*rdata,*rdata_len,p2);
4291 if (!p2) {
4292 return False;
4294 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
4295 *p2++ = 0;
4296 SSVAL(p,52,0); /* flags */
4297 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
4298 strlcpy(p2, info->info21.logon_script.string,
4299 PTR_DIFF(endp,p2));
4300 p2 = skip_string(*rdata,*rdata_len,p2);
4301 if (!p2) {
4302 return False;
4304 if (uLevel == 2) {
4305 SIVAL(p,58,0); /* auth_flags */
4306 SIVAL(p,62,PTR_DIFF(p2,*rdata)); /* full_name */
4307 strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4308 p2 = skip_string(*rdata,*rdata_len,p2);
4309 if (!p2) {
4310 return False;
4312 SIVAL(p,66,0); /* urs_comment */
4313 SIVAL(p,70,PTR_DIFF(p2,*rdata)); /* parms */
4314 strlcpy(p2,"",PTR_DIFF(endp,p2));
4315 p2 = skip_string(*rdata,*rdata_len,p2);
4316 if (!p2) {
4317 return False;
4319 SIVAL(p,74,0); /* workstations */
4320 SIVAL(p,78,0); /* last_logon */
4321 SIVAL(p,82,0); /* last_logoff */
4322 SIVALS(p,86,-1); /* acct_expires */
4323 SIVALS(p,90,-1); /* max_storage */
4324 SSVAL(p,94,168); /* units_per_week */
4325 SIVAL(p,96,PTR_DIFF(p2,*rdata)); /* logon_hours */
4326 memset(p2,-1,21);
4327 p2 += 21;
4328 SSVALS(p,100,-1); /* bad_pw_count */
4329 SSVALS(p,102,-1); /* num_logons */
4330 SIVAL(p,104,PTR_DIFF(p2,*rdata)); /* logon_server */
4332 TALLOC_CTX *ctx = talloc_tos();
4333 int space_rem = *rdata_len - (p2 - *rdata);
4334 char *tmp;
4336 if (space_rem <= 0) {
4337 return false;
4339 tmp = talloc_strdup(ctx, "\\\\%L");
4340 if (!tmp) {
4341 return false;
4343 tmp = talloc_sub_basic(ctx,
4346 tmp);
4347 if (!tmp) {
4348 return false;
4351 push_ascii(p2,
4352 tmp,
4353 space_rem,
4354 STR_TERMINATE);
4356 p2 = skip_string(*rdata,*rdata_len,p2);
4357 if (!p2) {
4358 return False;
4360 SSVAL(p,108,49); /* country_code */
4361 SSVAL(p,110,860); /* code page */
4365 errcode = NERR_Success;
4367 out:
4368 *rdata_len = PTR_DIFF(p2,*rdata);
4370 if (b && is_valid_policy_hnd(&user_handle)) {
4371 dcerpc_samr_Close(b, mem_ctx, &user_handle, &result);
4373 if (b && is_valid_policy_hnd(&domain_handle)) {
4374 dcerpc_samr_Close(b, mem_ctx, &domain_handle, &result);
4376 if (b && is_valid_policy_hnd(&connect_handle)) {
4377 dcerpc_samr_Close(b, mem_ctx, &connect_handle, &result);
4380 SSVAL(*rparam,0,errcode);
4381 SSVAL(*rparam,2,0); /* converter word */
4382 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
4384 return(True);
4387 static bool api_WWkstaUserLogon(struct smbd_server_connection *sconn,
4388 connection_struct *conn,uint64_t vuid,
4389 char *param, int tpscnt,
4390 char *data, int tdscnt,
4391 int mdrcnt,int mprcnt,
4392 char **rdata,char **rparam,
4393 int *rdata_len,int *rparam_len)
4395 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4396 char *str2 = skip_string(param,tpscnt,str1);
4397 char *p = skip_string(param,tpscnt,str2);
4398 int uLevel;
4399 struct pack_desc desc;
4400 char* name;
4401 /* With share level security vuid will always be zero.
4402 Don't depend on vuser being non-null !!. JRA */
4403 struct user_struct *vuser = get_valid_user_struct(sconn, vuid);
4405 if (!str1 || !str2 || !p) {
4406 return False;
4409 if(vuser != NULL) {
4410 DEBUG(3,(" Username of UID %d is %s\n",
4411 (int)vuser->session_info->unix_token->uid,
4412 vuser->session_info->unix_info->unix_name));
4415 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4416 name = get_safe_str_ptr(param,tpscnt,p,2);
4417 if (!name) {
4418 return False;
4421 memset((char *)&desc,'\0',sizeof(desc));
4423 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
4425 /* check it's a supported varient */
4426 if (strcmp(str1,"OOWb54WrLh") != 0) {
4427 return False;
4429 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
4430 return False;
4432 if (mdrcnt > 0) {
4433 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4434 if (!*rdata) {
4435 return False;
4439 desc.base = *rdata;
4440 desc.buflen = mdrcnt;
4441 desc.subformat = NULL;
4442 desc.format = str2;
4444 if (init_package(&desc,1,0)) {
4445 PACKI(&desc,"W",0); /* code */
4446 PACKS(&desc,"B21",name); /* eff. name */
4447 PACKS(&desc,"B",""); /* pad */
4448 PACKI(&desc,"W",
4449 (get_current_uid(conn) == sec_initial_uid())?
4450 USER_PRIV_ADMIN:USER_PRIV_USER);
4451 PACKI(&desc,"D",0); /* auth flags XXX */
4452 PACKI(&desc,"W",0); /* num logons */
4453 PACKI(&desc,"W",0); /* bad pw count */
4454 PACKI(&desc,"D",0); /* last logon */
4455 PACKI(&desc,"D",-1); /* last logoff */
4456 PACKI(&desc,"D",-1); /* logoff time */
4457 PACKI(&desc,"D",-1); /* kickoff time */
4458 PACKI(&desc,"D",0); /* password age */
4459 PACKI(&desc,"D",0); /* password can change */
4460 PACKI(&desc,"D",-1); /* password must change */
4463 fstring mypath;
4464 fstrcpy(mypath,"\\\\");
4465 fstrcat(mypath,get_local_machine_name());
4466 if (!strupper_m(mypath)) {
4467 return false;
4469 PACKS(&desc,"z",mypath); /* computer */
4472 PACKS(&desc,"z",lp_workgroup());/* domain */
4473 PACKS(&desc,"z", vuser ?
4474 vuser->session_info->info->logon_script
4475 : ""); /* script path */
4476 PACKI(&desc,"D",0x00000000); /* reserved */
4479 *rdata_len = desc.usedlen;
4480 *rparam_len = 6;
4481 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4482 if (!*rparam) {
4483 return False;
4485 SSVALS(*rparam,0,desc.errcode);
4486 SSVAL(*rparam,2,0);
4487 SSVAL(*rparam,4,desc.neededlen);
4489 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4491 return True;
4494 /****************************************************************************
4495 api_WAccessGetUserPerms
4496 ****************************************************************************/
4498 static bool api_WAccessGetUserPerms(struct smbd_server_connection *sconn,
4499 connection_struct *conn,uint64_t vuid,
4500 char *param, int tpscnt,
4501 char *data, int tdscnt,
4502 int mdrcnt,int mprcnt,
4503 char **rdata,char **rparam,
4504 int *rdata_len,int *rparam_len)
4506 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4507 char *str2 = skip_string(param,tpscnt,str1);
4508 char *user = skip_string(param,tpscnt,str2);
4509 char *resource = skip_string(param,tpscnt,user);
4511 if (!str1 || !str2 || !user || !resource) {
4512 return False;
4515 if (skip_string(param,tpscnt,resource) == NULL) {
4516 return False;
4518 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4520 /* check it's a supported varient */
4521 if (strcmp(str1,"zzh") != 0) {
4522 return False;
4524 if (strcmp(str2,"") != 0) {
4525 return False;
4528 *rparam_len = 6;
4529 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4530 if (!*rparam) {
4531 return False;
4533 SSVALS(*rparam,0,0); /* errorcode */
4534 SSVAL(*rparam,2,0); /* converter word */
4535 SSVAL(*rparam,4,0x7f); /* permission flags */
4537 return True;
4540 /****************************************************************************
4541 api_WPrintJobEnumerate
4542 ****************************************************************************/
4544 static bool api_WPrintJobGetInfo(struct smbd_server_connection *sconn,
4545 connection_struct *conn, uint64_t vuid,
4546 char *param, int tpscnt,
4547 char *data, int tdscnt,
4548 int mdrcnt,int mprcnt,
4549 char **rdata,char **rparam,
4550 int *rdata_len,int *rparam_len)
4552 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4553 char *str2 = skip_string(param,tpscnt,str1);
4554 char *p = skip_string(param,tpscnt,str2);
4555 int uLevel;
4556 fstring sharename;
4557 uint32_t jobid;
4558 struct pack_desc desc;
4559 char *tmpdata=NULL;
4561 TALLOC_CTX *mem_ctx = talloc_tos();
4562 WERROR werr;
4563 NTSTATUS status;
4564 struct rpc_pipe_client *cli = NULL;
4565 struct dcerpc_binding_handle *b = NULL;
4566 struct policy_handle handle;
4567 struct spoolss_DevmodeContainer devmode_ctr;
4568 union spoolss_JobInfo info;
4570 if (!str1 || !str2 || !p) {
4571 return False;
4574 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4576 memset((char *)&desc,'\0',sizeof(desc));
4577 memset((char *)&status,'\0',sizeof(status));
4579 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4581 /* check it's a supported varient */
4582 if (strcmp(str1,"WWrLh") != 0) {
4583 return False;
4585 if (!check_printjob_info(&desc,uLevel,str2)) {
4586 return False;
4589 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4590 return False;
4593 ZERO_STRUCT(handle);
4595 status = rpc_pipe_open_interface(conn,
4596 &ndr_table_spoolss,
4597 conn->session_info,
4598 conn->sconn->remote_address,
4599 conn->sconn->msg_ctx,
4600 &cli);
4601 if (!NT_STATUS_IS_OK(status)) {
4602 DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n",
4603 nt_errstr(status)));
4604 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4605 goto out;
4607 b = cli->binding_handle;
4609 ZERO_STRUCT(devmode_ctr);
4611 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
4612 sharename,
4613 "RAW",
4614 devmode_ctr,
4615 PRINTER_ACCESS_USE,
4616 &handle,
4617 &werr);
4618 if (!NT_STATUS_IS_OK(status)) {
4619 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4620 goto out;
4622 if (!W_ERROR_IS_OK(werr)) {
4623 desc.errcode = W_ERROR_V(werr);
4624 goto out;
4627 werr = rpccli_spoolss_getjob(cli, mem_ctx,
4628 &handle,
4629 jobid,
4630 2, /* level */
4631 0, /* offered */
4632 &info);
4633 if (!W_ERROR_IS_OK(werr)) {
4634 desc.errcode = W_ERROR_V(werr);
4635 goto out;
4638 if (mdrcnt > 0) {
4639 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4640 if (!*rdata) {
4641 return False;
4643 desc.base = *rdata;
4644 desc.buflen = mdrcnt;
4645 } else {
4647 * Don't return data but need to get correct length
4648 * init_package will return wrong size if buflen=0
4650 desc.buflen = getlen(desc.format);
4651 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4654 if (init_package(&desc,1,0)) {
4655 fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position);
4656 *rdata_len = desc.usedlen;
4657 } else {
4658 desc.errcode = NERR_JobNotFound;
4659 *rdata_len = 0;
4661 out:
4662 if (b && is_valid_policy_hnd(&handle)) {
4663 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
4666 *rparam_len = 6;
4667 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4668 if (!*rparam) {
4669 return False;
4671 SSVALS(*rparam,0,desc.errcode);
4672 SSVAL(*rparam,2,0);
4673 SSVAL(*rparam,4,desc.neededlen);
4675 SAFE_FREE(tmpdata);
4677 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4679 return True;
4682 static bool api_WPrintJobEnumerate(struct smbd_server_connection *sconn,
4683 connection_struct *conn, uint64_t vuid,
4684 char *param, int tpscnt,
4685 char *data, int tdscnt,
4686 int mdrcnt,int mprcnt,
4687 char **rdata,char **rparam,
4688 int *rdata_len,int *rparam_len)
4690 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4691 char *str2 = skip_string(param,tpscnt,str1);
4692 char *p = skip_string(param,tpscnt,str2);
4693 char *name = p;
4694 int uLevel;
4695 int i, succnt=0;
4696 struct pack_desc desc;
4698 TALLOC_CTX *mem_ctx = talloc_tos();
4699 WERROR werr;
4700 NTSTATUS status;
4701 struct rpc_pipe_client *cli = NULL;
4702 struct dcerpc_binding_handle *b = NULL;
4703 struct policy_handle handle;
4704 struct spoolss_DevmodeContainer devmode_ctr;
4705 uint32_t count = 0;
4706 union spoolss_JobInfo *info;
4708 if (!str1 || !str2 || !p) {
4709 return False;
4712 memset((char *)&desc,'\0',sizeof(desc));
4714 p = skip_string(param,tpscnt,p);
4715 if (!p) {
4716 return False;
4718 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4720 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4722 /* check it's a supported variant */
4723 if (strcmp(str1,"zWrLeh") != 0) {
4724 return False;
4727 if (uLevel > 2) {
4728 return False; /* defined only for uLevel 0,1,2 */
4731 if (!check_printjob_info(&desc,uLevel,str2)) {
4732 return False;
4735 ZERO_STRUCT(handle);
4737 status = rpc_pipe_open_interface(conn,
4738 &ndr_table_spoolss,
4739 conn->session_info,
4740 conn->sconn->remote_address,
4741 conn->sconn->msg_ctx,
4742 &cli);
4743 if (!NT_STATUS_IS_OK(status)) {
4744 DEBUG(0,("api_WPrintJobEnumerate: could not connect to spoolss: %s\n",
4745 nt_errstr(status)));
4746 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4747 goto out;
4749 b = cli->binding_handle;
4751 ZERO_STRUCT(devmode_ctr);
4753 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
4754 name,
4755 NULL,
4756 devmode_ctr,
4757 PRINTER_ACCESS_USE,
4758 &handle,
4759 &werr);
4760 if (!NT_STATUS_IS_OK(status)) {
4761 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4762 goto out;
4764 if (!W_ERROR_IS_OK(werr)) {
4765 desc.errcode = W_ERROR_V(werr);
4766 goto out;
4769 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
4770 &handle,
4771 0, /* firstjob */
4772 0xff, /* numjobs */
4773 2, /* level */
4774 0, /* offered */
4775 &count,
4776 &info);
4777 if (!W_ERROR_IS_OK(werr)) {
4778 desc.errcode = W_ERROR_V(werr);
4779 goto out;
4782 if (mdrcnt > 0) {
4783 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4784 if (!*rdata) {
4785 return False;
4788 desc.base = *rdata;
4789 desc.buflen = mdrcnt;
4791 if (init_package(&desc,count,0)) {
4792 succnt = 0;
4793 for (i = 0; i < count; i++) {
4794 fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i);
4795 if (desc.errcode == NERR_Success) {
4796 succnt = i+1;
4800 out:
4801 if (b && is_valid_policy_hnd(&handle)) {
4802 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
4805 *rdata_len = desc.usedlen;
4807 *rparam_len = 8;
4808 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4809 if (!*rparam) {
4810 return False;
4812 SSVALS(*rparam,0,desc.errcode);
4813 SSVAL(*rparam,2,0);
4814 SSVAL(*rparam,4,succnt);
4815 SSVAL(*rparam,6,count);
4817 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4819 return True;
4822 static int check_printdest_info(struct pack_desc* desc,
4823 int uLevel, char* id)
4825 desc->subformat = NULL;
4826 switch( uLevel ) {
4827 case 0:
4828 desc->format = "B9";
4829 break;
4830 case 1:
4831 desc->format = "B9B21WWzW";
4832 break;
4833 case 2:
4834 desc->format = "z";
4835 break;
4836 case 3:
4837 desc->format = "zzzWWzzzWW";
4838 break;
4839 default:
4840 DEBUG(0,("check_printdest_info: invalid level %d\n",
4841 uLevel));
4842 return False;
4844 if (id == NULL || strcmp(desc->format,id) != 0) {
4845 DEBUG(0,("check_printdest_info: invalid string %s\n",
4846 id ? id : "<NULL>" ));
4847 return False;
4849 return True;
4852 static void fill_printdest_info(struct spoolss_PrinterInfo2 *info2, int uLevel,
4853 struct pack_desc* desc)
4855 char buf[100];
4857 strncpy(buf, info2->printername, sizeof(buf)-1);
4858 buf[sizeof(buf)-1] = 0;
4859 (void)strupper_m(buf);
4861 if (uLevel <= 1) {
4862 PACKS(desc,"B9",buf); /* szName */
4863 if (uLevel == 1) {
4864 PACKS(desc,"B21",""); /* szUserName */
4865 PACKI(desc,"W",0); /* uJobId */
4866 PACKI(desc,"W",0); /* fsStatus */
4867 PACKS(desc,"z",""); /* pszStatus */
4868 PACKI(desc,"W",0); /* time */
4872 if (uLevel == 2 || uLevel == 3) {
4873 PACKS(desc,"z",buf); /* pszPrinterName */
4874 if (uLevel == 3) {
4875 PACKS(desc,"z",""); /* pszUserName */
4876 PACKS(desc,"z",""); /* pszLogAddr */
4877 PACKI(desc,"W",0); /* uJobId */
4878 PACKI(desc,"W",0); /* fsStatus */
4879 PACKS(desc,"z",""); /* pszStatus */
4880 PACKS(desc,"z",""); /* pszComment */
4881 PACKS(desc,"z","NULL"); /* pszDrivers */
4882 PACKI(desc,"W",0); /* time */
4883 PACKI(desc,"W",0); /* pad1 */
4888 static bool api_WPrintDestGetInfo(struct smbd_server_connection *sconn,
4889 connection_struct *conn, uint64_t vuid,
4890 char *param, int tpscnt,
4891 char *data, int tdscnt,
4892 int mdrcnt,int mprcnt,
4893 char **rdata,char **rparam,
4894 int *rdata_len,int *rparam_len)
4896 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4897 char *str2 = skip_string(param,tpscnt,str1);
4898 char *p = skip_string(param,tpscnt,str2);
4899 char* PrinterName = p;
4900 int uLevel;
4901 struct pack_desc desc;
4902 char *tmpdata=NULL;
4904 TALLOC_CTX *mem_ctx = talloc_tos();
4905 WERROR werr;
4906 NTSTATUS status;
4907 struct rpc_pipe_client *cli = NULL;
4908 struct dcerpc_binding_handle *b = NULL;
4909 struct policy_handle handle;
4910 struct spoolss_DevmodeContainer devmode_ctr;
4911 union spoolss_PrinterInfo info;
4913 if (!str1 || !str2 || !p) {
4914 return False;
4917 memset((char *)&desc,'\0',sizeof(desc));
4919 p = skip_string(param,tpscnt,p);
4920 if (!p) {
4921 return False;
4923 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4925 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4927 /* check it's a supported varient */
4928 if (strcmp(str1,"zWrLh") != 0) {
4929 return False;
4931 if (!check_printdest_info(&desc,uLevel,str2)) {
4932 return False;
4935 ZERO_STRUCT(handle);
4937 status = rpc_pipe_open_interface(conn,
4938 &ndr_table_spoolss,
4939 conn->session_info,
4940 conn->sconn->remote_address,
4941 conn->sconn->msg_ctx,
4942 &cli);
4943 if (!NT_STATUS_IS_OK(status)) {
4944 DEBUG(0,("api_WPrintDestGetInfo: could not connect to spoolss: %s\n",
4945 nt_errstr(status)));
4946 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4947 goto out;
4949 b = cli->binding_handle;
4951 ZERO_STRUCT(devmode_ctr);
4953 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
4954 PrinterName,
4955 NULL,
4956 devmode_ctr,
4957 PRINTER_ACCESS_USE,
4958 &handle,
4959 &werr);
4960 if (!NT_STATUS_IS_OK(status)) {
4961 *rdata_len = 0;
4962 desc.errcode = NERR_DestNotFound;
4963 desc.neededlen = 0;
4964 goto out;
4966 if (!W_ERROR_IS_OK(werr)) {
4967 *rdata_len = 0;
4968 desc.errcode = NERR_DestNotFound;
4969 desc.neededlen = 0;
4970 goto out;
4973 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
4974 &handle,
4977 &info);
4978 if (!W_ERROR_IS_OK(werr)) {
4979 *rdata_len = 0;
4980 desc.errcode = NERR_DestNotFound;
4981 desc.neededlen = 0;
4982 goto out;
4985 if (mdrcnt > 0) {
4986 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4987 if (!*rdata) {
4988 return False;
4990 desc.base = *rdata;
4991 desc.buflen = mdrcnt;
4992 } else {
4994 * Don't return data but need to get correct length
4995 * init_package will return wrong size if buflen=0
4997 desc.buflen = getlen(desc.format);
4998 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
5000 if (init_package(&desc,1,0)) {
5001 fill_printdest_info(&info.info2, uLevel,&desc);
5004 out:
5005 if (b && is_valid_policy_hnd(&handle)) {
5006 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5009 *rdata_len = desc.usedlen;
5011 *rparam_len = 6;
5012 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5013 if (!*rparam) {
5014 return False;
5016 SSVALS(*rparam,0,desc.errcode);
5017 SSVAL(*rparam,2,0);
5018 SSVAL(*rparam,4,desc.neededlen);
5020 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
5021 SAFE_FREE(tmpdata);
5023 return True;
5026 static bool api_WPrintDestEnum(struct smbd_server_connection *sconn,
5027 connection_struct *conn, uint64_t vuid,
5028 char *param, int tpscnt,
5029 char *data, int tdscnt,
5030 int mdrcnt,int mprcnt,
5031 char **rdata,char **rparam,
5032 int *rdata_len,int *rparam_len)
5034 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5035 char *str2 = skip_string(param,tpscnt,str1);
5036 char *p = skip_string(param,tpscnt,str2);
5037 int uLevel;
5038 int queuecnt;
5039 int i, n, succnt=0;
5040 struct pack_desc desc;
5042 TALLOC_CTX *mem_ctx = talloc_tos();
5043 WERROR werr;
5044 NTSTATUS status;
5045 struct rpc_pipe_client *cli = NULL;
5046 union spoolss_PrinterInfo *info;
5047 uint32_t count;
5049 if (!str1 || !str2 || !p) {
5050 return False;
5053 memset((char *)&desc,'\0',sizeof(desc));
5055 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5057 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
5059 /* check it's a supported varient */
5060 if (strcmp(str1,"WrLeh") != 0) {
5061 return False;
5063 if (!check_printdest_info(&desc,uLevel,str2)) {
5064 return False;
5067 queuecnt = 0;
5069 status = rpc_pipe_open_interface(conn,
5070 &ndr_table_spoolss,
5071 conn->session_info,
5072 conn->sconn->remote_address,
5073 conn->sconn->msg_ctx,
5074 &cli);
5075 if (!NT_STATUS_IS_OK(status)) {
5076 DEBUG(0,("api_WPrintDestEnum: could not connect to spoolss: %s\n",
5077 nt_errstr(status)));
5078 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5079 goto out;
5082 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
5083 PRINTER_ENUM_LOCAL,
5084 cli->srv_name_slash,
5087 &count,
5088 &info);
5089 if (!W_ERROR_IS_OK(werr)) {
5090 desc.errcode = W_ERROR_V(werr);
5091 *rdata_len = 0;
5092 desc.errcode = NERR_DestNotFound;
5093 desc.neededlen = 0;
5094 goto out;
5097 queuecnt = count;
5099 if (mdrcnt > 0) {
5100 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5101 if (!*rdata) {
5102 return False;
5106 desc.base = *rdata;
5107 desc.buflen = mdrcnt;
5108 if (init_package(&desc,queuecnt,0)) {
5109 succnt = 0;
5110 n = 0;
5111 for (i = 0; i < count; i++) {
5112 fill_printdest_info(&info[i].info2, uLevel,&desc);
5113 n++;
5114 if (desc.errcode == NERR_Success) {
5115 succnt = n;
5119 out:
5120 *rdata_len = desc.usedlen;
5122 *rparam_len = 8;
5123 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5124 if (!*rparam) {
5125 return False;
5127 SSVALS(*rparam,0,desc.errcode);
5128 SSVAL(*rparam,2,0);
5129 SSVAL(*rparam,4,succnt);
5130 SSVAL(*rparam,6,queuecnt);
5132 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
5134 return True;
5137 static bool api_WPrintDriverEnum(struct smbd_server_connection *sconn,
5138 connection_struct *conn, uint64_t vuid,
5139 char *param, int tpscnt,
5140 char *data, int tdscnt,
5141 int mdrcnt,int mprcnt,
5142 char **rdata,char **rparam,
5143 int *rdata_len,int *rparam_len)
5145 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5146 char *str2 = skip_string(param,tpscnt,str1);
5147 char *p = skip_string(param,tpscnt,str2);
5148 int uLevel;
5149 int succnt;
5150 struct pack_desc desc;
5152 if (!str1 || !str2 || !p) {
5153 return False;
5156 memset((char *)&desc,'\0',sizeof(desc));
5158 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5160 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
5162 /* check it's a supported varient */
5163 if (strcmp(str1,"WrLeh") != 0) {
5164 return False;
5166 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
5167 return False;
5170 if (mdrcnt > 0) {
5171 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5172 if (!*rdata) {
5173 return False;
5176 desc.base = *rdata;
5177 desc.buflen = mdrcnt;
5178 if (init_package(&desc,1,0)) {
5179 PACKS(&desc,"B41","NULL");
5182 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5184 *rdata_len = desc.usedlen;
5186 *rparam_len = 8;
5187 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5188 if (!*rparam) {
5189 return False;
5191 SSVALS(*rparam,0,desc.errcode);
5192 SSVAL(*rparam,2,0);
5193 SSVAL(*rparam,4,succnt);
5194 SSVAL(*rparam,6,1);
5196 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
5198 return True;
5201 static bool api_WPrintQProcEnum(struct smbd_server_connection *sconn,
5202 connection_struct *conn, uint64_t vuid,
5203 char *param, int tpscnt,
5204 char *data, int tdscnt,
5205 int mdrcnt,int mprcnt,
5206 char **rdata,char **rparam,
5207 int *rdata_len,int *rparam_len)
5209 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5210 char *str2 = skip_string(param,tpscnt,str1);
5211 char *p = skip_string(param,tpscnt,str2);
5212 int uLevel;
5213 int succnt;
5214 struct pack_desc desc;
5216 if (!str1 || !str2 || !p) {
5217 return False;
5219 memset((char *)&desc,'\0',sizeof(desc));
5221 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5223 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
5225 /* check it's a supported varient */
5226 if (strcmp(str1,"WrLeh") != 0) {
5227 return False;
5229 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
5230 return False;
5233 if (mdrcnt > 0) {
5234 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5235 if (!*rdata) {
5236 return False;
5239 desc.base = *rdata;
5240 desc.buflen = mdrcnt;
5241 desc.format = str2;
5242 if (init_package(&desc,1,0)) {
5243 PACKS(&desc,"B13","lpd");
5246 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5248 *rdata_len = desc.usedlen;
5250 *rparam_len = 8;
5251 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5252 if (!*rparam) {
5253 return False;
5255 SSVALS(*rparam,0,desc.errcode);
5256 SSVAL(*rparam,2,0);
5257 SSVAL(*rparam,4,succnt);
5258 SSVAL(*rparam,6,1);
5260 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
5262 return True;
5265 static bool api_WPrintPortEnum(struct smbd_server_connection *sconn,
5266 connection_struct *conn, uint64_t vuid,
5267 char *param, int tpscnt,
5268 char *data, int tdscnt,
5269 int mdrcnt,int mprcnt,
5270 char **rdata,char **rparam,
5271 int *rdata_len,int *rparam_len)
5273 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5274 char *str2 = skip_string(param,tpscnt,str1);
5275 char *p = skip_string(param,tpscnt,str2);
5276 int uLevel;
5277 int succnt;
5278 struct pack_desc desc;
5280 if (!str1 || !str2 || !p) {
5281 return False;
5284 memset((char *)&desc,'\0',sizeof(desc));
5286 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5288 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
5290 /* check it's a supported varient */
5291 if (strcmp(str1,"WrLeh") != 0) {
5292 return False;
5294 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
5295 return False;
5298 if (mdrcnt > 0) {
5299 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5300 if (!*rdata) {
5301 return False;
5304 memset((char *)&desc,'\0',sizeof(desc));
5305 desc.base = *rdata;
5306 desc.buflen = mdrcnt;
5307 desc.format = str2;
5308 if (init_package(&desc,1,0)) {
5309 PACKS(&desc,"B13","lp0");
5312 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5314 *rdata_len = desc.usedlen;
5316 *rparam_len = 8;
5317 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5318 if (!*rparam) {
5319 return False;
5321 SSVALS(*rparam,0,desc.errcode);
5322 SSVAL(*rparam,2,0);
5323 SSVAL(*rparam,4,succnt);
5324 SSVAL(*rparam,6,1);
5326 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
5328 return True;
5331 /****************************************************************************
5332 List open sessions
5333 ****************************************************************************/
5335 static bool api_RNetSessionEnum(struct smbd_server_connection *sconn,
5336 connection_struct *conn, uint64_t vuid,
5337 char *param, int tpscnt,
5338 char *data, int tdscnt,
5339 int mdrcnt,int mprcnt,
5340 char **rdata,char **rparam,
5341 int *rdata_len,int *rparam_len)
5344 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5345 char *str2 = skip_string(param,tpscnt,str1);
5346 char *p = skip_string(param,tpscnt,str2);
5347 int uLevel;
5348 struct pack_desc desc;
5349 int i;
5351 TALLOC_CTX *mem_ctx = talloc_tos();
5352 WERROR werr;
5353 NTSTATUS status;
5354 struct rpc_pipe_client *cli = NULL;
5355 struct dcerpc_binding_handle *b = NULL;
5356 struct srvsvc_NetSessInfoCtr info_ctr;
5357 uint32_t totalentries, resume_handle = 0;
5358 uint32_t count = 0;
5360 if (!str1 || !str2 || !p) {
5361 return False;
5364 ZERO_STRUCT(desc);
5366 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5368 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
5369 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
5370 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
5372 /* check it's a supported varient */
5373 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
5374 return False;
5376 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
5377 return False;
5380 status = rpc_pipe_open_interface(conn,
5381 &ndr_table_srvsvc,
5382 conn->session_info,
5383 conn->sconn->remote_address,
5384 conn->sconn->msg_ctx,
5385 &cli);
5386 if (!NT_STATUS_IS_OK(status)) {
5387 DEBUG(0,("RNetSessionEnum: could not connect to srvsvc: %s\n",
5388 nt_errstr(status)));
5389 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5390 goto out;
5392 b = cli->binding_handle;
5394 info_ctr.level = 1;
5395 info_ctr.ctr.ctr1 = talloc_zero(talloc_tos(), struct srvsvc_NetSessCtr1);
5396 if (info_ctr.ctr.ctr1 == NULL) {
5397 desc.errcode = W_ERROR_V(WERR_NOMEM);
5398 goto out;
5401 status = dcerpc_srvsvc_NetSessEnum(b, mem_ctx,
5402 cli->srv_name_slash,
5403 NULL, /* client */
5404 NULL, /* user */
5405 &info_ctr,
5406 (uint32_t)-1, /* max_buffer */
5407 &totalentries,
5408 &resume_handle,
5409 &werr);
5410 if (!NT_STATUS_IS_OK(status)) {
5411 DEBUG(0,("RNetSessionEnum: dcerpc_srvsvc_NetSessEnum failed: %s\n",
5412 nt_errstr(status)));
5413 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5414 goto out;
5417 if (!W_ERROR_IS_OK(werr)) {
5418 DEBUG(0,("RNetSessionEnum: dcerpc_srvsvc_NetSessEnum failed: %s\n",
5419 win_errstr(werr)));
5420 desc.errcode = W_ERROR_V(werr);
5421 goto out;
5424 count = info_ctr.ctr.ctr1->count;
5426 out:
5427 if (mdrcnt > 0) {
5428 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5429 if (!*rdata) {
5430 return False;
5434 desc.base = *rdata;
5435 desc.buflen = mdrcnt;
5436 desc.format = str2;
5437 if (!init_package(&desc, count,0)) {
5438 return False;
5441 for(i=0; i < count; i++) {
5442 PACKS(&desc, "z", info_ctr.ctr.ctr1->array[i].client);
5443 PACKS(&desc, "z", info_ctr.ctr.ctr1->array[i].user);
5444 PACKI(&desc, "W", 1); /* num conns */
5445 PACKI(&desc, "W", info_ctr.ctr.ctr1->array[i].num_open);
5446 PACKI(&desc, "W", 1); /* num users */
5447 PACKI(&desc, "D", 0); /* session time */
5448 PACKI(&desc, "D", 0); /* idle time */
5449 PACKI(&desc, "D", 0); /* flags */
5450 PACKS(&desc, "z", "Unknown Client"); /* client type string */
5453 *rdata_len = desc.usedlen;
5455 *rparam_len = 8;
5456 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5457 if (!*rparam) {
5458 return False;
5460 SSVALS(*rparam,0,desc.errcode);
5461 SSVAL(*rparam,2,0); /* converter */
5462 SSVAL(*rparam,4, count); /* count */
5464 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
5466 return True;
5470 /****************************************************************************
5471 The buffer was too small.
5472 ****************************************************************************/
5474 static bool api_TooSmall(struct smbd_server_connection *sconn,
5475 connection_struct *conn,uint64_t vuid, char *param, char *data,
5476 int mdrcnt, int mprcnt,
5477 char **rdata, char **rparam,
5478 int *rdata_len, int *rparam_len)
5480 *rparam_len = MIN(*rparam_len,mprcnt);
5481 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5482 if (!*rparam) {
5483 return False;
5486 *rdata_len = 0;
5488 SSVAL(*rparam,0,NERR_BufTooSmall);
5490 DEBUG(3,("Supplied buffer too small in API command\n"));
5492 return True;
5495 /****************************************************************************
5496 The request is not supported.
5497 ****************************************************************************/
5499 static bool api_Unsupported(struct smbd_server_connection *sconn,
5500 connection_struct *conn, uint64_t vuid,
5501 char *param, int tpscnt,
5502 char *data, int tdscnt,
5503 int mdrcnt, int mprcnt,
5504 char **rdata, char **rparam,
5505 int *rdata_len, int *rparam_len)
5507 *rparam_len = 4;
5508 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5509 if (!*rparam) {
5510 return False;
5513 *rdata_len = 0;
5515 SSVAL(*rparam,0,NERR_notsupported);
5516 SSVAL(*rparam,2,0); /* converter word */
5518 DEBUG(3,("Unsupported API command\n"));
5520 return True;
5523 static const struct {
5524 const char *name;
5525 int id;
5526 bool (*fn)(struct smbd_server_connection *sconn,
5527 connection_struct *, uint64_t,
5528 char *, int,
5529 char *, int,
5530 int,int,char **,char **,int *,int *);
5531 bool auth_user; /* Deny anonymous access? */
5532 } api_commands[] = {
5533 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
5534 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
5535 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
5536 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
5537 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
5538 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
5539 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
5540 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
5541 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
5542 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
5543 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
5544 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
5545 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
5546 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
5547 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
5548 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
5549 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
5550 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
5551 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
5552 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
5553 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
5554 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
5555 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
5556 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
5557 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
5558 {"NetServerEnum3", RAP_NetServerEnum3, api_RNetServerEnum3}, /* anon OK */
5559 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
5560 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
5561 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
5562 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
5563 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
5564 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
5565 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
5566 {NULL, -1, api_Unsupported}
5567 /* The following RAP calls are not implemented by Samba:
5569 RAP_WFileEnum2 - anon not OK
5574 /****************************************************************************
5575 Handle remote api calls.
5576 ****************************************************************************/
5578 void api_reply(connection_struct *conn, uint64_t vuid,
5579 struct smb_request *req,
5580 char *data, char *params,
5581 int tdscnt, int tpscnt,
5582 int mdrcnt, int mprcnt)
5584 int api_command;
5585 char *rdata = NULL;
5586 char *rparam = NULL;
5587 const char *name1 = NULL;
5588 const char *name2 = NULL;
5589 int rdata_len = 0;
5590 int rparam_len = 0;
5591 bool reply=False;
5592 int i;
5594 if (!params) {
5595 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
5596 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5597 return;
5600 if (tpscnt < 2) {
5601 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5602 return;
5604 api_command = SVAL(params,0);
5605 /* Is there a string at position params+2 ? */
5606 if (skip_string(params,tpscnt,params+2)) {
5607 name1 = params + 2;
5608 } else {
5609 name1 = "";
5611 name2 = skip_string(params,tpscnt,params+2);
5612 if (!name2) {
5613 name2 = "";
5616 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
5617 api_command,
5618 name1,
5619 name2,
5620 tdscnt,tpscnt,mdrcnt,mprcnt));
5622 for (i=0;api_commands[i].name;i++) {
5623 if (api_commands[i].id == api_command && api_commands[i].fn) {
5624 DEBUG(3,("Doing %s\n",api_commands[i].name));
5625 break;
5629 /* Check whether this api call can be done anonymously */
5631 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
5632 struct user_struct *user = get_valid_user_struct(req->sconn, vuid);
5634 if (!user || security_session_user_level(user->session_info, NULL) < SECURITY_USER) {
5635 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5636 return;
5640 rdata = (char *)SMB_MALLOC(1024);
5641 if (rdata) {
5642 memset(rdata,'\0',1024);
5645 rparam = (char *)SMB_MALLOC(1024);
5646 if (rparam) {
5647 memset(rparam,'\0',1024);
5650 if(!rdata || !rparam) {
5651 DEBUG(0,("api_reply: malloc fail !\n"));
5652 SAFE_FREE(rdata);
5653 SAFE_FREE(rparam);
5654 reply_nterror(req, NT_STATUS_NO_MEMORY);
5655 return;
5658 reply = api_commands[i].fn(req->sconn, conn,
5659 vuid,
5660 params,tpscnt, /* params + length */
5661 data,tdscnt, /* data + length */
5662 mdrcnt,mprcnt,
5663 &rdata,&rparam,&rdata_len,&rparam_len);
5666 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
5667 reply = api_TooSmall(req->sconn,conn,vuid,params,data,
5668 mdrcnt,mprcnt,
5669 &rdata,&rparam,&rdata_len,&rparam_len);
5672 /* if we get False back then it's actually unsupported */
5673 if (!reply) {
5674 reply = api_Unsupported(req->sconn,conn,vuid,params,tpscnt,
5675 data,
5676 tdscnt,mdrcnt,mprcnt,
5677 &rdata,&rparam,&rdata_len,&rparam_len);
5680 /* If api_Unsupported returns false we can't return anything. */
5681 if (reply) {
5682 send_trans_reply(conn, req, rparam, rparam_len,
5683 rdata, rdata_len, False);
5686 SAFE_FREE(rdata);
5687 SAFE_FREE(rparam);
5688 return;