s3: libsmb: In cli_qpathinfo_send() (SMBtrans2:TRANSACT2_QPATHINFO) check for DFS...
[Samba.git] / source3 / smbd / smb1_lanman.c
blobeb8148753b9022daa39a0945dc8c6a2466ab5c2e
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"
46 #include "lib/util/string_wrappers.h"
47 #include "source3/printing/rap_jobid.h"
48 #include "source3/lib/substitute.h"
50 #ifdef CHECK_TYPES
51 #undef CHECK_TYPES
52 #endif
53 #define CHECK_TYPES 0
55 #define NERR_Success 0
56 #define NERR_badpass 86
57 #define NERR_notsupported 50
59 #define NERR_BASE (2100)
60 #define NERR_BufTooSmall (NERR_BASE+23)
61 #define NERR_JobNotFound (NERR_BASE+51)
62 #define NERR_DestNotFound (NERR_BASE+52)
64 #define ACCESS_READ 0x01
65 #define ACCESS_WRITE 0x02
66 #define ACCESS_CREATE 0x04
68 #define SHPWLEN 8 /* share password length */
70 /* Limit size of ipc replies */
72 static char *smb_realloc_limit(void *ptr, size_t size)
74 char *val;
76 size = MAX((size),4*1024);
77 val = (char *)SMB_REALLOC(ptr,size);
78 if (val) {
79 memset(val,'\0',size);
81 return val;
84 static bool api_Unsupported(struct smbd_server_connection *sconn,
85 connection_struct *conn, uint64_t vuid,
86 char *param, int tpscnt,
87 char *data, int tdscnt,
88 int mdrcnt, int mprcnt,
89 char **rdata, char **rparam,
90 int *rdata_len, int *rparam_len);
92 static bool api_TooSmall(struct smbd_server_connection *sconn,
93 connection_struct *conn, uint64_t vuid, char *param, char *data,
94 int mdrcnt, int mprcnt,
95 char **rdata, char **rparam,
96 int *rdata_len, int *rparam_len);
99 static int CopyExpanded(connection_struct *conn,
100 int snum, char **dst, char *src, int *p_space_remaining)
102 TALLOC_CTX *ctx = talloc_tos();
103 const struct loadparm_substitution *lp_sub =
104 loadparm_s3_global_substitution();
105 char *buf = NULL;
106 int l;
108 if (!src || !dst || !p_space_remaining || !(*dst) ||
109 *p_space_remaining <= 0) {
110 return 0;
113 buf = talloc_strdup(ctx, src);
114 if (!buf) {
115 *p_space_remaining = 0;
116 return 0;
118 buf = talloc_string_sub(ctx, buf,"%S", lp_servicename(ctx, lp_sub, snum));
119 if (!buf) {
120 *p_space_remaining = 0;
121 return 0;
123 buf = talloc_sub_full(ctx,
124 lp_servicename(ctx, lp_sub, SNUM(conn)),
125 conn->session_info->unix_info->unix_name,
126 conn->connectpath,
127 conn->session_info->unix_token->gid,
128 conn->session_info->unix_info->sanitized_username,
129 conn->session_info->info->domain_name,
130 buf);
131 if (!buf) {
132 *p_space_remaining = 0;
133 return 0;
135 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
136 if (l == 0) {
137 return 0;
139 (*dst) += l;
140 (*p_space_remaining) -= l;
141 return l;
144 static int CopyAndAdvance(char **dst, char *src, int *n)
146 int l;
147 if (!src || !dst || !n || !(*dst)) {
148 return 0;
150 l = push_ascii(*dst,src,*n, STR_TERMINATE);
151 if (l == 0) {
152 return 0;
154 (*dst) += l;
155 (*n) -= l;
156 return l;
159 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
161 TALLOC_CTX *ctx = talloc_tos();
162 const struct loadparm_substitution *lp_sub =
163 loadparm_s3_global_substitution();
164 char *buf = NULL;
165 if (!s) {
166 return 0;
168 buf = talloc_strdup(ctx,s);
169 if (!buf) {
170 return 0;
172 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(ctx, lp_sub, snum));
173 if (!buf) {
174 return 0;
176 buf = talloc_sub_full(ctx,
177 lp_servicename(ctx, lp_sub, SNUM(conn)),
178 conn->session_info->unix_info->unix_name,
179 conn->connectpath,
180 conn->session_info->unix_token->gid,
181 conn->session_info->unix_info->sanitized_username,
182 conn->session_info->info->domain_name,
183 buf);
184 if (!buf) {
185 return 0;
187 return strlen(buf) + 1;
190 /*******************************************************************
191 Check a API string for validity when we only need to check the prefix.
192 ******************************************************************/
194 static bool prefix_ok(const char *str, const char *prefix)
196 return(strncmp(str,prefix,strlen(prefix)) == 0);
199 struct pack_desc {
200 const char *format; /* formatstring for structure */
201 const char *subformat; /* subformat for structure */
202 char *base; /* baseaddress of buffer */
203 int buflen; /* remaining size for fixed part; on init: length of base */
204 int subcount; /* count of substructures */
205 char *structbuf; /* pointer into buffer for remaining fixed part */
206 int stringlen; /* remaining size for variable part */
207 char *stringbuf; /* pointer into buffer for remaining variable part */
208 int neededlen; /* total needed size */
209 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
210 const char *curpos; /* current position; pointer into format or subformat */
211 int errcode;
214 static int get_counter(const char **p)
216 int i, n;
217 if (!p || !(*p)) {
218 return 1;
220 if (!isdigit((int)**p)) {
221 return 1;
223 for (n = 0;;) {
224 i = **p;
225 if (isdigit(i)) {
226 n = 10 * n + (i - '0');
227 } else {
228 return n;
230 (*p)++;
234 static int getlen(const char *p)
236 int n = 0;
237 if (!p) {
238 return 0;
241 while (*p) {
242 switch( *p++ ) {
243 case 'W': /* word (2 byte) */
244 n += 2;
245 break;
246 case 'K': /* status word? (2 byte) */
247 n += 2;
248 break;
249 case 'N': /* count of substructures (word) at end */
250 n += 2;
251 break;
252 case 'D': /* double word (4 byte) */
253 case 'z': /* offset to zero terminated string (4 byte) */
254 case 'l': /* offset to user data (4 byte) */
255 n += 4;
256 break;
257 case 'b': /* offset to data (with counter) (4 byte) */
258 n += 4;
259 get_counter(&p);
260 break;
261 case 'B': /* byte (with optional counter) */
262 n += get_counter(&p);
263 break;
266 return n;
269 static bool init_package(struct pack_desc *p, int count, int subcount)
271 int n = p->buflen;
272 int i;
274 if (!p->format || !p->base) {
275 return False;
278 i = count * getlen(p->format);
279 if (p->subformat) {
280 i += subcount * getlen(p->subformat);
282 p->structbuf = p->base;
283 p->neededlen = 0;
284 p->usedlen = 0;
285 p->subcount = 0;
286 p->curpos = p->format;
287 if (i > n) {
288 p->neededlen = i;
289 i = n = 0;
290 #if 0
292 * This is the old error code we used. Aparently
293 * WinNT/2k systems return ERRbuftoosmall (2123) and
294 * OS/2 needs this. I'm leaving this here so we can revert
295 * if needed. JRA.
297 p->errcode = ERRmoredata;
298 #else
299 p->errcode = ERRbuftoosmall;
300 #endif
301 } else {
302 p->errcode = NERR_Success;
304 p->buflen = i;
305 n -= i;
306 p->stringbuf = p->base + i;
307 p->stringlen = n;
308 return (p->errcode == NERR_Success);
311 static int package(struct pack_desc *p, ...)
313 va_list args;
314 int needed=0, stringneeded;
315 const char *str=NULL;
316 int is_string=0, stringused;
317 int32_t temp;
319 va_start(args,p);
321 if (!*p->curpos) {
322 if (!p->subcount) {
323 p->curpos = p->format;
324 } else {
325 p->curpos = p->subformat;
326 p->subcount--;
329 #if CHECK_TYPES
330 str = va_arg(args,char*);
331 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
332 #endif
333 stringneeded = -1;
335 if (!p->curpos) {
336 va_end(args);
337 return 0;
340 switch( *p->curpos++ ) {
341 case 'W': /* 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 'K': /* status word? (2 byte) */
349 needed = 2;
350 temp = va_arg(args,int);
351 if (p->buflen >= needed) {
352 SSVAL(p->structbuf,0,temp);
354 break;
355 case 'N': /* count of substructures (word) at end */
356 needed = 2;
357 p->subcount = va_arg(args,int);
358 if (p->buflen >= needed) {
359 SSVAL(p->structbuf,0,p->subcount);
361 break;
362 case 'D': /* double word (4 byte) */
363 needed = 4;
364 temp = va_arg(args,int);
365 if (p->buflen >= needed) {
366 SIVAL(p->structbuf,0,temp);
368 break;
369 case 'B': /* byte (with optional counter) */
370 needed = get_counter(&p->curpos);
372 char *s = va_arg(args,char*);
373 if (p->buflen >= needed) {
374 strlcpy(p->structbuf,s?s:"",needed);
377 break;
378 case 'z': /* offset to zero terminated string (4 byte) */
379 str = va_arg(args,char*);
380 stringneeded = (str ? strlen(str)+1 : 0);
381 is_string = 1;
382 break;
383 case 'l': /* offset to user data (4 byte) */
384 str = va_arg(args,char*);
385 stringneeded = va_arg(args,int);
386 is_string = 0;
387 break;
388 case 'b': /* offset to data (with counter) (4 byte) */
389 str = va_arg(args,char*);
390 stringneeded = get_counter(&p->curpos);
391 is_string = 0;
392 break;
395 va_end(args);
396 if (stringneeded >= 0) {
397 needed = 4;
398 if (p->buflen >= needed) {
399 stringused = stringneeded;
400 if (stringused > p->stringlen) {
401 stringused = (is_string ? p->stringlen : 0);
402 if (p->errcode == NERR_Success) {
403 p->errcode = ERRmoredata;
406 if (!stringused) {
407 SIVAL(p->structbuf,0,0);
408 } else {
409 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
410 memcpy(p->stringbuf,str?str:"",stringused);
411 if (is_string) {
412 p->stringbuf[stringused-1] = '\0';
414 p->stringbuf += stringused;
415 p->stringlen -= stringused;
416 p->usedlen += stringused;
419 p->neededlen += stringneeded;
422 p->neededlen += needed;
423 if (p->buflen >= needed) {
424 p->structbuf += needed;
425 p->buflen -= needed;
426 p->usedlen += needed;
427 } else {
428 if (p->errcode == NERR_Success) {
429 p->errcode = ERRmoredata;
432 return 1;
435 #if CHECK_TYPES
436 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
437 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
438 #else
439 #define PACK(desc,t,v) package(desc,v)
440 #define PACKl(desc,t,v,l) package(desc,v,l)
441 #endif
443 static void PACKI(struct pack_desc* desc, const char *t,int v)
445 PACK(desc,t,v);
448 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
450 PACK(desc,t,v);
453 /****************************************************************************
454 Get a print queue.
455 ****************************************************************************/
457 static void PackDriverData(struct pack_desc* desc)
459 char drivdata[4+4+32];
460 SIVAL(drivdata,0,sizeof drivdata); /* cb */
461 SIVAL(drivdata,4,1000); /* lVersion */
462 memset(drivdata+8,0,32); /* szDeviceName */
463 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
464 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
467 static int check_printq_info(struct pack_desc* desc,
468 unsigned int uLevel, char *id1, char *id2)
470 desc->subformat = NULL;
471 switch( uLevel ) {
472 case 0:
473 desc->format = "B13";
474 break;
475 case 1:
476 desc->format = "B13BWWWzzzzzWW";
477 break;
478 case 2:
479 desc->format = "B13BWWWzzzzzWN";
480 desc->subformat = "WB21BB16B10zWWzDDz";
481 break;
482 case 3:
483 desc->format = "zWWWWzzzzWWzzl";
484 break;
485 case 4:
486 desc->format = "zWWWWzzzzWNzzl";
487 desc->subformat = "WWzWWDDzz";
488 break;
489 case 5:
490 desc->format = "z";
491 break;
492 case 51:
493 desc->format = "K";
494 break;
495 case 52:
496 desc->format = "WzzzzzzzzN";
497 desc->subformat = "z";
498 break;
499 default:
500 DEBUG(0,("check_printq_info: invalid level %d\n",
501 uLevel ));
502 return False;
504 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
505 DEBUG(0,("check_printq_info: invalid format %s\n",
506 id1 ? id1 : "<NULL>" ));
507 return False;
509 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
510 DEBUG(0,("check_printq_info: invalid subformat %s\n",
511 id2 ? id2 : "<NULL>" ));
512 return False;
514 return True;
518 #define RAP_JOB_STATUS_QUEUED 0
519 #define RAP_JOB_STATUS_PAUSED 1
520 #define RAP_JOB_STATUS_SPOOLING 2
521 #define RAP_JOB_STATUS_PRINTING 3
522 #define RAP_JOB_STATUS_PRINTED 4
524 #define RAP_QUEUE_STATUS_PAUSED 1
525 #define RAP_QUEUE_STATUS_ERROR 2
527 /* turn a print job status into a on the wire status
529 static int printj_spoolss_status(int v)
531 if (v == JOB_STATUS_QUEUED)
532 return RAP_JOB_STATUS_QUEUED;
533 if (v & JOB_STATUS_PAUSED)
534 return RAP_JOB_STATUS_PAUSED;
535 if (v & JOB_STATUS_SPOOLING)
536 return RAP_JOB_STATUS_SPOOLING;
537 if (v & JOB_STATUS_PRINTING)
538 return RAP_JOB_STATUS_PRINTING;
539 return 0;
542 /* turn a print queue status into a on the wire status
544 static int printq_spoolss_status(int v)
546 if (v == PRINTER_STATUS_OK)
547 return 0;
548 if (v & PRINTER_STATUS_PAUSED)
549 return RAP_QUEUE_STATUS_PAUSED;
550 return RAP_QUEUE_STATUS_ERROR;
553 static void fill_spoolss_printjob_info(int uLevel,
554 struct pack_desc *desc,
555 struct spoolss_JobInfo2 *info2,
556 int n)
558 time_t t = spoolss_Time_to_time_t(&info2->submitted);
560 /* the client expects localtime */
561 t -= get_time_zone(t);
563 PACKI(desc,"W",pjobid_to_rap(info2->printer_name, info2->job_id)); /* uJobId */
564 if (uLevel == 1) {
565 PACKS(desc,"B21", info2->user_name); /* szUserName */
566 PACKS(desc,"B",""); /* pad */
567 PACKS(desc,"B16",""); /* szNotifyName */
568 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
569 PACKS(desc,"z",""); /* pszParms */
570 PACKI(desc,"W",n+1); /* uPosition */
571 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
572 PACKS(desc,"z",""); /* pszStatus */
573 PACKI(desc,"D", t); /* ulSubmitted */
574 PACKI(desc,"D", info2->size); /* ulSize */
575 PACKS(desc,"z", info2->document_name); /* pszComment */
577 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
578 PACKI(desc,"W", info2->priority); /* uPriority */
579 PACKS(desc,"z", info2->user_name); /* pszUserName */
580 PACKI(desc,"W",n+1); /* uPosition */
581 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
582 PACKI(desc,"D",t); /* ulSubmitted */
583 PACKI(desc,"D", info2->size); /* ulSize */
584 PACKS(desc,"z","Samba"); /* pszComment */
585 PACKS(desc,"z", info2->document_name); /* pszDocument */
586 if (uLevel == 3) {
587 PACKS(desc,"z",""); /* pszNotifyName */
588 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
589 PACKS(desc,"z",""); /* pszParms */
590 PACKS(desc,"z",""); /* pszStatus */
591 PACKS(desc,"z", info2->printer_name); /* pszQueue */
592 PACKS(desc,"z","lpd"); /* pszQProcName */
593 PACKS(desc,"z",""); /* pszQProcParms */
594 PACKS(desc,"z","NULL"); /* pszDriverName */
595 PackDriverData(desc); /* pDriverData */
596 PACKS(desc,"z",""); /* pszPrinterName */
597 } else if (uLevel == 4) { /* OS2 */
598 PACKS(desc,"z",""); /* pszSpoolFileName */
599 PACKS(desc,"z",""); /* pszPortName */
600 PACKS(desc,"z",""); /* pszStatus */
601 PACKI(desc,"D",0); /* ulPagesSpooled */
602 PACKI(desc,"D",0); /* ulPagesSent */
603 PACKI(desc,"D",0); /* ulPagesPrinted */
604 PACKI(desc,"D",0); /* ulTimePrinted */
605 PACKI(desc,"D",0); /* ulExtendJobStatus */
606 PACKI(desc,"D",0); /* ulStartPage */
607 PACKI(desc,"D",0); /* ulEndPage */
612 /********************************************************************
613 Respond to the DosPrintQInfo command with a level of 52
614 This is used to get printer driver information for Win9x clients
615 ********************************************************************/
616 static void fill_printq_info_52(struct spoolss_DriverInfo3 *driver,
617 struct pack_desc* desc, int count,
618 const char *printer_name)
620 int i;
621 fstring location;
622 trim_string(discard_const_p(char, driver->driver_path), "\\print$\\WIN40\\0\\", 0);
623 trim_string(discard_const_p(char, driver->data_file), "\\print$\\WIN40\\0\\", 0);
624 trim_string(discard_const_p(char, driver->help_file), "\\print$\\WIN40\\0\\", 0);
626 PACKI(desc, "W", 0x0400); /* don't know */
627 PACKS(desc, "z", driver->driver_name); /* long printer name */
628 PACKS(desc, "z", driver->driver_path); /* Driverfile Name */
629 PACKS(desc, "z", driver->data_file); /* Datafile name */
630 PACKS(desc, "z", driver->monitor_name); /* language monitor */
632 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
633 standard_sub_basic( "", "", location, sizeof(location)-1 );
634 PACKS(desc,"z", location); /* share to retrieve files */
636 PACKS(desc,"z", driver->default_datatype); /* default data type */
637 PACKS(desc,"z", driver->help_file); /* helpfile name */
638 PACKS(desc,"z", driver->driver_path); /* driver name */
640 DEBUG(3,("Printer Driver Name: %s:\n",driver->driver_name));
641 DEBUG(3,("Driver: %s:\n",driver->driver_path));
642 DEBUG(3,("Data File: %s:\n",driver->data_file));
643 DEBUG(3,("Language Monitor: %s:\n",driver->monitor_name));
644 DEBUG(3,("Driver Location: %s:\n",location));
645 DEBUG(3,("Data Type: %s:\n",driver->default_datatype));
646 DEBUG(3,("Help File: %s:\n",driver->help_file));
647 PACKI(desc,"N",count); /* number of files to copy */
649 for ( i=0; i<count && driver->dependent_files && *driver->dependent_files[i]; i++)
651 trim_string(discard_const_p(char, driver->dependent_files[i]), "\\print$\\WIN40\\0\\", 0);
652 PACKS(desc,"z",driver->dependent_files[i]); /* driver files to copy */
653 DEBUG(3,("Dependent File: %s:\n", driver->dependent_files[i]));
656 /* sanity check */
657 if ( i != count )
658 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
659 count, i));
661 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", printer_name, i));
663 desc->errcode=NERR_Success;
667 static const char *strip_unc(const char *unc)
669 char *p;
671 if (unc == NULL) {
672 return NULL;
675 if ((p = strrchr(unc, '\\')) != NULL) {
676 return p+1;
679 return unc;
682 static void fill_printq_info(int uLevel,
683 struct pack_desc* desc,
684 int count,
685 union spoolss_JobInfo *job_info,
686 struct spoolss_DriverInfo3 *driver_info,
687 struct spoolss_PrinterInfo2 *printer_info)
689 switch (uLevel) {
690 case 0:
691 case 1:
692 case 2:
693 PACKS(desc,"B13", strip_unc(printer_info->printername));
694 break;
695 case 3:
696 case 4:
697 case 5:
698 PACKS(desc,"z", strip_unc(printer_info->printername));
699 break;
700 case 51:
701 PACKI(desc,"K", printq_spoolss_status(printer_info->status));
702 break;
705 if (uLevel == 1 || uLevel == 2) {
706 PACKS(desc,"B",""); /* alignment */
707 PACKI(desc,"W",5); /* priority */
708 PACKI(desc,"W",0); /* start time */
709 PACKI(desc,"W",0); /* until time */
710 PACKS(desc,"z",""); /* pSepFile */
711 PACKS(desc,"z","lpd"); /* pPrProc */
712 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pDestinations */
713 PACKS(desc,"z",""); /* pParms */
714 if (printer_info->printername == NULL) {
715 PACKS(desc,"z","UNKNOWN PRINTER");
716 PACKI(desc,"W",LPSTAT_ERROR);
717 } else {
718 PACKS(desc,"z", printer_info->comment);
719 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* status */
721 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
724 if (uLevel == 3 || uLevel == 4) {
725 PACKI(desc,"W",5); /* uPriority */
726 PACKI(desc,"W",0); /* uStarttime */
727 PACKI(desc,"W",0); /* uUntiltime */
728 PACKI(desc,"W",5); /* pad1 */
729 PACKS(desc,"z",""); /* pszSepFile */
730 PACKS(desc,"z","WinPrint"); /* pszPrProc */
731 PACKS(desc,"z",NULL); /* pszParms */
732 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
733 /* "don't ask" that it's done this way to fix corrupted
734 Win9X/ME printer comments. */
735 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* fsStatus */
736 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
737 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pszPrinters */
738 PACKS(desc,"z", printer_info->drivername); /* pszDriverName */
739 PackDriverData(desc); /* pDriverData */
742 if (uLevel == 2 || uLevel == 4) {
743 int i;
744 for (i = 0; i < count; i++) {
745 fill_spoolss_printjob_info(uLevel == 2 ? 1 : 2, desc, &job_info[i].info2, i);
749 if (uLevel==52)
750 fill_printq_info_52(driver_info, desc, count, printer_info->printername);
753 /* This function returns the number of files for a given driver */
754 static int get_printerdrivernumber(const struct spoolss_DriverInfo3 *driver)
756 int result = 0;
758 /* count the number of files */
759 while (driver->dependent_files && *driver->dependent_files[result])
760 result++;
762 return result;
765 static bool api_DosPrintQGetInfo(struct smbd_server_connection *sconn,
766 connection_struct *conn, uint64_t vuid,
767 char *param, int tpscnt,
768 char *data, int tdscnt,
769 int mdrcnt,int mprcnt,
770 char **rdata,char **rparam,
771 int *rdata_len,int *rparam_len)
773 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
774 char *str2 = skip_string(param,tpscnt,str1);
775 char *p = skip_string(param,tpscnt,str2);
776 char *QueueName = p;
777 unsigned int uLevel;
778 uint32_t count = 0;
779 char *str3;
780 struct pack_desc desc;
781 char* tmpdata=NULL;
783 WERROR werr = WERR_OK;
784 TALLOC_CTX *mem_ctx = talloc_tos();
785 NTSTATUS status;
786 struct rpc_pipe_client *cli = NULL;
787 struct dcerpc_binding_handle *b = NULL;
788 struct policy_handle handle;
789 struct spoolss_DevmodeContainer devmode_ctr;
790 union spoolss_DriverInfo driver_info;
791 union spoolss_JobInfo *job_info = NULL;
792 union spoolss_PrinterInfo printer_info;
794 if (!str1 || !str2 || !p) {
795 return False;
797 memset((char *)&desc,'\0',sizeof(desc));
799 p = skip_string(param,tpscnt,p);
800 if (!p) {
801 return False;
803 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
804 str3 = get_safe_str_ptr(param,tpscnt,p,4);
805 /* str3 may be null here and is checked in check_printq_info(). */
807 /* remove any trailing username */
808 if ((p = strchr_m(QueueName,'%')))
809 *p = 0;
811 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
813 /* check it's a supported varient */
814 if (!prefix_ok(str1,"zWrLh"))
815 return False;
816 if (!check_printq_info(&desc,uLevel,str2,str3)) {
818 * Patch from Scott Moomaw <scott@bridgewater.edu>
819 * to return the 'invalid info level' error if an
820 * unknown level was requested.
822 *rdata_len = 0;
823 *rparam_len = 6;
824 *rparam = smb_realloc_limit(*rparam,*rparam_len);
825 if (!*rparam) {
826 return False;
828 SSVALS(*rparam,0,ERRunknownlevel);
829 SSVAL(*rparam,2,0);
830 SSVAL(*rparam,4,0);
831 return(True);
834 ZERO_STRUCT(handle);
836 if (QueueName == NULL || (strlen(QueueName) < 1)) {
837 desc.errcode = W_ERROR_V(WERR_INVALID_PARAMETER);
838 goto out;
841 status = rpc_pipe_open_interface(mem_ctx,
842 &ndr_table_spoolss,
843 conn->session_info,
844 conn->sconn->remote_address,
845 conn->sconn->local_address,
846 conn->sconn->msg_ctx,
847 &cli);
848 if (!NT_STATUS_IS_OK(status)) {
849 DEBUG(0,("api_DosPrintQGetInfo: could not connect to spoolss: %s\n",
850 nt_errstr(status)));
851 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
852 goto out;
854 b = cli->binding_handle;
856 ZERO_STRUCT(devmode_ctr);
858 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
859 QueueName,
860 "RAW",
861 devmode_ctr,
862 PRINTER_ACCESS_USE,
863 &handle,
864 &werr);
865 if (!NT_STATUS_IS_OK(status)) {
866 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
867 goto out;
869 if (!W_ERROR_IS_OK(werr)) {
870 desc.errcode = W_ERROR_V(werr);
871 goto out;
874 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
875 &handle,
878 &printer_info);
879 if (!W_ERROR_IS_OK(werr)) {
880 desc.errcode = W_ERROR_V(werr);
881 goto out;
884 if (uLevel==52) {
885 uint32_t server_major_version;
886 uint32_t server_minor_version;
888 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
889 &handle,
890 "Windows 4.0",
891 3, /* level */
893 0, /* version */
895 &driver_info,
896 &server_major_version,
897 &server_minor_version);
898 if (!W_ERROR_IS_OK(werr)) {
899 desc.errcode = W_ERROR_V(werr);
900 goto out;
903 count = get_printerdrivernumber(&driver_info.info3);
904 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
905 } else {
906 uint32_t num_jobs;
907 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
908 &handle,
909 0, /* firstjob */
910 0xff, /* numjobs */
911 2, /* level */
912 0, /* offered */
913 &num_jobs,
914 &job_info);
915 if (!W_ERROR_IS_OK(werr)) {
916 desc.errcode = W_ERROR_V(werr);
917 goto out;
920 count = num_jobs;
923 if (mdrcnt > 0) {
924 *rdata = smb_realloc_limit(*rdata,mdrcnt);
925 if (!*rdata) {
926 return False;
928 desc.base = *rdata;
929 desc.buflen = mdrcnt;
930 } else {
932 * Don't return data but need to get correct length
933 * init_package will return wrong size if buflen=0
935 desc.buflen = getlen(desc.format);
936 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
939 if (init_package(&desc,1,count)) {
940 desc.subcount = count;
941 fill_printq_info(uLevel,&desc,count, job_info, &driver_info.info3, &printer_info.info2);
944 *rdata_len = desc.usedlen;
947 * We must set the return code to ERRbuftoosmall
948 * in order to support lanman style printing with Win NT/2k
949 * clients --jerry
951 if (!mdrcnt && lp_disable_spoolss())
952 desc.errcode = ERRbuftoosmall;
954 out:
955 if (b && is_valid_policy_hnd(&handle)) {
956 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
959 *rdata_len = desc.usedlen;
960 *rparam_len = 6;
961 *rparam = smb_realloc_limit(*rparam,*rparam_len);
962 if (!*rparam) {
963 SAFE_FREE(tmpdata);
964 return False;
966 SSVALS(*rparam,0,desc.errcode);
967 SSVAL(*rparam,2,0);
968 SSVAL(*rparam,4,desc.neededlen);
970 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
972 SAFE_FREE(tmpdata);
974 return(True);
977 /****************************************************************************
978 View list of all print jobs on all queues.
979 ****************************************************************************/
981 static bool api_DosPrintQEnum(struct smbd_server_connection *sconn,
982 connection_struct *conn, uint64_t vuid,
983 char *param, int tpscnt,
984 char *data, int tdscnt,
985 int mdrcnt, int mprcnt,
986 char **rdata, char** rparam,
987 int *rdata_len, int *rparam_len)
989 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
990 char *output_format1 = skip_string(param,tpscnt,param_format);
991 char *p = skip_string(param,tpscnt,output_format1);
992 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
993 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
994 int i;
995 struct pack_desc desc;
996 int *subcntarr = NULL;
997 int queuecnt = 0, subcnt = 0, succnt = 0;
999 WERROR werr = WERR_OK;
1000 TALLOC_CTX *mem_ctx = talloc_tos();
1001 NTSTATUS status;
1002 struct rpc_pipe_client *cli = NULL;
1003 struct dcerpc_binding_handle *b = NULL;
1004 struct spoolss_DevmodeContainer devmode_ctr;
1005 uint32_t num_printers;
1006 union spoolss_PrinterInfo *printer_info;
1007 union spoolss_DriverInfo *driver_info;
1008 union spoolss_JobInfo **job_info;
1010 if (!param_format || !output_format1 || !p) {
1011 return False;
1014 memset((char *)&desc,'\0',sizeof(desc));
1016 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
1018 if (!prefix_ok(param_format,"WrLeh")) {
1019 return False;
1021 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
1023 * Patch from Scott Moomaw <scott@bridgewater.edu>
1024 * to return the 'invalid info level' error if an
1025 * unknown level was requested.
1027 *rdata_len = 0;
1028 *rparam_len = 6;
1029 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1030 if (!*rparam) {
1031 return False;
1033 SSVALS(*rparam,0,ERRunknownlevel);
1034 SSVAL(*rparam,2,0);
1035 SSVAL(*rparam,4,0);
1036 return(True);
1039 status = rpc_pipe_open_interface(mem_ctx,
1040 &ndr_table_spoolss,
1041 conn->session_info,
1042 conn->sconn->remote_address,
1043 conn->sconn->local_address,
1044 conn->sconn->msg_ctx,
1045 &cli);
1046 if (!NT_STATUS_IS_OK(status)) {
1047 DEBUG(0,("api_DosPrintQEnum: could not connect to spoolss: %s\n",
1048 nt_errstr(status)));
1049 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1050 goto out;
1052 b = cli->binding_handle;
1054 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
1055 PRINTER_ENUM_LOCAL,
1056 cli->srv_name_slash,
1059 &num_printers,
1060 &printer_info);
1061 if (!W_ERROR_IS_OK(werr)) {
1062 desc.errcode = W_ERROR_V(werr);
1063 goto out;
1066 queuecnt = num_printers;
1068 job_info = talloc_array(mem_ctx, union spoolss_JobInfo *, num_printers);
1069 if (job_info == NULL) {
1070 goto err;
1073 driver_info = talloc_array(mem_ctx, union spoolss_DriverInfo, num_printers);
1074 if (driver_info == NULL) {
1075 goto err;
1078 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1079 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1080 goto err;
1083 if (mdrcnt > 0) {
1084 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1085 if (!*rdata) {
1086 goto err;
1089 desc.base = *rdata;
1090 desc.buflen = mdrcnt;
1092 subcnt = 0;
1093 for (i = 0; i < num_printers; i++) {
1095 uint32_t num_jobs;
1096 struct policy_handle handle;
1097 const char *printername;
1099 printername = talloc_strdup(mem_ctx, printer_info[i].info2.printername);
1100 if (printername == NULL) {
1101 goto err;
1104 ZERO_STRUCT(handle);
1105 ZERO_STRUCT(devmode_ctr);
1107 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
1108 printername,
1109 "RAW",
1110 devmode_ctr,
1111 PRINTER_ACCESS_USE,
1112 &handle,
1113 &werr);
1114 if (!NT_STATUS_IS_OK(status)) {
1115 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1116 goto out;
1118 if (!W_ERROR_IS_OK(werr)) {
1119 desc.errcode = W_ERROR_V(werr);
1120 goto out;
1123 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
1124 &handle,
1125 0, /* firstjob */
1126 0xff, /* numjobs */
1127 2, /* level */
1128 0, /* offered */
1129 &num_jobs,
1130 &job_info[i]);
1131 if (!W_ERROR_IS_OK(werr)) {
1132 desc.errcode = W_ERROR_V(werr);
1133 goto out;
1136 if (uLevel==52) {
1137 uint32_t server_major_version;
1138 uint32_t server_minor_version;
1140 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1141 &handle,
1142 "Windows 4.0",
1143 3, /* level */
1145 0, /* version */
1147 &driver_info[i],
1148 &server_major_version,
1149 &server_minor_version);
1150 if (!W_ERROR_IS_OK(werr)) {
1151 desc.errcode = W_ERROR_V(werr);
1152 goto out;
1156 subcntarr[i] = num_jobs;
1157 subcnt += subcntarr[i];
1159 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
1162 if (init_package(&desc,queuecnt,subcnt)) {
1163 for (i = 0; i < num_printers; i++) {
1164 fill_printq_info(uLevel,&desc,subcntarr[i], job_info[i], &driver_info[i].info3, &printer_info[i].info2);
1165 if (desc.errcode == NERR_Success) {
1166 succnt = i;
1171 out:
1172 SAFE_FREE(subcntarr);
1173 *rdata_len = desc.usedlen;
1174 *rparam_len = 8;
1175 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1176 if (!*rparam) {
1177 goto err;
1179 SSVALS(*rparam,0,desc.errcode);
1180 SSVAL(*rparam,2,0);
1181 SSVAL(*rparam,4,succnt);
1182 SSVAL(*rparam,6,queuecnt);
1184 return True;
1186 err:
1188 SAFE_FREE(subcntarr);
1190 return False;
1193 /****************************************************************************
1194 Get info level for a server list query.
1195 ****************************************************************************/
1197 static bool check_session_info(int uLevel, char* id)
1199 switch( uLevel ) {
1200 case 0:
1201 if (strcmp(id,"B16") != 0) {
1202 return False;
1204 break;
1205 case 1:
1206 if (strcmp(id,"B16BBDz") != 0) {
1207 return False;
1209 break;
1210 default:
1211 return False;
1213 return True;
1216 struct srv_info_struct {
1217 fstring name;
1218 uint32_t type;
1219 fstring comment;
1220 fstring domain;
1221 bool server_added;
1224 /*******************************************************************
1225 Get server info lists from the files saved by nmbd. Return the
1226 number of entries.
1227 ******************************************************************/
1229 static int get_session_info(uint32_t servertype,
1230 struct srv_info_struct **servers,
1231 const char *domain)
1233 int count=0;
1234 int alloced=0;
1235 char **lines;
1236 bool local_list_only;
1237 int i;
1238 char *slist_cache_path = cache_path(talloc_tos(), SERVER_LIST);
1239 if (slist_cache_path == NULL) {
1240 return 0;
1243 lines = file_lines_load(slist_cache_path, NULL, 0, NULL);
1244 if (!lines) {
1245 DEBUG(4, ("Can't open %s - %s\n",
1246 slist_cache_path, strerror(errno)));
1247 TALLOC_FREE(slist_cache_path);
1248 return 0;
1250 TALLOC_FREE(slist_cache_path);
1252 /* request for everything is code for request all servers */
1253 if (servertype == SV_TYPE_ALL) {
1254 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1257 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1259 DEBUG(4,("Servertype search: %8x\n",servertype));
1261 for (i=0;lines[i];i++) {
1262 fstring stype;
1263 struct srv_info_struct *s;
1264 const char *ptr = lines[i];
1265 bool ok = True;
1266 TALLOC_CTX *frame = NULL;
1267 char *p;
1269 if (!*ptr) {
1270 continue;
1273 if (count == alloced) {
1274 alloced += 10;
1275 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1276 if (!*servers) {
1277 DEBUG(0,("get_session_info: failed to enlarge servers info struct!\n"));
1278 TALLOC_FREE(lines);
1279 return 0;
1281 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1283 s = &(*servers)[count];
1285 frame = talloc_stackframe();
1286 s->name[0] = '\0';
1287 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1288 TALLOC_FREE(frame);
1289 continue;
1291 fstrcpy(s->name, p);
1293 stype[0] = '\0';
1294 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1295 TALLOC_FREE(frame);
1296 continue;
1298 fstrcpy(stype, p);
1300 s->comment[0] = '\0';
1301 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1302 TALLOC_FREE(frame);
1303 continue;
1305 fstrcpy(s->comment, p);
1306 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1308 s->domain[0] = '\0';
1309 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1310 /* this allows us to cope with an old nmbd */
1311 fstrcpy(s->domain,lp_workgroup());
1312 } else {
1313 fstrcpy(s->domain, p);
1315 TALLOC_FREE(frame);
1317 if (sscanf(stype,"%X",&s->type) != 1) {
1318 DEBUG(4,("r:host file "));
1319 ok = False;
1322 /* Filter the servers/domains we return based on what was asked for. */
1324 /* Check to see if we are being asked for a local list only. */
1325 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1326 DEBUG(4,("r: local list only"));
1327 ok = False;
1330 /* doesn't match up: don't want it */
1331 if (!(servertype & s->type)) {
1332 DEBUG(4,("r:serv type "));
1333 ok = False;
1336 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1337 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1338 DEBUG(4,("s: dom mismatch "));
1339 ok = False;
1342 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1343 ok = False;
1346 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1347 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1349 if (ok) {
1350 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1351 s->name, s->type, s->comment, s->domain));
1352 s->server_added = True;
1353 count++;
1354 } else {
1355 DEBUG(4,("%20s %8x %25s %15s\n",
1356 s->name, s->type, s->comment, s->domain));
1360 TALLOC_FREE(lines);
1361 return count;
1364 /*******************************************************************
1365 Fill in a server info structure.
1366 ******************************************************************/
1368 static int fill_srv_info(struct srv_info_struct *service,
1369 int uLevel, char **buf, int *buflen,
1370 char **stringbuf, int *stringspace, char *baseaddr)
1372 int struct_len;
1373 char* p;
1374 char* p2;
1375 int l2;
1376 int len;
1378 switch (uLevel) {
1379 case 0:
1380 struct_len = 16;
1381 break;
1382 case 1:
1383 struct_len = 26;
1384 break;
1385 default:
1386 return -1;
1389 if (!buf) {
1390 len = 0;
1391 switch (uLevel) {
1392 case 1:
1393 len = strlen(service->comment)+1;
1394 break;
1397 *buflen = struct_len;
1398 *stringspace = len;
1399 return struct_len + len;
1402 len = struct_len;
1403 p = *buf;
1404 if (*buflen < struct_len) {
1405 return -1;
1407 if (stringbuf) {
1408 p2 = *stringbuf;
1409 l2 = *stringspace;
1410 } else {
1411 p2 = p + struct_len;
1412 l2 = *buflen - struct_len;
1414 if (!baseaddr) {
1415 baseaddr = p;
1418 switch (uLevel) {
1419 case 0:
1420 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1421 break;
1423 case 1:
1424 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1425 SIVAL(p,18,service->type);
1426 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1427 len += CopyAndAdvance(&p2,service->comment,&l2);
1428 break;
1431 if (stringbuf) {
1432 *buf = p + struct_len;
1433 *buflen -= struct_len;
1434 *stringbuf = p2;
1435 *stringspace = l2;
1436 } else {
1437 *buf = p2;
1438 *buflen -= len;
1440 return len;
1444 static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1446 return strcasecmp_m(s1->name,s2->name);
1449 /****************************************************************************
1450 View list of servers available (or possibly domains). The info is
1451 extracted from lists saved by nmbd on the local host.
1452 ****************************************************************************/
1454 static bool api_RNetServerEnum2(struct smbd_server_connection *sconn,
1455 connection_struct *conn, uint64_t vuid,
1456 char *param, int tpscnt,
1457 char *data, int tdscnt,
1458 int mdrcnt, int mprcnt, char **rdata,
1459 char **rparam, int *rdata_len, int *rparam_len)
1461 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1462 char *str2 = skip_string(param,tpscnt,str1);
1463 char *p = skip_string(param,tpscnt,str2);
1464 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1465 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1466 uint32_t servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1467 char *p2;
1468 int data_len, fixed_len, string_len;
1469 int f_len = 0, s_len = 0;
1470 struct srv_info_struct *servers=NULL;
1471 int counted=0,total=0;
1472 int i,missed;
1473 fstring domain;
1474 bool domain_request;
1475 bool local_request;
1477 if (!str1 || !str2 || !p) {
1478 return False;
1481 /* If someone sets all the bits they don't really mean to set
1482 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1483 known servers. */
1485 if (servertype == SV_TYPE_ALL) {
1486 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1489 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1490 any other bit (they may just set this bit on its own) they
1491 want all the locally seen servers. However this bit can be
1492 set on its own so set the requested servers to be
1493 ALL - DOMAIN_ENUM. */
1495 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1496 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1499 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1500 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1502 p += 8;
1504 if (!prefix_ok(str1,"WrLehD")) {
1505 return False;
1507 if (!check_session_info(uLevel,str2)) {
1508 return False;
1511 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1512 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1513 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1515 if (strcmp(str1, "WrLehDz") == 0) {
1516 if (skip_string(param,tpscnt,p) == NULL) {
1517 return False;
1519 pull_ascii_fstring(domain, p);
1520 } else {
1521 fstrcpy(domain, lp_workgroup());
1524 DEBUG(4, ("domain [%s]\n", domain));
1526 if (lp_browse_list()) {
1527 total = get_session_info(servertype,&servers,domain);
1530 data_len = fixed_len = string_len = 0;
1531 missed = 0;
1533 TYPESAFE_QSORT(servers, total, srv_comp);
1536 char *lastname=NULL;
1538 for (i=0;i<total;i++) {
1539 struct srv_info_struct *s = &servers[i];
1541 if (lastname && strequal(lastname,s->name)) {
1542 continue;
1544 lastname = s->name;
1545 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1546 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1547 i, s->name, s->type, s->comment, s->domain));
1549 if (data_len < buf_len) {
1550 counted++;
1551 fixed_len += f_len;
1552 string_len += s_len;
1553 } else {
1554 missed++;
1559 *rdata_len = fixed_len + string_len;
1560 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1561 if (!*rdata) {
1562 return False;
1565 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1566 p = *rdata;
1567 f_len = fixed_len;
1568 s_len = string_len;
1571 char *lastname=NULL;
1572 int count2 = counted;
1574 for (i = 0; i < total && count2;i++) {
1575 struct srv_info_struct *s = &servers[i];
1577 if (lastname && strequal(lastname,s->name)) {
1578 continue;
1580 lastname = s->name;
1581 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1582 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1583 i, s->name, s->type, s->comment, s->domain));
1584 count2--;
1588 *rparam_len = 8;
1589 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1590 if (!*rparam) {
1591 return False;
1593 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1594 SSVAL(*rparam,2,0);
1595 SSVAL(*rparam,4,counted);
1596 SSVAL(*rparam,6,counted+missed);
1598 SAFE_FREE(servers);
1600 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1601 domain,uLevel,counted,counted+missed));
1603 return True;
1606 static int srv_name_match(const char *n1, const char *n2)
1609 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1611 * In Windows, FirstNameToReturn need not be an exact match:
1612 * the server will return a list of servers that exist on
1613 * the network greater than or equal to the FirstNameToReturn.
1615 int ret = strcasecmp_m(n1, n2);
1617 if (ret <= 0) {
1618 return 0;
1621 return ret;
1624 static bool api_RNetServerEnum3(struct smbd_server_connection *sconn,
1625 connection_struct *conn, uint64_t vuid,
1626 char *param, int tpscnt,
1627 char *data, int tdscnt,
1628 int mdrcnt, int mprcnt, char **rdata,
1629 char **rparam, int *rdata_len, int *rparam_len)
1631 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1632 char *str2 = skip_string(param,tpscnt,str1);
1633 char *p = skip_string(param,tpscnt,str2);
1634 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1635 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1636 uint32_t servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1637 char *p2;
1638 int data_len, fixed_len, string_len;
1639 int f_len = 0, s_len = 0;
1640 struct srv_info_struct *servers=NULL;
1641 int counted=0,first=0,total=0;
1642 int i,missed;
1643 fstring domain;
1644 fstring first_name;
1645 bool domain_request;
1646 bool local_request;
1648 if (!str1 || !str2 || !p) {
1649 return False;
1652 /* If someone sets all the bits they don't really mean to set
1653 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1654 known servers. */
1656 if (servertype == SV_TYPE_ALL) {
1657 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1660 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1661 any other bit (they may just set this bit on its own) they
1662 want all the locally seen servers. However this bit can be
1663 set on its own so set the requested servers to be
1664 ALL - DOMAIN_ENUM. */
1666 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1667 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1670 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1671 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1673 p += 8;
1675 if (strcmp(str1, "WrLehDzz") != 0) {
1676 return false;
1678 if (!check_session_info(uLevel,str2)) {
1679 return False;
1682 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1683 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1684 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1686 if (skip_string(param,tpscnt,p) == NULL) {
1687 return False;
1689 pull_ascii_fstring(domain, p);
1690 if (domain[0] == '\0') {
1691 fstrcpy(domain, lp_workgroup());
1693 p = skip_string(param,tpscnt,p);
1694 if (skip_string(param,tpscnt,p) == NULL) {
1695 return False;
1697 pull_ascii_fstring(first_name, p);
1699 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1700 domain, first_name));
1702 if (lp_browse_list()) {
1703 total = get_session_info(servertype,&servers,domain);
1706 data_len = fixed_len = string_len = 0;
1707 missed = 0;
1709 TYPESAFE_QSORT(servers, total, srv_comp);
1711 if (first_name[0] != '\0') {
1712 struct srv_info_struct *first_server = NULL;
1714 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1715 srv_name_match, first_server);
1716 if (first_server) {
1717 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1719 * The binary search may not find the exact match
1720 * so we need to search backward to find the first match
1722 * This implements the strange matching windows
1723 * implements. (see the comment in srv_name_match().
1725 for (;first > 0;) {
1726 int ret;
1727 ret = strcasecmp_m(first_name,
1728 servers[first-1].name);
1729 if (ret > 0) {
1730 break;
1732 first--;
1734 } else {
1735 /* we should return no entries */
1736 first = total;
1741 char *lastname=NULL;
1743 for (i=first;i<total;i++) {
1744 struct srv_info_struct *s = &servers[i];
1746 if (lastname && strequal(lastname,s->name)) {
1747 continue;
1749 lastname = s->name;
1750 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1751 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1752 i, s->name, s->type, s->comment, s->domain));
1754 if (data_len < buf_len) {
1755 counted++;
1756 fixed_len += f_len;
1757 string_len += s_len;
1758 } else {
1759 missed++;
1764 *rdata_len = fixed_len + string_len;
1765 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1766 if (!*rdata) {
1767 return False;
1770 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1771 p = *rdata;
1772 f_len = fixed_len;
1773 s_len = string_len;
1776 char *lastname=NULL;
1777 int count2 = counted;
1779 for (i = first; i < total && count2;i++) {
1780 struct srv_info_struct *s = &servers[i];
1782 if (lastname && strequal(lastname,s->name)) {
1783 continue;
1785 lastname = s->name;
1786 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1787 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1788 i, s->name, s->type, s->comment, s->domain));
1789 count2--;
1793 *rparam_len = 8;
1794 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1795 if (!*rparam) {
1796 return False;
1798 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1799 SSVAL(*rparam,2,0);
1800 SSVAL(*rparam,4,counted);
1801 SSVAL(*rparam,6,counted+missed);
1803 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1804 domain,uLevel,first,first_name,
1805 first < total ? servers[first].name : "",
1806 counted,counted+missed));
1808 SAFE_FREE(servers);
1810 return True;
1813 /****************************************************************************
1814 command 0x34 - suspected of being a "Lookup Names" stub api
1815 ****************************************************************************/
1817 static bool api_RNetGroupGetUsers(struct smbd_server_connection *sconn,
1818 connection_struct *conn, uint64_t vuid,
1819 char *param, int tpscnt,
1820 char *data, int tdscnt,
1821 int mdrcnt, int mprcnt, char **rdata,
1822 char **rparam, int *rdata_len, int *rparam_len)
1824 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1825 char *str2 = skip_string(param,tpscnt,str1);
1826 char *p = skip_string(param,tpscnt,str2);
1827 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1828 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1829 int counted=0;
1830 int missed=0;
1832 if (!str1 || !str2 || !p) {
1833 return False;
1836 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1837 str1, str2, p, uLevel, buf_len));
1839 if (!prefix_ok(str1,"zWrLeh")) {
1840 return False;
1843 *rdata_len = 0;
1845 *rparam_len = 8;
1846 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1847 if (!*rparam) {
1848 return False;
1851 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1852 SSVAL(*rparam,2,0);
1853 SSVAL(*rparam,4,counted);
1854 SSVAL(*rparam,6,counted+missed);
1856 return True;
1859 /****************************************************************************
1860 get info about a share
1861 ****************************************************************************/
1863 static bool check_share_info(int uLevel, char* id)
1865 switch( uLevel ) {
1866 case 0:
1867 if (strcmp(id,"B13") != 0) {
1868 return False;
1870 break;
1871 case 1:
1872 /* Level-2 descriptor is allowed (and ignored) */
1873 if (strcmp(id,"B13BWz") != 0 &&
1874 strcmp(id,"B13BWzWWWzB9B") != 0) {
1875 return False;
1877 break;
1878 case 2:
1879 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1880 return False;
1882 break;
1883 case 91:
1884 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1885 return False;
1887 break;
1888 default:
1889 return False;
1891 return True;
1894 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1895 char** buf, int* buflen,
1896 char** stringbuf, int* stringspace, char* baseaddr)
1898 const struct loadparm_substitution *lp_sub =
1899 loadparm_s3_global_substitution();
1900 int struct_len;
1901 char* p;
1902 char* p2;
1903 int l2;
1904 int len;
1906 switch( uLevel ) {
1907 case 0:
1908 struct_len = 13;
1909 break;
1910 case 1:
1911 struct_len = 20;
1912 break;
1913 case 2:
1914 struct_len = 40;
1915 break;
1916 case 91:
1917 struct_len = 68;
1918 break;
1919 default:
1920 return -1;
1923 if (!buf) {
1924 len = 0;
1926 if (uLevel > 0) {
1927 len += StrlenExpanded(conn,snum,lp_comment(talloc_tos(), lp_sub, snum));
1929 if (uLevel > 1) {
1930 len += strlen(lp_path(talloc_tos(), lp_sub, snum)) + 1;
1932 if (buflen) {
1933 *buflen = struct_len;
1935 if (stringspace) {
1936 *stringspace = len;
1938 return struct_len + len;
1941 len = struct_len;
1942 p = *buf;
1943 if ((*buflen) < struct_len) {
1944 return -1;
1947 if (stringbuf) {
1948 p2 = *stringbuf;
1949 l2 = *stringspace;
1950 } else {
1951 p2 = p + struct_len;
1952 l2 = (*buflen) - struct_len;
1955 if (!baseaddr) {
1956 baseaddr = p;
1959 push_ascii(p,lp_servicename(talloc_tos(), lp_sub, snum),13, STR_TERMINATE);
1961 if (uLevel > 0) {
1962 int type;
1964 SCVAL(p,13,0);
1965 type = STYPE_DISKTREE;
1966 if (lp_printable(snum)) {
1967 type = STYPE_PRINTQ;
1969 if (strequal("IPC",lp_fstype(snum))) {
1970 type = STYPE_IPC;
1972 SSVAL(p,14,type); /* device type */
1973 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1974 len += CopyExpanded(conn,snum,&p2,lp_comment(talloc_tos(), lp_sub, snum),&l2);
1977 if (uLevel > 1) {
1978 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1979 SSVALS(p,22,-1); /* max uses */
1980 SSVAL(p,24,1); /* current uses */
1981 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1982 len += CopyAndAdvance(&p2,lp_path(talloc_tos(),lp_sub, snum),&l2);
1983 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1986 if (uLevel > 2) {
1987 memset(p+40,0,SHPWLEN+2);
1988 SSVAL(p,50,0);
1989 SIVAL(p,52,0);
1990 SSVAL(p,56,0);
1991 SSVAL(p,58,0);
1992 SIVAL(p,60,0);
1993 SSVAL(p,64,0);
1994 SSVAL(p,66,0);
1997 if (stringbuf) {
1998 (*buf) = p + struct_len;
1999 (*buflen) -= struct_len;
2000 (*stringbuf) = p2;
2001 (*stringspace) = l2;
2002 } else {
2003 (*buf) = p2;
2004 (*buflen) -= len;
2007 return len;
2010 static bool api_RNetShareGetInfo(struct smbd_server_connection *sconn,
2011 connection_struct *conn,uint64_t vuid,
2012 char *param, int tpscnt,
2013 char *data, int tdscnt,
2014 int mdrcnt,int mprcnt,
2015 char **rdata,char **rparam,
2016 int *rdata_len,int *rparam_len)
2018 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2019 char *str2 = skip_string(param,tpscnt,str1);
2020 char *netname_in = skip_string(param,tpscnt,str2);
2021 char *netname = NULL;
2022 char *p = skip_string(param,tpscnt,netname);
2023 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2024 int snum;
2026 if (!str1 || !str2 || !netname_in || !p) {
2027 return False;
2030 snum = find_service(talloc_tos(), netname_in, &netname);
2031 if (snum < 0 || !netname) {
2032 return False;
2035 /* check it's a supported varient */
2036 if (!prefix_ok(str1,"zWrLh")) {
2037 return False;
2039 if (!check_share_info(uLevel,str2)) {
2040 return False;
2043 *rdata = smb_realloc_limit(*rdata,mdrcnt);
2044 if (!*rdata) {
2045 return False;
2047 p = *rdata;
2048 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
2049 if (*rdata_len < 0) {
2050 return False;
2053 *rparam_len = 6;
2054 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2055 if (!*rparam) {
2056 return False;
2058 SSVAL(*rparam,0,NERR_Success);
2059 SSVAL(*rparam,2,0); /* converter word */
2060 SSVAL(*rparam,4,*rdata_len);
2062 return True;
2065 /****************************************************************************
2066 View the list of available shares.
2068 This function is the server side of the NetShareEnum() RAP call.
2069 It fills the return buffer with share names and share comments.
2070 Note that the return buffer normally (in all known cases) allows only
2071 twelve byte strings for share names (plus one for a nul terminator).
2072 Share names longer than 12 bytes must be skipped.
2073 ****************************************************************************/
2075 static bool api_RNetShareEnum(struct smbd_server_connection *sconn,
2076 connection_struct *conn, uint64_t vuid,
2077 char *param, int tpscnt,
2078 char *data, int tdscnt,
2079 int mdrcnt,
2080 int mprcnt,
2081 char **rdata,
2082 char **rparam,
2083 int *rdata_len,
2084 int *rparam_len )
2086 const struct loadparm_substitution *lp_sub =
2087 loadparm_s3_global_substitution();
2088 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2089 char *str2 = skip_string(param,tpscnt,str1);
2090 char *p = skip_string(param,tpscnt,str2);
2091 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2092 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
2093 char *p2;
2094 int count = 0;
2095 int total=0,counted=0;
2096 bool missed = False;
2097 int i;
2098 int data_len, fixed_len, string_len;
2099 int f_len = 0, s_len = 0;
2101 if (!str1 || !str2 || !p) {
2102 return False;
2105 if (!prefix_ok(str1,"WrLeh")) {
2106 return False;
2108 if (!check_share_info(uLevel,str2)) {
2109 return False;
2112 /* Ensure all the usershares are loaded. */
2113 become_root();
2114 delete_and_reload_printers();
2115 load_registry_shares();
2116 count = load_usershare_shares(NULL, connections_snum_used);
2117 unbecome_root();
2119 data_len = fixed_len = string_len = 0;
2120 for (i=0;i<count;i++) {
2121 fstring servicename_dos;
2122 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2123 continue;
2125 push_ascii_fstring(servicename_dos, lp_servicename(talloc_tos(), lp_sub, i));
2126 /* Maximum name length = 13. */
2127 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
2128 total++;
2129 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
2130 if (data_len < buf_len) {
2131 counted++;
2132 fixed_len += f_len;
2133 string_len += s_len;
2134 } else {
2135 missed = True;
2140 *rdata_len = fixed_len + string_len;
2141 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2142 if (!*rdata) {
2143 return False;
2146 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
2147 p = *rdata;
2148 f_len = fixed_len;
2149 s_len = string_len;
2151 for( i = 0; i < count; i++ ) {
2152 fstring servicename_dos;
2153 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2154 continue;
2157 push_ascii_fstring(servicename_dos,
2158 lp_servicename(talloc_tos(), lp_sub, i));
2159 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2160 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2161 break;
2166 *rparam_len = 8;
2167 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2168 if (!*rparam) {
2169 return False;
2171 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2172 SSVAL(*rparam,2,0);
2173 SSVAL(*rparam,4,counted);
2174 SSVAL(*rparam,6,total);
2176 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2177 counted,total,uLevel,
2178 buf_len,*rdata_len,mdrcnt));
2180 return True;
2183 /****************************************************************************
2184 Add a share
2185 ****************************************************************************/
2187 static bool api_RNetShareAdd(struct smbd_server_connection *sconn,
2188 connection_struct *conn,uint64_t vuid,
2189 char *param, int tpscnt,
2190 char *data, int tdscnt,
2191 int mdrcnt,int mprcnt,
2192 char **rdata,char **rparam,
2193 int *rdata_len,int *rparam_len)
2195 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2196 char *str2 = skip_string(param,tpscnt,str1);
2197 char *p = skip_string(param,tpscnt,str2);
2198 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2199 fstring sharename;
2200 fstring comment;
2201 char *pathname = NULL;
2202 unsigned int offset;
2203 int res = ERRunsup;
2204 size_t converted_size;
2206 WERROR werr = WERR_OK;
2207 TALLOC_CTX *mem_ctx = talloc_tos();
2208 NTSTATUS status;
2209 struct rpc_pipe_client *cli = NULL;
2210 union srvsvc_NetShareInfo info;
2211 struct srvsvc_NetShareInfo2 info2;
2212 struct dcerpc_binding_handle *b;
2214 if (!str1 || !str2 || !p) {
2215 return False;
2218 /* check it's a supported varient */
2219 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2220 return False;
2222 if (!check_share_info(uLevel,str2)) {
2223 return False;
2225 if (uLevel != 2) {
2226 return False;
2229 /* Do we have a string ? */
2230 if (skip_string(data,mdrcnt,data) == NULL) {
2231 return False;
2233 pull_ascii_fstring(sharename,data);
2235 if (mdrcnt < 28) {
2236 return False;
2239 /* only support disk share adds */
2240 if (SVAL(data,14)!=STYPE_DISKTREE) {
2241 return False;
2244 offset = IVAL(data, 16);
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;
2254 pull_ascii_fstring(comment, offset? (data+offset) : "");
2256 offset = IVAL(data, 26);
2258 if (offset >= mdrcnt) {
2259 res = ERRinvalidparam;
2260 goto out;
2263 /* Do we have a string ? */
2264 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2265 return False;
2268 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2269 offset ? (data+offset) : "", &converted_size))
2271 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
2272 strerror(errno)));
2275 if (!pathname) {
2276 return false;
2279 status = rpc_pipe_open_interface(mem_ctx, &ndr_table_srvsvc,
2280 conn->session_info,
2281 conn->sconn->remote_address,
2282 conn->sconn->local_address,
2283 conn->sconn->msg_ctx,
2284 &cli);
2285 if (!NT_STATUS_IS_OK(status)) {
2286 DEBUG(0,("api_RNetShareAdd: could not connect to srvsvc: %s\n",
2287 nt_errstr(status)));
2288 res = W_ERROR_V(ntstatus_to_werror(status));
2289 goto out;
2292 b = cli->binding_handle;
2294 info2.name = sharename;
2295 info2.type = STYPE_DISKTREE;
2296 info2.comment = comment;
2297 info2.permissions = 0;
2298 info2.max_users = 0;
2299 info2.current_users = 0;
2300 info2.path = pathname;
2301 info2.password = NULL;
2303 info.info2 = &info2;
2305 status = dcerpc_srvsvc_NetShareAdd(b, mem_ctx,
2306 cli->srv_name_slash,
2308 &info,
2309 NULL,
2310 &werr);
2311 if (!NT_STATUS_IS_OK(status)) {
2312 res = W_ERROR_V(ntstatus_to_werror(status));
2313 goto out;
2315 if (!W_ERROR_IS_OK(werr)) {
2316 res = W_ERROR_V(werr);
2317 goto out;
2320 *rparam_len = 6;
2321 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2322 if (!*rparam) {
2323 return False;
2325 SSVAL(*rparam,0,NERR_Success);
2326 SSVAL(*rparam,2,0); /* converter word */
2327 SSVAL(*rparam,4,*rdata_len);
2328 *rdata_len = 0;
2330 return True;
2332 out:
2334 *rparam_len = 4;
2335 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2336 if (!*rparam) {
2337 return False;
2339 *rdata_len = 0;
2340 SSVAL(*rparam,0,res);
2341 SSVAL(*rparam,2,0);
2342 return True;
2345 /****************************************************************************
2346 view list of groups available
2347 ****************************************************************************/
2349 static bool api_RNetGroupEnum(struct smbd_server_connection *sconn,
2350 connection_struct *conn,uint64_t vuid,
2351 char *param, int tpscnt,
2352 char *data, int tdscnt,
2353 int mdrcnt,int mprcnt,
2354 char **rdata,char **rparam,
2355 int *rdata_len,int *rparam_len)
2357 int i;
2358 int errflags=0;
2359 int resume_context, cli_buf_size;
2360 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2361 char *str2 = skip_string(param,tpscnt,str1);
2362 char *p = skip_string(param,tpscnt,str2);
2364 uint32_t num_groups;
2365 uint32_t resume_handle;
2366 struct rpc_pipe_client *samr_pipe = NULL;
2367 struct policy_handle samr_handle, domain_handle;
2368 NTSTATUS status, result;
2369 struct dcerpc_binding_handle *b;
2371 if (!str1 || !str2 || !p) {
2372 return False;
2375 if (strcmp(str1,"WrLeh") != 0) {
2376 return False;
2379 /* parameters
2380 * W-> resume context (number of users to skip)
2381 * r -> return parameter pointer to receive buffer
2382 * L -> length of receive buffer
2383 * e -> return parameter number of entries
2384 * h -> return parameter total number of users
2387 if (strcmp("B21",str2) != 0) {
2388 return False;
2391 status = rpc_pipe_open_interface(
2392 talloc_tos(), &ndr_table_samr,
2393 conn->session_info, conn->sconn->remote_address,
2394 conn->sconn->local_address, conn->sconn->msg_ctx, &samr_pipe);
2395 if (!NT_STATUS_IS_OK(status)) {
2396 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2397 nt_errstr(status)));
2398 return false;
2401 b = samr_pipe->binding_handle;
2403 status = dcerpc_samr_Connect2(b, talloc_tos(), lp_netbios_name(),
2404 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle,
2405 &result);
2406 if (!NT_STATUS_IS_OK(status)) {
2407 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2408 nt_errstr(status)));
2409 return false;
2411 if (!NT_STATUS_IS_OK(result)) {
2412 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2413 nt_errstr(result)));
2414 return false;
2417 status = dcerpc_samr_OpenDomain(b, talloc_tos(), &samr_handle,
2418 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2419 get_global_sam_sid(), &domain_handle,
2420 &result);
2421 if (!NT_STATUS_IS_OK(status)) {
2422 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2423 nt_errstr(status)));
2424 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2425 return false;
2427 if (!NT_STATUS_IS_OK(result)) {
2428 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2429 nt_errstr(result)));
2430 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2431 return false;
2434 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2435 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2436 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2437 "%d\n", resume_context, cli_buf_size));
2439 *rdata_len = cli_buf_size;
2440 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2441 if (!*rdata) {
2442 return False;
2445 p = *rdata;
2447 errflags = NERR_Success;
2448 num_groups = 0;
2449 resume_handle = 0;
2451 while (true) {
2452 struct samr_SamArray *sam_entries;
2453 uint32_t num_entries;
2455 status = dcerpc_samr_EnumDomainGroups(b, talloc_tos(),
2456 &domain_handle,
2457 &resume_handle,
2458 &sam_entries, 1,
2459 &num_entries,
2460 &result);
2461 if (!NT_STATUS_IS_OK(status)) {
2462 DEBUG(10, ("dcerpc_samr_EnumDomainGroups returned "
2463 "%s\n", nt_errstr(status)));
2464 break;
2466 if (!NT_STATUS_IS_OK(result)) {
2467 status = result;
2468 DEBUG(10, ("dcerpc_samr_EnumDomainGroups returned "
2469 "%s\n", nt_errstr(result)));
2470 break;
2473 if (num_entries == 0) {
2474 DEBUG(10, ("dcerpc_samr_EnumDomainGroups returned "
2475 "no entries -- done\n"));
2476 break;
2479 for(i=0; i<num_entries; i++) {
2480 const char *name;
2482 name = sam_entries->entries[i].name.string;
2484 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2485 /* set overflow error */
2486 DEBUG(3,("overflow on entry %d group %s\n", i,
2487 name));
2488 errflags=234;
2489 break;
2492 /* truncate the name at 21 chars. */
2493 memset(p, 0, 21);
2494 strlcpy(p, name, 21);
2495 DEBUG(10,("adding entry %d group %s\n", i, p));
2496 p += 21;
2497 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2498 * idea why... */
2499 num_groups += 1;
2502 if (errflags != NERR_Success) {
2503 break;
2506 TALLOC_FREE(sam_entries);
2509 dcerpc_samr_Close(b, talloc_tos(), &domain_handle, &result);
2510 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2512 *rdata_len = PTR_DIFF(p,*rdata);
2514 *rparam_len = 8;
2515 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2516 if (!*rparam) {
2517 return False;
2519 SSVAL(*rparam, 0, errflags);
2520 SSVAL(*rparam, 2, 0); /* converter word */
2521 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2522 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2524 return(True);
2527 /*******************************************************************
2528 Get groups that a user is a member of.
2529 ******************************************************************/
2531 static bool api_NetUserGetGroups(struct smbd_server_connection *sconn,
2532 connection_struct *conn,uint64_t vuid,
2533 char *param, int tpscnt,
2534 char *data, int tdscnt,
2535 int mdrcnt,int mprcnt,
2536 char **rdata,char **rparam,
2537 int *rdata_len,int *rparam_len)
2539 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2540 char *str2 = skip_string(param,tpscnt,str1);
2541 char *UserName = skip_string(param,tpscnt,str2);
2542 char *p = skip_string(param,tpscnt,UserName);
2543 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2544 const char *level_string;
2545 int count=0;
2546 bool ret = False;
2547 uint32_t i;
2548 char *endp = NULL;
2550 struct rpc_pipe_client *samr_pipe = NULL;
2551 struct policy_handle samr_handle, domain_handle, user_handle;
2552 struct lsa_String name;
2553 struct lsa_Strings names;
2554 struct samr_Ids type, rid;
2555 struct samr_RidWithAttributeArray *rids;
2556 NTSTATUS status, result;
2557 struct dcerpc_binding_handle *b;
2559 if (!str1 || !str2 || !UserName || !p) {
2560 return False;
2563 *rparam_len = 8;
2564 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2565 if (!*rparam) {
2566 return False;
2569 /* check it's a supported varient */
2571 if ( strcmp(str1,"zWrLeh") != 0 )
2572 return False;
2574 switch( uLevel ) {
2575 case 0:
2576 level_string = "B21";
2577 break;
2578 default:
2579 return False;
2582 if (strcmp(level_string,str2) != 0)
2583 return False;
2585 *rdata_len = mdrcnt + 1024;
2586 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2587 if (!*rdata) {
2588 return False;
2591 SSVAL(*rparam,0,NERR_Success);
2592 SSVAL(*rparam,2,0); /* converter word */
2594 p = *rdata;
2595 endp = *rdata + *rdata_len;
2597 status = rpc_pipe_open_interface(
2598 talloc_tos(), &ndr_table_samr,
2599 conn->session_info, conn->sconn->remote_address,
2600 conn->sconn->local_address, conn->sconn->msg_ctx, &samr_pipe);
2601 if (!NT_STATUS_IS_OK(status)) {
2602 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2603 nt_errstr(status)));
2604 return false;
2607 b = samr_pipe->binding_handle;
2609 status = dcerpc_samr_Connect2(b, talloc_tos(), lp_netbios_name(),
2610 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle,
2611 &result);
2612 if (!NT_STATUS_IS_OK(status)) {
2613 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2614 nt_errstr(status)));
2615 return false;
2617 if (!NT_STATUS_IS_OK(result)) {
2618 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2619 nt_errstr(result)));
2620 return false;
2623 status = dcerpc_samr_OpenDomain(b, talloc_tos(), &samr_handle,
2624 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2625 get_global_sam_sid(), &domain_handle,
2626 &result);
2627 if (!NT_STATUS_IS_OK(status)) {
2628 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2629 nt_errstr(status)));
2630 goto close_sam;
2632 if (!NT_STATUS_IS_OK(result)) {
2633 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2634 nt_errstr(result)));
2635 goto close_sam;
2638 name.string = UserName;
2640 status = dcerpc_samr_LookupNames(b, talloc_tos(),
2641 &domain_handle, 1, &name,
2642 &rid, &type,
2643 &result);
2644 if (!NT_STATUS_IS_OK(status)) {
2645 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2646 nt_errstr(status)));
2647 goto close_domain;
2649 if (!NT_STATUS_IS_OK(result)) {
2650 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2651 nt_errstr(result)));
2652 goto close_domain;
2654 if (rid.count != 1) {
2655 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2656 goto close_domain;
2658 if (type.count != 1) {
2659 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2660 goto close_domain;
2663 if (type.ids[0] != SID_NAME_USER) {
2664 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2665 sid_type_lookup(type.ids[0])));
2666 goto close_domain;
2669 status = dcerpc_samr_OpenUser(b, talloc_tos(),
2670 &domain_handle,
2671 SAMR_USER_ACCESS_GET_GROUPS,
2672 rid.ids[0], &user_handle,
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_domain;
2679 if (!NT_STATUS_IS_OK(result)) {
2680 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2681 nt_errstr(result)));
2682 goto close_domain;
2685 status = dcerpc_samr_GetGroupsForUser(b, talloc_tos(),
2686 &user_handle, &rids,
2687 &result);
2688 if (!NT_STATUS_IS_OK(status)) {
2689 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2690 nt_errstr(status)));
2691 goto close_user;
2693 if (!NT_STATUS_IS_OK(result)) {
2694 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2695 nt_errstr(result)));
2696 goto close_user;
2699 for (i=0; i<rids->count; i++) {
2701 status = dcerpc_samr_LookupRids(b, talloc_tos(),
2702 &domain_handle,
2703 1, &rids->rids[i].rid,
2704 &names, &type,
2705 &result);
2706 if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result) && (names.count == 1)) {
2707 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2708 p += 21;
2709 count++;
2713 *rdata_len = PTR_DIFF(p,*rdata);
2715 SSVAL(*rparam,4,count); /* is this right?? */
2716 SSVAL(*rparam,6,count); /* is this right?? */
2718 ret = True;
2720 close_user:
2721 dcerpc_samr_Close(b, talloc_tos(), &user_handle, &result);
2722 close_domain:
2723 dcerpc_samr_Close(b, talloc_tos(), &domain_handle, &result);
2724 close_sam:
2725 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2727 return ret;
2730 /*******************************************************************
2731 Get all users.
2732 ******************************************************************/
2734 static bool api_RNetUserEnum(struct smbd_server_connection *sconn,
2735 connection_struct *conn, uint64_t vuid,
2736 char *param, int tpscnt,
2737 char *data, int tdscnt,
2738 int mdrcnt,int mprcnt,
2739 char **rdata,char **rparam,
2740 int *rdata_len,int *rparam_len)
2742 int count_sent=0;
2743 int num_users=0;
2744 int errflags=0;
2745 int i, resume_context, cli_buf_size;
2746 uint32_t resume_handle;
2748 struct rpc_pipe_client *samr_pipe = NULL;
2749 struct policy_handle samr_handle, domain_handle;
2750 NTSTATUS status, result;
2752 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2753 char *str2 = skip_string(param,tpscnt,str1);
2754 char *p = skip_string(param,tpscnt,str2);
2755 char *endp = NULL;
2757 struct dcerpc_binding_handle *b;
2759 if (!str1 || !str2 || !p) {
2760 return False;
2763 if (strcmp(str1,"WrLeh") != 0)
2764 return False;
2765 /* parameters
2766 * W-> resume context (number of users to skip)
2767 * r -> return parameter pointer to receive buffer
2768 * L -> length of receive buffer
2769 * e -> return parameter number of entries
2770 * h -> return parameter total number of users
2773 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2774 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2775 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2776 resume_context, cli_buf_size));
2778 *rparam_len = 8;
2779 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2780 if (!*rparam) {
2781 return False;
2784 /* check it's a supported varient */
2785 if (strcmp("B21",str2) != 0)
2786 return False;
2788 *rdata_len = cli_buf_size;
2789 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2790 if (!*rdata) {
2791 return False;
2794 p = *rdata;
2795 endp = *rdata + *rdata_len;
2797 status = rpc_pipe_open_interface(
2798 talloc_tos(), &ndr_table_samr,
2799 conn->session_info, conn->sconn->remote_address,
2800 conn->sconn->local_address, conn->sconn->msg_ctx, &samr_pipe);
2801 if (!NT_STATUS_IS_OK(status)) {
2802 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2803 nt_errstr(status)));
2804 return false;
2807 b = samr_pipe->binding_handle;
2809 status = dcerpc_samr_Connect2(b, talloc_tos(), lp_netbios_name(),
2810 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle,
2811 &result);
2812 if (!NT_STATUS_IS_OK(status)) {
2813 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2814 nt_errstr(status)));
2815 return false;
2817 if (!NT_STATUS_IS_OK(result)) {
2818 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2819 nt_errstr(result)));
2820 return false;
2823 status = dcerpc_samr_OpenDomain(b, talloc_tos(), &samr_handle,
2824 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2825 get_global_sam_sid(), &domain_handle,
2826 &result);
2827 if (!NT_STATUS_IS_OK(status)) {
2828 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2829 nt_errstr(status)));
2830 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2831 return false;
2833 if (!NT_STATUS_IS_OK(result)) {
2834 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2835 nt_errstr(result)));
2836 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2837 return false;
2840 errflags=NERR_Success;
2842 resume_handle = 0;
2844 while (true) {
2845 struct samr_SamArray *sam_entries;
2846 uint32_t num_entries;
2848 status = dcerpc_samr_EnumDomainUsers(b, talloc_tos(),
2849 &domain_handle,
2850 &resume_handle,
2851 0, &sam_entries, 1,
2852 &num_entries,
2853 &result);
2855 if (!NT_STATUS_IS_OK(status)) {
2856 DEBUG(10, ("dcerpc_samr_EnumDomainUsers returned "
2857 "%s\n", nt_errstr(status)));
2858 break;
2860 if (!NT_STATUS_IS_OK(result)) {
2861 DEBUG(10, ("dcerpc_samr_EnumDomainUsers returned "
2862 "%s\n", nt_errstr(result)));
2863 break;
2866 if (num_entries == 0) {
2867 DEBUG(10, ("dcerpc_samr_EnumDomainUsers returned "
2868 "no entries -- done\n"));
2869 break;
2872 for (i=0; i<num_entries; i++) {
2873 const char *name;
2875 name = sam_entries->entries[i].name.string;
2877 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2878 &&(strlen(name)<=21)) {
2879 strlcpy(p,name,PTR_DIFF(endp,p));
2880 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2881 "username %s\n",count_sent,p));
2882 p += 21;
2883 count_sent++;
2884 } else {
2885 /* set overflow error */
2886 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2887 "username %s\n",count_sent,name));
2888 errflags=234;
2889 break;
2893 if (errflags != NERR_Success) {
2894 break;
2897 TALLOC_FREE(sam_entries);
2900 dcerpc_samr_Close(b, talloc_tos(), &domain_handle, &result);
2901 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2903 *rdata_len = PTR_DIFF(p,*rdata);
2905 SSVAL(*rparam,0,errflags);
2906 SSVAL(*rparam,2,0); /* converter word */
2907 SSVAL(*rparam,4,count_sent); /* is this right?? */
2908 SSVAL(*rparam,6,num_users); /* is this right?? */
2910 return True;
2913 /****************************************************************************
2914 Get the time of day info.
2915 ****************************************************************************/
2917 static bool api_NetRemoteTOD(struct smbd_server_connection *sconn,
2918 connection_struct *conn,uint64_t vuid,
2919 char *param, int tpscnt,
2920 char *data, int tdscnt,
2921 int mdrcnt,int mprcnt,
2922 char **rdata,char **rparam,
2923 int *rdata_len,int *rparam_len)
2925 struct tm *t;
2926 time_t unixdate = time(NULL);
2927 char *p;
2929 *rparam_len = 4;
2930 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2931 if (!*rparam) {
2932 return False;
2935 *rdata_len = 21;
2936 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2937 if (!*rdata) {
2938 return False;
2941 SSVAL(*rparam,0,NERR_Success);
2942 SSVAL(*rparam,2,0); /* converter word */
2944 p = *rdata;
2946 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2947 by NT in a "net time" operation,
2948 it seems to ignore the one below */
2950 /* the client expects to get localtime, not GMT, in this bit
2951 (I think, this needs testing) */
2952 t = localtime(&unixdate);
2953 if (!t) {
2954 return False;
2957 SIVAL(p,4,0); /* msecs ? */
2958 SCVAL(p,8,t->tm_hour);
2959 SCVAL(p,9,t->tm_min);
2960 SCVAL(p,10,t->tm_sec);
2961 SCVAL(p,11,0); /* hundredths of seconds */
2962 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2963 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2964 SCVAL(p,16,t->tm_mday);
2965 SCVAL(p,17,t->tm_mon + 1);
2966 SSVAL(p,18,1900+t->tm_year);
2967 SCVAL(p,20,t->tm_wday);
2969 return True;
2972 /****************************************************************************
2973 Set the user password (SamOEM version - gets plaintext).
2974 ****************************************************************************/
2976 static bool api_SamOEMChangePassword(struct smbd_server_connection *sconn,
2977 connection_struct *conn,uint64_t vuid,
2978 char *param, int tpscnt,
2979 char *data, int tdscnt,
2980 int mdrcnt,int mprcnt,
2981 char **rdata,char **rparam,
2982 int *rdata_len,int *rparam_len)
2984 fstring user;
2985 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2987 TALLOC_CTX *mem_ctx = talloc_tos();
2988 NTSTATUS status, result;
2989 struct rpc_pipe_client *cli = NULL;
2990 struct lsa_AsciiString server, account;
2991 struct samr_CryptPassword password;
2992 struct samr_Password hash;
2993 int errcode = NERR_badpass;
2994 int bufsize;
2995 struct dcerpc_binding_handle *b;
2997 *rparam_len = 4;
2998 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2999 if (!*rparam) {
3000 return False;
3003 if (!p) {
3004 return False;
3006 *rdata_len = 0;
3008 SSVAL(*rparam,0,NERR_badpass);
3011 * Check the parameter definition is correct.
3014 /* Do we have a string ? */
3015 if (skip_string(param,tpscnt,p) == 0) {
3016 return False;
3018 if(!strequal(p, "zsT")) {
3019 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
3020 return False;
3022 p = skip_string(param, tpscnt, p);
3023 if (!p) {
3024 return False;
3027 /* Do we have a string ? */
3028 if (skip_string(param,tpscnt,p) == 0) {
3029 return False;
3031 if(!strequal(p, "B516B16")) {
3032 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
3033 return False;
3035 p = skip_string(param,tpscnt,p);
3036 if (!p) {
3037 return False;
3039 /* Do we have a string ? */
3040 if (skip_string(param,tpscnt,p) == 0) {
3041 return False;
3043 p += pull_ascii_fstring(user,p);
3045 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
3047 if (tdscnt != 532) {
3048 errcode = W_ERROR_V(WERR_INVALID_PARAMETER);
3049 goto out;
3052 bufsize = get_safe_SVAL(param,tpscnt,p,0,-1);
3053 if (bufsize != 532) {
3054 errcode = W_ERROR_V(WERR_INVALID_PARAMETER);
3055 goto out;
3058 memcpy(password.data, data, 516);
3059 memcpy(hash.hash, data+516, 16);
3061 status = rpc_pipe_open_interface(mem_ctx, &ndr_table_samr,
3062 conn->session_info,
3063 conn->sconn->remote_address,
3064 conn->sconn->local_address,
3065 conn->sconn->msg_ctx,
3066 &cli);
3067 if (!NT_STATUS_IS_OK(status)) {
3068 DEBUG(0,("api_SamOEMChangePassword: could not connect to samr: %s\n",
3069 nt_errstr(status)));
3070 errcode = W_ERROR_V(ntstatus_to_werror(status));
3071 goto out;
3074 b = cli->binding_handle;
3076 init_lsa_AsciiString(&server, lp_netbios_name());
3077 init_lsa_AsciiString(&account, user);
3079 status = dcerpc_samr_OemChangePasswordUser2(b, mem_ctx,
3080 &server,
3081 &account,
3082 &password,
3083 &hash,
3084 &result);
3085 if (!NT_STATUS_IS_OK(status)) {
3086 errcode = W_ERROR_V(ntstatus_to_werror(status));
3087 goto out;
3089 if (!NT_STATUS_IS_OK(result)) {
3090 errcode = W_ERROR_V(ntstatus_to_werror(result));
3091 goto out;
3094 errcode = NERR_Success;
3095 out:
3096 SSVAL(*rparam,0,errcode);
3097 SSVAL(*rparam,2,0); /* converter word */
3099 return(True);
3102 /****************************************************************************
3103 delete a print job
3104 Form: <W> <>
3105 ****************************************************************************/
3107 static bool api_RDosPrintJobDel(struct smbd_server_connection *sconn,
3108 connection_struct *conn,uint64_t vuid,
3109 char *param, int tpscnt,
3110 char *data, int tdscnt,
3111 int mdrcnt,int mprcnt,
3112 char **rdata,char **rparam,
3113 int *rdata_len,int *rparam_len)
3115 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3116 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3117 char *str2 = skip_string(param,tpscnt,str1);
3118 char *p = skip_string(param,tpscnt,str2);
3119 uint32_t jobid;
3120 fstring sharename;
3121 int errcode;
3122 WERROR werr = WERR_OK;
3124 TALLOC_CTX *mem_ctx = talloc_tos();
3125 NTSTATUS status;
3126 struct rpc_pipe_client *cli = NULL;
3127 struct dcerpc_binding_handle *b = NULL;
3128 struct policy_handle handle;
3129 struct spoolss_DevmodeContainer devmode_ctr;
3130 enum spoolss_JobControl command;
3132 if (!str1 || !str2 || !p) {
3133 return False;
3136 * We use 1 here not 2 as we're checking
3137 * the last byte we want to access is safe.
3139 if (!is_offset_safe(param,tpscnt,p,1)) {
3140 return False;
3142 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3143 return False;
3145 /* check it's a supported varient */
3146 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
3147 return(False);
3149 *rparam_len = 4;
3150 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3151 if (!*rparam) {
3152 return False;
3154 *rdata_len = 0;
3156 ZERO_STRUCT(handle);
3158 status = rpc_pipe_open_interface(mem_ctx,
3159 &ndr_table_spoolss,
3160 conn->session_info,
3161 conn->sconn->remote_address,
3162 conn->sconn->local_address,
3163 conn->sconn->msg_ctx,
3164 &cli);
3165 if (!NT_STATUS_IS_OK(status)) {
3166 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
3167 nt_errstr(status)));
3168 errcode = W_ERROR_V(ntstatus_to_werror(status));
3169 goto out;
3171 b = cli->binding_handle;
3173 ZERO_STRUCT(devmode_ctr);
3175 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
3176 sharename,
3177 "RAW",
3178 devmode_ctr,
3179 JOB_ACCESS_ADMINISTER,
3180 &handle,
3181 &werr);
3182 if (!NT_STATUS_IS_OK(status)) {
3183 errcode = W_ERROR_V(ntstatus_to_werror(status));
3184 goto out;
3186 if (!W_ERROR_IS_OK(werr)) {
3187 errcode = W_ERROR_V(werr);
3188 goto out;
3191 /* FIXME: formerly NERR_JobNotFound was returned if job did not exist
3192 * and NERR_DestNotFound if share did not exist */
3194 errcode = NERR_Success;
3196 switch (function) {
3197 case 81: /* delete */
3198 command = SPOOLSS_JOB_CONTROL_DELETE;
3199 break;
3200 case 82: /* pause */
3201 command = SPOOLSS_JOB_CONTROL_PAUSE;
3202 break;
3203 case 83: /* resume */
3204 command = SPOOLSS_JOB_CONTROL_RESUME;
3205 break;
3206 default:
3207 errcode = NERR_notsupported;
3208 goto out;
3211 status = dcerpc_spoolss_SetJob(b, mem_ctx,
3212 &handle,
3213 jobid,
3214 NULL, /* unique ptr ctr */
3215 command,
3216 &werr);
3217 if (!NT_STATUS_IS_OK(status)) {
3218 errcode = W_ERROR_V(ntstatus_to_werror(status));
3219 goto out;
3221 if (!W_ERROR_IS_OK(werr)) {
3222 errcode = W_ERROR_V(werr);
3223 goto out;
3226 out:
3227 if (b && is_valid_policy_hnd(&handle)) {
3228 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
3231 SSVAL(*rparam,0,errcode);
3232 SSVAL(*rparam,2,0); /* converter word */
3234 return(True);
3237 /****************************************************************************
3238 Purge a print queue - or pause or resume it.
3239 ****************************************************************************/
3241 static bool api_WPrintQueueCtrl(struct smbd_server_connection *sconn,
3242 connection_struct *conn,uint64_t vuid,
3243 char *param, int tpscnt,
3244 char *data, int tdscnt,
3245 int mdrcnt,int mprcnt,
3246 char **rdata,char **rparam,
3247 int *rdata_len,int *rparam_len)
3249 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3250 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3251 char *str2 = skip_string(param,tpscnt,str1);
3252 char *QueueName = skip_string(param,tpscnt,str2);
3253 int errcode = NERR_notsupported;
3254 WERROR werr = WERR_OK;
3255 NTSTATUS status;
3257 TALLOC_CTX *mem_ctx = talloc_tos();
3258 struct rpc_pipe_client *cli = NULL;
3259 struct dcerpc_binding_handle *b = NULL;
3260 struct policy_handle handle;
3261 struct spoolss_SetPrinterInfoCtr info_ctr;
3262 struct spoolss_DevmodeContainer devmode_ctr;
3263 struct sec_desc_buf secdesc_ctr;
3264 enum spoolss_PrinterControl command = SPOOLSS_PRINTER_CONTROL_UNPAUSE;
3266 if (!str1 || !str2 || !QueueName) {
3267 return False;
3270 /* check it's a supported varient */
3271 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3272 return(False);
3274 *rparam_len = 4;
3275 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3276 if (!*rparam) {
3277 return False;
3279 *rdata_len = 0;
3281 if (skip_string(param,tpscnt,QueueName) == NULL) {
3282 return False;
3285 ZERO_STRUCT(handle);
3287 status = rpc_pipe_open_interface(mem_ctx,
3288 &ndr_table_spoolss,
3289 conn->session_info,
3290 conn->sconn->remote_address,
3291 conn->sconn->local_address,
3292 conn->sconn->msg_ctx,
3293 &cli);
3294 if (!NT_STATUS_IS_OK(status)) {
3295 DEBUG(0,("api_WPrintQueueCtrl: could not connect to spoolss: %s\n",
3296 nt_errstr(status)));
3297 errcode = W_ERROR_V(ntstatus_to_werror(status));
3298 goto out;
3300 b = cli->binding_handle;
3302 ZERO_STRUCT(devmode_ctr);
3304 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
3305 QueueName,
3306 NULL,
3307 devmode_ctr,
3308 PRINTER_ACCESS_ADMINISTER,
3309 &handle,
3310 &werr);
3311 if (!NT_STATUS_IS_OK(status)) {
3312 errcode = W_ERROR_V(ntstatus_to_werror(status));
3313 goto out;
3315 if (!W_ERROR_IS_OK(werr)) {
3316 errcode = W_ERROR_V(werr);
3317 goto out;
3320 switch (function) {
3321 case 74: /* Pause queue */
3322 command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3323 break;
3324 case 75: /* Resume queue */
3325 command = SPOOLSS_PRINTER_CONTROL_RESUME;
3326 break;
3327 case 103: /* Purge */
3328 command = SPOOLSS_PRINTER_CONTROL_PURGE;
3329 break;
3330 default:
3331 werr = WERR_NOT_SUPPORTED;
3332 break;
3335 if (!W_ERROR_IS_OK(werr)) {
3336 errcode = W_ERROR_V(werr);
3337 goto out;
3340 ZERO_STRUCT(info_ctr);
3341 ZERO_STRUCT(secdesc_ctr);
3343 status = dcerpc_spoolss_SetPrinter(b, mem_ctx,
3344 &handle,
3345 &info_ctr,
3346 &devmode_ctr,
3347 &secdesc_ctr,
3348 command,
3349 &werr);
3350 if (!NT_STATUS_IS_OK(status)) {
3351 errcode = W_ERROR_V(ntstatus_to_werror(status));
3352 goto out;
3354 if (!W_ERROR_IS_OK(werr)) {
3355 errcode = W_ERROR_V(werr);
3356 goto out;
3359 errcode = W_ERROR_V(werr);
3361 out:
3363 if (b && is_valid_policy_hnd(&handle)) {
3364 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
3367 SSVAL(*rparam,0,errcode);
3368 SSVAL(*rparam,2,0); /* converter word */
3370 return(True);
3373 /****************************************************************************
3374 set the property of a print job (undocumented?)
3375 ? function = 0xb -> set name of print job
3376 ? function = 0x6 -> move print job up/down
3377 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3378 or <WWsTP> <WB21BB16B10zWWzDDz>
3379 ****************************************************************************/
3381 static int check_printjob_info(struct pack_desc* desc,
3382 int uLevel, char* id)
3384 desc->subformat = NULL;
3385 switch( uLevel ) {
3386 case 0: desc->format = "W"; break;
3387 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3388 case 2: desc->format = "WWzWWDDzz"; break;
3389 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3390 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3391 default:
3392 DEBUG(0,("check_printjob_info: invalid level %d\n",
3393 uLevel ));
3394 return False;
3396 if (id == NULL || strcmp(desc->format,id) != 0) {
3397 DEBUG(0,("check_printjob_info: invalid format %s\n",
3398 id ? id : "<NULL>" ));
3399 return False;
3401 return True;
3404 static bool api_PrintJobInfo(struct smbd_server_connection *sconn,
3405 connection_struct *conn, uint64_t vuid,
3406 char *param, int tpscnt,
3407 char *data, int tdscnt,
3408 int mdrcnt,int mprcnt,
3409 char **rdata,char **rparam,
3410 int *rdata_len,int *rparam_len)
3412 struct pack_desc desc;
3413 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3414 char *str2 = skip_string(param,tpscnt,str1);
3415 char *p = skip_string(param,tpscnt,str2);
3416 uint32_t jobid;
3417 fstring sharename;
3418 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3419 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3420 int errcode;
3422 TALLOC_CTX *mem_ctx = talloc_tos();
3423 WERROR werr;
3424 NTSTATUS status;
3425 struct rpc_pipe_client *cli = NULL;
3426 struct dcerpc_binding_handle *b = NULL;
3427 struct policy_handle handle;
3428 struct spoolss_DevmodeContainer devmode_ctr;
3429 struct spoolss_JobInfoContainer ctr;
3430 union spoolss_JobInfo info;
3431 struct spoolss_SetJobInfo1 info1;
3433 if (!str1 || !str2 || !p) {
3434 return False;
3437 * We use 1 here not 2 as we're checking
3438 * the last byte we want to access is safe.
3440 if (!is_offset_safe(param,tpscnt,p,1)) {
3441 return False;
3443 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3444 return False;
3445 *rparam_len = 4;
3446 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3447 if (!*rparam) {
3448 return False;
3451 *rdata_len = 0;
3453 /* check it's a supported varient */
3454 if ((strcmp(str1,"WWsTP")) ||
3455 (!check_printjob_info(&desc,uLevel,str2)))
3456 return(False);
3458 errcode = NERR_notsupported;
3460 switch (function) {
3461 case 0xb:
3462 /* change print job name, data gives the name */
3463 break;
3464 default:
3465 goto out;
3468 ZERO_STRUCT(handle);
3470 status = rpc_pipe_open_interface(mem_ctx,
3471 &ndr_table_spoolss,
3472 conn->session_info,
3473 conn->sconn->remote_address,
3474 conn->sconn->local_address,
3475 conn->sconn->msg_ctx,
3476 &cli);
3477 if (!NT_STATUS_IS_OK(status)) {
3478 DEBUG(0,("api_PrintJobInfo: could not connect to spoolss: %s\n",
3479 nt_errstr(status)));
3480 errcode = W_ERROR_V(ntstatus_to_werror(status));
3481 goto out;
3483 b = cli->binding_handle;
3485 ZERO_STRUCT(devmode_ctr);
3487 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
3488 sharename,
3489 "RAW",
3490 devmode_ctr,
3491 PRINTER_ACCESS_USE,
3492 &handle,
3493 &werr);
3494 if (!NT_STATUS_IS_OK(status)) {
3495 errcode = W_ERROR_V(ntstatus_to_werror(status));
3496 goto out;
3498 if (!W_ERROR_IS_OK(werr)) {
3499 errcode = W_ERROR_V(werr);
3500 goto out;
3503 werr = rpccli_spoolss_getjob(cli, mem_ctx,
3504 &handle,
3505 jobid,
3506 1, /* level */
3507 0, /* offered */
3508 &info);
3509 if (!W_ERROR_IS_OK(werr)) {
3510 errcode = W_ERROR_V(werr);
3511 goto out;
3514 ZERO_STRUCT(ctr);
3516 info1.job_id = info.info1.job_id;
3517 info1.printer_name = info.info1.printer_name;
3518 info1.user_name = info.info1.user_name;
3519 info1.document_name = data;
3520 info1.data_type = info.info1.data_type;
3521 info1.text_status = info.info1.text_status;
3522 info1.status = info.info1.status;
3523 info1.priority = info.info1.priority;
3524 info1.position = info.info1.position;
3525 info1.total_pages = info.info1.total_pages;
3526 info1.pages_printed = info.info1.pages_printed;
3527 info1.submitted = info.info1.submitted;
3529 ctr.level = 1;
3530 ctr.info.info1 = &info1;
3532 status = dcerpc_spoolss_SetJob(b, mem_ctx,
3533 &handle,
3534 jobid,
3535 &ctr,
3537 &werr);
3538 if (!NT_STATUS_IS_OK(status)) {
3539 errcode = W_ERROR_V(ntstatus_to_werror(status));
3540 goto out;
3542 if (!W_ERROR_IS_OK(werr)) {
3543 errcode = W_ERROR_V(werr);
3544 goto out;
3547 errcode = NERR_Success;
3548 out:
3550 if (b && is_valid_policy_hnd(&handle)) {
3551 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
3554 SSVALS(*rparam,0,errcode);
3555 SSVAL(*rparam,2,0); /* converter word */
3557 return(True);
3561 /****************************************************************************
3562 Get info about the server.
3563 ****************************************************************************/
3565 static bool api_RNetServerGetInfo(struct smbd_server_connection *sconn,
3566 connection_struct *conn,uint64_t vuid,
3567 char *param, int tpscnt,
3568 char *data, int tdscnt,
3569 int mdrcnt,int mprcnt,
3570 char **rdata,char **rparam,
3571 int *rdata_len,int *rparam_len)
3573 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3574 char *str2 = skip_string(param,tpscnt,str1);
3575 char *p = skip_string(param,tpscnt,str2);
3576 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3577 char *p2;
3578 int struct_len;
3580 NTSTATUS status;
3581 WERROR werr;
3582 TALLOC_CTX *mem_ctx = talloc_tos();
3583 struct rpc_pipe_client *cli = NULL;
3584 union srvsvc_NetSrvInfo info;
3585 int errcode;
3586 struct dcerpc_binding_handle *b;
3588 if (!str1 || !str2 || !p) {
3589 return False;
3592 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3594 /* check it's a supported varient */
3595 if (!prefix_ok(str1,"WrLh")) {
3596 return False;
3599 switch( uLevel ) {
3600 case 0:
3601 if (strcmp(str2,"B16") != 0) {
3602 return False;
3604 struct_len = 16;
3605 break;
3606 case 1:
3607 if (strcmp(str2,"B16BBDz") != 0) {
3608 return False;
3610 struct_len = 26;
3611 break;
3612 case 2:
3613 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3614 return False;
3616 struct_len = 134;
3617 break;
3618 case 3:
3619 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3620 return False;
3622 struct_len = 144;
3623 break;
3624 case 20:
3625 if (strcmp(str2,"DN") != 0) {
3626 return False;
3628 struct_len = 6;
3629 break;
3630 case 50:
3631 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3632 return False;
3634 struct_len = 42;
3635 break;
3636 default:
3637 return False;
3640 *rdata_len = mdrcnt;
3641 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3642 if (!*rdata) {
3643 return False;
3646 p = *rdata;
3647 p2 = p + struct_len;
3649 status = rpc_pipe_open_interface(mem_ctx, &ndr_table_srvsvc,
3650 conn->session_info,
3651 conn->sconn->remote_address,
3652 conn->sconn->local_address,
3653 conn->sconn->msg_ctx,
3654 &cli);
3655 if (!NT_STATUS_IS_OK(status)) {
3656 DEBUG(0,("api_RNetServerGetInfo: could not connect to srvsvc: %s\n",
3657 nt_errstr(status)));
3658 errcode = W_ERROR_V(ntstatus_to_werror(status));
3659 goto out;
3662 b = cli->binding_handle;
3664 status = dcerpc_srvsvc_NetSrvGetInfo(b, mem_ctx,
3665 NULL,
3666 101,
3667 &info,
3668 &werr);
3669 if (!NT_STATUS_IS_OK(status)) {
3670 errcode = W_ERROR_V(ntstatus_to_werror(status));
3671 goto out;
3673 if (!W_ERROR_IS_OK(werr)) {
3674 errcode = W_ERROR_V(werr);
3675 goto out;
3678 if (info.info101 == NULL) {
3679 errcode = W_ERROR_V(WERR_INVALID_PARAMETER);
3680 goto out;
3683 if (uLevel != 20) {
3684 size_t len = 0;
3685 status = srvstr_push(NULL, 0, p, info.info101->server_name, 16,
3686 STR_ASCII|STR_UPPER|STR_TERMINATE, &len);
3687 if (!NT_STATUS_IS_OK(status)) {
3688 errcode = W_ERROR_V(ntstatus_to_werror(status));
3689 goto out;
3692 p += 16;
3693 if (uLevel > 0) {
3694 SCVAL(p,0,info.info101->version_major);
3695 SCVAL(p,1,info.info101->version_minor);
3696 SIVAL(p,2,info.info101->server_type);
3698 if (mdrcnt == struct_len) {
3699 SIVAL(p,6,0);
3700 } else {
3701 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3702 if (mdrcnt - struct_len <= 0) {
3703 return false;
3705 push_ascii(p2,
3706 info.info101->comment,
3707 MIN(mdrcnt - struct_len,
3708 MAX_SERVER_STRING_LENGTH),
3709 STR_TERMINATE);
3710 p2 = skip_string(*rdata,*rdata_len,p2);
3711 if (!p2) {
3712 return False;
3717 if (uLevel > 1) {
3718 return False; /* not yet implemented */
3721 errcode = NERR_Success;
3723 out:
3725 *rdata_len = PTR_DIFF(p2,*rdata);
3727 *rparam_len = 6;
3728 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3729 if (!*rparam) {
3730 return False;
3732 SSVAL(*rparam,0,errcode);
3733 SSVAL(*rparam,2,0); /* converter word */
3734 SSVAL(*rparam,4,*rdata_len);
3736 return True;
3739 /****************************************************************************
3740 Get info about the server.
3741 ****************************************************************************/
3743 static bool api_NetWkstaGetInfo(struct smbd_server_connection *sconn,
3744 connection_struct *conn,uint64_t vuid,
3745 char *param, int tpscnt,
3746 char *data, int tdscnt,
3747 int mdrcnt,int mprcnt,
3748 char **rdata,char **rparam,
3749 int *rdata_len,int *rparam_len)
3751 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3752 char *str2 = skip_string(param,tpscnt,str1);
3753 char *p = skip_string(param,tpscnt,str2);
3754 char *p2;
3755 char *endp;
3756 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3758 if (!str1 || !str2 || !p) {
3759 return False;
3762 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3764 *rparam_len = 6;
3765 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3766 if (!*rparam) {
3767 return False;
3770 /* check it's a supported varient */
3771 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3772 return False;
3775 *rdata_len = mdrcnt + 1024;
3776 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3777 if (!*rdata) {
3778 return False;
3781 SSVAL(*rparam,0,NERR_Success);
3782 SSVAL(*rparam,2,0); /* converter word */
3784 p = *rdata;
3785 endp = *rdata + *rdata_len;
3787 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3788 if (!p2) {
3789 return False;
3792 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3793 strlcpy(p2,get_local_machine_name(),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 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3804 strlcpy(p2,conn->session_info->unix_info->sanitized_username,PTR_DIFF(endp,p2));
3805 p2 = skip_string(*rdata,*rdata_len,p2);
3806 if (!p2) {
3807 return False;
3809 p += 4;
3811 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3812 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3813 if (!strupper_m(p2)) {
3814 return false;
3816 p2 = skip_string(*rdata,*rdata_len,p2);
3817 if (!p2) {
3818 return False;
3820 p += 4;
3822 SCVAL(p,0,SAMBA_MAJOR_NBT_ANNOUNCE_VERSION); /* system version - e.g 4 in 4.1 */
3823 SCVAL(p,1,SAMBA_MINOR_NBT_ANNOUNCE_VERSION); /* system version - e.g .1 in 4.1 */
3824 p += 2;
3826 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3827 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3828 p2 = skip_string(*rdata,*rdata_len,p2);
3829 if (!p2) {
3830 return False;
3832 p += 4;
3834 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3835 strlcpy(p2,"",PTR_DIFF(endp,p2));
3836 p2 = skip_string(*rdata,*rdata_len,p2);
3837 if (!p2) {
3838 return False;
3840 p += 4;
3842 *rdata_len = PTR_DIFF(p2,*rdata);
3844 SSVAL(*rparam,4,*rdata_len);
3846 return True;
3849 /****************************************************************************
3850 get info about a user
3852 struct user_info_11 {
3853 char usri11_name[21]; 0-20
3854 char usri11_pad; 21
3855 char *usri11_comment; 22-25
3856 char *usri11_usr_comment; 26-29
3857 unsigned short usri11_priv; 30-31
3858 unsigned long usri11_auth_flags; 32-35
3859 long usri11_password_age; 36-39
3860 char *usri11_homedir; 40-43
3861 char *usri11_parms; 44-47
3862 long usri11_last_logon; 48-51
3863 long usri11_last_logoff; 52-55
3864 unsigned short usri11_bad_pw_count; 56-57
3865 unsigned short usri11_num_logons; 58-59
3866 char *usri11_logon_server; 60-63
3867 unsigned short usri11_country_code; 64-65
3868 char *usri11_workstations; 66-69
3869 unsigned long usri11_max_storage; 70-73
3870 unsigned short usri11_units_per_week; 74-75
3871 unsigned char *usri11_logon_hours; 76-79
3872 unsigned short usri11_code_page; 80-81
3875 where:
3877 usri11_name specifies the user name for which information is retrieved
3879 usri11_pad aligns the next data structure element to a word boundary
3881 usri11_comment is a null terminated ASCII comment
3883 usri11_user_comment is a null terminated ASCII comment about the user
3885 usri11_priv specifies the level of the privilege assigned to the user.
3886 The possible values are:
3888 Name Value Description
3889 USER_PRIV_GUEST 0 Guest privilege
3890 USER_PRIV_USER 1 User privilege
3891 USER_PRV_ADMIN 2 Administrator privilege
3893 usri11_auth_flags specifies the account operator privileges. The
3894 possible values are:
3896 Name Value Description
3897 AF_OP_PRINT 0 Print operator
3900 Leach, Naik [Page 28]
3904 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3907 AF_OP_COMM 1 Communications operator
3908 AF_OP_SERVER 2 Server operator
3909 AF_OP_ACCOUNTS 3 Accounts operator
3912 usri11_password_age specifies how many seconds have elapsed since the
3913 password was last changed.
3915 usri11_home_dir points to a null terminated ASCII string that contains
3916 the path name of the user's home directory.
3918 usri11_parms points to a null terminated ASCII string that is set
3919 aside for use by applications.
3921 usri11_last_logon specifies the time when the user last logged on.
3922 This value is stored as the number of seconds elapsed since
3923 00:00:00, January 1, 1970.
3925 usri11_last_logoff specifies the time when the user last logged off.
3926 This value is stored as the number of seconds elapsed since
3927 00:00:00, January 1, 1970. A value of 0 means the last logoff
3928 time is unknown.
3930 usri11_bad_pw_count specifies the number of incorrect passwords
3931 entered since the last successful logon.
3933 usri11_log1_num_logons specifies the number of times this user has
3934 logged on. A value of -1 means the number of logons is unknown.
3936 usri11_logon_server points to a null terminated ASCII string that
3937 contains the name of the server to which logon requests are sent.
3938 A null string indicates logon requests should be sent to the
3939 domain controller.
3941 usri11_country_code specifies the country code for the user's language
3942 of choice.
3944 usri11_workstations points to a null terminated ASCII string that
3945 contains the names of workstations the user may log on from.
3946 There may be up to 8 workstations, with the names separated by
3947 commas. A null strings indicates there are no restrictions.
3949 usri11_max_storage specifies the maximum amount of disk space the user
3950 can occupy. A value of 0xffffffff indicates there are no
3951 restrictions.
3953 usri11_units_per_week specifies the equal number of time units into
3954 which a week is divided. This value must be equal to 168.
3956 usri11_logon_hours points to a 21 byte (168 bits) string that
3957 specifies the time during which the user can log on. Each bit
3958 represents one unique hour in a week. The first bit (bit 0, word
3959 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3963 Leach, Naik [Page 29]
3967 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3970 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3971 are no restrictions.
3973 usri11_code_page specifies the code page for the user's language of
3974 choice
3976 All of the pointers in this data structure need to be treated
3977 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3978 to be ignored. The converter word returned in the parameters section
3979 needs to be subtracted from the lower 16 bits to calculate an offset
3980 into the return buffer where this ASCII string resides.
3982 There is no auxiliary data in the response.
3984 ****************************************************************************/
3986 #define usri11_name 0
3987 #define usri11_pad 21
3988 #define usri11_comment 22
3989 #define usri11_usr_comment 26
3990 #define usri11_full_name 30
3991 #define usri11_priv 34
3992 #define usri11_auth_flags 36
3993 #define usri11_password_age 40
3994 #define usri11_homedir 44
3995 #define usri11_parms 48
3996 #define usri11_last_logon 52
3997 #define usri11_last_logoff 56
3998 #define usri11_bad_pw_count 60
3999 #define usri11_num_logons 62
4000 #define usri11_logon_server 64
4001 #define usri11_country_code 68
4002 #define usri11_workstations 70
4003 #define usri11_max_storage 74
4004 #define usri11_units_per_week 78
4005 #define usri11_logon_hours 80
4006 #define usri11_code_page 84
4007 #define usri11_end 86
4009 static bool api_RNetUserGetInfo(struct smbd_server_connection *sconn,
4010 connection_struct *conn, uint64_t vuid,
4011 char *param, int tpscnt,
4012 char *data, int tdscnt,
4013 int mdrcnt,int mprcnt,
4014 char **rdata,char **rparam,
4015 int *rdata_len,int *rparam_len)
4017 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4018 char *str2 = skip_string(param,tpscnt,str1);
4019 char *UserName = skip_string(param,tpscnt,str2);
4020 char *p = skip_string(param,tpscnt,UserName);
4021 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4022 char *p2;
4023 char *endp;
4024 const char *level_string;
4026 TALLOC_CTX *mem_ctx = talloc_tos();
4027 NTSTATUS status, result;
4028 struct rpc_pipe_client *cli = NULL;
4029 struct policy_handle connect_handle, domain_handle, user_handle;
4030 struct lsa_String domain_name;
4031 struct dom_sid2 *domain_sid;
4032 struct lsa_String names;
4033 struct samr_Ids rids;
4034 struct samr_Ids types;
4035 int errcode = W_ERROR_V(WERR_NERR_USERNOTFOUND);
4036 uint32_t rid;
4037 union samr_UserInfo *info;
4038 struct dcerpc_binding_handle *b = NULL;
4040 if (!str1 || !str2 || !UserName || !p) {
4041 return False;
4044 *rparam_len = 6;
4045 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4046 if (!*rparam) {
4047 return False;
4050 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
4052 /* check it's a supported variant */
4053 if (strcmp(str1,"zWrLh") != 0) {
4054 return False;
4056 switch( uLevel ) {
4057 case 0: level_string = "B21"; break;
4058 case 1: level_string = "B21BB16DWzzWz"; break;
4059 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
4060 case 10: level_string = "B21Bzzz"; break;
4061 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
4062 default: return False;
4065 if (strcmp(level_string,str2) != 0) {
4066 return False;
4069 *rdata_len = mdrcnt + 1024;
4070 *rdata = smb_realloc_limit(*rdata,*rdata_len);
4071 if (!*rdata) {
4072 return False;
4075 p = *rdata;
4076 endp = *rdata + *rdata_len;
4077 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
4078 if (!p2) {
4079 return False;
4082 ZERO_STRUCT(connect_handle);
4083 ZERO_STRUCT(domain_handle);
4084 ZERO_STRUCT(user_handle);
4086 status = rpc_pipe_open_interface(mem_ctx, &ndr_table_samr,
4087 conn->session_info,
4088 conn->sconn->remote_address,
4089 conn->sconn->local_address,
4090 conn->sconn->msg_ctx,
4091 &cli);
4092 if (!NT_STATUS_IS_OK(status)) {
4093 DEBUG(0,("api_RNetUserGetInfo: could not connect to samr: %s\n",
4094 nt_errstr(status)));
4095 errcode = W_ERROR_V(ntstatus_to_werror(status));
4096 goto out;
4099 b = cli->binding_handle;
4101 status = dcerpc_samr_Connect2(b, mem_ctx,
4102 lp_netbios_name(),
4103 SAMR_ACCESS_CONNECT_TO_SERVER |
4104 SAMR_ACCESS_ENUM_DOMAINS |
4105 SAMR_ACCESS_LOOKUP_DOMAIN,
4106 &connect_handle,
4107 &result);
4108 if (!NT_STATUS_IS_OK(status)) {
4109 errcode = W_ERROR_V(ntstatus_to_werror(status));
4110 goto out;
4112 if (!NT_STATUS_IS_OK(result)) {
4113 errcode = W_ERROR_V(ntstatus_to_werror(result));
4114 goto out;
4117 init_lsa_String(&domain_name, get_global_sam_name());
4119 status = dcerpc_samr_LookupDomain(b, mem_ctx,
4120 &connect_handle,
4121 &domain_name,
4122 &domain_sid,
4123 &result);
4124 if (!NT_STATUS_IS_OK(status)) {
4125 errcode = W_ERROR_V(ntstatus_to_werror(status));
4126 goto out;
4128 if (!NT_STATUS_IS_OK(result)) {
4129 errcode = W_ERROR_V(ntstatus_to_werror(result));
4130 goto out;
4133 status = dcerpc_samr_OpenDomain(b, mem_ctx,
4134 &connect_handle,
4135 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
4136 domain_sid,
4137 &domain_handle,
4138 &result);
4139 if (!NT_STATUS_IS_OK(status)) {
4140 errcode = W_ERROR_V(ntstatus_to_werror(status));
4141 goto out;
4143 if (!NT_STATUS_IS_OK(result)) {
4144 errcode = W_ERROR_V(ntstatus_to_werror(result));
4145 goto out;
4148 init_lsa_String(&names, UserName);
4150 status = dcerpc_samr_LookupNames(b, mem_ctx,
4151 &domain_handle,
4153 &names,
4154 &rids,
4155 &types,
4156 &result);
4157 if (!NT_STATUS_IS_OK(status)) {
4158 errcode = W_ERROR_V(ntstatus_to_werror(status));
4159 goto out;
4161 if (!NT_STATUS_IS_OK(result)) {
4162 errcode = W_ERROR_V(ntstatus_to_werror(result));
4163 goto out;
4166 if (rids.count != 1) {
4167 errcode = W_ERROR_V(WERR_NO_SUCH_USER);
4168 goto out;
4170 if (rids.count != types.count) {
4171 errcode = W_ERROR_V(WERR_INVALID_PARAMETER);
4172 goto out;
4174 if (types.ids[0] != SID_NAME_USER) {
4175 errcode = W_ERROR_V(WERR_INVALID_PARAMETER);
4176 goto out;
4179 rid = rids.ids[0];
4181 status = dcerpc_samr_OpenUser(b, mem_ctx,
4182 &domain_handle,
4183 SAMR_USER_ACCESS_GET_LOCALE |
4184 SAMR_USER_ACCESS_GET_LOGONINFO |
4185 SAMR_USER_ACCESS_GET_ATTRIBUTES |
4186 SAMR_USER_ACCESS_GET_GROUPS |
4187 SAMR_USER_ACCESS_GET_GROUP_MEMBERSHIP |
4188 SEC_STD_READ_CONTROL,
4189 rid,
4190 &user_handle,
4191 &result);
4192 if (!NT_STATUS_IS_OK(status)) {
4193 errcode = W_ERROR_V(ntstatus_to_werror(status));
4194 goto out;
4196 if (!NT_STATUS_IS_OK(result)) {
4197 errcode = W_ERROR_V(ntstatus_to_werror(result));
4198 goto out;
4201 status = dcerpc_samr_QueryUserInfo2(b, mem_ctx,
4202 &user_handle,
4203 UserAllInformation,
4204 &info,
4205 &result);
4206 if (!NT_STATUS_IS_OK(status)) {
4207 errcode = W_ERROR_V(ntstatus_to_werror(status));
4208 goto out;
4210 if (!NT_STATUS_IS_OK(result)) {
4211 errcode = W_ERROR_V(ntstatus_to_werror(result));
4212 goto out;
4215 memset(p,0,21);
4216 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
4218 if (uLevel > 0) {
4219 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
4220 *p2 = 0;
4223 if (uLevel >= 10) {
4224 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
4225 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
4226 p2 = skip_string(*rdata,*rdata_len,p2);
4227 if (!p2) {
4228 return False;
4231 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
4232 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
4233 p2 = skip_string(*rdata,*rdata_len,p2);
4234 if (!p2) {
4235 return False;
4238 /* EEK! the cifsrap.txt doesn't have this in!!!! */
4239 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
4240 strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4241 p2 = skip_string(*rdata,*rdata_len,p2);
4242 if (!p2) {
4243 return False;
4247 if (uLevel == 11) {
4248 const char *homedir = info->info21.home_directory.string;
4249 /* modelled after NTAS 3.51 reply */
4250 SSVAL(p,usri11_priv,
4251 (get_current_uid(conn) == sec_initial_uid())?
4252 USER_PRIV_ADMIN:USER_PRIV_USER);
4253 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
4254 SIVALS(p,usri11_password_age,-1); /* password age */
4255 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
4256 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
4257 p2 = skip_string(*rdata,*rdata_len,p2);
4258 if (!p2) {
4259 return False;
4261 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
4262 strlcpy(p2,"",PTR_DIFF(endp,p2));
4263 p2 = skip_string(*rdata,*rdata_len,p2);
4264 if (!p2) {
4265 return False;
4267 SIVAL(p,usri11_last_logon,0); /* last logon */
4268 SIVAL(p,usri11_last_logoff,0); /* last logoff */
4269 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
4270 SSVALS(p,usri11_num_logons,-1); /* num logons */
4271 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
4272 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
4273 p2 = skip_string(*rdata,*rdata_len,p2);
4274 if (!p2) {
4275 return False;
4277 SSVAL(p,usri11_country_code,0); /* country code */
4279 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
4280 strlcpy(p2,"",PTR_DIFF(endp,p2));
4281 p2 = skip_string(*rdata,*rdata_len,p2);
4282 if (!p2) {
4283 return False;
4286 SIVALS(p,usri11_max_storage,-1); /* max storage */
4287 SSVAL(p,usri11_units_per_week,168); /* units per week */
4288 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
4290 /* a simple way to get logon hours at all times. */
4291 memset(p2,0xff,21);
4292 SCVAL(p2,21,0); /* fix zero termination */
4293 p2 = skip_string(*rdata,*rdata_len,p2);
4294 if (!p2) {
4295 return False;
4298 SSVAL(p,usri11_code_page,0); /* code page */
4301 if (uLevel == 1 || uLevel == 2) {
4302 memset(p+22,' ',16); /* password */
4303 SIVALS(p,38,-1); /* password age */
4304 SSVAL(p,42,
4305 (get_current_uid(conn) == sec_initial_uid())?
4306 USER_PRIV_ADMIN:USER_PRIV_USER);
4307 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
4308 strlcpy(p2, info->info21.home_directory.string,
4309 PTR_DIFF(endp,p2));
4310 p2 = skip_string(*rdata,*rdata_len,p2);
4311 if (!p2) {
4312 return False;
4314 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
4315 *p2++ = 0;
4316 SSVAL(p,52,0); /* flags */
4317 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
4318 strlcpy(p2, info->info21.logon_script.string,
4319 PTR_DIFF(endp,p2));
4320 p2 = skip_string(*rdata,*rdata_len,p2);
4321 if (!p2) {
4322 return False;
4324 if (uLevel == 2) {
4325 SIVAL(p,58,0); /* auth_flags */
4326 SIVAL(p,62,PTR_DIFF(p2,*rdata)); /* full_name */
4327 strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4328 p2 = skip_string(*rdata,*rdata_len,p2);
4329 if (!p2) {
4330 return False;
4332 SIVAL(p,66,0); /* urs_comment */
4333 SIVAL(p,70,PTR_DIFF(p2,*rdata)); /* parms */
4334 strlcpy(p2,"",PTR_DIFF(endp,p2));
4335 p2 = skip_string(*rdata,*rdata_len,p2);
4336 if (!p2) {
4337 return False;
4339 SIVAL(p,74,0); /* workstations */
4340 SIVAL(p,78,0); /* last_logon */
4341 SIVAL(p,82,0); /* last_logoff */
4342 SIVALS(p,86,-1); /* acct_expires */
4343 SIVALS(p,90,-1); /* max_storage */
4344 SSVAL(p,94,168); /* units_per_week */
4345 SIVAL(p,96,PTR_DIFF(p2,*rdata)); /* logon_hours */
4346 memset(p2,-1,21);
4347 p2 += 21;
4348 SSVALS(p,100,-1); /* bad_pw_count */
4349 SSVALS(p,102,-1); /* num_logons */
4350 SIVAL(p,104,PTR_DIFF(p2,*rdata)); /* logon_server */
4352 TALLOC_CTX *ctx = talloc_tos();
4353 int space_rem = *rdata_len - (p2 - *rdata);
4354 char *tmp;
4356 if (space_rem <= 0) {
4357 return false;
4359 tmp = talloc_strdup(ctx, "\\\\%L");
4360 if (!tmp) {
4361 return false;
4363 tmp = talloc_sub_basic(ctx,
4366 tmp);
4367 if (!tmp) {
4368 return false;
4371 push_ascii(p2,
4372 tmp,
4373 space_rem,
4374 STR_TERMINATE);
4376 p2 = skip_string(*rdata,*rdata_len,p2);
4377 if (!p2) {
4378 return False;
4380 SSVAL(p,108,49); /* country_code */
4381 SSVAL(p,110,860); /* code page */
4385 errcode = NERR_Success;
4387 out:
4388 *rdata_len = PTR_DIFF(p2,*rdata);
4390 if (b && is_valid_policy_hnd(&user_handle)) {
4391 dcerpc_samr_Close(b, mem_ctx, &user_handle, &result);
4393 if (b && is_valid_policy_hnd(&domain_handle)) {
4394 dcerpc_samr_Close(b, mem_ctx, &domain_handle, &result);
4396 if (b && is_valid_policy_hnd(&connect_handle)) {
4397 dcerpc_samr_Close(b, mem_ctx, &connect_handle, &result);
4400 SSVAL(*rparam,0,errcode);
4401 SSVAL(*rparam,2,0); /* converter word */
4402 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
4404 return(True);
4407 static bool api_WWkstaUserLogon(struct smbd_server_connection *sconn,
4408 connection_struct *conn,uint64_t vuid,
4409 char *param, int tpscnt,
4410 char *data, int tdscnt,
4411 int mdrcnt,int mprcnt,
4412 char **rdata,char **rparam,
4413 int *rdata_len,int *rparam_len)
4415 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4416 char *str2 = skip_string(param,tpscnt,str1);
4417 char *p = skip_string(param,tpscnt,str2);
4418 int uLevel;
4419 struct pack_desc desc;
4420 char* name;
4421 struct auth_session_info *si = NULL;
4422 NTSTATUS status;
4424 status = smbXsrv_session_info_lookup(conn->sconn->client,
4425 vuid,
4426 &si);
4427 if (!NT_STATUS_IS_OK(status)) {
4428 return false;
4431 if (!str1 || !str2 || !p) {
4432 return False;
4435 DBG_INFO("Username of UID %ju is %s\n",
4436 (uintmax_t)si->unix_token->uid,
4437 si->unix_info->unix_name);
4439 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4440 name = get_safe_str_ptr(param,tpscnt,p,2);
4441 if (!name) {
4442 return False;
4445 memset((char *)&desc,'\0',sizeof(desc));
4447 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
4449 /* check it's a supported varient */
4450 if (strcmp(str1,"OOWb54WrLh") != 0) {
4451 return False;
4453 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
4454 return False;
4456 if (mdrcnt > 0) {
4457 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4458 if (!*rdata) {
4459 return False;
4463 desc.base = *rdata;
4464 desc.buflen = mdrcnt;
4465 desc.subformat = NULL;
4466 desc.format = str2;
4468 if (init_package(&desc,1,0)) {
4469 PACKI(&desc,"W",0); /* code */
4470 PACKS(&desc,"B21",name); /* eff. name */
4471 PACKS(&desc,"B",""); /* pad */
4472 PACKI(&desc,"W",
4473 (get_current_uid(conn) == sec_initial_uid())?
4474 USER_PRIV_ADMIN:USER_PRIV_USER);
4475 PACKI(&desc,"D",0); /* auth flags XXX */
4476 PACKI(&desc,"W",0); /* num logons */
4477 PACKI(&desc,"W",0); /* bad pw count */
4478 PACKI(&desc,"D",0); /* last logon */
4479 PACKI(&desc,"D",-1); /* last logoff */
4480 PACKI(&desc,"D",-1); /* logoff time */
4481 PACKI(&desc,"D",-1); /* kickoff time */
4482 PACKI(&desc,"D",0); /* password age */
4483 PACKI(&desc,"D",0); /* password can change */
4484 PACKI(&desc,"D",-1); /* password must change */
4487 fstring mypath;
4488 fstrcpy(mypath,"\\\\");
4489 fstrcat(mypath,get_local_machine_name());
4490 if (!strupper_m(mypath)) {
4491 return false;
4493 PACKS(&desc,"z",mypath); /* computer */
4496 PACKS(&desc,"z",lp_workgroup());/* domain */
4497 PACKS(&desc,"z", si->info->logon_script); /* script path */
4498 PACKI(&desc,"D",0x00000000); /* reserved */
4501 *rdata_len = desc.usedlen;
4502 *rparam_len = 6;
4503 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4504 if (!*rparam) {
4505 return False;
4507 SSVALS(*rparam,0,desc.errcode);
4508 SSVAL(*rparam,2,0);
4509 SSVAL(*rparam,4,desc.neededlen);
4511 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4513 return True;
4516 /****************************************************************************
4517 api_WAccessGetUserPerms
4518 ****************************************************************************/
4520 static bool api_WAccessGetUserPerms(struct smbd_server_connection *sconn,
4521 connection_struct *conn,uint64_t vuid,
4522 char *param, int tpscnt,
4523 char *data, int tdscnt,
4524 int mdrcnt,int mprcnt,
4525 char **rdata,char **rparam,
4526 int *rdata_len,int *rparam_len)
4528 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4529 char *str2 = skip_string(param,tpscnt,str1);
4530 char *user = skip_string(param,tpscnt,str2);
4531 char *resource = skip_string(param,tpscnt,user);
4533 if (!str1 || !str2 || !user || !resource) {
4534 return False;
4537 if (skip_string(param,tpscnt,resource) == NULL) {
4538 return False;
4540 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4542 /* check it's a supported varient */
4543 if (strcmp(str1,"zzh") != 0) {
4544 return False;
4546 if (strcmp(str2,"") != 0) {
4547 return False;
4550 *rparam_len = 6;
4551 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4552 if (!*rparam) {
4553 return False;
4555 SSVALS(*rparam,0,0); /* errorcode */
4556 SSVAL(*rparam,2,0); /* converter word */
4557 SSVAL(*rparam,4,0x7f); /* permission flags */
4559 return True;
4562 /****************************************************************************
4563 api_WPrintJobEnumerate
4564 ****************************************************************************/
4566 static bool api_WPrintJobGetInfo(struct smbd_server_connection *sconn,
4567 connection_struct *conn, uint64_t vuid,
4568 char *param, int tpscnt,
4569 char *data, int tdscnt,
4570 int mdrcnt,int mprcnt,
4571 char **rdata,char **rparam,
4572 int *rdata_len,int *rparam_len)
4574 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4575 char *str2 = skip_string(param,tpscnt,str1);
4576 char *p = skip_string(param,tpscnt,str2);
4577 int uLevel;
4578 fstring sharename;
4579 uint32_t jobid;
4580 struct pack_desc desc;
4581 char *tmpdata=NULL;
4583 TALLOC_CTX *mem_ctx = talloc_tos();
4584 WERROR werr;
4585 NTSTATUS status;
4586 struct rpc_pipe_client *cli = NULL;
4587 struct dcerpc_binding_handle *b = NULL;
4588 struct policy_handle handle;
4589 struct spoolss_DevmodeContainer devmode_ctr;
4590 union spoolss_JobInfo info;
4592 if (!str1 || !str2 || !p) {
4593 return False;
4596 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4598 memset((char *)&desc,'\0',sizeof(desc));
4599 memset((char *)&status,'\0',sizeof(status));
4601 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4603 /* check it's a supported varient */
4604 if (strcmp(str1,"WWrLh") != 0) {
4605 return False;
4607 if (!check_printjob_info(&desc,uLevel,str2)) {
4608 return False;
4611 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4612 return False;
4615 ZERO_STRUCT(handle);
4617 status = rpc_pipe_open_interface(mem_ctx,
4618 &ndr_table_spoolss,
4619 conn->session_info,
4620 conn->sconn->remote_address,
4621 conn->sconn->local_address,
4622 conn->sconn->msg_ctx,
4623 &cli);
4624 if (!NT_STATUS_IS_OK(status)) {
4625 DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n",
4626 nt_errstr(status)));
4627 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4628 goto out;
4630 b = cli->binding_handle;
4632 ZERO_STRUCT(devmode_ctr);
4634 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
4635 sharename,
4636 "RAW",
4637 devmode_ctr,
4638 PRINTER_ACCESS_USE,
4639 &handle,
4640 &werr);
4641 if (!NT_STATUS_IS_OK(status)) {
4642 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4643 goto out;
4645 if (!W_ERROR_IS_OK(werr)) {
4646 desc.errcode = W_ERROR_V(werr);
4647 goto out;
4650 werr = rpccli_spoolss_getjob(cli, mem_ctx,
4651 &handle,
4652 jobid,
4653 2, /* level */
4654 0, /* offered */
4655 &info);
4656 if (!W_ERROR_IS_OK(werr)) {
4657 desc.errcode = W_ERROR_V(werr);
4658 goto out;
4661 if (mdrcnt > 0) {
4662 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4663 if (!*rdata) {
4664 return False;
4666 desc.base = *rdata;
4667 desc.buflen = mdrcnt;
4668 } else {
4670 * Don't return data but need to get correct length
4671 * init_package will return wrong size if buflen=0
4673 desc.buflen = getlen(desc.format);
4674 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4677 if (init_package(&desc,1,0)) {
4678 fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position);
4679 *rdata_len = desc.usedlen;
4680 } else {
4681 desc.errcode = NERR_JobNotFound;
4682 *rdata_len = 0;
4684 out:
4685 if (b && is_valid_policy_hnd(&handle)) {
4686 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
4689 *rparam_len = 6;
4690 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4691 if (!*rparam) {
4692 return False;
4694 SSVALS(*rparam,0,desc.errcode);
4695 SSVAL(*rparam,2,0);
4696 SSVAL(*rparam,4,desc.neededlen);
4698 SAFE_FREE(tmpdata);
4700 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4702 return True;
4705 static bool api_WPrintJobEnumerate(struct smbd_server_connection *sconn,
4706 connection_struct *conn, uint64_t vuid,
4707 char *param, int tpscnt,
4708 char *data, int tdscnt,
4709 int mdrcnt,int mprcnt,
4710 char **rdata,char **rparam,
4711 int *rdata_len,int *rparam_len)
4713 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4714 char *str2 = skip_string(param,tpscnt,str1);
4715 char *p = skip_string(param,tpscnt,str2);
4716 char *name = p;
4717 int uLevel;
4718 int i, succnt=0;
4719 struct pack_desc desc;
4721 TALLOC_CTX *mem_ctx = talloc_tos();
4722 WERROR werr;
4723 NTSTATUS status;
4724 struct rpc_pipe_client *cli = NULL;
4725 struct dcerpc_binding_handle *b = NULL;
4726 struct policy_handle handle;
4727 struct spoolss_DevmodeContainer devmode_ctr;
4728 uint32_t count = 0;
4729 union spoolss_JobInfo *info;
4731 if (!str1 || !str2 || !p) {
4732 return False;
4735 memset((char *)&desc,'\0',sizeof(desc));
4737 p = skip_string(param,tpscnt,p);
4738 if (!p) {
4739 return False;
4741 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4743 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4745 /* check it's a supported variant */
4746 if (strcmp(str1,"zWrLeh") != 0) {
4747 return False;
4750 if (uLevel > 2) {
4751 return False; /* defined only for uLevel 0,1,2 */
4754 if (!check_printjob_info(&desc,uLevel,str2)) {
4755 return False;
4758 ZERO_STRUCT(handle);
4760 status = rpc_pipe_open_interface(mem_ctx,
4761 &ndr_table_spoolss,
4762 conn->session_info,
4763 conn->sconn->remote_address,
4764 conn->sconn->local_address,
4765 conn->sconn->msg_ctx,
4766 &cli);
4767 if (!NT_STATUS_IS_OK(status)) {
4768 DEBUG(0,("api_WPrintJobEnumerate: could not connect to spoolss: %s\n",
4769 nt_errstr(status)));
4770 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4771 goto out;
4773 b = cli->binding_handle;
4775 ZERO_STRUCT(devmode_ctr);
4777 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
4778 name,
4779 NULL,
4780 devmode_ctr,
4781 PRINTER_ACCESS_USE,
4782 &handle,
4783 &werr);
4784 if (!NT_STATUS_IS_OK(status)) {
4785 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4786 goto out;
4788 if (!W_ERROR_IS_OK(werr)) {
4789 desc.errcode = W_ERROR_V(werr);
4790 goto out;
4793 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
4794 &handle,
4795 0, /* firstjob */
4796 0xff, /* numjobs */
4797 2, /* level */
4798 0, /* offered */
4799 &count,
4800 &info);
4801 if (!W_ERROR_IS_OK(werr)) {
4802 desc.errcode = W_ERROR_V(werr);
4803 goto out;
4806 if (mdrcnt > 0) {
4807 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4808 if (!*rdata) {
4809 return False;
4812 desc.base = *rdata;
4813 desc.buflen = mdrcnt;
4815 if (init_package(&desc,count,0)) {
4816 succnt = 0;
4817 for (i = 0; i < count; i++) {
4818 fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i);
4819 if (desc.errcode == NERR_Success) {
4820 succnt = i+1;
4824 out:
4825 if (b && is_valid_policy_hnd(&handle)) {
4826 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
4829 *rdata_len = desc.usedlen;
4831 *rparam_len = 8;
4832 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4833 if (!*rparam) {
4834 return False;
4836 SSVALS(*rparam,0,desc.errcode);
4837 SSVAL(*rparam,2,0);
4838 SSVAL(*rparam,4,succnt);
4839 SSVAL(*rparam,6,count);
4841 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4843 return True;
4846 static int check_printdest_info(struct pack_desc* desc,
4847 int uLevel, char* id)
4849 desc->subformat = NULL;
4850 switch( uLevel ) {
4851 case 0:
4852 desc->format = "B9";
4853 break;
4854 case 1:
4855 desc->format = "B9B21WWzW";
4856 break;
4857 case 2:
4858 desc->format = "z";
4859 break;
4860 case 3:
4861 desc->format = "zzzWWzzzWW";
4862 break;
4863 default:
4864 DEBUG(0,("check_printdest_info: invalid level %d\n",
4865 uLevel));
4866 return False;
4868 if (id == NULL || strcmp(desc->format,id) != 0) {
4869 DEBUG(0,("check_printdest_info: invalid string %s\n",
4870 id ? id : "<NULL>" ));
4871 return False;
4873 return True;
4876 static void fill_printdest_info(struct spoolss_PrinterInfo2 *info2, int uLevel,
4877 struct pack_desc* desc)
4879 char buf[100];
4881 strncpy(buf, info2->printername, sizeof(buf)-1);
4882 buf[sizeof(buf)-1] = 0;
4883 (void)strupper_m(buf);
4885 if (uLevel <= 1) {
4886 PACKS(desc,"B9",buf); /* szName */
4887 if (uLevel == 1) {
4888 PACKS(desc,"B21",""); /* szUserName */
4889 PACKI(desc,"W",0); /* uJobId */
4890 PACKI(desc,"W",0); /* fsStatus */
4891 PACKS(desc,"z",""); /* pszStatus */
4892 PACKI(desc,"W",0); /* time */
4896 if (uLevel == 2 || uLevel == 3) {
4897 PACKS(desc,"z",buf); /* pszPrinterName */
4898 if (uLevel == 3) {
4899 PACKS(desc,"z",""); /* pszUserName */
4900 PACKS(desc,"z",""); /* pszLogAddr */
4901 PACKI(desc,"W",0); /* uJobId */
4902 PACKI(desc,"W",0); /* fsStatus */
4903 PACKS(desc,"z",""); /* pszStatus */
4904 PACKS(desc,"z",""); /* pszComment */
4905 PACKS(desc,"z","NULL"); /* pszDrivers */
4906 PACKI(desc,"W",0); /* time */
4907 PACKI(desc,"W",0); /* pad1 */
4912 static bool api_WPrintDestGetInfo(struct smbd_server_connection *sconn,
4913 connection_struct *conn, uint64_t vuid,
4914 char *param, int tpscnt,
4915 char *data, int tdscnt,
4916 int mdrcnt,int mprcnt,
4917 char **rdata,char **rparam,
4918 int *rdata_len,int *rparam_len)
4920 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4921 char *str2 = skip_string(param,tpscnt,str1);
4922 char *p = skip_string(param,tpscnt,str2);
4923 char* PrinterName = p;
4924 int uLevel;
4925 struct pack_desc desc;
4926 char *tmpdata=NULL;
4928 TALLOC_CTX *mem_ctx = talloc_tos();
4929 WERROR werr;
4930 NTSTATUS status;
4931 struct rpc_pipe_client *cli = NULL;
4932 struct dcerpc_binding_handle *b = NULL;
4933 struct policy_handle handle;
4934 struct spoolss_DevmodeContainer devmode_ctr;
4935 union spoolss_PrinterInfo info;
4937 if (!str1 || !str2 || !p) {
4938 return False;
4941 memset((char *)&desc,'\0',sizeof(desc));
4943 p = skip_string(param,tpscnt,p);
4944 if (!p) {
4945 return False;
4947 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4949 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4951 /* check it's a supported varient */
4952 if (strcmp(str1,"zWrLh") != 0) {
4953 return False;
4955 if (!check_printdest_info(&desc,uLevel,str2)) {
4956 return False;
4959 ZERO_STRUCT(handle);
4961 status = rpc_pipe_open_interface(mem_ctx,
4962 &ndr_table_spoolss,
4963 conn->session_info,
4964 conn->sconn->remote_address,
4965 conn->sconn->local_address,
4966 conn->sconn->msg_ctx,
4967 &cli);
4968 if (!NT_STATUS_IS_OK(status)) {
4969 DEBUG(0,("api_WPrintDestGetInfo: could not connect to spoolss: %s\n",
4970 nt_errstr(status)));
4971 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4972 goto out;
4974 b = cli->binding_handle;
4976 ZERO_STRUCT(devmode_ctr);
4978 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
4979 PrinterName,
4980 NULL,
4981 devmode_ctr,
4982 PRINTER_ACCESS_USE,
4983 &handle,
4984 &werr);
4985 if (!NT_STATUS_IS_OK(status)) {
4986 *rdata_len = 0;
4987 desc.errcode = NERR_DestNotFound;
4988 desc.neededlen = 0;
4989 goto out;
4991 if (!W_ERROR_IS_OK(werr)) {
4992 *rdata_len = 0;
4993 desc.errcode = NERR_DestNotFound;
4994 desc.neededlen = 0;
4995 goto out;
4998 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
4999 &handle,
5002 &info);
5003 if (!W_ERROR_IS_OK(werr)) {
5004 *rdata_len = 0;
5005 desc.errcode = NERR_DestNotFound;
5006 desc.neededlen = 0;
5007 goto out;
5010 if (mdrcnt > 0) {
5011 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5012 if (!*rdata) {
5013 return False;
5015 desc.base = *rdata;
5016 desc.buflen = mdrcnt;
5017 } else {
5019 * Don't return data but need to get correct length
5020 * init_package will return wrong size if buflen=0
5022 desc.buflen = getlen(desc.format);
5023 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
5025 if (init_package(&desc,1,0)) {
5026 fill_printdest_info(&info.info2, uLevel,&desc);
5029 out:
5030 if (b && is_valid_policy_hnd(&handle)) {
5031 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5034 *rdata_len = desc.usedlen;
5036 *rparam_len = 6;
5037 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5038 if (!*rparam) {
5039 return False;
5041 SSVALS(*rparam,0,desc.errcode);
5042 SSVAL(*rparam,2,0);
5043 SSVAL(*rparam,4,desc.neededlen);
5045 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
5046 SAFE_FREE(tmpdata);
5048 return True;
5051 static bool api_WPrintDestEnum(struct smbd_server_connection *sconn,
5052 connection_struct *conn, uint64_t vuid,
5053 char *param, int tpscnt,
5054 char *data, int tdscnt,
5055 int mdrcnt,int mprcnt,
5056 char **rdata,char **rparam,
5057 int *rdata_len,int *rparam_len)
5059 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5060 char *str2 = skip_string(param,tpscnt,str1);
5061 char *p = skip_string(param,tpscnt,str2);
5062 int uLevel;
5063 int queuecnt;
5064 int i, n, succnt=0;
5065 struct pack_desc desc;
5067 TALLOC_CTX *mem_ctx = talloc_tos();
5068 WERROR werr;
5069 NTSTATUS status;
5070 struct rpc_pipe_client *cli = NULL;
5071 union spoolss_PrinterInfo *info;
5072 uint32_t count;
5074 if (!str1 || !str2 || !p) {
5075 return False;
5078 memset((char *)&desc,'\0',sizeof(desc));
5080 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5082 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
5084 /* check it's a supported varient */
5085 if (strcmp(str1,"WrLeh") != 0) {
5086 return False;
5088 if (!check_printdest_info(&desc,uLevel,str2)) {
5089 return False;
5092 queuecnt = 0;
5094 status = rpc_pipe_open_interface(mem_ctx,
5095 &ndr_table_spoolss,
5096 conn->session_info,
5097 conn->sconn->remote_address,
5098 conn->sconn->local_address,
5099 conn->sconn->msg_ctx,
5100 &cli);
5101 if (!NT_STATUS_IS_OK(status)) {
5102 DEBUG(0,("api_WPrintDestEnum: could not connect to spoolss: %s\n",
5103 nt_errstr(status)));
5104 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5105 goto out;
5108 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
5109 PRINTER_ENUM_LOCAL,
5110 cli->srv_name_slash,
5113 &count,
5114 &info);
5115 if (!W_ERROR_IS_OK(werr)) {
5116 desc.errcode = W_ERROR_V(werr);
5117 *rdata_len = 0;
5118 desc.errcode = NERR_DestNotFound;
5119 desc.neededlen = 0;
5120 goto out;
5123 queuecnt = count;
5125 if (mdrcnt > 0) {
5126 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5127 if (!*rdata) {
5128 return False;
5132 desc.base = *rdata;
5133 desc.buflen = mdrcnt;
5134 if (init_package(&desc,queuecnt,0)) {
5135 succnt = 0;
5136 n = 0;
5137 for (i = 0; i < count; i++) {
5138 fill_printdest_info(&info[i].info2, uLevel,&desc);
5139 n++;
5140 if (desc.errcode == NERR_Success) {
5141 succnt = n;
5145 out:
5146 *rdata_len = desc.usedlen;
5148 *rparam_len = 8;
5149 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5150 if (!*rparam) {
5151 return False;
5153 SSVALS(*rparam,0,desc.errcode);
5154 SSVAL(*rparam,2,0);
5155 SSVAL(*rparam,4,succnt);
5156 SSVAL(*rparam,6,queuecnt);
5158 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
5160 return True;
5163 static bool api_WPrintDriverEnum(struct smbd_server_connection *sconn,
5164 connection_struct *conn, uint64_t vuid,
5165 char *param, int tpscnt,
5166 char *data, int tdscnt,
5167 int mdrcnt,int mprcnt,
5168 char **rdata,char **rparam,
5169 int *rdata_len,int *rparam_len)
5171 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5172 char *str2 = skip_string(param,tpscnt,str1);
5173 char *p = skip_string(param,tpscnt,str2);
5174 int uLevel;
5175 int succnt;
5176 struct pack_desc desc;
5178 if (!str1 || !str2 || !p) {
5179 return False;
5182 memset((char *)&desc,'\0',sizeof(desc));
5184 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5186 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
5188 /* check it's a supported varient */
5189 if (strcmp(str1,"WrLeh") != 0) {
5190 return False;
5192 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
5193 return False;
5196 if (mdrcnt > 0) {
5197 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5198 if (!*rdata) {
5199 return False;
5202 desc.base = *rdata;
5203 desc.buflen = mdrcnt;
5204 if (init_package(&desc,1,0)) {
5205 PACKS(&desc,"B41","NULL");
5208 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5210 *rdata_len = desc.usedlen;
5212 *rparam_len = 8;
5213 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5214 if (!*rparam) {
5215 return False;
5217 SSVALS(*rparam,0,desc.errcode);
5218 SSVAL(*rparam,2,0);
5219 SSVAL(*rparam,4,succnt);
5220 SSVAL(*rparam,6,1);
5222 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
5224 return True;
5227 static bool api_WPrintQProcEnum(struct smbd_server_connection *sconn,
5228 connection_struct *conn, uint64_t vuid,
5229 char *param, int tpscnt,
5230 char *data, int tdscnt,
5231 int mdrcnt,int mprcnt,
5232 char **rdata,char **rparam,
5233 int *rdata_len,int *rparam_len)
5235 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5236 char *str2 = skip_string(param,tpscnt,str1);
5237 char *p = skip_string(param,tpscnt,str2);
5238 int uLevel;
5239 int succnt;
5240 struct pack_desc desc;
5242 if (!str1 || !str2 || !p) {
5243 return False;
5245 memset((char *)&desc,'\0',sizeof(desc));
5247 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5249 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
5251 /* check it's a supported varient */
5252 if (strcmp(str1,"WrLeh") != 0) {
5253 return False;
5255 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
5256 return False;
5259 if (mdrcnt > 0) {
5260 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5261 if (!*rdata) {
5262 return False;
5265 desc.base = *rdata;
5266 desc.buflen = mdrcnt;
5267 desc.format = str2;
5268 if (init_package(&desc,1,0)) {
5269 PACKS(&desc,"B13","lpd");
5272 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5274 *rdata_len = desc.usedlen;
5276 *rparam_len = 8;
5277 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5278 if (!*rparam) {
5279 return False;
5281 SSVALS(*rparam,0,desc.errcode);
5282 SSVAL(*rparam,2,0);
5283 SSVAL(*rparam,4,succnt);
5284 SSVAL(*rparam,6,1);
5286 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
5288 return True;
5291 static bool api_WPrintPortEnum(struct smbd_server_connection *sconn,
5292 connection_struct *conn, uint64_t vuid,
5293 char *param, int tpscnt,
5294 char *data, int tdscnt,
5295 int mdrcnt,int mprcnt,
5296 char **rdata,char **rparam,
5297 int *rdata_len,int *rparam_len)
5299 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5300 char *str2 = skip_string(param,tpscnt,str1);
5301 char *p = skip_string(param,tpscnt,str2);
5302 int uLevel;
5303 int succnt;
5304 struct pack_desc desc;
5306 if (!str1 || !str2 || !p) {
5307 return False;
5310 memset((char *)&desc,'\0',sizeof(desc));
5312 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5314 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
5316 /* check it's a supported varient */
5317 if (strcmp(str1,"WrLeh") != 0) {
5318 return False;
5320 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
5321 return False;
5324 if (mdrcnt > 0) {
5325 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5326 if (!*rdata) {
5327 return False;
5330 memset((char *)&desc,'\0',sizeof(desc));
5331 desc.base = *rdata;
5332 desc.buflen = mdrcnt;
5333 desc.format = str2;
5334 if (init_package(&desc,1,0)) {
5335 PACKS(&desc,"B13","lp0");
5338 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5340 *rdata_len = desc.usedlen;
5342 *rparam_len = 8;
5343 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5344 if (!*rparam) {
5345 return False;
5347 SSVALS(*rparam,0,desc.errcode);
5348 SSVAL(*rparam,2,0);
5349 SSVAL(*rparam,4,succnt);
5350 SSVAL(*rparam,6,1);
5352 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
5354 return True;
5357 /****************************************************************************
5358 List open sessions
5359 ****************************************************************************/
5361 static bool api_RNetSessionEnum(struct smbd_server_connection *sconn,
5362 connection_struct *conn, uint64_t vuid,
5363 char *param, int tpscnt,
5364 char *data, int tdscnt,
5365 int mdrcnt,int mprcnt,
5366 char **rdata,char **rparam,
5367 int *rdata_len,int *rparam_len)
5370 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5371 char *str2 = skip_string(param,tpscnt,str1);
5372 char *p = skip_string(param,tpscnt,str2);
5373 int uLevel;
5374 struct pack_desc desc;
5375 int i;
5377 TALLOC_CTX *mem_ctx = talloc_tos();
5378 WERROR werr;
5379 NTSTATUS status;
5380 struct rpc_pipe_client *cli = NULL;
5381 struct dcerpc_binding_handle *b = NULL;
5382 struct srvsvc_NetSessInfoCtr info_ctr;
5383 uint32_t totalentries, resume_handle = 0;
5384 uint32_t count = 0;
5386 if (!str1 || !str2 || !p) {
5387 return False;
5390 ZERO_STRUCT(desc);
5392 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5394 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
5395 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
5396 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
5398 /* check it's a supported varient */
5399 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
5400 return False;
5402 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
5403 return False;
5406 status = rpc_pipe_open_interface(mem_ctx,
5407 &ndr_table_srvsvc,
5408 conn->session_info,
5409 conn->sconn->remote_address,
5410 conn->sconn->local_address,
5411 conn->sconn->msg_ctx,
5412 &cli);
5413 if (!NT_STATUS_IS_OK(status)) {
5414 DEBUG(0,("RNetSessionEnum: could not connect to srvsvc: %s\n",
5415 nt_errstr(status)));
5416 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5417 goto out;
5419 b = cli->binding_handle;
5421 info_ctr.level = 1;
5422 info_ctr.ctr.ctr1 = talloc_zero(talloc_tos(), struct srvsvc_NetSessCtr1);
5423 if (info_ctr.ctr.ctr1 == NULL) {
5424 desc.errcode = W_ERROR_V(WERR_NOT_ENOUGH_MEMORY);
5425 goto out;
5428 status = dcerpc_srvsvc_NetSessEnum(b, mem_ctx,
5429 cli->srv_name_slash,
5430 NULL, /* client */
5431 NULL, /* user */
5432 &info_ctr,
5433 (uint32_t)-1, /* max_buffer */
5434 &totalentries,
5435 &resume_handle,
5436 &werr);
5437 if (!NT_STATUS_IS_OK(status)) {
5438 DEBUG(0,("RNetSessionEnum: dcerpc_srvsvc_NetSessEnum failed: %s\n",
5439 nt_errstr(status)));
5440 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5441 goto out;
5444 if (!W_ERROR_IS_OK(werr)) {
5445 DEBUG(0,("RNetSessionEnum: dcerpc_srvsvc_NetSessEnum failed: %s\n",
5446 win_errstr(werr)));
5447 desc.errcode = W_ERROR_V(werr);
5448 goto out;
5451 count = info_ctr.ctr.ctr1->count;
5453 out:
5454 if (mdrcnt > 0) {
5455 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5456 if (!*rdata) {
5457 return False;
5461 desc.base = *rdata;
5462 desc.buflen = mdrcnt;
5463 desc.format = str2;
5464 if (!init_package(&desc, count,0)) {
5465 return False;
5468 for(i=0; i < count; i++) {
5469 PACKS(&desc, "z", info_ctr.ctr.ctr1->array[i].client);
5470 PACKS(&desc, "z", info_ctr.ctr.ctr1->array[i].user);
5471 PACKI(&desc, "W", 1); /* num conns */
5472 PACKI(&desc, "W", info_ctr.ctr.ctr1->array[i].num_open);
5473 PACKI(&desc, "W", 1); /* num users */
5474 PACKI(&desc, "D", 0); /* session time */
5475 PACKI(&desc, "D", 0); /* idle time */
5476 PACKI(&desc, "D", 0); /* flags */
5477 PACKS(&desc, "z", "Unknown Client"); /* client type string */
5480 *rdata_len = desc.usedlen;
5482 *rparam_len = 8;
5483 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5484 if (!*rparam) {
5485 return False;
5487 SSVALS(*rparam,0,desc.errcode);
5488 SSVAL(*rparam,2,0); /* converter */
5489 SSVAL(*rparam,4, count); /* count */
5491 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
5493 return True;
5497 /****************************************************************************
5498 The buffer was too small.
5499 ****************************************************************************/
5501 static bool api_TooSmall(struct smbd_server_connection *sconn,
5502 connection_struct *conn,uint64_t vuid, char *param, char *data,
5503 int mdrcnt, int mprcnt,
5504 char **rdata, char **rparam,
5505 int *rdata_len, int *rparam_len)
5507 *rparam_len = MIN(*rparam_len,mprcnt);
5508 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5509 if (!*rparam) {
5510 return False;
5513 *rdata_len = 0;
5515 SSVAL(*rparam,0,NERR_BufTooSmall);
5517 DEBUG(3,("Supplied buffer too small in API command\n"));
5519 return True;
5522 /****************************************************************************
5523 The request is not supported.
5524 ****************************************************************************/
5526 static bool api_Unsupported(struct smbd_server_connection *sconn,
5527 connection_struct *conn, uint64_t vuid,
5528 char *param, int tpscnt,
5529 char *data, int tdscnt,
5530 int mdrcnt, int mprcnt,
5531 char **rdata, char **rparam,
5532 int *rdata_len, int *rparam_len)
5534 *rparam_len = 4;
5535 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5536 if (!*rparam) {
5537 return False;
5540 *rdata_len = 0;
5542 SSVAL(*rparam,0,NERR_notsupported);
5543 SSVAL(*rparam,2,0); /* converter word */
5545 DEBUG(3,("Unsupported API command\n"));
5547 return True;
5550 static const struct {
5551 const char *name;
5552 int id;
5553 bool (*fn)(struct smbd_server_connection *sconn,
5554 connection_struct *, uint64_t,
5555 char *, int,
5556 char *, int,
5557 int,int,char **,char **,int *,int *);
5558 bool auth_user; /* Deny anonymous access? */
5559 } api_commands[] = {
5561 .name = "RNetShareEnum",
5562 .id = RAP_WshareEnum,
5563 .fn = api_RNetShareEnum,
5564 .auth_user = true,
5567 .name = "RNetShareGetInfo",
5568 .id = RAP_WshareGetInfo,
5569 .fn = api_RNetShareGetInfo
5572 .name = "RNetShareAdd",
5573 .id = RAP_WshareAdd,
5574 .fn = api_RNetShareAdd
5577 .name = "RNetSessionEnum",
5578 .id = RAP_WsessionEnum,
5579 .fn = api_RNetSessionEnum,
5580 .auth_user = true,
5583 .name = "RNetServerGetInfo",
5584 .id = RAP_WserverGetInfo,
5585 .fn = api_RNetServerGetInfo
5588 .name = "RNetGroupEnum",
5589 .id = RAP_WGroupEnum,
5590 .fn = api_RNetGroupEnum, True
5593 .name = "RNetGroupGetUsers",
5594 .id = RAP_WGroupGetUsers,
5595 .fn = api_RNetGroupGetUsers,
5596 .auth_user = true},
5598 .name = "RNetUserEnum",
5599 .id = RAP_WUserEnum,
5600 .fn = api_RNetUserEnum,
5601 .auth_user = true,
5604 .name = "RNetUserGetInfo",
5605 .id = RAP_WUserGetInfo,
5606 .fn = api_RNetUserGetInfo
5609 .name = "NetUserGetGroups",
5610 .id = RAP_WUserGetGroups,
5611 .fn = api_NetUserGetGroups
5614 .name = "NetWkstaGetInfo",
5615 .id = RAP_WWkstaGetInfo,
5616 .fn = api_NetWkstaGetInfo
5619 .name = "DosPrintQEnum",
5620 .id = RAP_WPrintQEnum,
5621 .fn = api_DosPrintQEnum,
5622 .auth_user = true,
5625 .name = "DosPrintQGetInfo",
5626 .id = RAP_WPrintQGetInfo,
5627 .fn = api_DosPrintQGetInfo
5630 .name = "WPrintQueuePause",
5631 .id = RAP_WPrintQPause,
5632 .fn = api_WPrintQueueCtrl
5635 .name = "WPrintQueueResume",
5636 .id = RAP_WPrintQContinue,
5637 .fn = api_WPrintQueueCtrl
5640 .name = "WPrintJobEnumerate",
5641 .id = RAP_WPrintJobEnum,
5642 .fn = api_WPrintJobEnumerate
5645 .name = "WPrintJobGetInfo",
5646 .id = RAP_WPrintJobGetInfo,
5647 .fn = api_WPrintJobGetInfo
5650 .name = "RDosPrintJobDel",
5651 .id = RAP_WPrintJobDel,
5652 .fn = api_RDosPrintJobDel
5655 .name = "RDosPrintJobPause",
5656 .id = RAP_WPrintJobPause,
5657 .fn = api_RDosPrintJobDel
5660 .name = "RDosPrintJobResume",
5661 .id = RAP_WPrintJobContinue,
5662 .fn = api_RDosPrintJobDel
5665 .name = "WPrintDestEnum",
5666 .id = RAP_WPrintDestEnum,
5667 .fn = api_WPrintDestEnum
5670 .name = "WPrintDestGetInfo",
5671 .id = RAP_WPrintDestGetInfo,
5672 .fn = api_WPrintDestGetInfo
5675 .name = "NetRemoteTOD",
5676 .id = RAP_NetRemoteTOD,
5677 .fn = api_NetRemoteTOD
5680 .name = "WPrintQueuePurge",
5681 .id = RAP_WPrintQPurge,
5682 .fn = api_WPrintQueueCtrl
5685 .name = "NetServerEnum2",
5686 .id = RAP_NetServerEnum2,
5687 .fn = api_RNetServerEnum2
5688 }, /* anon OK */
5690 .name = "NetServerEnum3",
5691 .id = RAP_NetServerEnum3,
5692 .fn = api_RNetServerEnum3
5693 }, /* anon OK */
5695 .name = "WAccessGetUserPerms",
5696 .id = RAP_WAccessGetUserPerms,
5697 .fn = api_WAccessGetUserPerms
5700 .name = "WWkstaUserLogon",
5701 .id = RAP_WWkstaUserLogon,
5702 .fn = api_WWkstaUserLogon
5705 .name = "PrintJobInfo",
5706 .id = RAP_WPrintJobSetInfo,
5707 .fn = api_PrintJobInfo
5710 .name = "WPrintDriverEnum",
5711 .id = RAP_WPrintDriverEnum,
5712 .fn = api_WPrintDriverEnum
5715 .name = "WPrintQProcEnum",
5716 .id = RAP_WPrintQProcessorEnum,
5717 .fn = api_WPrintQProcEnum
5720 .name = "WPrintPortEnum",
5721 .id = RAP_WPrintPortEnum,
5722 .fn = api_WPrintPortEnum
5725 .name = "SamOEMChangePassword",
5726 .id = RAP_SamOEMChgPasswordUser2_P,
5727 .fn = api_SamOEMChangePassword
5728 }, /* anon OK */
5730 .name = NULL,
5731 .id = -1,
5732 .fn = api_Unsupported}
5734 * The following RAP calls are not implemented by Samba:
5735 * RAP_WFileEnum2 - anon not OK
5740 /****************************************************************************
5741 Handle remote api calls.
5742 ****************************************************************************/
5744 void api_reply(connection_struct *conn, uint64_t vuid,
5745 struct smb_request *req,
5746 char *data, char *params,
5747 int tdscnt, int tpscnt,
5748 int mdrcnt, int mprcnt)
5750 int api_command;
5751 char *rdata = NULL;
5752 char *rparam = NULL;
5753 const char *name1 = NULL;
5754 const char *name2 = NULL;
5755 int rdata_len = 0;
5756 int rparam_len = 0;
5757 bool reply=False;
5758 int i;
5760 if (!params) {
5761 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
5762 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5763 return;
5766 if (tpscnt < 2) {
5767 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5768 return;
5770 api_command = SVAL(params,0);
5771 /* Is there a string at position params+2 ? */
5772 if (skip_string(params,tpscnt,params+2)) {
5773 name1 = params + 2;
5774 } else {
5775 name1 = "";
5777 name2 = skip_string(params,tpscnt,params+2);
5778 if (!name2) {
5779 name2 = "";
5782 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
5783 api_command,
5784 name1,
5785 name2,
5786 tdscnt,tpscnt,mdrcnt,mprcnt));
5788 for (i=0;api_commands[i].name;i++) {
5789 if (api_commands[i].id == api_command && api_commands[i].fn) {
5790 DEBUG(3,("Doing %s\n",api_commands[i].name));
5791 break;
5795 /* Check whether this api call can be done anonymously */
5797 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
5798 struct auth_session_info *si = NULL;
5799 NTSTATUS status;
5801 status = smbXsrv_session_info_lookup(conn->sconn->client,
5802 vuid,
5803 &si);
5804 if (!NT_STATUS_IS_OK(status)) {
5805 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5806 return;
5809 if (security_session_user_level(si, NULL) < SECURITY_USER) {
5810 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5811 return;
5815 rdata = (char *)SMB_MALLOC(1024);
5816 if (rdata) {
5817 memset(rdata,'\0',1024);
5820 rparam = (char *)SMB_MALLOC(1024);
5821 if (rparam) {
5822 memset(rparam,'\0',1024);
5825 if(!rdata || !rparam) {
5826 DEBUG(0,("api_reply: malloc fail !\n"));
5827 SAFE_FREE(rdata);
5828 SAFE_FREE(rparam);
5829 reply_nterror(req, NT_STATUS_NO_MEMORY);
5830 return;
5833 reply = api_commands[i].fn(req->sconn, conn,
5834 vuid,
5835 params,tpscnt, /* params + length */
5836 data,tdscnt, /* data + length */
5837 mdrcnt,mprcnt,
5838 &rdata,&rparam,&rdata_len,&rparam_len);
5841 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
5842 reply = api_TooSmall(req->sconn,conn,vuid,params,data,
5843 mdrcnt,mprcnt,
5844 &rdata,&rparam,&rdata_len,&rparam_len);
5847 /* if we get False back then it's actually unsupported */
5848 if (!reply) {
5849 reply = api_Unsupported(req->sconn,conn,vuid,params,tpscnt,
5850 data,
5851 tdscnt,mdrcnt,mprcnt,
5852 &rdata,&rparam,&rdata_len,&rparam_len);
5855 /* If api_Unsupported returns false we can't return anything. */
5856 if (reply) {
5857 send_trans_reply(conn, req, rparam, rparam_len,
5858 rdata, rdata_len, False);
5861 SAFE_FREE(rdata);
5862 SAFE_FREE(rparam);
5863 return;