VERSION: Re-enable git snapshots.
[Samba.git] / source3 / smbd / lanman.c
blobd0dae36db2eb5d29324458c4d2de3d542c04515a
1 /*
2 Unix SMB/CIFS implementation.
3 Inter-process communication and named pipe handling
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Jeremy Allison 2007.
7 SMB Version handling
8 Copyright (C) John H Terpstra 1995-1998
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 This file handles the named pipe and mailslot calls
25 in the SMBtrans protocol
28 #include "includes.h"
29 #include "smbd/smbd.h"
30 #include "smbd/globals.h"
31 #include "rpc_client/rpc_client.h"
32 #include "../librpc/gen_ndr/ndr_samr_c.h"
33 #include "../librpc/gen_ndr/ndr_spoolss_c.h"
34 #include "rpc_client/cli_spoolss.h"
35 #include "rpc_client/init_spoolss.h"
36 #include "../librpc/gen_ndr/ndr_srvsvc_c.h"
37 #include "../librpc/gen_ndr/rap.h"
38 #include "../lib/util/binsearch.h"
39 #include "../libcli/auth/libcli_auth.h"
40 #include "rpc_client/init_lsa.h"
41 #include "../libcli/security/security.h"
42 #include "printing.h"
43 #include "passdb/machine_sid.h"
44 #include "auth.h"
45 #include "rpc_server/rpc_ncacn_np.h"
47 #ifdef CHECK_TYPES
48 #undef CHECK_TYPES
49 #endif
50 #define CHECK_TYPES 0
52 #define NERR_Success 0
53 #define NERR_badpass 86
54 #define NERR_notsupported 50
56 #define NERR_BASE (2100)
57 #define NERR_BufTooSmall (NERR_BASE+23)
58 #define NERR_JobNotFound (NERR_BASE+51)
59 #define NERR_DestNotFound (NERR_BASE+52)
61 #define ACCESS_READ 0x01
62 #define ACCESS_WRITE 0x02
63 #define ACCESS_CREATE 0x04
65 #define SHPWLEN 8 /* share password length */
67 /* Limit size of ipc replies */
69 static char *smb_realloc_limit(void *ptr, size_t size)
71 char *val;
73 size = MAX((size),4*1024);
74 val = (char *)SMB_REALLOC(ptr,size);
75 if (val) {
76 memset(val,'\0',size);
78 return val;
81 static bool api_Unsupported(struct smbd_server_connection *sconn,
82 connection_struct *conn, uint64_t vuid,
83 char *param, int tpscnt,
84 char *data, int tdscnt,
85 int mdrcnt, int mprcnt,
86 char **rdata, char **rparam,
87 int *rdata_len, int *rparam_len);
89 static bool api_TooSmall(struct smbd_server_connection *sconn,
90 connection_struct *conn, uint64_t vuid, char *param, char *data,
91 int mdrcnt, int mprcnt,
92 char **rdata, char **rparam,
93 int *rdata_len, int *rparam_len);
96 static int CopyExpanded(connection_struct *conn,
97 int snum, char **dst, char *src, int *p_space_remaining)
99 TALLOC_CTX *ctx = talloc_tos();
100 char *buf = NULL;
101 int l;
103 if (!src || !dst || !p_space_remaining || !(*dst) ||
104 *p_space_remaining <= 0) {
105 return 0;
108 buf = talloc_strdup(ctx, src);
109 if (!buf) {
110 *p_space_remaining = 0;
111 return 0;
113 buf = talloc_string_sub(ctx, buf,"%S", lp_servicename(ctx, snum));
114 if (!buf) {
115 *p_space_remaining = 0;
116 return 0;
118 buf = talloc_sub_advanced(ctx,
119 lp_servicename(ctx, SNUM(conn)),
120 conn->session_info->unix_info->unix_name,
121 conn->connectpath,
122 conn->session_info->unix_token->gid,
123 conn->session_info->unix_info->sanitized_username,
124 conn->session_info->info->domain_name,
125 buf);
126 if (!buf) {
127 *p_space_remaining = 0;
128 return 0;
130 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
131 if (l == 0) {
132 return 0;
134 (*dst) += l;
135 (*p_space_remaining) -= l;
136 return l;
139 static int CopyAndAdvance(char **dst, char *src, int *n)
141 int l;
142 if (!src || !dst || !n || !(*dst)) {
143 return 0;
145 l = push_ascii(*dst,src,*n, STR_TERMINATE);
146 if (l == 0) {
147 return 0;
149 (*dst) += l;
150 (*n) -= l;
151 return l;
154 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
156 TALLOC_CTX *ctx = talloc_tos();
157 char *buf = NULL;
158 if (!s) {
159 return 0;
161 buf = talloc_strdup(ctx,s);
162 if (!buf) {
163 return 0;
165 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(ctx, snum));
166 if (!buf) {
167 return 0;
169 buf = talloc_sub_advanced(ctx,
170 lp_servicename(ctx, SNUM(conn)),
171 conn->session_info->unix_info->unix_name,
172 conn->connectpath,
173 conn->session_info->unix_token->gid,
174 conn->session_info->unix_info->sanitized_username,
175 conn->session_info->info->domain_name,
176 buf);
177 if (!buf) {
178 return 0;
180 return strlen(buf) + 1;
183 /*******************************************************************
184 Check a API string for validity when we only need to check the prefix.
185 ******************************************************************/
187 static bool prefix_ok(const char *str, const char *prefix)
189 return(strncmp(str,prefix,strlen(prefix)) == 0);
192 struct pack_desc {
193 const char *format; /* formatstring for structure */
194 const char *subformat; /* subformat for structure */
195 char *base; /* baseaddress of buffer */
196 int buflen; /* remaining size for fixed part; on init: length of base */
197 int subcount; /* count of substructures */
198 char *structbuf; /* pointer into buffer for remaining fixed part */
199 int stringlen; /* remaining size for variable part */
200 char *stringbuf; /* pointer into buffer for remaining variable part */
201 int neededlen; /* total needed size */
202 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
203 const char *curpos; /* current position; pointer into format or subformat */
204 int errcode;
207 static int get_counter(const char **p)
209 int i, n;
210 if (!p || !(*p)) {
211 return 1;
213 if (!isdigit((int)**p)) {
214 return 1;
216 for (n = 0;;) {
217 i = **p;
218 if (isdigit(i)) {
219 n = 10 * n + (i - '0');
220 } else {
221 return n;
223 (*p)++;
227 static int getlen(const char *p)
229 int n = 0;
230 if (!p) {
231 return 0;
234 while (*p) {
235 switch( *p++ ) {
236 case 'W': /* word (2 byte) */
237 n += 2;
238 break;
239 case 'K': /* status word? (2 byte) */
240 n += 2;
241 break;
242 case 'N': /* count of substructures (word) at end */
243 n += 2;
244 break;
245 case 'D': /* double word (4 byte) */
246 case 'z': /* offset to zero terminated string (4 byte) */
247 case 'l': /* offset to user data (4 byte) */
248 n += 4;
249 break;
250 case 'b': /* offset to data (with counter) (4 byte) */
251 n += 4;
252 get_counter(&p);
253 break;
254 case 'B': /* byte (with optional counter) */
255 n += get_counter(&p);
256 break;
259 return n;
262 static bool init_package(struct pack_desc *p, int count, int subcount)
264 int n = p->buflen;
265 int i;
267 if (!p->format || !p->base) {
268 return False;
271 i = count * getlen(p->format);
272 if (p->subformat) {
273 i += subcount * getlen(p->subformat);
275 p->structbuf = p->base;
276 p->neededlen = 0;
277 p->usedlen = 0;
278 p->subcount = 0;
279 p->curpos = p->format;
280 if (i > n) {
281 p->neededlen = i;
282 i = n = 0;
283 #if 0
285 * This is the old error code we used. Aparently
286 * WinNT/2k systems return ERRbuftoosmall (2123) and
287 * OS/2 needs this. I'm leaving this here so we can revert
288 * if needed. JRA.
290 p->errcode = ERRmoredata;
291 #else
292 p->errcode = ERRbuftoosmall;
293 #endif
294 } else {
295 p->errcode = NERR_Success;
297 p->buflen = i;
298 n -= i;
299 p->stringbuf = p->base + i;
300 p->stringlen = n;
301 return (p->errcode == NERR_Success);
304 static int package(struct pack_desc *p, ...)
306 va_list args;
307 int needed=0, stringneeded;
308 const char *str=NULL;
309 int is_string=0, stringused;
310 int32 temp;
312 va_start(args,p);
314 if (!*p->curpos) {
315 if (!p->subcount) {
316 p->curpos = p->format;
317 } else {
318 p->curpos = p->subformat;
319 p->subcount--;
322 #if CHECK_TYPES
323 str = va_arg(args,char*);
324 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
325 #endif
326 stringneeded = -1;
328 if (!p->curpos) {
329 va_end(args);
330 return 0;
333 switch( *p->curpos++ ) {
334 case 'W': /* word (2 byte) */
335 needed = 2;
336 temp = va_arg(args,int);
337 if (p->buflen >= needed) {
338 SSVAL(p->structbuf,0,temp);
340 break;
341 case 'K': /* status word? (2 byte) */
342 needed = 2;
343 temp = va_arg(args,int);
344 if (p->buflen >= needed) {
345 SSVAL(p->structbuf,0,temp);
347 break;
348 case 'N': /* count of substructures (word) at end */
349 needed = 2;
350 p->subcount = va_arg(args,int);
351 if (p->buflen >= needed) {
352 SSVAL(p->structbuf,0,p->subcount);
354 break;
355 case 'D': /* double word (4 byte) */
356 needed = 4;
357 temp = va_arg(args,int);
358 if (p->buflen >= needed) {
359 SIVAL(p->structbuf,0,temp);
361 break;
362 case 'B': /* byte (with optional counter) */
363 needed = get_counter(&p->curpos);
365 char *s = va_arg(args,char*);
366 if (p->buflen >= needed) {
367 StrnCpy(p->structbuf,s?s:"",needed-1);
370 break;
371 case 'z': /* offset to zero terminated string (4 byte) */
372 str = va_arg(args,char*);
373 stringneeded = (str ? strlen(str)+1 : 0);
374 is_string = 1;
375 break;
376 case 'l': /* offset to user data (4 byte) */
377 str = va_arg(args,char*);
378 stringneeded = va_arg(args,int);
379 is_string = 0;
380 break;
381 case 'b': /* offset to data (with counter) (4 byte) */
382 str = va_arg(args,char*);
383 stringneeded = get_counter(&p->curpos);
384 is_string = 0;
385 break;
388 va_end(args);
389 if (stringneeded >= 0) {
390 needed = 4;
391 if (p->buflen >= needed) {
392 stringused = stringneeded;
393 if (stringused > p->stringlen) {
394 stringused = (is_string ? p->stringlen : 0);
395 if (p->errcode == NERR_Success) {
396 p->errcode = ERRmoredata;
399 if (!stringused) {
400 SIVAL(p->structbuf,0,0);
401 } else {
402 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
403 memcpy(p->stringbuf,str?str:"",stringused);
404 if (is_string) {
405 p->stringbuf[stringused-1] = '\0';
407 p->stringbuf += stringused;
408 p->stringlen -= stringused;
409 p->usedlen += stringused;
412 p->neededlen += stringneeded;
415 p->neededlen += needed;
416 if (p->buflen >= needed) {
417 p->structbuf += needed;
418 p->buflen -= needed;
419 p->usedlen += needed;
420 } else {
421 if (p->errcode == NERR_Success) {
422 p->errcode = ERRmoredata;
425 return 1;
428 #if CHECK_TYPES
429 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
430 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
431 #else
432 #define PACK(desc,t,v) package(desc,v)
433 #define PACKl(desc,t,v,l) package(desc,v,l)
434 #endif
436 static void PACKI(struct pack_desc* desc, const char *t,int v)
438 PACK(desc,t,v);
441 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
443 PACK(desc,t,v);
446 /****************************************************************************
447 Get a print queue.
448 ****************************************************************************/
450 static void PackDriverData(struct pack_desc* desc)
452 char drivdata[4+4+32];
453 SIVAL(drivdata,0,sizeof drivdata); /* cb */
454 SIVAL(drivdata,4,1000); /* lVersion */
455 memset(drivdata+8,0,32); /* szDeviceName */
456 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
457 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
460 static int check_printq_info(struct pack_desc* desc,
461 unsigned int uLevel, char *id1, char *id2)
463 desc->subformat = NULL;
464 switch( uLevel ) {
465 case 0:
466 desc->format = "B13";
467 break;
468 case 1:
469 desc->format = "B13BWWWzzzzzWW";
470 break;
471 case 2:
472 desc->format = "B13BWWWzzzzzWN";
473 desc->subformat = "WB21BB16B10zWWzDDz";
474 break;
475 case 3:
476 desc->format = "zWWWWzzzzWWzzl";
477 break;
478 case 4:
479 desc->format = "zWWWWzzzzWNzzl";
480 desc->subformat = "WWzWWDDzz";
481 break;
482 case 5:
483 desc->format = "z";
484 break;
485 case 51:
486 desc->format = "K";
487 break;
488 case 52:
489 desc->format = "WzzzzzzzzN";
490 desc->subformat = "z";
491 break;
492 default:
493 DEBUG(0,("check_printq_info: invalid level %d\n",
494 uLevel ));
495 return False;
497 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
498 DEBUG(0,("check_printq_info: invalid format %s\n",
499 id1 ? id1 : "<NULL>" ));
500 return False;
502 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
503 DEBUG(0,("check_printq_info: invalid subformat %s\n",
504 id2 ? id2 : "<NULL>" ));
505 return False;
507 return True;
511 #define RAP_JOB_STATUS_QUEUED 0
512 #define RAP_JOB_STATUS_PAUSED 1
513 #define RAP_JOB_STATUS_SPOOLING 2
514 #define RAP_JOB_STATUS_PRINTING 3
515 #define RAP_JOB_STATUS_PRINTED 4
517 #define RAP_QUEUE_STATUS_PAUSED 1
518 #define RAP_QUEUE_STATUS_ERROR 2
520 /* turn a print job status into a on the wire status
522 static int printj_spoolss_status(int v)
524 if (v == JOB_STATUS_QUEUED)
525 return RAP_JOB_STATUS_QUEUED;
526 if (v & JOB_STATUS_PAUSED)
527 return RAP_JOB_STATUS_PAUSED;
528 if (v & JOB_STATUS_SPOOLING)
529 return RAP_JOB_STATUS_SPOOLING;
530 if (v & JOB_STATUS_PRINTING)
531 return RAP_JOB_STATUS_PRINTING;
532 return 0;
535 /* turn a print queue status into a on the wire status
537 static int printq_spoolss_status(int v)
539 if (v == PRINTER_STATUS_OK)
540 return 0;
541 if (v & PRINTER_STATUS_PAUSED)
542 return RAP_QUEUE_STATUS_PAUSED;
543 return RAP_QUEUE_STATUS_ERROR;
546 static void fill_spoolss_printjob_info(int uLevel,
547 struct pack_desc *desc,
548 struct spoolss_JobInfo2 *info2,
549 int n)
551 time_t t = spoolss_Time_to_time_t(&info2->submitted);
553 /* the client expects localtime */
554 t -= get_time_zone(t);
556 PACKI(desc,"W",pjobid_to_rap(info2->printer_name, info2->job_id)); /* uJobId */
557 if (uLevel == 1) {
558 PACKS(desc,"B21", info2->user_name); /* szUserName */
559 PACKS(desc,"B",""); /* pad */
560 PACKS(desc,"B16",""); /* szNotifyName */
561 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
562 PACKS(desc,"z",""); /* pszParms */
563 PACKI(desc,"W",n+1); /* uPosition */
564 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
565 PACKS(desc,"z",""); /* pszStatus */
566 PACKI(desc,"D", t); /* ulSubmitted */
567 PACKI(desc,"D", info2->size); /* ulSize */
568 PACKS(desc,"z", info2->document_name); /* pszComment */
570 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
571 PACKI(desc,"W", info2->priority); /* uPriority */
572 PACKS(desc,"z", info2->user_name); /* pszUserName */
573 PACKI(desc,"W",n+1); /* uPosition */
574 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
575 PACKI(desc,"D",t); /* ulSubmitted */
576 PACKI(desc,"D", info2->size); /* ulSize */
577 PACKS(desc,"z","Samba"); /* pszComment */
578 PACKS(desc,"z", info2->document_name); /* pszDocument */
579 if (uLevel == 3) {
580 PACKS(desc,"z",""); /* pszNotifyName */
581 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
582 PACKS(desc,"z",""); /* pszParms */
583 PACKS(desc,"z",""); /* pszStatus */
584 PACKS(desc,"z", info2->printer_name); /* pszQueue */
585 PACKS(desc,"z","lpd"); /* pszQProcName */
586 PACKS(desc,"z",""); /* pszQProcParms */
587 PACKS(desc,"z","NULL"); /* pszDriverName */
588 PackDriverData(desc); /* pDriverData */
589 PACKS(desc,"z",""); /* pszPrinterName */
590 } else if (uLevel == 4) { /* OS2 */
591 PACKS(desc,"z",""); /* pszSpoolFileName */
592 PACKS(desc,"z",""); /* pszPortName */
593 PACKS(desc,"z",""); /* pszStatus */
594 PACKI(desc,"D",0); /* ulPagesSpooled */
595 PACKI(desc,"D",0); /* ulPagesSent */
596 PACKI(desc,"D",0); /* ulPagesPrinted */
597 PACKI(desc,"D",0); /* ulTimePrinted */
598 PACKI(desc,"D",0); /* ulExtendJobStatus */
599 PACKI(desc,"D",0); /* ulStartPage */
600 PACKI(desc,"D",0); /* ulEndPage */
605 /********************************************************************
606 Respond to the DosPrintQInfo command with a level of 52
607 This is used to get printer driver information for Win9x clients
608 ********************************************************************/
609 static void fill_printq_info_52(struct spoolss_DriverInfo3 *driver,
610 struct pack_desc* desc, int count,
611 const char *printer_name)
613 int i;
614 fstring location;
615 trim_string(discard_const_p(char, driver->driver_path), "\\print$\\WIN40\\0\\", 0);
616 trim_string(discard_const_p(char, driver->data_file), "\\print$\\WIN40\\0\\", 0);
617 trim_string(discard_const_p(char, driver->help_file), "\\print$\\WIN40\\0\\", 0);
619 PACKI(desc, "W", 0x0400); /* don't know */
620 PACKS(desc, "z", driver->driver_name); /* long printer name */
621 PACKS(desc, "z", driver->driver_path); /* Driverfile Name */
622 PACKS(desc, "z", driver->data_file); /* Datafile name */
623 PACKS(desc, "z", driver->monitor_name); /* language monitor */
625 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
626 standard_sub_basic( "", "", location, sizeof(location)-1 );
627 PACKS(desc,"z", location); /* share to retrieve files */
629 PACKS(desc,"z", driver->default_datatype); /* default data type */
630 PACKS(desc,"z", driver->help_file); /* helpfile name */
631 PACKS(desc,"z", driver->driver_path); /* driver name */
633 DEBUG(3,("Printer Driver Name: %s:\n",driver->driver_name));
634 DEBUG(3,("Driver: %s:\n",driver->driver_path));
635 DEBUG(3,("Data File: %s:\n",driver->data_file));
636 DEBUG(3,("Language Monitor: %s:\n",driver->monitor_name));
637 DEBUG(3,("Driver Location: %s:\n",location));
638 DEBUG(3,("Data Type: %s:\n",driver->default_datatype));
639 DEBUG(3,("Help File: %s:\n",driver->help_file));
640 PACKI(desc,"N",count); /* number of files to copy */
642 for ( i=0; i<count && driver->dependent_files && *driver->dependent_files[i]; i++)
644 trim_string(discard_const_p(char, driver->dependent_files[i]), "\\print$\\WIN40\\0\\", 0);
645 PACKS(desc,"z",driver->dependent_files[i]); /* driver files to copy */
646 DEBUG(3,("Dependent File: %s:\n", driver->dependent_files[i]));
649 /* sanity check */
650 if ( i != count )
651 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
652 count, i));
654 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", printer_name, i));
656 desc->errcode=NERR_Success;
660 static const char *strip_unc(const char *unc)
662 char *p;
664 if (unc == NULL) {
665 return NULL;
668 if ((p = strrchr(unc, '\\')) != NULL) {
669 return p+1;
672 return unc;
675 static void fill_printq_info(int uLevel,
676 struct pack_desc* desc,
677 int count,
678 union spoolss_JobInfo *job_info,
679 struct spoolss_DriverInfo3 *driver_info,
680 struct spoolss_PrinterInfo2 *printer_info)
682 switch (uLevel) {
683 case 0:
684 case 1:
685 case 2:
686 PACKS(desc,"B13", strip_unc(printer_info->printername));
687 break;
688 case 3:
689 case 4:
690 case 5:
691 PACKS(desc,"z", strip_unc(printer_info->printername));
692 break;
693 case 51:
694 PACKI(desc,"K", printq_spoolss_status(printer_info->status));
695 break;
698 if (uLevel == 1 || uLevel == 2) {
699 PACKS(desc,"B",""); /* alignment */
700 PACKI(desc,"W",5); /* priority */
701 PACKI(desc,"W",0); /* start time */
702 PACKI(desc,"W",0); /* until time */
703 PACKS(desc,"z",""); /* pSepFile */
704 PACKS(desc,"z","lpd"); /* pPrProc */
705 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pDestinations */
706 PACKS(desc,"z",""); /* pParms */
707 if (printer_info->printername == NULL) {
708 PACKS(desc,"z","UNKNOWN PRINTER");
709 PACKI(desc,"W",LPSTAT_ERROR);
710 } else {
711 PACKS(desc,"z", printer_info->comment);
712 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* status */
714 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
717 if (uLevel == 3 || uLevel == 4) {
718 PACKI(desc,"W",5); /* uPriority */
719 PACKI(desc,"W",0); /* uStarttime */
720 PACKI(desc,"W",0); /* uUntiltime */
721 PACKI(desc,"W",5); /* pad1 */
722 PACKS(desc,"z",""); /* pszSepFile */
723 PACKS(desc,"z","WinPrint"); /* pszPrProc */
724 PACKS(desc,"z",NULL); /* pszParms */
725 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
726 /* "don't ask" that it's done this way to fix corrupted
727 Win9X/ME printer comments. */
728 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* fsStatus */
729 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
730 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pszPrinters */
731 PACKS(desc,"z", printer_info->drivername); /* pszDriverName */
732 PackDriverData(desc); /* pDriverData */
735 if (uLevel == 2 || uLevel == 4) {
736 int i;
737 for (i = 0; i < count; i++) {
738 fill_spoolss_printjob_info(uLevel == 2 ? 1 : 2, desc, &job_info[i].info2, i);
742 if (uLevel==52)
743 fill_printq_info_52(driver_info, desc, count, printer_info->printername);
746 /* This function returns the number of files for a given driver */
747 static int get_printerdrivernumber(const struct spoolss_DriverInfo3 *driver)
749 int result = 0;
751 /* count the number of files */
752 while (driver->dependent_files && *driver->dependent_files[result])
753 result++;
755 return result;
758 static bool api_DosPrintQGetInfo(struct smbd_server_connection *sconn,
759 connection_struct *conn, uint64_t vuid,
760 char *param, int tpscnt,
761 char *data, int tdscnt,
762 int mdrcnt,int mprcnt,
763 char **rdata,char **rparam,
764 int *rdata_len,int *rparam_len)
766 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
767 char *str2 = skip_string(param,tpscnt,str1);
768 char *p = skip_string(param,tpscnt,str2);
769 char *QueueName = p;
770 unsigned int uLevel;
771 uint32_t count = 0;
772 char *str3;
773 struct pack_desc desc;
774 char* tmpdata=NULL;
776 WERROR werr = WERR_OK;
777 TALLOC_CTX *mem_ctx = talloc_tos();
778 NTSTATUS status;
779 struct rpc_pipe_client *cli = NULL;
780 struct dcerpc_binding_handle *b = NULL;
781 struct policy_handle handle;
782 struct spoolss_DevmodeContainer devmode_ctr;
783 union spoolss_DriverInfo driver_info;
784 union spoolss_JobInfo *job_info = NULL;
785 union spoolss_PrinterInfo printer_info;
787 if (!str1 || !str2 || !p) {
788 return False;
790 memset((char *)&desc,'\0',sizeof(desc));
792 p = skip_string(param,tpscnt,p);
793 if (!p) {
794 return False;
796 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
797 str3 = get_safe_str_ptr(param,tpscnt,p,4);
798 /* str3 may be null here and is checked in check_printq_info(). */
800 /* remove any trailing username */
801 if ((p = strchr_m(QueueName,'%')))
802 *p = 0;
804 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
806 /* check it's a supported varient */
807 if (!prefix_ok(str1,"zWrLh"))
808 return False;
809 if (!check_printq_info(&desc,uLevel,str2,str3)) {
811 * Patch from Scott Moomaw <scott@bridgewater.edu>
812 * to return the 'invalid info level' error if an
813 * unknown level was requested.
815 *rdata_len = 0;
816 *rparam_len = 6;
817 *rparam = smb_realloc_limit(*rparam,*rparam_len);
818 if (!*rparam) {
819 return False;
821 SSVALS(*rparam,0,ERRunknownlevel);
822 SSVAL(*rparam,2,0);
823 SSVAL(*rparam,4,0);
824 return(True);
827 ZERO_STRUCT(handle);
829 if (QueueName == NULL || (strlen(QueueName) < 1)) {
830 desc.errcode = W_ERROR_V(WERR_INVALID_PARAM);
831 goto out;
834 status = rpc_pipe_open_interface(conn,
835 &ndr_table_spoolss.syntax_id,
836 conn->session_info,
837 conn->sconn->remote_address,
838 conn->sconn->msg_ctx,
839 &cli);
840 if (!NT_STATUS_IS_OK(status)) {
841 DEBUG(0,("api_DosPrintQGetInfo: could not connect to spoolss: %s\n",
842 nt_errstr(status)));
843 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
844 goto out;
846 b = cli->binding_handle;
848 ZERO_STRUCT(devmode_ctr);
850 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
851 QueueName,
852 "RAW",
853 devmode_ctr,
854 PRINTER_ACCESS_USE,
855 &handle,
856 &werr);
857 if (!NT_STATUS_IS_OK(status)) {
858 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
859 goto out;
861 if (!W_ERROR_IS_OK(werr)) {
862 desc.errcode = W_ERROR_V(werr);
863 goto out;
866 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
867 &handle,
870 &printer_info);
871 if (!W_ERROR_IS_OK(werr)) {
872 desc.errcode = W_ERROR_V(werr);
873 goto out;
876 if (uLevel==52) {
877 uint32_t server_major_version;
878 uint32_t server_minor_version;
880 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
881 &handle,
882 "Windows 4.0",
883 3, /* level */
885 0, /* version */
887 &driver_info,
888 &server_major_version,
889 &server_minor_version);
890 if (!W_ERROR_IS_OK(werr)) {
891 desc.errcode = W_ERROR_V(werr);
892 goto out;
895 count = get_printerdrivernumber(&driver_info.info3);
896 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
897 } else {
898 uint32_t num_jobs;
899 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
900 &handle,
901 0, /* firstjob */
902 0xff, /* numjobs */
903 2, /* level */
904 0, /* offered */
905 &num_jobs,
906 &job_info);
907 if (!W_ERROR_IS_OK(werr)) {
908 desc.errcode = W_ERROR_V(werr);
909 goto out;
912 count = num_jobs;
915 if (mdrcnt > 0) {
916 *rdata = smb_realloc_limit(*rdata,mdrcnt);
917 if (!*rdata) {
918 return False;
920 desc.base = *rdata;
921 desc.buflen = mdrcnt;
922 } else {
924 * Don't return data but need to get correct length
925 * init_package will return wrong size if buflen=0
927 desc.buflen = getlen(desc.format);
928 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
931 if (init_package(&desc,1,count)) {
932 desc.subcount = count;
933 fill_printq_info(uLevel,&desc,count, job_info, &driver_info.info3, &printer_info.info2);
936 *rdata_len = desc.usedlen;
939 * We must set the return code to ERRbuftoosmall
940 * in order to support lanman style printing with Win NT/2k
941 * clients --jerry
943 if (!mdrcnt && lp_disable_spoolss())
944 desc.errcode = ERRbuftoosmall;
946 out:
947 if (b && is_valid_policy_hnd(&handle)) {
948 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
951 *rdata_len = desc.usedlen;
952 *rparam_len = 6;
953 *rparam = smb_realloc_limit(*rparam,*rparam_len);
954 if (!*rparam) {
955 SAFE_FREE(tmpdata);
956 return False;
958 SSVALS(*rparam,0,desc.errcode);
959 SSVAL(*rparam,2,0);
960 SSVAL(*rparam,4,desc.neededlen);
962 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
964 SAFE_FREE(tmpdata);
966 return(True);
969 /****************************************************************************
970 View list of all print jobs on all queues.
971 ****************************************************************************/
973 static bool api_DosPrintQEnum(struct smbd_server_connection *sconn,
974 connection_struct *conn, uint64_t vuid,
975 char *param, int tpscnt,
976 char *data, int tdscnt,
977 int mdrcnt, int mprcnt,
978 char **rdata, char** rparam,
979 int *rdata_len, int *rparam_len)
981 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
982 char *output_format1 = skip_string(param,tpscnt,param_format);
983 char *p = skip_string(param,tpscnt,output_format1);
984 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
985 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
986 int i;
987 struct pack_desc desc;
988 int *subcntarr = NULL;
989 int queuecnt = 0, subcnt = 0, succnt = 0;
991 WERROR werr = WERR_OK;
992 TALLOC_CTX *mem_ctx = talloc_tos();
993 NTSTATUS status;
994 struct rpc_pipe_client *cli = NULL;
995 struct dcerpc_binding_handle *b = NULL;
996 struct spoolss_DevmodeContainer devmode_ctr;
997 uint32_t num_printers;
998 union spoolss_PrinterInfo *printer_info;
999 union spoolss_DriverInfo *driver_info;
1000 union spoolss_JobInfo **job_info;
1002 if (!param_format || !output_format1 || !p) {
1003 return False;
1006 memset((char *)&desc,'\0',sizeof(desc));
1008 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
1010 if (!prefix_ok(param_format,"WrLeh")) {
1011 return False;
1013 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
1015 * Patch from Scott Moomaw <scott@bridgewater.edu>
1016 * to return the 'invalid info level' error if an
1017 * unknown level was requested.
1019 *rdata_len = 0;
1020 *rparam_len = 6;
1021 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1022 if (!*rparam) {
1023 return False;
1025 SSVALS(*rparam,0,ERRunknownlevel);
1026 SSVAL(*rparam,2,0);
1027 SSVAL(*rparam,4,0);
1028 return(True);
1031 status = rpc_pipe_open_interface(conn,
1032 &ndr_table_spoolss.syntax_id,
1033 conn->session_info,
1034 conn->sconn->remote_address,
1035 conn->sconn->msg_ctx,
1036 &cli);
1037 if (!NT_STATUS_IS_OK(status)) {
1038 DEBUG(0,("api_DosPrintQEnum: could not connect to spoolss: %s\n",
1039 nt_errstr(status)));
1040 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1041 goto out;
1043 b = cli->binding_handle;
1045 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
1046 PRINTER_ENUM_LOCAL,
1047 cli->srv_name_slash,
1050 &num_printers,
1051 &printer_info);
1052 if (!W_ERROR_IS_OK(werr)) {
1053 desc.errcode = W_ERROR_V(werr);
1054 goto out;
1057 queuecnt = num_printers;
1059 job_info = talloc_array(mem_ctx, union spoolss_JobInfo *, num_printers);
1060 if (job_info == NULL) {
1061 goto err;
1064 driver_info = talloc_array(mem_ctx, union spoolss_DriverInfo, num_printers);
1065 if (driver_info == NULL) {
1066 goto err;
1069 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1070 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1071 goto err;
1074 if (mdrcnt > 0) {
1075 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1076 if (!*rdata) {
1077 goto err;
1080 desc.base = *rdata;
1081 desc.buflen = mdrcnt;
1083 subcnt = 0;
1084 for (i = 0; i < num_printers; i++) {
1086 uint32_t num_jobs;
1087 struct policy_handle handle;
1088 const char *printername;
1090 printername = talloc_strdup(mem_ctx, printer_info[i].info2.printername);
1091 if (printername == NULL) {
1092 goto err;
1095 ZERO_STRUCT(handle);
1096 ZERO_STRUCT(devmode_ctr);
1098 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
1099 printername,
1100 "RAW",
1101 devmode_ctr,
1102 PRINTER_ACCESS_USE,
1103 &handle,
1104 &werr);
1105 if (!NT_STATUS_IS_OK(status)) {
1106 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1107 goto out;
1109 if (!W_ERROR_IS_OK(werr)) {
1110 desc.errcode = W_ERROR_V(werr);
1111 goto out;
1114 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
1115 &handle,
1116 0, /* firstjob */
1117 0xff, /* numjobs */
1118 2, /* level */
1119 0, /* offered */
1120 &num_jobs,
1121 &job_info[i]);
1122 if (!W_ERROR_IS_OK(werr)) {
1123 desc.errcode = W_ERROR_V(werr);
1124 goto out;
1127 if (uLevel==52) {
1128 uint32_t server_major_version;
1129 uint32_t server_minor_version;
1131 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1132 &handle,
1133 "Windows 4.0",
1134 3, /* level */
1136 0, /* version */
1138 &driver_info[i],
1139 &server_major_version,
1140 &server_minor_version);
1141 if (!W_ERROR_IS_OK(werr)) {
1142 desc.errcode = W_ERROR_V(werr);
1143 goto out;
1147 subcntarr[i] = num_jobs;
1148 subcnt += subcntarr[i];
1150 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
1153 if (init_package(&desc,queuecnt,subcnt)) {
1154 for (i = 0; i < num_printers; i++) {
1155 fill_printq_info(uLevel,&desc,subcntarr[i], job_info[i], &driver_info[i].info3, &printer_info[i].info2);
1156 if (desc.errcode == NERR_Success) {
1157 succnt = i;
1162 out:
1163 SAFE_FREE(subcntarr);
1164 *rdata_len = desc.usedlen;
1165 *rparam_len = 8;
1166 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1167 if (!*rparam) {
1168 goto err;
1170 SSVALS(*rparam,0,desc.errcode);
1171 SSVAL(*rparam,2,0);
1172 SSVAL(*rparam,4,succnt);
1173 SSVAL(*rparam,6,queuecnt);
1175 return True;
1177 err:
1179 SAFE_FREE(subcntarr);
1181 return False;
1184 /****************************************************************************
1185 Get info level for a server list query.
1186 ****************************************************************************/
1188 static bool check_session_info(int uLevel, char* id)
1190 switch( uLevel ) {
1191 case 0:
1192 if (strcmp(id,"B16") != 0) {
1193 return False;
1195 break;
1196 case 1:
1197 if (strcmp(id,"B16BBDz") != 0) {
1198 return False;
1200 break;
1201 default:
1202 return False;
1204 return True;
1207 struct srv_info_struct {
1208 fstring name;
1209 uint32 type;
1210 fstring comment;
1211 fstring domain;
1212 bool server_added;
1215 /*******************************************************************
1216 Get server info lists from the files saved by nmbd. Return the
1217 number of entries.
1218 ******************************************************************/
1220 static int get_session_info(uint32 servertype,
1221 struct srv_info_struct **servers,
1222 const char *domain)
1224 int count=0;
1225 int alloced=0;
1226 char **lines;
1227 bool local_list_only;
1228 int i;
1230 lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
1231 if (!lines) {
1232 DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
1233 return 0;
1236 /* request for everything is code for request all servers */
1237 if (servertype == SV_TYPE_ALL) {
1238 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1241 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1243 DEBUG(4,("Servertype search: %8x\n",servertype));
1245 for (i=0;lines[i];i++) {
1246 fstring stype;
1247 struct srv_info_struct *s;
1248 const char *ptr = lines[i];
1249 bool ok = True;
1250 TALLOC_CTX *frame = NULL;
1251 char *p;
1253 if (!*ptr) {
1254 continue;
1257 if (count == alloced) {
1258 alloced += 10;
1259 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1260 if (!*servers) {
1261 DEBUG(0,("get_session_info: failed to enlarge servers info struct!\n"));
1262 TALLOC_FREE(lines);
1263 return 0;
1265 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1267 s = &(*servers)[count];
1269 frame = talloc_stackframe();
1270 s->name[0] = '\0';
1271 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1272 TALLOC_FREE(frame);
1273 continue;
1275 fstrcpy(s->name, p);
1277 stype[0] = '\0';
1278 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1279 TALLOC_FREE(frame);
1280 continue;
1282 fstrcpy(stype, p);
1284 s->comment[0] = '\0';
1285 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1286 TALLOC_FREE(frame);
1287 continue;
1289 fstrcpy(s->comment, p);
1290 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1292 s->domain[0] = '\0';
1293 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1294 /* this allows us to cope with an old nmbd */
1295 fstrcpy(s->domain,lp_workgroup());
1296 } else {
1297 fstrcpy(s->domain, p);
1299 TALLOC_FREE(frame);
1301 if (sscanf(stype,"%X",&s->type) != 1) {
1302 DEBUG(4,("r:host file "));
1303 ok = False;
1306 /* Filter the servers/domains we return based on what was asked for. */
1308 /* Check to see if we are being asked for a local list only. */
1309 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1310 DEBUG(4,("r: local list only"));
1311 ok = False;
1314 /* doesn't match up: don't want it */
1315 if (!(servertype & s->type)) {
1316 DEBUG(4,("r:serv type "));
1317 ok = False;
1320 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1321 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1322 DEBUG(4,("s: dom mismatch "));
1323 ok = False;
1326 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1327 ok = False;
1330 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1331 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1333 if (ok) {
1334 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1335 s->name, s->type, s->comment, s->domain));
1336 s->server_added = True;
1337 count++;
1338 } else {
1339 DEBUG(4,("%20s %8x %25s %15s\n",
1340 s->name, s->type, s->comment, s->domain));
1344 TALLOC_FREE(lines);
1345 return count;
1348 /*******************************************************************
1349 Fill in a server info structure.
1350 ******************************************************************/
1352 static int fill_srv_info(struct srv_info_struct *service,
1353 int uLevel, char **buf, int *buflen,
1354 char **stringbuf, int *stringspace, char *baseaddr)
1356 int struct_len;
1357 char* p;
1358 char* p2;
1359 int l2;
1360 int len;
1362 switch (uLevel) {
1363 case 0:
1364 struct_len = 16;
1365 break;
1366 case 1:
1367 struct_len = 26;
1368 break;
1369 default:
1370 return -1;
1373 if (!buf) {
1374 len = 0;
1375 switch (uLevel) {
1376 case 1:
1377 len = strlen(service->comment)+1;
1378 break;
1381 *buflen = struct_len;
1382 *stringspace = len;
1383 return struct_len + len;
1386 len = struct_len;
1387 p = *buf;
1388 if (*buflen < struct_len) {
1389 return -1;
1391 if (stringbuf) {
1392 p2 = *stringbuf;
1393 l2 = *stringspace;
1394 } else {
1395 p2 = p + struct_len;
1396 l2 = *buflen - struct_len;
1398 if (!baseaddr) {
1399 baseaddr = p;
1402 switch (uLevel) {
1403 case 0:
1404 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1405 break;
1407 case 1:
1408 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1409 SIVAL(p,18,service->type);
1410 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1411 len += CopyAndAdvance(&p2,service->comment,&l2);
1412 break;
1415 if (stringbuf) {
1416 *buf = p + struct_len;
1417 *buflen -= struct_len;
1418 *stringbuf = p2;
1419 *stringspace = l2;
1420 } else {
1421 *buf = p2;
1422 *buflen -= len;
1424 return len;
1428 static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1430 return strcasecmp_m(s1->name,s2->name);
1433 /****************************************************************************
1434 View list of servers available (or possibly domains). The info is
1435 extracted from lists saved by nmbd on the local host.
1436 ****************************************************************************/
1438 static bool api_RNetServerEnum2(struct smbd_server_connection *sconn,
1439 connection_struct *conn, uint64_t vuid,
1440 char *param, int tpscnt,
1441 char *data, int tdscnt,
1442 int mdrcnt, int mprcnt, char **rdata,
1443 char **rparam, int *rdata_len, int *rparam_len)
1445 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1446 char *str2 = skip_string(param,tpscnt,str1);
1447 char *p = skip_string(param,tpscnt,str2);
1448 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1449 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1450 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1451 char *p2;
1452 int data_len, fixed_len, string_len;
1453 int f_len = 0, s_len = 0;
1454 struct srv_info_struct *servers=NULL;
1455 int counted=0,total=0;
1456 int i,missed;
1457 fstring domain;
1458 bool domain_request;
1459 bool local_request;
1461 if (!str1 || !str2 || !p) {
1462 return False;
1465 /* If someone sets all the bits they don't really mean to set
1466 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1467 known servers. */
1469 if (servertype == SV_TYPE_ALL) {
1470 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1473 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1474 any other bit (they may just set this bit on its own) they
1475 want all the locally seen servers. However this bit can be
1476 set on its own so set the requested servers to be
1477 ALL - DOMAIN_ENUM. */
1479 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1480 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1483 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1484 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1486 p += 8;
1488 if (!prefix_ok(str1,"WrLehD")) {
1489 return False;
1491 if (!check_session_info(uLevel,str2)) {
1492 return False;
1495 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1496 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1497 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1499 if (strcmp(str1, "WrLehDz") == 0) {
1500 if (skip_string(param,tpscnt,p) == NULL) {
1501 return False;
1503 pull_ascii_fstring(domain, p);
1504 } else {
1505 fstrcpy(domain, lp_workgroup());
1508 DEBUG(4, ("domain [%s]\n", domain));
1510 if (lp_browse_list()) {
1511 total = get_session_info(servertype,&servers,domain);
1514 data_len = fixed_len = string_len = 0;
1515 missed = 0;
1517 TYPESAFE_QSORT(servers, total, srv_comp);
1520 char *lastname=NULL;
1522 for (i=0;i<total;i++) {
1523 struct srv_info_struct *s = &servers[i];
1525 if (lastname && strequal(lastname,s->name)) {
1526 continue;
1528 lastname = s->name;
1529 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1530 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1531 i, s->name, s->type, s->comment, s->domain));
1533 if (data_len < buf_len) {
1534 counted++;
1535 fixed_len += f_len;
1536 string_len += s_len;
1537 } else {
1538 missed++;
1543 *rdata_len = fixed_len + string_len;
1544 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1545 if (!*rdata) {
1546 return False;
1549 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1550 p = *rdata;
1551 f_len = fixed_len;
1552 s_len = string_len;
1555 char *lastname=NULL;
1556 int count2 = counted;
1558 for (i = 0; i < total && count2;i++) {
1559 struct srv_info_struct *s = &servers[i];
1561 if (lastname && strequal(lastname,s->name)) {
1562 continue;
1564 lastname = s->name;
1565 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1566 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1567 i, s->name, s->type, s->comment, s->domain));
1568 count2--;
1572 *rparam_len = 8;
1573 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1574 if (!*rparam) {
1575 return False;
1577 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1578 SSVAL(*rparam,2,0);
1579 SSVAL(*rparam,4,counted);
1580 SSVAL(*rparam,6,counted+missed);
1582 SAFE_FREE(servers);
1584 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1585 domain,uLevel,counted,counted+missed));
1587 return True;
1590 static int srv_name_match(const char *n1, const char *n2)
1593 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1595 * In Windows, FirstNameToReturn need not be an exact match:
1596 * the server will return a list of servers that exist on
1597 * the network greater than or equal to the FirstNameToReturn.
1599 int ret = strcasecmp_m(n1, n2);
1601 if (ret <= 0) {
1602 return 0;
1605 return ret;
1608 static bool api_RNetServerEnum3(struct smbd_server_connection *sconn,
1609 connection_struct *conn, uint64_t vuid,
1610 char *param, int tpscnt,
1611 char *data, int tdscnt,
1612 int mdrcnt, int mprcnt, char **rdata,
1613 char **rparam, int *rdata_len, int *rparam_len)
1615 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1616 char *str2 = skip_string(param,tpscnt,str1);
1617 char *p = skip_string(param,tpscnt,str2);
1618 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1619 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1620 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1621 char *p2;
1622 int data_len, fixed_len, string_len;
1623 int f_len = 0, s_len = 0;
1624 struct srv_info_struct *servers=NULL;
1625 int counted=0,first=0,total=0;
1626 int i,missed;
1627 fstring domain;
1628 fstring first_name;
1629 bool domain_request;
1630 bool local_request;
1632 if (!str1 || !str2 || !p) {
1633 return False;
1636 /* If someone sets all the bits they don't really mean to set
1637 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1638 known servers. */
1640 if (servertype == SV_TYPE_ALL) {
1641 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1644 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1645 any other bit (they may just set this bit on its own) they
1646 want all the locally seen servers. However this bit can be
1647 set on its own so set the requested servers to be
1648 ALL - DOMAIN_ENUM. */
1650 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1651 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1654 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1655 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1657 p += 8;
1659 if (strcmp(str1, "WrLehDzz") != 0) {
1660 return false;
1662 if (!check_session_info(uLevel,str2)) {
1663 return False;
1666 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1667 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1668 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1670 if (skip_string(param,tpscnt,p) == NULL) {
1671 return False;
1673 pull_ascii_fstring(domain, p);
1674 if (domain[0] == '\0') {
1675 fstrcpy(domain, lp_workgroup());
1677 p = skip_string(param,tpscnt,p);
1678 if (skip_string(param,tpscnt,p) == NULL) {
1679 return False;
1681 pull_ascii_fstring(first_name, p);
1683 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1684 domain, first_name));
1686 if (lp_browse_list()) {
1687 total = get_session_info(servertype,&servers,domain);
1690 data_len = fixed_len = string_len = 0;
1691 missed = 0;
1693 TYPESAFE_QSORT(servers, total, srv_comp);
1695 if (first_name[0] != '\0') {
1696 struct srv_info_struct *first_server = NULL;
1698 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1699 srv_name_match, first_server);
1700 if (first_server) {
1701 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1703 * The binary search may not find the exact match
1704 * so we need to search backward to find the first match
1706 * This implements the strange matching windows
1707 * implements. (see the comment in srv_name_match().
1709 for (;first > 0;) {
1710 int ret;
1711 ret = strcasecmp_m(first_name,
1712 servers[first-1].name);
1713 if (ret > 0) {
1714 break;
1716 first--;
1718 } else {
1719 /* we should return no entries */
1720 first = total;
1725 char *lastname=NULL;
1727 for (i=first;i<total;i++) {
1728 struct srv_info_struct *s = &servers[i];
1730 if (lastname && strequal(lastname,s->name)) {
1731 continue;
1733 lastname = s->name;
1734 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1735 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1736 i, s->name, s->type, s->comment, s->domain));
1738 if (data_len < buf_len) {
1739 counted++;
1740 fixed_len += f_len;
1741 string_len += s_len;
1742 } else {
1743 missed++;
1748 *rdata_len = fixed_len + string_len;
1749 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1750 if (!*rdata) {
1751 return False;
1754 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1755 p = *rdata;
1756 f_len = fixed_len;
1757 s_len = string_len;
1760 char *lastname=NULL;
1761 int count2 = counted;
1763 for (i = first; i < total && count2;i++) {
1764 struct srv_info_struct *s = &servers[i];
1766 if (lastname && strequal(lastname,s->name)) {
1767 continue;
1769 lastname = s->name;
1770 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1771 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1772 i, s->name, s->type, s->comment, s->domain));
1773 count2--;
1777 *rparam_len = 8;
1778 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1779 if (!*rparam) {
1780 return False;
1782 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1783 SSVAL(*rparam,2,0);
1784 SSVAL(*rparam,4,counted);
1785 SSVAL(*rparam,6,counted+missed);
1787 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1788 domain,uLevel,first,first_name,
1789 first < total ? servers[first].name : "",
1790 counted,counted+missed));
1792 SAFE_FREE(servers);
1794 return True;
1797 /****************************************************************************
1798 command 0x34 - suspected of being a "Lookup Names" stub api
1799 ****************************************************************************/
1801 static bool api_RNetGroupGetUsers(struct smbd_server_connection *sconn,
1802 connection_struct *conn, uint64_t vuid,
1803 char *param, int tpscnt,
1804 char *data, int tdscnt,
1805 int mdrcnt, int mprcnt, char **rdata,
1806 char **rparam, int *rdata_len, int *rparam_len)
1808 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1809 char *str2 = skip_string(param,tpscnt,str1);
1810 char *p = skip_string(param,tpscnt,str2);
1811 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1812 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1813 int counted=0;
1814 int missed=0;
1816 if (!str1 || !str2 || !p) {
1817 return False;
1820 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1821 str1, str2, p, uLevel, buf_len));
1823 if (!prefix_ok(str1,"zWrLeh")) {
1824 return False;
1827 *rdata_len = 0;
1829 *rparam_len = 8;
1830 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1831 if (!*rparam) {
1832 return False;
1835 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1836 SSVAL(*rparam,2,0);
1837 SSVAL(*rparam,4,counted);
1838 SSVAL(*rparam,6,counted+missed);
1840 return True;
1843 /****************************************************************************
1844 get info about a share
1845 ****************************************************************************/
1847 static bool check_share_info(int uLevel, char* id)
1849 switch( uLevel ) {
1850 case 0:
1851 if (strcmp(id,"B13") != 0) {
1852 return False;
1854 break;
1855 case 1:
1856 /* Level-2 descriptor is allowed (and ignored) */
1857 if (strcmp(id,"B13BWz") != 0 &&
1858 strcmp(id,"B13BWzWWWzB9B") != 0) {
1859 return False;
1861 break;
1862 case 2:
1863 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1864 return False;
1866 break;
1867 case 91:
1868 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1869 return False;
1871 break;
1872 default:
1873 return False;
1875 return True;
1878 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1879 char** buf, int* buflen,
1880 char** stringbuf, int* stringspace, char* baseaddr)
1882 int struct_len;
1883 char* p;
1884 char* p2;
1885 int l2;
1886 int len;
1888 switch( uLevel ) {
1889 case 0:
1890 struct_len = 13;
1891 break;
1892 case 1:
1893 struct_len = 20;
1894 break;
1895 case 2:
1896 struct_len = 40;
1897 break;
1898 case 91:
1899 struct_len = 68;
1900 break;
1901 default:
1902 return -1;
1905 if (!buf) {
1906 len = 0;
1908 if (uLevel > 0) {
1909 len += StrlenExpanded(conn,snum,lp_comment(talloc_tos(), snum));
1911 if (uLevel > 1) {
1912 len += strlen(lp_pathname(talloc_tos(), snum)) + 1;
1914 if (buflen) {
1915 *buflen = struct_len;
1917 if (stringspace) {
1918 *stringspace = len;
1920 return struct_len + len;
1923 len = struct_len;
1924 p = *buf;
1925 if ((*buflen) < struct_len) {
1926 return -1;
1929 if (stringbuf) {
1930 p2 = *stringbuf;
1931 l2 = *stringspace;
1932 } else {
1933 p2 = p + struct_len;
1934 l2 = (*buflen) - struct_len;
1937 if (!baseaddr) {
1938 baseaddr = p;
1941 push_ascii(p,lp_servicename(talloc_tos(), snum),13, STR_TERMINATE);
1943 if (uLevel > 0) {
1944 int type;
1946 SCVAL(p,13,0);
1947 type = STYPE_DISKTREE;
1948 if (lp_print_ok(snum)) {
1949 type = STYPE_PRINTQ;
1951 if (strequal("IPC",lp_fstype(talloc_tos(),snum))) {
1952 type = STYPE_IPC;
1954 SSVAL(p,14,type); /* device type */
1955 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1956 len += CopyExpanded(conn,snum,&p2,lp_comment(talloc_tos(),snum),&l2);
1959 if (uLevel > 1) {
1960 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1961 SSVALS(p,22,-1); /* max uses */
1962 SSVAL(p,24,1); /* current uses */
1963 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1964 len += CopyAndAdvance(&p2,lp_pathname(talloc_tos(),snum),&l2);
1965 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1968 if (uLevel > 2) {
1969 memset(p+40,0,SHPWLEN+2);
1970 SSVAL(p,50,0);
1971 SIVAL(p,52,0);
1972 SSVAL(p,56,0);
1973 SSVAL(p,58,0);
1974 SIVAL(p,60,0);
1975 SSVAL(p,64,0);
1976 SSVAL(p,66,0);
1979 if (stringbuf) {
1980 (*buf) = p + struct_len;
1981 (*buflen) -= struct_len;
1982 (*stringbuf) = p2;
1983 (*stringspace) = l2;
1984 } else {
1985 (*buf) = p2;
1986 (*buflen) -= len;
1989 return len;
1992 static bool api_RNetShareGetInfo(struct smbd_server_connection *sconn,
1993 connection_struct *conn,uint64_t vuid,
1994 char *param, int tpscnt,
1995 char *data, int tdscnt,
1996 int mdrcnt,int mprcnt,
1997 char **rdata,char **rparam,
1998 int *rdata_len,int *rparam_len)
2000 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2001 char *str2 = skip_string(param,tpscnt,str1);
2002 char *netname_in = skip_string(param,tpscnt,str2);
2003 char *netname = NULL;
2004 char *p = skip_string(param,tpscnt,netname);
2005 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2006 int snum;
2008 if (!str1 || !str2 || !netname_in || !p) {
2009 return False;
2012 snum = find_service(talloc_tos(), netname_in, &netname);
2013 if (snum < 0 || !netname) {
2014 return False;
2017 /* check it's a supported varient */
2018 if (!prefix_ok(str1,"zWrLh")) {
2019 return False;
2021 if (!check_share_info(uLevel,str2)) {
2022 return False;
2025 *rdata = smb_realloc_limit(*rdata,mdrcnt);
2026 if (!*rdata) {
2027 return False;
2029 p = *rdata;
2030 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
2031 if (*rdata_len < 0) {
2032 return False;
2035 *rparam_len = 6;
2036 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2037 if (!*rparam) {
2038 return False;
2040 SSVAL(*rparam,0,NERR_Success);
2041 SSVAL(*rparam,2,0); /* converter word */
2042 SSVAL(*rparam,4,*rdata_len);
2044 return True;
2047 /****************************************************************************
2048 View the list of available shares.
2050 This function is the server side of the NetShareEnum() RAP call.
2051 It fills the return buffer with share names and share comments.
2052 Note that the return buffer normally (in all known cases) allows only
2053 twelve byte strings for share names (plus one for a nul terminator).
2054 Share names longer than 12 bytes must be skipped.
2055 ****************************************************************************/
2057 static bool api_RNetShareEnum(struct smbd_server_connection *sconn,
2058 connection_struct *conn, uint64_t vuid,
2059 char *param, int tpscnt,
2060 char *data, int tdscnt,
2061 int mdrcnt,
2062 int mprcnt,
2063 char **rdata,
2064 char **rparam,
2065 int *rdata_len,
2066 int *rparam_len )
2068 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2069 char *str2 = skip_string(param,tpscnt,str1);
2070 char *p = skip_string(param,tpscnt,str2);
2071 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2072 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
2073 char *p2;
2074 int count = 0;
2075 int total=0,counted=0;
2076 bool missed = False;
2077 int i;
2078 int data_len, fixed_len, string_len;
2079 int f_len = 0, s_len = 0;
2081 if (!str1 || !str2 || !p) {
2082 return False;
2085 if (!prefix_ok(str1,"WrLeh")) {
2086 return False;
2088 if (!check_share_info(uLevel,str2)) {
2089 return False;
2092 /* Ensure all the usershares are loaded. */
2093 become_root();
2094 delete_and_reload_printers(sconn->ev_ctx, sconn->msg_ctx);
2095 load_registry_shares();
2096 count = load_usershare_shares(NULL, connections_snum_used);
2097 unbecome_root();
2099 data_len = fixed_len = string_len = 0;
2100 for (i=0;i<count;i++) {
2101 fstring servicename_dos;
2102 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2103 continue;
2105 push_ascii_fstring(servicename_dos, lp_servicename(talloc_tos(), i));
2106 /* Maximum name length = 13. */
2107 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
2108 total++;
2109 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
2110 if (data_len < buf_len) {
2111 counted++;
2112 fixed_len += f_len;
2113 string_len += s_len;
2114 } else {
2115 missed = True;
2120 *rdata_len = fixed_len + string_len;
2121 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2122 if (!*rdata) {
2123 return False;
2126 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
2127 p = *rdata;
2128 f_len = fixed_len;
2129 s_len = string_len;
2131 for( i = 0; i < count; i++ ) {
2132 fstring servicename_dos;
2133 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2134 continue;
2137 push_ascii_fstring(servicename_dos,
2138 lp_servicename(talloc_tos(), i));
2139 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2140 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2141 break;
2146 *rparam_len = 8;
2147 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2148 if (!*rparam) {
2149 return False;
2151 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2152 SSVAL(*rparam,2,0);
2153 SSVAL(*rparam,4,counted);
2154 SSVAL(*rparam,6,total);
2156 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2157 counted,total,uLevel,
2158 buf_len,*rdata_len,mdrcnt));
2160 return True;
2163 /****************************************************************************
2164 Add a share
2165 ****************************************************************************/
2167 static bool api_RNetShareAdd(struct smbd_server_connection *sconn,
2168 connection_struct *conn,uint64_t vuid,
2169 char *param, int tpscnt,
2170 char *data, int tdscnt,
2171 int mdrcnt,int mprcnt,
2172 char **rdata,char **rparam,
2173 int *rdata_len,int *rparam_len)
2175 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2176 char *str2 = skip_string(param,tpscnt,str1);
2177 char *p = skip_string(param,tpscnt,str2);
2178 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2179 fstring sharename;
2180 fstring comment;
2181 char *pathname = NULL;
2182 unsigned int offset;
2183 int res = ERRunsup;
2184 size_t converted_size;
2186 WERROR werr = WERR_OK;
2187 TALLOC_CTX *mem_ctx = talloc_tos();
2188 NTSTATUS status;
2189 struct rpc_pipe_client *cli = NULL;
2190 union srvsvc_NetShareInfo info;
2191 struct srvsvc_NetShareInfo2 info2;
2192 struct dcerpc_binding_handle *b;
2194 if (!str1 || !str2 || !p) {
2195 return False;
2198 /* check it's a supported varient */
2199 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2200 return False;
2202 if (!check_share_info(uLevel,str2)) {
2203 return False;
2205 if (uLevel != 2) {
2206 return False;
2209 /* Do we have a string ? */
2210 if (skip_string(data,mdrcnt,data) == NULL) {
2211 return False;
2213 pull_ascii_fstring(sharename,data);
2215 if (mdrcnt < 28) {
2216 return False;
2219 /* only support disk share adds */
2220 if (SVAL(data,14)!=STYPE_DISKTREE) {
2221 return False;
2224 offset = IVAL(data, 16);
2225 if (offset >= mdrcnt) {
2226 res = ERRinvalidparam;
2227 goto out;
2230 /* Do we have a string ? */
2231 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2232 return False;
2234 pull_ascii_fstring(comment, offset? (data+offset) : "");
2236 offset = IVAL(data, 26);
2238 if (offset >= mdrcnt) {
2239 res = ERRinvalidparam;
2240 goto out;
2243 /* Do we have a string ? */
2244 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2245 return False;
2248 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2249 offset ? (data+offset) : "", &converted_size))
2251 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
2252 strerror(errno)));
2255 if (!pathname) {
2256 return false;
2259 status = rpc_pipe_open_interface(mem_ctx, &ndr_table_srvsvc.syntax_id,
2260 conn->session_info,
2261 conn->sconn->remote_address,
2262 conn->sconn->msg_ctx,
2263 &cli);
2264 if (!NT_STATUS_IS_OK(status)) {
2265 DEBUG(0,("api_RNetShareAdd: could not connect to srvsvc: %s\n",
2266 nt_errstr(status)));
2267 res = W_ERROR_V(ntstatus_to_werror(status));
2268 goto out;
2271 b = cli->binding_handle;
2273 info2.name = sharename;
2274 info2.type = STYPE_DISKTREE;
2275 info2.comment = comment;
2276 info2.permissions = 0;
2277 info2.max_users = 0;
2278 info2.current_users = 0;
2279 info2.path = pathname;
2280 info2.password = NULL;
2282 info.info2 = &info2;
2284 status = dcerpc_srvsvc_NetShareAdd(b, mem_ctx,
2285 cli->srv_name_slash,
2287 &info,
2288 NULL,
2289 &werr);
2290 if (!NT_STATUS_IS_OK(status)) {
2291 res = W_ERROR_V(ntstatus_to_werror(status));
2292 goto out;
2294 if (!W_ERROR_IS_OK(werr)) {
2295 res = W_ERROR_V(werr);
2296 goto out;
2299 *rparam_len = 6;
2300 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2301 if (!*rparam) {
2302 return False;
2304 SSVAL(*rparam,0,NERR_Success);
2305 SSVAL(*rparam,2,0); /* converter word */
2306 SSVAL(*rparam,4,*rdata_len);
2307 *rdata_len = 0;
2309 return True;
2311 out:
2313 *rparam_len = 4;
2314 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2315 if (!*rparam) {
2316 return False;
2318 *rdata_len = 0;
2319 SSVAL(*rparam,0,res);
2320 SSVAL(*rparam,2,0);
2321 return True;
2324 /****************************************************************************
2325 view list of groups available
2326 ****************************************************************************/
2328 static bool api_RNetGroupEnum(struct smbd_server_connection *sconn,
2329 connection_struct *conn,uint64_t vuid,
2330 char *param, int tpscnt,
2331 char *data, int tdscnt,
2332 int mdrcnt,int mprcnt,
2333 char **rdata,char **rparam,
2334 int *rdata_len,int *rparam_len)
2336 int i;
2337 int errflags=0;
2338 int resume_context, cli_buf_size;
2339 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2340 char *str2 = skip_string(param,tpscnt,str1);
2341 char *p = skip_string(param,tpscnt,str2);
2343 uint32_t num_groups;
2344 uint32_t resume_handle;
2345 struct rpc_pipe_client *samr_pipe;
2346 struct policy_handle samr_handle, domain_handle;
2347 NTSTATUS status, result;
2348 struct dcerpc_binding_handle *b;
2350 if (!str1 || !str2 || !p) {
2351 return False;
2354 if (strcmp(str1,"WrLeh") != 0) {
2355 return False;
2358 /* parameters
2359 * W-> resume context (number of users to skip)
2360 * r -> return parameter pointer to receive buffer
2361 * L -> length of receive buffer
2362 * e -> return parameter number of entries
2363 * h -> return parameter total number of users
2366 if (strcmp("B21",str2) != 0) {
2367 return False;
2370 status = rpc_pipe_open_interface(
2371 talloc_tos(), &ndr_table_samr.syntax_id,
2372 conn->session_info, conn->sconn->remote_address,
2373 conn->sconn->msg_ctx, &samr_pipe);
2374 if (!NT_STATUS_IS_OK(status)) {
2375 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2376 nt_errstr(status)));
2377 return false;
2380 b = samr_pipe->binding_handle;
2382 status = dcerpc_samr_Connect2(b, talloc_tos(), lp_netbios_name(),
2383 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle,
2384 &result);
2385 if (!NT_STATUS_IS_OK(status)) {
2386 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2387 nt_errstr(status)));
2388 return false;
2390 if (!NT_STATUS_IS_OK(result)) {
2391 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2392 nt_errstr(result)));
2393 return false;
2396 status = dcerpc_samr_OpenDomain(b, talloc_tos(), &samr_handle,
2397 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2398 get_global_sam_sid(), &domain_handle,
2399 &result);
2400 if (!NT_STATUS_IS_OK(status)) {
2401 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2402 nt_errstr(status)));
2403 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2404 return false;
2406 if (!NT_STATUS_IS_OK(result)) {
2407 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2408 nt_errstr(result)));
2409 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2410 return false;
2413 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2414 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2415 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2416 "%d\n", resume_context, cli_buf_size));
2418 *rdata_len = cli_buf_size;
2419 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2420 if (!*rdata) {
2421 return False;
2424 p = *rdata;
2426 errflags = NERR_Success;
2427 num_groups = 0;
2428 resume_handle = 0;
2430 while (true) {
2431 struct samr_SamArray *sam_entries;
2432 uint32_t num_entries;
2434 status = dcerpc_samr_EnumDomainGroups(b, talloc_tos(),
2435 &domain_handle,
2436 &resume_handle,
2437 &sam_entries, 1,
2438 &num_entries,
2439 &result);
2440 if (!NT_STATUS_IS_OK(status)) {
2441 DEBUG(10, ("dcerpc_samr_EnumDomainGroups returned "
2442 "%s\n", nt_errstr(status)));
2443 break;
2445 if (!NT_STATUS_IS_OK(result)) {
2446 status = result;
2447 DEBUG(10, ("dcerpc_samr_EnumDomainGroups returned "
2448 "%s\n", nt_errstr(result)));
2449 break;
2452 if (num_entries == 0) {
2453 DEBUG(10, ("dcerpc_samr_EnumDomainGroups returned "
2454 "no entries -- done\n"));
2455 break;
2458 for(i=0; i<num_entries; i++) {
2459 const char *name;
2461 name = sam_entries->entries[i].name.string;
2463 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2464 /* set overflow error */
2465 DEBUG(3,("overflow on entry %d group %s\n", i,
2466 name));
2467 errflags=234;
2468 break;
2471 /* truncate the name at 21 chars. */
2472 memset(p, 0, 21);
2473 strlcpy(p, name, 21);
2474 DEBUG(10,("adding entry %d group %s\n", i, p));
2475 p += 21;
2476 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2477 * idea why... */
2478 num_groups += 1;
2481 if (errflags != NERR_Success) {
2482 break;
2485 TALLOC_FREE(sam_entries);
2488 dcerpc_samr_Close(b, talloc_tos(), &domain_handle, &result);
2489 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2491 *rdata_len = PTR_DIFF(p,*rdata);
2493 *rparam_len = 8;
2494 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2495 if (!*rparam) {
2496 return False;
2498 SSVAL(*rparam, 0, errflags);
2499 SSVAL(*rparam, 2, 0); /* converter word */
2500 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2501 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2503 return(True);
2506 /*******************************************************************
2507 Get groups that a user is a member of.
2508 ******************************************************************/
2510 static bool api_NetUserGetGroups(struct smbd_server_connection *sconn,
2511 connection_struct *conn,uint64_t vuid,
2512 char *param, int tpscnt,
2513 char *data, int tdscnt,
2514 int mdrcnt,int mprcnt,
2515 char **rdata,char **rparam,
2516 int *rdata_len,int *rparam_len)
2518 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2519 char *str2 = skip_string(param,tpscnt,str1);
2520 char *UserName = skip_string(param,tpscnt,str2);
2521 char *p = skip_string(param,tpscnt,UserName);
2522 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2523 const char *level_string;
2524 int count=0;
2525 bool ret = False;
2526 uint32_t i;
2527 char *endp = NULL;
2529 struct rpc_pipe_client *samr_pipe;
2530 struct policy_handle samr_handle, domain_handle, user_handle;
2531 struct lsa_String name;
2532 struct lsa_Strings names;
2533 struct samr_Ids type, rid;
2534 struct samr_RidWithAttributeArray *rids;
2535 NTSTATUS status, result;
2536 struct dcerpc_binding_handle *b;
2538 if (!str1 || !str2 || !UserName || !p) {
2539 return False;
2542 *rparam_len = 8;
2543 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2544 if (!*rparam) {
2545 return False;
2548 /* check it's a supported varient */
2550 if ( strcmp(str1,"zWrLeh") != 0 )
2551 return False;
2553 switch( uLevel ) {
2554 case 0:
2555 level_string = "B21";
2556 break;
2557 default:
2558 return False;
2561 if (strcmp(level_string,str2) != 0)
2562 return False;
2564 *rdata_len = mdrcnt + 1024;
2565 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2566 if (!*rdata) {
2567 return False;
2570 SSVAL(*rparam,0,NERR_Success);
2571 SSVAL(*rparam,2,0); /* converter word */
2573 p = *rdata;
2574 endp = *rdata + *rdata_len;
2576 status = rpc_pipe_open_interface(
2577 talloc_tos(), &ndr_table_samr.syntax_id,
2578 conn->session_info, conn->sconn->remote_address,
2579 conn->sconn->msg_ctx, &samr_pipe);
2580 if (!NT_STATUS_IS_OK(status)) {
2581 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2582 nt_errstr(status)));
2583 return false;
2586 b = samr_pipe->binding_handle;
2588 status = dcerpc_samr_Connect2(b, talloc_tos(), lp_netbios_name(),
2589 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle,
2590 &result);
2591 if (!NT_STATUS_IS_OK(status)) {
2592 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2593 nt_errstr(status)));
2594 return false;
2596 if (!NT_STATUS_IS_OK(result)) {
2597 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2598 nt_errstr(result)));
2599 return false;
2602 status = dcerpc_samr_OpenDomain(b, talloc_tos(), &samr_handle,
2603 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2604 get_global_sam_sid(), &domain_handle,
2605 &result);
2606 if (!NT_STATUS_IS_OK(status)) {
2607 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2608 nt_errstr(status)));
2609 goto close_sam;
2611 if (!NT_STATUS_IS_OK(result)) {
2612 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2613 nt_errstr(result)));
2614 goto close_sam;
2617 name.string = UserName;
2619 status = dcerpc_samr_LookupNames(b, talloc_tos(),
2620 &domain_handle, 1, &name,
2621 &rid, &type,
2622 &result);
2623 if (!NT_STATUS_IS_OK(status)) {
2624 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2625 nt_errstr(status)));
2626 goto close_domain;
2628 if (!NT_STATUS_IS_OK(result)) {
2629 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2630 nt_errstr(result)));
2631 goto close_domain;
2633 if (rid.count != 1) {
2634 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2635 goto close_domain;
2637 if (type.count != 1) {
2638 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2639 goto close_domain;
2642 if (type.ids[0] != SID_NAME_USER) {
2643 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2644 sid_type_lookup(type.ids[0])));
2645 goto close_domain;
2648 status = dcerpc_samr_OpenUser(b, talloc_tos(),
2649 &domain_handle,
2650 SAMR_USER_ACCESS_GET_GROUPS,
2651 rid.ids[0], &user_handle,
2652 &result);
2653 if (!NT_STATUS_IS_OK(status)) {
2654 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2655 nt_errstr(status)));
2656 goto close_domain;
2658 if (!NT_STATUS_IS_OK(result)) {
2659 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2660 nt_errstr(result)));
2661 goto close_domain;
2664 status = dcerpc_samr_GetGroupsForUser(b, talloc_tos(),
2665 &user_handle, &rids,
2666 &result);
2667 if (!NT_STATUS_IS_OK(status)) {
2668 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2669 nt_errstr(status)));
2670 goto close_user;
2672 if (!NT_STATUS_IS_OK(result)) {
2673 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2674 nt_errstr(result)));
2675 goto close_user;
2678 for (i=0; i<rids->count; i++) {
2680 status = dcerpc_samr_LookupRids(b, talloc_tos(),
2681 &domain_handle,
2682 1, &rids->rids[i].rid,
2683 &names, &type,
2684 &result);
2685 if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result) && (names.count == 1)) {
2686 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2687 p += 21;
2688 count++;
2692 *rdata_len = PTR_DIFF(p,*rdata);
2694 SSVAL(*rparam,4,count); /* is this right?? */
2695 SSVAL(*rparam,6,count); /* is this right?? */
2697 ret = True;
2699 close_user:
2700 dcerpc_samr_Close(b, talloc_tos(), &user_handle, &result);
2701 close_domain:
2702 dcerpc_samr_Close(b, talloc_tos(), &domain_handle, &result);
2703 close_sam:
2704 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2706 return ret;
2709 /*******************************************************************
2710 Get all users.
2711 ******************************************************************/
2713 static bool api_RNetUserEnum(struct smbd_server_connection *sconn,
2714 connection_struct *conn, uint64_t vuid,
2715 char *param, int tpscnt,
2716 char *data, int tdscnt,
2717 int mdrcnt,int mprcnt,
2718 char **rdata,char **rparam,
2719 int *rdata_len,int *rparam_len)
2721 int count_sent=0;
2722 int num_users=0;
2723 int errflags=0;
2724 int i, resume_context, cli_buf_size;
2725 uint32_t resume_handle;
2727 struct rpc_pipe_client *samr_pipe;
2728 struct policy_handle samr_handle, domain_handle;
2729 NTSTATUS status, result;
2731 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2732 char *str2 = skip_string(param,tpscnt,str1);
2733 char *p = skip_string(param,tpscnt,str2);
2734 char *endp = NULL;
2736 struct dcerpc_binding_handle *b;
2738 if (!str1 || !str2 || !p) {
2739 return False;
2742 if (strcmp(str1,"WrLeh") != 0)
2743 return False;
2744 /* parameters
2745 * W-> resume context (number of users to skip)
2746 * r -> return parameter pointer to receive buffer
2747 * L -> length of receive buffer
2748 * e -> return parameter number of entries
2749 * h -> return parameter total number of users
2752 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2753 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2754 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2755 resume_context, cli_buf_size));
2757 *rparam_len = 8;
2758 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2759 if (!*rparam) {
2760 return False;
2763 /* check it's a supported varient */
2764 if (strcmp("B21",str2) != 0)
2765 return False;
2767 *rdata_len = cli_buf_size;
2768 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2769 if (!*rdata) {
2770 return False;
2773 p = *rdata;
2774 endp = *rdata + *rdata_len;
2776 status = rpc_pipe_open_interface(
2777 talloc_tos(), &ndr_table_samr.syntax_id,
2778 conn->session_info, conn->sconn->remote_address,
2779 conn->sconn->msg_ctx, &samr_pipe);
2780 if (!NT_STATUS_IS_OK(status)) {
2781 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2782 nt_errstr(status)));
2783 return false;
2786 b = samr_pipe->binding_handle;
2788 status = dcerpc_samr_Connect2(b, talloc_tos(), lp_netbios_name(),
2789 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle,
2790 &result);
2791 if (!NT_STATUS_IS_OK(status)) {
2792 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2793 nt_errstr(status)));
2794 return false;
2796 if (!NT_STATUS_IS_OK(result)) {
2797 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2798 nt_errstr(result)));
2799 return false;
2802 status = dcerpc_samr_OpenDomain(b, talloc_tos(), &samr_handle,
2803 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2804 get_global_sam_sid(), &domain_handle,
2805 &result);
2806 if (!NT_STATUS_IS_OK(status)) {
2807 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2808 nt_errstr(status)));
2809 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2810 return false;
2812 if (!NT_STATUS_IS_OK(result)) {
2813 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2814 nt_errstr(result)));
2815 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2816 return false;
2819 errflags=NERR_Success;
2821 resume_handle = 0;
2823 while (true) {
2824 struct samr_SamArray *sam_entries;
2825 uint32_t num_entries;
2827 status = dcerpc_samr_EnumDomainUsers(b, talloc_tos(),
2828 &domain_handle,
2829 &resume_handle,
2830 0, &sam_entries, 1,
2831 &num_entries,
2832 &result);
2834 if (!NT_STATUS_IS_OK(status)) {
2835 DEBUG(10, ("dcerpc_samr_EnumDomainUsers returned "
2836 "%s\n", nt_errstr(status)));
2837 break;
2839 if (!NT_STATUS_IS_OK(result)) {
2840 DEBUG(10, ("dcerpc_samr_EnumDomainUsers returned "
2841 "%s\n", nt_errstr(result)));
2842 break;
2845 if (num_entries == 0) {
2846 DEBUG(10, ("dcerpc_samr_EnumDomainUsers returned "
2847 "no entries -- done\n"));
2848 break;
2851 for (i=0; i<num_entries; i++) {
2852 const char *name;
2854 name = sam_entries->entries[i].name.string;
2856 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2857 &&(strlen(name)<=21)) {
2858 strlcpy(p,name,PTR_DIFF(endp,p));
2859 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2860 "username %s\n",count_sent,p));
2861 p += 21;
2862 count_sent++;
2863 } else {
2864 /* set overflow error */
2865 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2866 "username %s\n",count_sent,name));
2867 errflags=234;
2868 break;
2872 if (errflags != NERR_Success) {
2873 break;
2876 TALLOC_FREE(sam_entries);
2879 dcerpc_samr_Close(b, talloc_tos(), &domain_handle, &result);
2880 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2882 *rdata_len = PTR_DIFF(p,*rdata);
2884 SSVAL(*rparam,0,errflags);
2885 SSVAL(*rparam,2,0); /* converter word */
2886 SSVAL(*rparam,4,count_sent); /* is this right?? */
2887 SSVAL(*rparam,6,num_users); /* is this right?? */
2889 return True;
2892 /****************************************************************************
2893 Get the time of day info.
2894 ****************************************************************************/
2896 static bool api_NetRemoteTOD(struct smbd_server_connection *sconn,
2897 connection_struct *conn,uint64_t vuid,
2898 char *param, int tpscnt,
2899 char *data, int tdscnt,
2900 int mdrcnt,int mprcnt,
2901 char **rdata,char **rparam,
2902 int *rdata_len,int *rparam_len)
2904 struct tm *t;
2905 time_t unixdate = time(NULL);
2906 char *p;
2908 *rparam_len = 4;
2909 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2910 if (!*rparam) {
2911 return False;
2914 *rdata_len = 21;
2915 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2916 if (!*rdata) {
2917 return False;
2920 SSVAL(*rparam,0,NERR_Success);
2921 SSVAL(*rparam,2,0); /* converter word */
2923 p = *rdata;
2925 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2926 by NT in a "net time" operation,
2927 it seems to ignore the one below */
2929 /* the client expects to get localtime, not GMT, in this bit
2930 (I think, this needs testing) */
2931 t = localtime(&unixdate);
2932 if (!t) {
2933 return False;
2936 SIVAL(p,4,0); /* msecs ? */
2937 SCVAL(p,8,t->tm_hour);
2938 SCVAL(p,9,t->tm_min);
2939 SCVAL(p,10,t->tm_sec);
2940 SCVAL(p,11,0); /* hundredths of seconds */
2941 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2942 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2943 SCVAL(p,16,t->tm_mday);
2944 SCVAL(p,17,t->tm_mon + 1);
2945 SSVAL(p,18,1900+t->tm_year);
2946 SCVAL(p,20,t->tm_wday);
2948 return True;
2951 /****************************************************************************
2952 Set the user password (SamOEM version - gets plaintext).
2953 ****************************************************************************/
2955 static bool api_SamOEMChangePassword(struct smbd_server_connection *sconn,
2956 connection_struct *conn,uint64_t vuid,
2957 char *param, int tpscnt,
2958 char *data, int tdscnt,
2959 int mdrcnt,int mprcnt,
2960 char **rdata,char **rparam,
2961 int *rdata_len,int *rparam_len)
2963 fstring user;
2964 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2966 TALLOC_CTX *mem_ctx = talloc_tos();
2967 NTSTATUS status, result;
2968 struct rpc_pipe_client *cli = NULL;
2969 struct lsa_AsciiString server, account;
2970 struct samr_CryptPassword password;
2971 struct samr_Password hash;
2972 int errcode = NERR_badpass;
2973 int bufsize;
2974 struct dcerpc_binding_handle *b;
2976 *rparam_len = 4;
2977 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2978 if (!*rparam) {
2979 return False;
2982 if (!p) {
2983 return False;
2985 *rdata_len = 0;
2987 SSVAL(*rparam,0,NERR_badpass);
2990 * Check the parameter definition is correct.
2993 /* Do we have a string ? */
2994 if (skip_string(param,tpscnt,p) == 0) {
2995 return False;
2997 if(!strequal(p, "zsT")) {
2998 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2999 return False;
3001 p = skip_string(param, tpscnt, p);
3002 if (!p) {
3003 return False;
3006 /* Do we have a string ? */
3007 if (skip_string(param,tpscnt,p) == 0) {
3008 return False;
3010 if(!strequal(p, "B516B16")) {
3011 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
3012 return False;
3014 p = skip_string(param,tpscnt,p);
3015 if (!p) {
3016 return False;
3018 /* Do we have a string ? */
3019 if (skip_string(param,tpscnt,p) == 0) {
3020 return False;
3022 p += pull_ascii_fstring(user,p);
3024 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
3026 if (tdscnt != 532) {
3027 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3028 goto out;
3031 bufsize = get_safe_SVAL(param,tpscnt,p,0,-1);
3032 if (bufsize != 532) {
3033 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3034 goto out;
3037 memcpy(password.data, data, 516);
3038 memcpy(hash.hash, data+516, 16);
3040 status = rpc_pipe_open_interface(mem_ctx, &ndr_table_samr.syntax_id,
3041 conn->session_info,
3042 conn->sconn->remote_address,
3043 conn->sconn->msg_ctx,
3044 &cli);
3045 if (!NT_STATUS_IS_OK(status)) {
3046 DEBUG(0,("api_SamOEMChangePassword: could not connect to samr: %s\n",
3047 nt_errstr(status)));
3048 errcode = W_ERROR_V(ntstatus_to_werror(status));
3049 goto out;
3052 b = cli->binding_handle;
3054 init_lsa_AsciiString(&server, lp_netbios_name());
3055 init_lsa_AsciiString(&account, user);
3057 status = dcerpc_samr_OemChangePasswordUser2(b, mem_ctx,
3058 &server,
3059 &account,
3060 &password,
3061 &hash,
3062 &result);
3063 if (!NT_STATUS_IS_OK(status)) {
3064 errcode = W_ERROR_V(ntstatus_to_werror(status));
3065 goto out;
3067 if (!NT_STATUS_IS_OK(result)) {
3068 errcode = W_ERROR_V(ntstatus_to_werror(result));
3069 goto out;
3072 errcode = NERR_Success;
3073 out:
3074 SSVAL(*rparam,0,errcode);
3075 SSVAL(*rparam,2,0); /* converter word */
3077 return(True);
3080 /****************************************************************************
3081 delete a print job
3082 Form: <W> <>
3083 ****************************************************************************/
3085 static bool api_RDosPrintJobDel(struct smbd_server_connection *sconn,
3086 connection_struct *conn,uint64_t vuid,
3087 char *param, int tpscnt,
3088 char *data, int tdscnt,
3089 int mdrcnt,int mprcnt,
3090 char **rdata,char **rparam,
3091 int *rdata_len,int *rparam_len)
3093 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3094 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3095 char *str2 = skip_string(param,tpscnt,str1);
3096 char *p = skip_string(param,tpscnt,str2);
3097 uint32 jobid;
3098 fstring sharename;
3099 int errcode;
3100 WERROR werr = WERR_OK;
3102 TALLOC_CTX *mem_ctx = talloc_tos();
3103 NTSTATUS status;
3104 struct rpc_pipe_client *cli = NULL;
3105 struct dcerpc_binding_handle *b = NULL;
3106 struct policy_handle handle;
3107 struct spoolss_DevmodeContainer devmode_ctr;
3108 enum spoolss_JobControl command;
3110 if (!str1 || !str2 || !p) {
3111 return False;
3114 * We use 1 here not 2 as we're checking
3115 * the last byte we want to access is safe.
3117 if (!is_offset_safe(param,tpscnt,p,1)) {
3118 return False;
3120 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3121 return False;
3123 /* check it's a supported varient */
3124 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
3125 return(False);
3127 *rparam_len = 4;
3128 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3129 if (!*rparam) {
3130 return False;
3132 *rdata_len = 0;
3134 ZERO_STRUCT(handle);
3136 status = rpc_pipe_open_interface(conn,
3137 &ndr_table_spoolss.syntax_id,
3138 conn->session_info,
3139 conn->sconn->remote_address,
3140 conn->sconn->msg_ctx,
3141 &cli);
3142 if (!NT_STATUS_IS_OK(status)) {
3143 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
3144 nt_errstr(status)));
3145 errcode = W_ERROR_V(ntstatus_to_werror(status));
3146 goto out;
3148 b = cli->binding_handle;
3150 ZERO_STRUCT(devmode_ctr);
3152 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
3153 sharename,
3154 "RAW",
3155 devmode_ctr,
3156 JOB_ACCESS_ADMINISTER,
3157 &handle,
3158 &werr);
3159 if (!NT_STATUS_IS_OK(status)) {
3160 errcode = W_ERROR_V(ntstatus_to_werror(status));
3161 goto out;
3163 if (!W_ERROR_IS_OK(werr)) {
3164 errcode = W_ERROR_V(werr);
3165 goto out;
3168 /* FIXME: formerly NERR_JobNotFound was returned if job did not exist
3169 * and NERR_DestNotFound if share did not exist */
3171 errcode = NERR_Success;
3173 switch (function) {
3174 case 81: /* delete */
3175 command = SPOOLSS_JOB_CONTROL_DELETE;
3176 break;
3177 case 82: /* pause */
3178 command = SPOOLSS_JOB_CONTROL_PAUSE;
3179 break;
3180 case 83: /* resume */
3181 command = SPOOLSS_JOB_CONTROL_RESUME;
3182 break;
3183 default:
3184 errcode = NERR_notsupported;
3185 goto out;
3188 status = dcerpc_spoolss_SetJob(b, mem_ctx,
3189 &handle,
3190 jobid,
3191 NULL, /* unique ptr ctr */
3192 command,
3193 &werr);
3194 if (!NT_STATUS_IS_OK(status)) {
3195 errcode = W_ERROR_V(ntstatus_to_werror(status));
3196 goto out;
3198 if (!W_ERROR_IS_OK(werr)) {
3199 errcode = W_ERROR_V(werr);
3200 goto out;
3203 out:
3204 if (b && is_valid_policy_hnd(&handle)) {
3205 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
3208 SSVAL(*rparam,0,errcode);
3209 SSVAL(*rparam,2,0); /* converter word */
3211 return(True);
3214 /****************************************************************************
3215 Purge a print queue - or pause or resume it.
3216 ****************************************************************************/
3218 static bool api_WPrintQueueCtrl(struct smbd_server_connection *sconn,
3219 connection_struct *conn,uint64_t vuid,
3220 char *param, int tpscnt,
3221 char *data, int tdscnt,
3222 int mdrcnt,int mprcnt,
3223 char **rdata,char **rparam,
3224 int *rdata_len,int *rparam_len)
3226 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3227 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3228 char *str2 = skip_string(param,tpscnt,str1);
3229 char *QueueName = skip_string(param,tpscnt,str2);
3230 int errcode = NERR_notsupported;
3231 WERROR werr = WERR_OK;
3232 NTSTATUS status;
3234 TALLOC_CTX *mem_ctx = talloc_tos();
3235 struct rpc_pipe_client *cli = NULL;
3236 struct dcerpc_binding_handle *b = NULL;
3237 struct policy_handle handle;
3238 struct spoolss_SetPrinterInfoCtr info_ctr;
3239 struct spoolss_DevmodeContainer devmode_ctr;
3240 struct sec_desc_buf secdesc_ctr;
3241 enum spoolss_PrinterControl command;
3243 if (!str1 || !str2 || !QueueName) {
3244 return False;
3247 /* check it's a supported varient */
3248 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3249 return(False);
3251 *rparam_len = 4;
3252 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3253 if (!*rparam) {
3254 return False;
3256 *rdata_len = 0;
3258 if (skip_string(param,tpscnt,QueueName) == NULL) {
3259 return False;
3262 ZERO_STRUCT(handle);
3264 status = rpc_pipe_open_interface(conn,
3265 &ndr_table_spoolss.syntax_id,
3266 conn->session_info,
3267 conn->sconn->remote_address,
3268 conn->sconn->msg_ctx,
3269 &cli);
3270 if (!NT_STATUS_IS_OK(status)) {
3271 DEBUG(0,("api_WPrintQueueCtrl: could not connect to spoolss: %s\n",
3272 nt_errstr(status)));
3273 errcode = W_ERROR_V(ntstatus_to_werror(status));
3274 goto out;
3276 b = cli->binding_handle;
3278 ZERO_STRUCT(devmode_ctr);
3280 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
3281 QueueName,
3282 NULL,
3283 devmode_ctr,
3284 PRINTER_ACCESS_ADMINISTER,
3285 &handle,
3286 &werr);
3287 if (!NT_STATUS_IS_OK(status)) {
3288 errcode = W_ERROR_V(ntstatus_to_werror(status));
3289 goto out;
3291 if (!W_ERROR_IS_OK(werr)) {
3292 errcode = W_ERROR_V(werr);
3293 goto out;
3296 switch (function) {
3297 case 74: /* Pause queue */
3298 command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3299 break;
3300 case 75: /* Resume queue */
3301 command = SPOOLSS_PRINTER_CONTROL_RESUME;
3302 break;
3303 case 103: /* Purge */
3304 command = SPOOLSS_PRINTER_CONTROL_PURGE;
3305 break;
3306 default:
3307 werr = WERR_NOT_SUPPORTED;
3308 break;
3311 if (!W_ERROR_IS_OK(werr)) {
3312 errcode = W_ERROR_V(werr);
3313 goto out;
3316 ZERO_STRUCT(info_ctr);
3317 ZERO_STRUCT(secdesc_ctr);
3319 status = dcerpc_spoolss_SetPrinter(b, mem_ctx,
3320 &handle,
3321 &info_ctr,
3322 &devmode_ctr,
3323 &secdesc_ctr,
3324 command,
3325 &werr);
3326 if (!NT_STATUS_IS_OK(status)) {
3327 errcode = W_ERROR_V(ntstatus_to_werror(status));
3328 goto out;
3330 if (!W_ERROR_IS_OK(werr)) {
3331 errcode = W_ERROR_V(werr);
3332 goto out;
3335 errcode = W_ERROR_V(werr);
3337 out:
3339 if (b && is_valid_policy_hnd(&handle)) {
3340 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
3343 SSVAL(*rparam,0,errcode);
3344 SSVAL(*rparam,2,0); /* converter word */
3346 return(True);
3349 /****************************************************************************
3350 set the property of a print job (undocumented?)
3351 ? function = 0xb -> set name of print job
3352 ? function = 0x6 -> move print job up/down
3353 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3354 or <WWsTP> <WB21BB16B10zWWzDDz>
3355 ****************************************************************************/
3357 static int check_printjob_info(struct pack_desc* desc,
3358 int uLevel, char* id)
3360 desc->subformat = NULL;
3361 switch( uLevel ) {
3362 case 0: desc->format = "W"; break;
3363 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3364 case 2: desc->format = "WWzWWDDzz"; break;
3365 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3366 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3367 default:
3368 DEBUG(0,("check_printjob_info: invalid level %d\n",
3369 uLevel ));
3370 return False;
3372 if (id == NULL || strcmp(desc->format,id) != 0) {
3373 DEBUG(0,("check_printjob_info: invalid format %s\n",
3374 id ? id : "<NULL>" ));
3375 return False;
3377 return True;
3380 static bool api_PrintJobInfo(struct smbd_server_connection *sconn,
3381 connection_struct *conn, uint64_t vuid,
3382 char *param, int tpscnt,
3383 char *data, int tdscnt,
3384 int mdrcnt,int mprcnt,
3385 char **rdata,char **rparam,
3386 int *rdata_len,int *rparam_len)
3388 struct pack_desc desc;
3389 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3390 char *str2 = skip_string(param,tpscnt,str1);
3391 char *p = skip_string(param,tpscnt,str2);
3392 uint32 jobid;
3393 fstring sharename;
3394 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3395 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3396 int errcode;
3398 TALLOC_CTX *mem_ctx = talloc_tos();
3399 WERROR werr;
3400 NTSTATUS status;
3401 struct rpc_pipe_client *cli = NULL;
3402 struct dcerpc_binding_handle *b = NULL;
3403 struct policy_handle handle;
3404 struct spoolss_DevmodeContainer devmode_ctr;
3405 struct spoolss_JobInfoContainer ctr;
3406 union spoolss_JobInfo info;
3407 struct spoolss_SetJobInfo1 info1;
3409 if (!str1 || !str2 || !p) {
3410 return False;
3413 * We use 1 here not 2 as we're checking
3414 * the last byte we want to access is safe.
3416 if (!is_offset_safe(param,tpscnt,p,1)) {
3417 return False;
3419 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3420 return False;
3421 *rparam_len = 4;
3422 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3423 if (!*rparam) {
3424 return False;
3427 *rdata_len = 0;
3429 /* check it's a supported varient */
3430 if ((strcmp(str1,"WWsTP")) ||
3431 (!check_printjob_info(&desc,uLevel,str2)))
3432 return(False);
3434 errcode = NERR_notsupported;
3436 switch (function) {
3437 case 0xb:
3438 /* change print job name, data gives the name */
3439 break;
3440 default:
3441 goto out;
3444 ZERO_STRUCT(handle);
3446 status = rpc_pipe_open_interface(conn,
3447 &ndr_table_spoolss.syntax_id,
3448 conn->session_info,
3449 conn->sconn->remote_address,
3450 conn->sconn->msg_ctx,
3451 &cli);
3452 if (!NT_STATUS_IS_OK(status)) {
3453 DEBUG(0,("api_PrintJobInfo: could not connect to spoolss: %s\n",
3454 nt_errstr(status)));
3455 errcode = W_ERROR_V(ntstatus_to_werror(status));
3456 goto out;
3458 b = cli->binding_handle;
3460 ZERO_STRUCT(devmode_ctr);
3462 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
3463 sharename,
3464 "RAW",
3465 devmode_ctr,
3466 PRINTER_ACCESS_USE,
3467 &handle,
3468 &werr);
3469 if (!NT_STATUS_IS_OK(status)) {
3470 errcode = W_ERROR_V(ntstatus_to_werror(status));
3471 goto out;
3473 if (!W_ERROR_IS_OK(werr)) {
3474 errcode = W_ERROR_V(werr);
3475 goto out;
3478 werr = rpccli_spoolss_getjob(cli, mem_ctx,
3479 &handle,
3480 jobid,
3481 1, /* level */
3482 0, /* offered */
3483 &info);
3484 if (!W_ERROR_IS_OK(werr)) {
3485 errcode = W_ERROR_V(werr);
3486 goto out;
3489 ZERO_STRUCT(ctr);
3491 info1.job_id = info.info1.job_id;
3492 info1.printer_name = info.info1.printer_name;
3493 info1.user_name = info.info1.user_name;
3494 info1.document_name = data;
3495 info1.data_type = info.info1.data_type;
3496 info1.text_status = info.info1.text_status;
3497 info1.status = info.info1.status;
3498 info1.priority = info.info1.priority;
3499 info1.position = info.info1.position;
3500 info1.total_pages = info.info1.total_pages;
3501 info1.pages_printed = info.info1.pages_printed;
3502 info1.submitted = info.info1.submitted;
3504 ctr.level = 1;
3505 ctr.info.info1 = &info1;
3507 status = dcerpc_spoolss_SetJob(b, mem_ctx,
3508 &handle,
3509 jobid,
3510 &ctr,
3512 &werr);
3513 if (!NT_STATUS_IS_OK(status)) {
3514 errcode = W_ERROR_V(ntstatus_to_werror(status));
3515 goto out;
3517 if (!W_ERROR_IS_OK(werr)) {
3518 errcode = W_ERROR_V(werr);
3519 goto out;
3522 errcode = NERR_Success;
3523 out:
3525 if (b && is_valid_policy_hnd(&handle)) {
3526 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
3529 SSVALS(*rparam,0,errcode);
3530 SSVAL(*rparam,2,0); /* converter word */
3532 return(True);
3536 /****************************************************************************
3537 Get info about the server.
3538 ****************************************************************************/
3540 static bool api_RNetServerGetInfo(struct smbd_server_connection *sconn,
3541 connection_struct *conn,uint64_t vuid,
3542 char *param, int tpscnt,
3543 char *data, int tdscnt,
3544 int mdrcnt,int mprcnt,
3545 char **rdata,char **rparam,
3546 int *rdata_len,int *rparam_len)
3548 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3549 char *str2 = skip_string(param,tpscnt,str1);
3550 char *p = skip_string(param,tpscnt,str2);
3551 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3552 char *p2;
3553 int struct_len;
3555 NTSTATUS status;
3556 WERROR werr;
3557 TALLOC_CTX *mem_ctx = talloc_tos();
3558 struct rpc_pipe_client *cli = NULL;
3559 union srvsvc_NetSrvInfo info;
3560 int errcode;
3561 struct dcerpc_binding_handle *b;
3563 if (!str1 || !str2 || !p) {
3564 return False;
3567 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3569 /* check it's a supported varient */
3570 if (!prefix_ok(str1,"WrLh")) {
3571 return False;
3574 switch( uLevel ) {
3575 case 0:
3576 if (strcmp(str2,"B16") != 0) {
3577 return False;
3579 struct_len = 16;
3580 break;
3581 case 1:
3582 if (strcmp(str2,"B16BBDz") != 0) {
3583 return False;
3585 struct_len = 26;
3586 break;
3587 case 2:
3588 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3589 return False;
3591 struct_len = 134;
3592 break;
3593 case 3:
3594 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3595 return False;
3597 struct_len = 144;
3598 break;
3599 case 20:
3600 if (strcmp(str2,"DN") != 0) {
3601 return False;
3603 struct_len = 6;
3604 break;
3605 case 50:
3606 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3607 return False;
3609 struct_len = 42;
3610 break;
3611 default:
3612 return False;
3615 *rdata_len = mdrcnt;
3616 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3617 if (!*rdata) {
3618 return False;
3621 p = *rdata;
3622 p2 = p + struct_len;
3624 status = rpc_pipe_open_interface(mem_ctx, &ndr_table_srvsvc.syntax_id,
3625 conn->session_info,
3626 conn->sconn->remote_address,
3627 conn->sconn->msg_ctx,
3628 &cli);
3629 if (!NT_STATUS_IS_OK(status)) {
3630 DEBUG(0,("api_RNetServerGetInfo: could not connect to srvsvc: %s\n",
3631 nt_errstr(status)));
3632 errcode = W_ERROR_V(ntstatus_to_werror(status));
3633 goto out;
3636 b = cli->binding_handle;
3638 status = dcerpc_srvsvc_NetSrvGetInfo(b, mem_ctx,
3639 NULL,
3640 101,
3641 &info,
3642 &werr);
3643 if (!NT_STATUS_IS_OK(status)) {
3644 errcode = W_ERROR_V(ntstatus_to_werror(status));
3645 goto out;
3647 if (!W_ERROR_IS_OK(werr)) {
3648 errcode = W_ERROR_V(werr);
3649 goto out;
3652 if (info.info101 == NULL) {
3653 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3654 goto out;
3657 if (uLevel != 20) {
3658 srvstr_push(NULL, 0, p, info.info101->server_name, 16,
3659 STR_ASCII|STR_UPPER|STR_TERMINATE);
3661 p += 16;
3662 if (uLevel > 0) {
3663 SCVAL(p,0,info.info101->version_major);
3664 SCVAL(p,1,info.info101->version_minor);
3665 SIVAL(p,2,info.info101->server_type);
3667 if (mdrcnt == struct_len) {
3668 SIVAL(p,6,0);
3669 } else {
3670 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3671 if (mdrcnt - struct_len <= 0) {
3672 return false;
3674 push_ascii(p2,
3675 info.info101->comment,
3676 MIN(mdrcnt - struct_len,
3677 MAX_SERVER_STRING_LENGTH),
3678 STR_TERMINATE);
3679 p2 = skip_string(*rdata,*rdata_len,p2);
3680 if (!p2) {
3681 return False;
3686 if (uLevel > 1) {
3687 return False; /* not yet implemented */
3690 errcode = NERR_Success;
3692 out:
3694 *rdata_len = PTR_DIFF(p2,*rdata);
3696 *rparam_len = 6;
3697 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3698 if (!*rparam) {
3699 return False;
3701 SSVAL(*rparam,0,errcode);
3702 SSVAL(*rparam,2,0); /* converter word */
3703 SSVAL(*rparam,4,*rdata_len);
3705 return True;
3708 /****************************************************************************
3709 Get info about the server.
3710 ****************************************************************************/
3712 static bool api_NetWkstaGetInfo(struct smbd_server_connection *sconn,
3713 connection_struct *conn,uint64_t vuid,
3714 char *param, int tpscnt,
3715 char *data, int tdscnt,
3716 int mdrcnt,int mprcnt,
3717 char **rdata,char **rparam,
3718 int *rdata_len,int *rparam_len)
3720 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3721 char *str2 = skip_string(param,tpscnt,str1);
3722 char *p = skip_string(param,tpscnt,str2);
3723 char *p2;
3724 char *endp;
3725 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3727 if (!str1 || !str2 || !p) {
3728 return False;
3731 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3733 *rparam_len = 6;
3734 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3735 if (!*rparam) {
3736 return False;
3739 /* check it's a supported varient */
3740 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3741 return False;
3744 *rdata_len = mdrcnt + 1024;
3745 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3746 if (!*rdata) {
3747 return False;
3750 SSVAL(*rparam,0,NERR_Success);
3751 SSVAL(*rparam,2,0); /* converter word */
3753 p = *rdata;
3754 endp = *rdata + *rdata_len;
3756 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3757 if (!p2) {
3758 return False;
3761 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3762 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3763 if (!strupper_m(p2)) {
3764 return false;
3766 p2 = skip_string(*rdata,*rdata_len,p2);
3767 if (!p2) {
3768 return False;
3770 p += 4;
3772 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3773 strlcpy(p2,conn->session_info->unix_info->sanitized_username,PTR_DIFF(endp,p2));
3774 p2 = skip_string(*rdata,*rdata_len,p2);
3775 if (!p2) {
3776 return False;
3778 p += 4;
3780 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3781 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3782 if (!strupper_m(p2)) {
3783 return false;
3785 p2 = skip_string(*rdata,*rdata_len,p2);
3786 if (!p2) {
3787 return False;
3789 p += 4;
3791 SCVAL(p,0,SAMBA_MAJOR_NBT_ANNOUNCE_VERSION); /* system version - e.g 4 in 4.1 */
3792 SCVAL(p,1,SAMBA_MINOR_NBT_ANNOUNCE_VERSION); /* system version - e.g .1 in 4.1 */
3793 p += 2;
3795 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3796 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
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)); /* don't know */
3804 strlcpy(p2,"",PTR_DIFF(endp,p2));
3805 p2 = skip_string(*rdata,*rdata_len,p2);
3806 if (!p2) {
3807 return False;
3809 p += 4;
3811 *rdata_len = PTR_DIFF(p2,*rdata);
3813 SSVAL(*rparam,4,*rdata_len);
3815 return True;
3818 /****************************************************************************
3819 get info about a user
3821 struct user_info_11 {
3822 char usri11_name[21]; 0-20
3823 char usri11_pad; 21
3824 char *usri11_comment; 22-25
3825 char *usri11_usr_comment; 26-29
3826 unsigned short usri11_priv; 30-31
3827 unsigned long usri11_auth_flags; 32-35
3828 long usri11_password_age; 36-39
3829 char *usri11_homedir; 40-43
3830 char *usri11_parms; 44-47
3831 long usri11_last_logon; 48-51
3832 long usri11_last_logoff; 52-55
3833 unsigned short usri11_bad_pw_count; 56-57
3834 unsigned short usri11_num_logons; 58-59
3835 char *usri11_logon_server; 60-63
3836 unsigned short usri11_country_code; 64-65
3837 char *usri11_workstations; 66-69
3838 unsigned long usri11_max_storage; 70-73
3839 unsigned short usri11_units_per_week; 74-75
3840 unsigned char *usri11_logon_hours; 76-79
3841 unsigned short usri11_code_page; 80-81
3844 where:
3846 usri11_name specifies the user name for which information is retrieved
3848 usri11_pad aligns the next data structure element to a word boundary
3850 usri11_comment is a null terminated ASCII comment
3852 usri11_user_comment is a null terminated ASCII comment about the user
3854 usri11_priv specifies the level of the privilege assigned to the user.
3855 The possible values are:
3857 Name Value Description
3858 USER_PRIV_GUEST 0 Guest privilege
3859 USER_PRIV_USER 1 User privilege
3860 USER_PRV_ADMIN 2 Administrator privilege
3862 usri11_auth_flags specifies the account operator privileges. The
3863 possible values are:
3865 Name Value Description
3866 AF_OP_PRINT 0 Print operator
3869 Leach, Naik [Page 28]
3873 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3876 AF_OP_COMM 1 Communications operator
3877 AF_OP_SERVER 2 Server operator
3878 AF_OP_ACCOUNTS 3 Accounts operator
3881 usri11_password_age specifies how many seconds have elapsed since the
3882 password was last changed.
3884 usri11_home_dir points to a null terminated ASCII string that contains
3885 the path name of the user's home directory.
3887 usri11_parms points to a null terminated ASCII string that is set
3888 aside for use by applications.
3890 usri11_last_logon specifies the time when the user last logged on.
3891 This value is stored as the number of seconds elapsed since
3892 00:00:00, January 1, 1970.
3894 usri11_last_logoff specifies the time when the user last logged off.
3895 This value is stored as the number of seconds elapsed since
3896 00:00:00, January 1, 1970. A value of 0 means the last logoff
3897 time is unknown.
3899 usri11_bad_pw_count specifies the number of incorrect passwords
3900 entered since the last successful logon.
3902 usri11_log1_num_logons specifies the number of times this user has
3903 logged on. A value of -1 means the number of logons is unknown.
3905 usri11_logon_server points to a null terminated ASCII string that
3906 contains the name of the server to which logon requests are sent.
3907 A null string indicates logon requests should be sent to the
3908 domain controller.
3910 usri11_country_code specifies the country code for the user's language
3911 of choice.
3913 usri11_workstations points to a null terminated ASCII string that
3914 contains the names of workstations the user may log on from.
3915 There may be up to 8 workstations, with the names separated by
3916 commas. A null strings indicates there are no restrictions.
3918 usri11_max_storage specifies the maximum amount of disk space the user
3919 can occupy. A value of 0xffffffff indicates there are no
3920 restrictions.
3922 usri11_units_per_week specifies the equal number of time units into
3923 which a week is divided. This value must be equal to 168.
3925 usri11_logon_hours points to a 21 byte (168 bits) string that
3926 specifies the time during which the user can log on. Each bit
3927 represents one unique hour in a week. The first bit (bit 0, word
3928 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3932 Leach, Naik [Page 29]
3936 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3939 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3940 are no restrictions.
3942 usri11_code_page specifies the code page for the user's language of
3943 choice
3945 All of the pointers in this data structure need to be treated
3946 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3947 to be ignored. The converter word returned in the parameters section
3948 needs to be subtracted from the lower 16 bits to calculate an offset
3949 into the return buffer where this ASCII string resides.
3951 There is no auxiliary data in the response.
3953 ****************************************************************************/
3955 #define usri11_name 0
3956 #define usri11_pad 21
3957 #define usri11_comment 22
3958 #define usri11_usr_comment 26
3959 #define usri11_full_name 30
3960 #define usri11_priv 34
3961 #define usri11_auth_flags 36
3962 #define usri11_password_age 40
3963 #define usri11_homedir 44
3964 #define usri11_parms 48
3965 #define usri11_last_logon 52
3966 #define usri11_last_logoff 56
3967 #define usri11_bad_pw_count 60
3968 #define usri11_num_logons 62
3969 #define usri11_logon_server 64
3970 #define usri11_country_code 68
3971 #define usri11_workstations 70
3972 #define usri11_max_storage 74
3973 #define usri11_units_per_week 78
3974 #define usri11_logon_hours 80
3975 #define usri11_code_page 84
3976 #define usri11_end 86
3978 static bool api_RNetUserGetInfo(struct smbd_server_connection *sconn,
3979 connection_struct *conn, uint64_t vuid,
3980 char *param, int tpscnt,
3981 char *data, int tdscnt,
3982 int mdrcnt,int mprcnt,
3983 char **rdata,char **rparam,
3984 int *rdata_len,int *rparam_len)
3986 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3987 char *str2 = skip_string(param,tpscnt,str1);
3988 char *UserName = skip_string(param,tpscnt,str2);
3989 char *p = skip_string(param,tpscnt,UserName);
3990 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3991 char *p2;
3992 char *endp;
3993 const char *level_string;
3995 TALLOC_CTX *mem_ctx = talloc_tos();
3996 NTSTATUS status, result;
3997 struct rpc_pipe_client *cli = NULL;
3998 struct policy_handle connect_handle, domain_handle, user_handle;
3999 struct lsa_String domain_name;
4000 struct dom_sid2 *domain_sid;
4001 struct lsa_String names;
4002 struct samr_Ids rids;
4003 struct samr_Ids types;
4004 int errcode = W_ERROR_V(WERR_USER_NOT_FOUND);
4005 uint32_t rid;
4006 union samr_UserInfo *info;
4007 struct dcerpc_binding_handle *b = NULL;
4009 if (!str1 || !str2 || !UserName || !p) {
4010 return False;
4013 *rparam_len = 6;
4014 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4015 if (!*rparam) {
4016 return False;
4019 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
4021 /* check it's a supported variant */
4022 if (strcmp(str1,"zWrLh") != 0) {
4023 return False;
4025 switch( uLevel ) {
4026 case 0: level_string = "B21"; break;
4027 case 1: level_string = "B21BB16DWzzWz"; break;
4028 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
4029 case 10: level_string = "B21Bzzz"; break;
4030 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
4031 default: return False;
4034 if (strcmp(level_string,str2) != 0) {
4035 return False;
4038 *rdata_len = mdrcnt + 1024;
4039 *rdata = smb_realloc_limit(*rdata,*rdata_len);
4040 if (!*rdata) {
4041 return False;
4044 p = *rdata;
4045 endp = *rdata + *rdata_len;
4046 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
4047 if (!p2) {
4048 return False;
4051 ZERO_STRUCT(connect_handle);
4052 ZERO_STRUCT(domain_handle);
4053 ZERO_STRUCT(user_handle);
4055 status = rpc_pipe_open_interface(mem_ctx, &ndr_table_samr.syntax_id,
4056 conn->session_info,
4057 conn->sconn->remote_address,
4058 conn->sconn->msg_ctx,
4059 &cli);
4060 if (!NT_STATUS_IS_OK(status)) {
4061 DEBUG(0,("api_RNetUserGetInfo: could not connect to samr: %s\n",
4062 nt_errstr(status)));
4063 errcode = W_ERROR_V(ntstatus_to_werror(status));
4064 goto out;
4067 b = cli->binding_handle;
4069 status = dcerpc_samr_Connect2(b, mem_ctx,
4070 lp_netbios_name(),
4071 SAMR_ACCESS_CONNECT_TO_SERVER |
4072 SAMR_ACCESS_ENUM_DOMAINS |
4073 SAMR_ACCESS_LOOKUP_DOMAIN,
4074 &connect_handle,
4075 &result);
4076 if (!NT_STATUS_IS_OK(status)) {
4077 errcode = W_ERROR_V(ntstatus_to_werror(status));
4078 goto out;
4080 if (!NT_STATUS_IS_OK(result)) {
4081 errcode = W_ERROR_V(ntstatus_to_werror(result));
4082 goto out;
4085 init_lsa_String(&domain_name, get_global_sam_name());
4087 status = dcerpc_samr_LookupDomain(b, mem_ctx,
4088 &connect_handle,
4089 &domain_name,
4090 &domain_sid,
4091 &result);
4092 if (!NT_STATUS_IS_OK(status)) {
4093 errcode = W_ERROR_V(ntstatus_to_werror(status));
4094 goto out;
4096 if (!NT_STATUS_IS_OK(result)) {
4097 errcode = W_ERROR_V(ntstatus_to_werror(result));
4098 goto out;
4101 status = dcerpc_samr_OpenDomain(b, mem_ctx,
4102 &connect_handle,
4103 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
4104 domain_sid,
4105 &domain_handle,
4106 &result);
4107 if (!NT_STATUS_IS_OK(status)) {
4108 errcode = W_ERROR_V(ntstatus_to_werror(status));
4109 goto out;
4111 if (!NT_STATUS_IS_OK(result)) {
4112 errcode = W_ERROR_V(ntstatus_to_werror(result));
4113 goto out;
4116 init_lsa_String(&names, UserName);
4118 status = dcerpc_samr_LookupNames(b, mem_ctx,
4119 &domain_handle,
4121 &names,
4122 &rids,
4123 &types,
4124 &result);
4125 if (!NT_STATUS_IS_OK(status)) {
4126 errcode = W_ERROR_V(ntstatus_to_werror(status));
4127 goto out;
4129 if (!NT_STATUS_IS_OK(result)) {
4130 errcode = W_ERROR_V(ntstatus_to_werror(result));
4131 goto out;
4134 if (rids.count != 1) {
4135 errcode = W_ERROR_V(WERR_NO_SUCH_USER);
4136 goto out;
4138 if (rids.count != types.count) {
4139 errcode = W_ERROR_V(WERR_INVALID_PARAM);
4140 goto out;
4142 if (types.ids[0] != SID_NAME_USER) {
4143 errcode = W_ERROR_V(WERR_INVALID_PARAM);
4144 goto out;
4147 rid = rids.ids[0];
4149 status = dcerpc_samr_OpenUser(b, mem_ctx,
4150 &domain_handle,
4151 SAMR_USER_ACCESS_GET_LOCALE |
4152 SAMR_USER_ACCESS_GET_LOGONINFO |
4153 SAMR_USER_ACCESS_GET_ATTRIBUTES |
4154 SAMR_USER_ACCESS_GET_GROUPS |
4155 SAMR_USER_ACCESS_GET_GROUP_MEMBERSHIP |
4156 SEC_STD_READ_CONTROL,
4157 rid,
4158 &user_handle,
4159 &result);
4160 if (!NT_STATUS_IS_OK(status)) {
4161 errcode = W_ERROR_V(ntstatus_to_werror(status));
4162 goto out;
4164 if (!NT_STATUS_IS_OK(result)) {
4165 errcode = W_ERROR_V(ntstatus_to_werror(result));
4166 goto out;
4169 status = dcerpc_samr_QueryUserInfo2(b, mem_ctx,
4170 &user_handle,
4171 UserAllInformation,
4172 &info,
4173 &result);
4174 if (!NT_STATUS_IS_OK(status)) {
4175 errcode = W_ERROR_V(ntstatus_to_werror(status));
4176 goto out;
4178 if (!NT_STATUS_IS_OK(result)) {
4179 errcode = W_ERROR_V(ntstatus_to_werror(result));
4180 goto out;
4183 memset(p,0,21);
4184 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
4186 if (uLevel > 0) {
4187 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
4188 *p2 = 0;
4191 if (uLevel >= 10) {
4192 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
4193 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
4194 p2 = skip_string(*rdata,*rdata_len,p2);
4195 if (!p2) {
4196 return False;
4199 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
4200 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
4201 p2 = skip_string(*rdata,*rdata_len,p2);
4202 if (!p2) {
4203 return False;
4206 /* EEK! the cifsrap.txt doesn't have this in!!!! */
4207 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
4208 strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4209 p2 = skip_string(*rdata,*rdata_len,p2);
4210 if (!p2) {
4211 return False;
4215 if (uLevel == 11) {
4216 const char *homedir = info->info21.home_directory.string;
4217 /* modelled after NTAS 3.51 reply */
4218 SSVAL(p,usri11_priv,
4219 (get_current_uid(conn) == sec_initial_uid())?
4220 USER_PRIV_ADMIN:USER_PRIV_USER);
4221 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
4222 SIVALS(p,usri11_password_age,-1); /* password age */
4223 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
4224 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
4225 p2 = skip_string(*rdata,*rdata_len,p2);
4226 if (!p2) {
4227 return False;
4229 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
4230 strlcpy(p2,"",PTR_DIFF(endp,p2));
4231 p2 = skip_string(*rdata,*rdata_len,p2);
4232 if (!p2) {
4233 return False;
4235 SIVAL(p,usri11_last_logon,0); /* last logon */
4236 SIVAL(p,usri11_last_logoff,0); /* last logoff */
4237 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
4238 SSVALS(p,usri11_num_logons,-1); /* num logons */
4239 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
4240 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
4241 p2 = skip_string(*rdata,*rdata_len,p2);
4242 if (!p2) {
4243 return False;
4245 SSVAL(p,usri11_country_code,0); /* country code */
4247 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
4248 strlcpy(p2,"",PTR_DIFF(endp,p2));
4249 p2 = skip_string(*rdata,*rdata_len,p2);
4250 if (!p2) {
4251 return False;
4254 SIVALS(p,usri11_max_storage,-1); /* max storage */
4255 SSVAL(p,usri11_units_per_week,168); /* units per week */
4256 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
4258 /* a simple way to get logon hours at all times. */
4259 memset(p2,0xff,21);
4260 SCVAL(p2,21,0); /* fix zero termination */
4261 p2 = skip_string(*rdata,*rdata_len,p2);
4262 if (!p2) {
4263 return False;
4266 SSVAL(p,usri11_code_page,0); /* code page */
4269 if (uLevel == 1 || uLevel == 2) {
4270 memset(p+22,' ',16); /* password */
4271 SIVALS(p,38,-1); /* password age */
4272 SSVAL(p,42,
4273 (get_current_uid(conn) == sec_initial_uid())?
4274 USER_PRIV_ADMIN:USER_PRIV_USER);
4275 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
4276 strlcpy(p2, info->info21.home_directory.string,
4277 PTR_DIFF(endp,p2));
4278 p2 = skip_string(*rdata,*rdata_len,p2);
4279 if (!p2) {
4280 return False;
4282 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
4283 *p2++ = 0;
4284 SSVAL(p,52,0); /* flags */
4285 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
4286 strlcpy(p2, info->info21.logon_script.string,
4287 PTR_DIFF(endp,p2));
4288 p2 = skip_string(*rdata,*rdata_len,p2);
4289 if (!p2) {
4290 return False;
4292 if (uLevel == 2) {
4293 SIVAL(p,58,0); /* auth_flags */
4294 SIVAL(p,62,PTR_DIFF(p2,*rdata)); /* full_name */
4295 strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4296 p2 = skip_string(*rdata,*rdata_len,p2);
4297 if (!p2) {
4298 return False;
4300 SIVAL(p,66,0); /* urs_comment */
4301 SIVAL(p,70,PTR_DIFF(p2,*rdata)); /* parms */
4302 strlcpy(p2,"",PTR_DIFF(endp,p2));
4303 p2 = skip_string(*rdata,*rdata_len,p2);
4304 if (!p2) {
4305 return False;
4307 SIVAL(p,74,0); /* workstations */
4308 SIVAL(p,78,0); /* last_logon */
4309 SIVAL(p,82,0); /* last_logoff */
4310 SIVALS(p,86,-1); /* acct_expires */
4311 SIVALS(p,90,-1); /* max_storage */
4312 SSVAL(p,94,168); /* units_per_week */
4313 SIVAL(p,96,PTR_DIFF(p2,*rdata)); /* logon_hours */
4314 memset(p2,-1,21);
4315 p2 += 21;
4316 SSVALS(p,100,-1); /* bad_pw_count */
4317 SSVALS(p,102,-1); /* num_logons */
4318 SIVAL(p,104,PTR_DIFF(p2,*rdata)); /* logon_server */
4320 TALLOC_CTX *ctx = talloc_tos();
4321 int space_rem = *rdata_len - (p2 - *rdata);
4322 char *tmp;
4324 if (space_rem <= 0) {
4325 return false;
4327 tmp = talloc_strdup(ctx, "\\\\%L");
4328 if (!tmp) {
4329 return false;
4331 tmp = talloc_sub_basic(ctx,
4334 tmp);
4335 if (!tmp) {
4336 return false;
4339 push_ascii(p2,
4340 tmp,
4341 space_rem,
4342 STR_TERMINATE);
4344 p2 = skip_string(*rdata,*rdata_len,p2);
4345 if (!p2) {
4346 return False;
4348 SSVAL(p,108,49); /* country_code */
4349 SSVAL(p,110,860); /* code page */
4353 errcode = NERR_Success;
4355 out:
4356 *rdata_len = PTR_DIFF(p2,*rdata);
4358 if (b && is_valid_policy_hnd(&user_handle)) {
4359 dcerpc_samr_Close(b, mem_ctx, &user_handle, &result);
4361 if (b && is_valid_policy_hnd(&domain_handle)) {
4362 dcerpc_samr_Close(b, mem_ctx, &domain_handle, &result);
4364 if (b && is_valid_policy_hnd(&connect_handle)) {
4365 dcerpc_samr_Close(b, mem_ctx, &connect_handle, &result);
4368 SSVAL(*rparam,0,errcode);
4369 SSVAL(*rparam,2,0); /* converter word */
4370 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
4372 return(True);
4375 static bool api_WWkstaUserLogon(struct smbd_server_connection *sconn,
4376 connection_struct *conn,uint64_t vuid,
4377 char *param, int tpscnt,
4378 char *data, int tdscnt,
4379 int mdrcnt,int mprcnt,
4380 char **rdata,char **rparam,
4381 int *rdata_len,int *rparam_len)
4383 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4384 char *str2 = skip_string(param,tpscnt,str1);
4385 char *p = skip_string(param,tpscnt,str2);
4386 int uLevel;
4387 struct pack_desc desc;
4388 char* name;
4389 /* With share level security vuid will always be zero.
4390 Don't depend on vuser being non-null !!. JRA */
4391 struct user_struct *vuser = get_valid_user_struct(sconn, vuid);
4393 if (!str1 || !str2 || !p) {
4394 return False;
4397 if(vuser != NULL) {
4398 DEBUG(3,(" Username of UID %d is %s\n",
4399 (int)vuser->session_info->unix_token->uid,
4400 vuser->session_info->unix_info->unix_name));
4403 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4404 name = get_safe_str_ptr(param,tpscnt,p,2);
4405 if (!name) {
4406 return False;
4409 memset((char *)&desc,'\0',sizeof(desc));
4411 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
4413 /* check it's a supported varient */
4414 if (strcmp(str1,"OOWb54WrLh") != 0) {
4415 return False;
4417 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
4418 return False;
4420 if (mdrcnt > 0) {
4421 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4422 if (!*rdata) {
4423 return False;
4427 desc.base = *rdata;
4428 desc.buflen = mdrcnt;
4429 desc.subformat = NULL;
4430 desc.format = str2;
4432 if (init_package(&desc,1,0)) {
4433 PACKI(&desc,"W",0); /* code */
4434 PACKS(&desc,"B21",name); /* eff. name */
4435 PACKS(&desc,"B",""); /* pad */
4436 PACKI(&desc,"W",
4437 (get_current_uid(conn) == sec_initial_uid())?
4438 USER_PRIV_ADMIN:USER_PRIV_USER);
4439 PACKI(&desc,"D",0); /* auth flags XXX */
4440 PACKI(&desc,"W",0); /* num logons */
4441 PACKI(&desc,"W",0); /* bad pw count */
4442 PACKI(&desc,"D",0); /* last logon */
4443 PACKI(&desc,"D",-1); /* last logoff */
4444 PACKI(&desc,"D",-1); /* logoff time */
4445 PACKI(&desc,"D",-1); /* kickoff time */
4446 PACKI(&desc,"D",0); /* password age */
4447 PACKI(&desc,"D",0); /* password can change */
4448 PACKI(&desc,"D",-1); /* password must change */
4451 fstring mypath;
4452 fstrcpy(mypath,"\\\\");
4453 fstrcat(mypath,get_local_machine_name());
4454 if (!strupper_m(mypath)) {
4455 return false;
4457 PACKS(&desc,"z",mypath); /* computer */
4460 PACKS(&desc,"z",lp_workgroup());/* domain */
4461 PACKS(&desc,"z", vuser ?
4462 vuser->session_info->info->logon_script
4463 : ""); /* script path */
4464 PACKI(&desc,"D",0x00000000); /* reserved */
4467 *rdata_len = desc.usedlen;
4468 *rparam_len = 6;
4469 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4470 if (!*rparam) {
4471 return False;
4473 SSVALS(*rparam,0,desc.errcode);
4474 SSVAL(*rparam,2,0);
4475 SSVAL(*rparam,4,desc.neededlen);
4477 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4479 return True;
4482 /****************************************************************************
4483 api_WAccessGetUserPerms
4484 ****************************************************************************/
4486 static bool api_WAccessGetUserPerms(struct smbd_server_connection *sconn,
4487 connection_struct *conn,uint64_t vuid,
4488 char *param, int tpscnt,
4489 char *data, int tdscnt,
4490 int mdrcnt,int mprcnt,
4491 char **rdata,char **rparam,
4492 int *rdata_len,int *rparam_len)
4494 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4495 char *str2 = skip_string(param,tpscnt,str1);
4496 char *user = skip_string(param,tpscnt,str2);
4497 char *resource = skip_string(param,tpscnt,user);
4499 if (!str1 || !str2 || !user || !resource) {
4500 return False;
4503 if (skip_string(param,tpscnt,resource) == NULL) {
4504 return False;
4506 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4508 /* check it's a supported varient */
4509 if (strcmp(str1,"zzh") != 0) {
4510 return False;
4512 if (strcmp(str2,"") != 0) {
4513 return False;
4516 *rparam_len = 6;
4517 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4518 if (!*rparam) {
4519 return False;
4521 SSVALS(*rparam,0,0); /* errorcode */
4522 SSVAL(*rparam,2,0); /* converter word */
4523 SSVAL(*rparam,4,0x7f); /* permission flags */
4525 return True;
4528 /****************************************************************************
4529 api_WPrintJobEnumerate
4530 ****************************************************************************/
4532 static bool api_WPrintJobGetInfo(struct smbd_server_connection *sconn,
4533 connection_struct *conn, uint64_t vuid,
4534 char *param, int tpscnt,
4535 char *data, int tdscnt,
4536 int mdrcnt,int mprcnt,
4537 char **rdata,char **rparam,
4538 int *rdata_len,int *rparam_len)
4540 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4541 char *str2 = skip_string(param,tpscnt,str1);
4542 char *p = skip_string(param,tpscnt,str2);
4543 int uLevel;
4544 fstring sharename;
4545 uint32 jobid;
4546 struct pack_desc desc;
4547 char *tmpdata=NULL;
4549 TALLOC_CTX *mem_ctx = talloc_tos();
4550 WERROR werr;
4551 NTSTATUS status;
4552 struct rpc_pipe_client *cli = NULL;
4553 struct dcerpc_binding_handle *b = NULL;
4554 struct policy_handle handle;
4555 struct spoolss_DevmodeContainer devmode_ctr;
4556 union spoolss_JobInfo info;
4558 if (!str1 || !str2 || !p) {
4559 return False;
4562 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4564 memset((char *)&desc,'\0',sizeof(desc));
4565 memset((char *)&status,'\0',sizeof(status));
4567 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4569 /* check it's a supported varient */
4570 if (strcmp(str1,"WWrLh") != 0) {
4571 return False;
4573 if (!check_printjob_info(&desc,uLevel,str2)) {
4574 return False;
4577 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4578 return False;
4581 ZERO_STRUCT(handle);
4583 status = rpc_pipe_open_interface(conn,
4584 &ndr_table_spoolss.syntax_id,
4585 conn->session_info,
4586 conn->sconn->remote_address,
4587 conn->sconn->msg_ctx,
4588 &cli);
4589 if (!NT_STATUS_IS_OK(status)) {
4590 DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n",
4591 nt_errstr(status)));
4592 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4593 goto out;
4595 b = cli->binding_handle;
4597 ZERO_STRUCT(devmode_ctr);
4599 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
4600 sharename,
4601 "RAW",
4602 devmode_ctr,
4603 PRINTER_ACCESS_USE,
4604 &handle,
4605 &werr);
4606 if (!NT_STATUS_IS_OK(status)) {
4607 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4608 goto out;
4610 if (!W_ERROR_IS_OK(werr)) {
4611 desc.errcode = W_ERROR_V(werr);
4612 goto out;
4615 werr = rpccli_spoolss_getjob(cli, mem_ctx,
4616 &handle,
4617 jobid,
4618 2, /* level */
4619 0, /* offered */
4620 &info);
4621 if (!W_ERROR_IS_OK(werr)) {
4622 desc.errcode = W_ERROR_V(werr);
4623 goto out;
4626 if (mdrcnt > 0) {
4627 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4628 if (!*rdata) {
4629 return False;
4631 desc.base = *rdata;
4632 desc.buflen = mdrcnt;
4633 } else {
4635 * Don't return data but need to get correct length
4636 * init_package will return wrong size if buflen=0
4638 desc.buflen = getlen(desc.format);
4639 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4642 if (init_package(&desc,1,0)) {
4643 fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position);
4644 *rdata_len = desc.usedlen;
4645 } else {
4646 desc.errcode = NERR_JobNotFound;
4647 *rdata_len = 0;
4649 out:
4650 if (b && is_valid_policy_hnd(&handle)) {
4651 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
4654 *rparam_len = 6;
4655 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4656 if (!*rparam) {
4657 return False;
4659 SSVALS(*rparam,0,desc.errcode);
4660 SSVAL(*rparam,2,0);
4661 SSVAL(*rparam,4,desc.neededlen);
4663 SAFE_FREE(tmpdata);
4665 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4667 return True;
4670 static bool api_WPrintJobEnumerate(struct smbd_server_connection *sconn,
4671 connection_struct *conn, uint64_t vuid,
4672 char *param, int tpscnt,
4673 char *data, int tdscnt,
4674 int mdrcnt,int mprcnt,
4675 char **rdata,char **rparam,
4676 int *rdata_len,int *rparam_len)
4678 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4679 char *str2 = skip_string(param,tpscnt,str1);
4680 char *p = skip_string(param,tpscnt,str2);
4681 char *name = p;
4682 int uLevel;
4683 int i, succnt=0;
4684 struct pack_desc desc;
4686 TALLOC_CTX *mem_ctx = talloc_tos();
4687 WERROR werr;
4688 NTSTATUS status;
4689 struct rpc_pipe_client *cli = NULL;
4690 struct dcerpc_binding_handle *b = NULL;
4691 struct policy_handle handle;
4692 struct spoolss_DevmodeContainer devmode_ctr;
4693 uint32_t count = 0;
4694 union spoolss_JobInfo *info;
4696 if (!str1 || !str2 || !p) {
4697 return False;
4700 memset((char *)&desc,'\0',sizeof(desc));
4702 p = skip_string(param,tpscnt,p);
4703 if (!p) {
4704 return False;
4706 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4708 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4710 /* check it's a supported variant */
4711 if (strcmp(str1,"zWrLeh") != 0) {
4712 return False;
4715 if (uLevel > 2) {
4716 return False; /* defined only for uLevel 0,1,2 */
4719 if (!check_printjob_info(&desc,uLevel,str2)) {
4720 return False;
4723 ZERO_STRUCT(handle);
4725 status = rpc_pipe_open_interface(conn,
4726 &ndr_table_spoolss.syntax_id,
4727 conn->session_info,
4728 conn->sconn->remote_address,
4729 conn->sconn->msg_ctx,
4730 &cli);
4731 if (!NT_STATUS_IS_OK(status)) {
4732 DEBUG(0,("api_WPrintJobEnumerate: could not connect to spoolss: %s\n",
4733 nt_errstr(status)));
4734 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4735 goto out;
4737 b = cli->binding_handle;
4739 ZERO_STRUCT(devmode_ctr);
4741 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
4742 name,
4743 NULL,
4744 devmode_ctr,
4745 PRINTER_ACCESS_USE,
4746 &handle,
4747 &werr);
4748 if (!NT_STATUS_IS_OK(status)) {
4749 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4750 goto out;
4752 if (!W_ERROR_IS_OK(werr)) {
4753 desc.errcode = W_ERROR_V(werr);
4754 goto out;
4757 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
4758 &handle,
4759 0, /* firstjob */
4760 0xff, /* numjobs */
4761 2, /* level */
4762 0, /* offered */
4763 &count,
4764 &info);
4765 if (!W_ERROR_IS_OK(werr)) {
4766 desc.errcode = W_ERROR_V(werr);
4767 goto out;
4770 if (mdrcnt > 0) {
4771 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4772 if (!*rdata) {
4773 return False;
4776 desc.base = *rdata;
4777 desc.buflen = mdrcnt;
4779 if (init_package(&desc,count,0)) {
4780 succnt = 0;
4781 for (i = 0; i < count; i++) {
4782 fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i);
4783 if (desc.errcode == NERR_Success) {
4784 succnt = i+1;
4788 out:
4789 if (b && is_valid_policy_hnd(&handle)) {
4790 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
4793 *rdata_len = desc.usedlen;
4795 *rparam_len = 8;
4796 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4797 if (!*rparam) {
4798 return False;
4800 SSVALS(*rparam,0,desc.errcode);
4801 SSVAL(*rparam,2,0);
4802 SSVAL(*rparam,4,succnt);
4803 SSVAL(*rparam,6,count);
4805 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4807 return True;
4810 static int check_printdest_info(struct pack_desc* desc,
4811 int uLevel, char* id)
4813 desc->subformat = NULL;
4814 switch( uLevel ) {
4815 case 0:
4816 desc->format = "B9";
4817 break;
4818 case 1:
4819 desc->format = "B9B21WWzW";
4820 break;
4821 case 2:
4822 desc->format = "z";
4823 break;
4824 case 3:
4825 desc->format = "zzzWWzzzWW";
4826 break;
4827 default:
4828 DEBUG(0,("check_printdest_info: invalid level %d\n",
4829 uLevel));
4830 return False;
4832 if (id == NULL || strcmp(desc->format,id) != 0) {
4833 DEBUG(0,("check_printdest_info: invalid string %s\n",
4834 id ? id : "<NULL>" ));
4835 return False;
4837 return True;
4840 static void fill_printdest_info(struct spoolss_PrinterInfo2 *info2, int uLevel,
4841 struct pack_desc* desc)
4843 char buf[100];
4845 strncpy(buf, info2->printername, sizeof(buf)-1);
4846 buf[sizeof(buf)-1] = 0;
4847 (void)strupper_m(buf);
4849 if (uLevel <= 1) {
4850 PACKS(desc,"B9",buf); /* szName */
4851 if (uLevel == 1) {
4852 PACKS(desc,"B21",""); /* szUserName */
4853 PACKI(desc,"W",0); /* uJobId */
4854 PACKI(desc,"W",0); /* fsStatus */
4855 PACKS(desc,"z",""); /* pszStatus */
4856 PACKI(desc,"W",0); /* time */
4860 if (uLevel == 2 || uLevel == 3) {
4861 PACKS(desc,"z",buf); /* pszPrinterName */
4862 if (uLevel == 3) {
4863 PACKS(desc,"z",""); /* pszUserName */
4864 PACKS(desc,"z",""); /* pszLogAddr */
4865 PACKI(desc,"W",0); /* uJobId */
4866 PACKI(desc,"W",0); /* fsStatus */
4867 PACKS(desc,"z",""); /* pszStatus */
4868 PACKS(desc,"z",""); /* pszComment */
4869 PACKS(desc,"z","NULL"); /* pszDrivers */
4870 PACKI(desc,"W",0); /* time */
4871 PACKI(desc,"W",0); /* pad1 */
4876 static bool api_WPrintDestGetInfo(struct smbd_server_connection *sconn,
4877 connection_struct *conn, uint64_t vuid,
4878 char *param, int tpscnt,
4879 char *data, int tdscnt,
4880 int mdrcnt,int mprcnt,
4881 char **rdata,char **rparam,
4882 int *rdata_len,int *rparam_len)
4884 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4885 char *str2 = skip_string(param,tpscnt,str1);
4886 char *p = skip_string(param,tpscnt,str2);
4887 char* PrinterName = p;
4888 int uLevel;
4889 struct pack_desc desc;
4890 char *tmpdata=NULL;
4892 TALLOC_CTX *mem_ctx = talloc_tos();
4893 WERROR werr;
4894 NTSTATUS status;
4895 struct rpc_pipe_client *cli = NULL;
4896 struct dcerpc_binding_handle *b = NULL;
4897 struct policy_handle handle;
4898 struct spoolss_DevmodeContainer devmode_ctr;
4899 union spoolss_PrinterInfo info;
4901 if (!str1 || !str2 || !p) {
4902 return False;
4905 memset((char *)&desc,'\0',sizeof(desc));
4907 p = skip_string(param,tpscnt,p);
4908 if (!p) {
4909 return False;
4911 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4913 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4915 /* check it's a supported varient */
4916 if (strcmp(str1,"zWrLh") != 0) {
4917 return False;
4919 if (!check_printdest_info(&desc,uLevel,str2)) {
4920 return False;
4923 ZERO_STRUCT(handle);
4925 status = rpc_pipe_open_interface(conn,
4926 &ndr_table_spoolss.syntax_id,
4927 conn->session_info,
4928 conn->sconn->remote_address,
4929 conn->sconn->msg_ctx,
4930 &cli);
4931 if (!NT_STATUS_IS_OK(status)) {
4932 DEBUG(0,("api_WPrintDestGetInfo: could not connect to spoolss: %s\n",
4933 nt_errstr(status)));
4934 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4935 goto out;
4937 b = cli->binding_handle;
4939 ZERO_STRUCT(devmode_ctr);
4941 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
4942 PrinterName,
4943 NULL,
4944 devmode_ctr,
4945 PRINTER_ACCESS_USE,
4946 &handle,
4947 &werr);
4948 if (!NT_STATUS_IS_OK(status)) {
4949 *rdata_len = 0;
4950 desc.errcode = NERR_DestNotFound;
4951 desc.neededlen = 0;
4952 goto out;
4954 if (!W_ERROR_IS_OK(werr)) {
4955 *rdata_len = 0;
4956 desc.errcode = NERR_DestNotFound;
4957 desc.neededlen = 0;
4958 goto out;
4961 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
4962 &handle,
4965 &info);
4966 if (!W_ERROR_IS_OK(werr)) {
4967 *rdata_len = 0;
4968 desc.errcode = NERR_DestNotFound;
4969 desc.neededlen = 0;
4970 goto out;
4973 if (mdrcnt > 0) {
4974 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4975 if (!*rdata) {
4976 return False;
4978 desc.base = *rdata;
4979 desc.buflen = mdrcnt;
4980 } else {
4982 * Don't return data but need to get correct length
4983 * init_package will return wrong size if buflen=0
4985 desc.buflen = getlen(desc.format);
4986 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4988 if (init_package(&desc,1,0)) {
4989 fill_printdest_info(&info.info2, uLevel,&desc);
4992 out:
4993 if (b && is_valid_policy_hnd(&handle)) {
4994 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
4997 *rdata_len = desc.usedlen;
4999 *rparam_len = 6;
5000 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5001 if (!*rparam) {
5002 return False;
5004 SSVALS(*rparam,0,desc.errcode);
5005 SSVAL(*rparam,2,0);
5006 SSVAL(*rparam,4,desc.neededlen);
5008 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
5009 SAFE_FREE(tmpdata);
5011 return True;
5014 static bool api_WPrintDestEnum(struct smbd_server_connection *sconn,
5015 connection_struct *conn, uint64_t vuid,
5016 char *param, int tpscnt,
5017 char *data, int tdscnt,
5018 int mdrcnt,int mprcnt,
5019 char **rdata,char **rparam,
5020 int *rdata_len,int *rparam_len)
5022 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5023 char *str2 = skip_string(param,tpscnt,str1);
5024 char *p = skip_string(param,tpscnt,str2);
5025 int uLevel;
5026 int queuecnt;
5027 int i, n, succnt=0;
5028 struct pack_desc desc;
5030 TALLOC_CTX *mem_ctx = talloc_tos();
5031 WERROR werr;
5032 NTSTATUS status;
5033 struct rpc_pipe_client *cli = NULL;
5034 union spoolss_PrinterInfo *info;
5035 uint32_t count;
5037 if (!str1 || !str2 || !p) {
5038 return False;
5041 memset((char *)&desc,'\0',sizeof(desc));
5043 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5045 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
5047 /* check it's a supported varient */
5048 if (strcmp(str1,"WrLeh") != 0) {
5049 return False;
5051 if (!check_printdest_info(&desc,uLevel,str2)) {
5052 return False;
5055 queuecnt = 0;
5057 status = rpc_pipe_open_interface(conn,
5058 &ndr_table_spoolss.syntax_id,
5059 conn->session_info,
5060 conn->sconn->remote_address,
5061 conn->sconn->msg_ctx,
5062 &cli);
5063 if (!NT_STATUS_IS_OK(status)) {
5064 DEBUG(0,("api_WPrintDestEnum: could not connect to spoolss: %s\n",
5065 nt_errstr(status)));
5066 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5067 goto out;
5070 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
5071 PRINTER_ENUM_LOCAL,
5072 cli->srv_name_slash,
5075 &count,
5076 &info);
5077 if (!W_ERROR_IS_OK(werr)) {
5078 desc.errcode = W_ERROR_V(werr);
5079 *rdata_len = 0;
5080 desc.errcode = NERR_DestNotFound;
5081 desc.neededlen = 0;
5082 goto out;
5085 queuecnt = count;
5087 if (mdrcnt > 0) {
5088 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5089 if (!*rdata) {
5090 return False;
5094 desc.base = *rdata;
5095 desc.buflen = mdrcnt;
5096 if (init_package(&desc,queuecnt,0)) {
5097 succnt = 0;
5098 n = 0;
5099 for (i = 0; i < count; i++) {
5100 fill_printdest_info(&info[i].info2, uLevel,&desc);
5101 n++;
5102 if (desc.errcode == NERR_Success) {
5103 succnt = n;
5107 out:
5108 *rdata_len = desc.usedlen;
5110 *rparam_len = 8;
5111 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5112 if (!*rparam) {
5113 return False;
5115 SSVALS(*rparam,0,desc.errcode);
5116 SSVAL(*rparam,2,0);
5117 SSVAL(*rparam,4,succnt);
5118 SSVAL(*rparam,6,queuecnt);
5120 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
5122 return True;
5125 static bool api_WPrintDriverEnum(struct smbd_server_connection *sconn,
5126 connection_struct *conn, uint64_t vuid,
5127 char *param, int tpscnt,
5128 char *data, int tdscnt,
5129 int mdrcnt,int mprcnt,
5130 char **rdata,char **rparam,
5131 int *rdata_len,int *rparam_len)
5133 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5134 char *str2 = skip_string(param,tpscnt,str1);
5135 char *p = skip_string(param,tpscnt,str2);
5136 int uLevel;
5137 int succnt;
5138 struct pack_desc desc;
5140 if (!str1 || !str2 || !p) {
5141 return False;
5144 memset((char *)&desc,'\0',sizeof(desc));
5146 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5148 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
5150 /* check it's a supported varient */
5151 if (strcmp(str1,"WrLeh") != 0) {
5152 return False;
5154 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
5155 return False;
5158 if (mdrcnt > 0) {
5159 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5160 if (!*rdata) {
5161 return False;
5164 desc.base = *rdata;
5165 desc.buflen = mdrcnt;
5166 if (init_package(&desc,1,0)) {
5167 PACKS(&desc,"B41","NULL");
5170 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5172 *rdata_len = desc.usedlen;
5174 *rparam_len = 8;
5175 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5176 if (!*rparam) {
5177 return False;
5179 SSVALS(*rparam,0,desc.errcode);
5180 SSVAL(*rparam,2,0);
5181 SSVAL(*rparam,4,succnt);
5182 SSVAL(*rparam,6,1);
5184 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
5186 return True;
5189 static bool api_WPrintQProcEnum(struct smbd_server_connection *sconn,
5190 connection_struct *conn, uint64_t vuid,
5191 char *param, int tpscnt,
5192 char *data, int tdscnt,
5193 int mdrcnt,int mprcnt,
5194 char **rdata,char **rparam,
5195 int *rdata_len,int *rparam_len)
5197 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5198 char *str2 = skip_string(param,tpscnt,str1);
5199 char *p = skip_string(param,tpscnt,str2);
5200 int uLevel;
5201 int succnt;
5202 struct pack_desc desc;
5204 if (!str1 || !str2 || !p) {
5205 return False;
5207 memset((char *)&desc,'\0',sizeof(desc));
5209 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5211 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
5213 /* check it's a supported varient */
5214 if (strcmp(str1,"WrLeh") != 0) {
5215 return False;
5217 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
5218 return False;
5221 if (mdrcnt > 0) {
5222 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5223 if (!*rdata) {
5224 return False;
5227 desc.base = *rdata;
5228 desc.buflen = mdrcnt;
5229 desc.format = str2;
5230 if (init_package(&desc,1,0)) {
5231 PACKS(&desc,"B13","lpd");
5234 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5236 *rdata_len = desc.usedlen;
5238 *rparam_len = 8;
5239 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5240 if (!*rparam) {
5241 return False;
5243 SSVALS(*rparam,0,desc.errcode);
5244 SSVAL(*rparam,2,0);
5245 SSVAL(*rparam,4,succnt);
5246 SSVAL(*rparam,6,1);
5248 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
5250 return True;
5253 static bool api_WPrintPortEnum(struct smbd_server_connection *sconn,
5254 connection_struct *conn, uint64_t vuid,
5255 char *param, int tpscnt,
5256 char *data, int tdscnt,
5257 int mdrcnt,int mprcnt,
5258 char **rdata,char **rparam,
5259 int *rdata_len,int *rparam_len)
5261 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5262 char *str2 = skip_string(param,tpscnt,str1);
5263 char *p = skip_string(param,tpscnt,str2);
5264 int uLevel;
5265 int succnt;
5266 struct pack_desc desc;
5268 if (!str1 || !str2 || !p) {
5269 return False;
5272 memset((char *)&desc,'\0',sizeof(desc));
5274 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5276 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
5278 /* check it's a supported varient */
5279 if (strcmp(str1,"WrLeh") != 0) {
5280 return False;
5282 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
5283 return False;
5286 if (mdrcnt > 0) {
5287 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5288 if (!*rdata) {
5289 return False;
5292 memset((char *)&desc,'\0',sizeof(desc));
5293 desc.base = *rdata;
5294 desc.buflen = mdrcnt;
5295 desc.format = str2;
5296 if (init_package(&desc,1,0)) {
5297 PACKS(&desc,"B13","lp0");
5300 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5302 *rdata_len = desc.usedlen;
5304 *rparam_len = 8;
5305 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5306 if (!*rparam) {
5307 return False;
5309 SSVALS(*rparam,0,desc.errcode);
5310 SSVAL(*rparam,2,0);
5311 SSVAL(*rparam,4,succnt);
5312 SSVAL(*rparam,6,1);
5314 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
5316 return True;
5319 /****************************************************************************
5320 List open sessions
5321 ****************************************************************************/
5323 static bool api_RNetSessionEnum(struct smbd_server_connection *sconn,
5324 connection_struct *conn, uint64_t vuid,
5325 char *param, int tpscnt,
5326 char *data, int tdscnt,
5327 int mdrcnt,int mprcnt,
5328 char **rdata,char **rparam,
5329 int *rdata_len,int *rparam_len)
5332 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5333 char *str2 = skip_string(param,tpscnt,str1);
5334 char *p = skip_string(param,tpscnt,str2);
5335 int uLevel;
5336 struct pack_desc desc;
5337 int i;
5339 TALLOC_CTX *mem_ctx = talloc_tos();
5340 WERROR werr;
5341 NTSTATUS status;
5342 struct rpc_pipe_client *cli = NULL;
5343 struct dcerpc_binding_handle *b = NULL;
5344 struct srvsvc_NetSessInfoCtr info_ctr;
5345 uint32_t totalentries, resume_handle = 0;
5346 uint32_t count = 0;
5348 if (!str1 || !str2 || !p) {
5349 return False;
5352 ZERO_STRUCT(desc);
5354 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5356 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
5357 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
5358 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
5360 /* check it's a supported varient */
5361 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
5362 return False;
5364 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
5365 return False;
5368 status = rpc_pipe_open_interface(conn,
5369 &ndr_table_srvsvc.syntax_id,
5370 conn->session_info,
5371 conn->sconn->remote_address,
5372 conn->sconn->msg_ctx,
5373 &cli);
5374 if (!NT_STATUS_IS_OK(status)) {
5375 DEBUG(0,("RNetSessionEnum: could not connect to srvsvc: %s\n",
5376 nt_errstr(status)));
5377 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5378 goto out;
5380 b = cli->binding_handle;
5382 info_ctr.level = 1;
5383 info_ctr.ctr.ctr1 = talloc_zero(talloc_tos(), struct srvsvc_NetSessCtr1);
5384 if (info_ctr.ctr.ctr1 == NULL) {
5385 desc.errcode = W_ERROR_V(WERR_NOMEM);
5386 goto out;
5389 status = dcerpc_srvsvc_NetSessEnum(b, mem_ctx,
5390 cli->srv_name_slash,
5391 NULL, /* client */
5392 NULL, /* user */
5393 &info_ctr,
5394 (uint32_t)-1, /* max_buffer */
5395 &totalentries,
5396 &resume_handle,
5397 &werr);
5398 if (!NT_STATUS_IS_OK(status)) {
5399 DEBUG(0,("RNetSessionEnum: dcerpc_srvsvc_NetSessEnum failed: %s\n",
5400 nt_errstr(status)));
5401 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5402 goto out;
5405 if (!W_ERROR_IS_OK(werr)) {
5406 DEBUG(0,("RNetSessionEnum: dcerpc_srvsvc_NetSessEnum failed: %s\n",
5407 win_errstr(werr)));
5408 desc.errcode = W_ERROR_V(werr);
5409 goto out;
5412 count = info_ctr.ctr.ctr1->count;
5414 out:
5415 if (mdrcnt > 0) {
5416 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5417 if (!*rdata) {
5418 return False;
5422 desc.base = *rdata;
5423 desc.buflen = mdrcnt;
5424 desc.format = str2;
5425 if (!init_package(&desc, count,0)) {
5426 return False;
5429 for(i=0; i < count; i++) {
5430 PACKS(&desc, "z", info_ctr.ctr.ctr1->array[i].client);
5431 PACKS(&desc, "z", info_ctr.ctr.ctr1->array[i].user);
5432 PACKI(&desc, "W", 1); /* num conns */
5433 PACKI(&desc, "W", info_ctr.ctr.ctr1->array[i].num_open);
5434 PACKI(&desc, "W", 1); /* num users */
5435 PACKI(&desc, "D", 0); /* session time */
5436 PACKI(&desc, "D", 0); /* idle time */
5437 PACKI(&desc, "D", 0); /* flags */
5438 PACKS(&desc, "z", "Unknown Client"); /* client type string */
5441 *rdata_len = desc.usedlen;
5443 *rparam_len = 8;
5444 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5445 if (!*rparam) {
5446 return False;
5448 SSVALS(*rparam,0,desc.errcode);
5449 SSVAL(*rparam,2,0); /* converter */
5450 SSVAL(*rparam,4, count); /* count */
5452 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
5454 return True;
5458 /****************************************************************************
5459 The buffer was too small.
5460 ****************************************************************************/
5462 static bool api_TooSmall(struct smbd_server_connection *sconn,
5463 connection_struct *conn,uint64_t vuid, char *param, char *data,
5464 int mdrcnt, int mprcnt,
5465 char **rdata, char **rparam,
5466 int *rdata_len, int *rparam_len)
5468 *rparam_len = MIN(*rparam_len,mprcnt);
5469 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5470 if (!*rparam) {
5471 return False;
5474 *rdata_len = 0;
5476 SSVAL(*rparam,0,NERR_BufTooSmall);
5478 DEBUG(3,("Supplied buffer too small in API command\n"));
5480 return True;
5483 /****************************************************************************
5484 The request is not supported.
5485 ****************************************************************************/
5487 static bool api_Unsupported(struct smbd_server_connection *sconn,
5488 connection_struct *conn, uint64_t vuid,
5489 char *param, int tpscnt,
5490 char *data, int tdscnt,
5491 int mdrcnt, int mprcnt,
5492 char **rdata, char **rparam,
5493 int *rdata_len, int *rparam_len)
5495 *rparam_len = 4;
5496 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5497 if (!*rparam) {
5498 return False;
5501 *rdata_len = 0;
5503 SSVAL(*rparam,0,NERR_notsupported);
5504 SSVAL(*rparam,2,0); /* converter word */
5506 DEBUG(3,("Unsupported API command\n"));
5508 return True;
5511 static const struct {
5512 const char *name;
5513 int id;
5514 bool (*fn)(struct smbd_server_connection *sconn,
5515 connection_struct *, uint64_t,
5516 char *, int,
5517 char *, int,
5518 int,int,char **,char **,int *,int *);
5519 bool auth_user; /* Deny anonymous access? */
5520 } api_commands[] = {
5521 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
5522 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
5523 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
5524 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
5525 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
5526 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
5527 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
5528 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
5529 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
5530 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
5531 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
5532 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
5533 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
5534 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
5535 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
5536 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
5537 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
5538 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
5539 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
5540 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
5541 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
5542 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
5543 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
5544 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
5545 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
5546 {"NetServerEnum3", RAP_NetServerEnum3, api_RNetServerEnum3}, /* anon OK */
5547 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
5548 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
5549 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
5550 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
5551 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
5552 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
5553 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
5554 {NULL, -1, api_Unsupported}
5555 /* The following RAP calls are not implemented by Samba:
5557 RAP_WFileEnum2 - anon not OK
5562 /****************************************************************************
5563 Handle remote api calls.
5564 ****************************************************************************/
5566 void api_reply(connection_struct *conn, uint64_t vuid,
5567 struct smb_request *req,
5568 char *data, char *params,
5569 int tdscnt, int tpscnt,
5570 int mdrcnt, int mprcnt)
5572 int api_command;
5573 char *rdata = NULL;
5574 char *rparam = NULL;
5575 const char *name1 = NULL;
5576 const char *name2 = NULL;
5577 int rdata_len = 0;
5578 int rparam_len = 0;
5579 bool reply=False;
5580 int i;
5582 if (!params) {
5583 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
5584 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5585 return;
5588 if (tpscnt < 2) {
5589 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5590 return;
5592 api_command = SVAL(params,0);
5593 /* Is there a string at position params+2 ? */
5594 if (skip_string(params,tpscnt,params+2)) {
5595 name1 = params + 2;
5596 } else {
5597 name1 = "";
5599 name2 = skip_string(params,tpscnt,params+2);
5600 if (!name2) {
5601 name2 = "";
5604 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
5605 api_command,
5606 name1,
5607 name2,
5608 tdscnt,tpscnt,mdrcnt,mprcnt));
5610 for (i=0;api_commands[i].name;i++) {
5611 if (api_commands[i].id == api_command && api_commands[i].fn) {
5612 DEBUG(3,("Doing %s\n",api_commands[i].name));
5613 break;
5617 /* Check whether this api call can be done anonymously */
5619 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
5620 struct user_struct *user = get_valid_user_struct(req->sconn, vuid);
5622 if (!user || security_session_user_level(user->session_info, NULL) < SECURITY_USER) {
5623 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5624 return;
5628 rdata = (char *)SMB_MALLOC(1024);
5629 if (rdata) {
5630 memset(rdata,'\0',1024);
5633 rparam = (char *)SMB_MALLOC(1024);
5634 if (rparam) {
5635 memset(rparam,'\0',1024);
5638 if(!rdata || !rparam) {
5639 DEBUG(0,("api_reply: malloc fail !\n"));
5640 SAFE_FREE(rdata);
5641 SAFE_FREE(rparam);
5642 reply_nterror(req, NT_STATUS_NO_MEMORY);
5643 return;
5646 reply = api_commands[i].fn(req->sconn, conn,
5647 vuid,
5648 params,tpscnt, /* params + length */
5649 data,tdscnt, /* data + length */
5650 mdrcnt,mprcnt,
5651 &rdata,&rparam,&rdata_len,&rparam_len);
5654 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
5655 reply = api_TooSmall(req->sconn,conn,vuid,params,data,
5656 mdrcnt,mprcnt,
5657 &rdata,&rparam,&rdata_len,&rparam_len);
5660 /* if we get False back then it's actually unsupported */
5661 if (!reply) {
5662 reply = api_Unsupported(req->sconn,conn,vuid,params,tpscnt,
5663 data,
5664 tdscnt,mdrcnt,mprcnt,
5665 &rdata,&rparam,&rdata_len,&rparam_len);
5668 /* If api_Unsupported returns false we can't return anything. */
5669 if (reply) {
5670 send_trans_reply(conn, req, rparam, rparam_len,
5671 rdata, rdata_len, False);
5674 SAFE_FREE(rdata);
5675 SAFE_FREE(rparam);
5676 return;