s3: Retry the join with the short name
[Samba.git] / source3 / smbd / lanman.c
blob8c49b433b0cd888c98dee80f1d09a8476ec652df
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 "../librpc/gen_ndr/ndr_samr_c.h"
32 #include "../librpc/gen_ndr/ndr_spoolss_c.h"
33 #include "rpc_client/cli_spoolss.h"
34 #include "rpc_client/init_spoolss.h"
35 #include "../librpc/gen_ndr/ndr_srvsvc_c.h"
36 #include "../librpc/gen_ndr/srv_samr.h"
37 #include "../librpc/gen_ndr/srv_srvsvc.h"
38 #include "../librpc/gen_ndr/rap.h"
39 #include "../lib/util/binsearch.h"
40 #include "../libcli/auth/libcli_auth.h"
41 #include "rpc_client/init_lsa.h"
42 #include "rpc_server/rpc_ncacn_np.h"
43 #include "../libcli/security/security.h"
44 #include "printing.h"
45 #include "passdb/machine_sid.h"
46 #include "auth.h"
48 #ifdef CHECK_TYPES
49 #undef CHECK_TYPES
50 #endif
51 #define CHECK_TYPES 0
53 #define NERR_Success 0
54 #define NERR_badpass 86
55 #define NERR_notsupported 50
57 #define NERR_BASE (2100)
58 #define NERR_BufTooSmall (NERR_BASE+23)
59 #define NERR_JobNotFound (NERR_BASE+51)
60 #define NERR_DestNotFound (NERR_BASE+52)
62 #define ACCESS_READ 0x01
63 #define ACCESS_WRITE 0x02
64 #define ACCESS_CREATE 0x04
66 #define SHPWLEN 8 /* share password length */
68 /* Limit size of ipc replies */
70 static char *smb_realloc_limit(void *ptr, size_t size)
72 char *val;
74 size = MAX((size),4*1024);
75 val = (char *)SMB_REALLOC(ptr,size);
76 if (val) {
77 memset(val,'\0',size);
79 return val;
82 static bool api_Unsupported(struct smbd_server_connection *sconn,
83 connection_struct *conn, uint16 vuid,
84 char *param, int tpscnt,
85 char *data, int tdscnt,
86 int mdrcnt, int mprcnt,
87 char **rdata, char **rparam,
88 int *rdata_len, int *rparam_len);
90 static bool api_TooSmall(struct smbd_server_connection *sconn,
91 connection_struct *conn, uint16 vuid, char *param, char *data,
92 int mdrcnt, int mprcnt,
93 char **rdata, char **rparam,
94 int *rdata_len, int *rparam_len);
97 static int CopyExpanded(connection_struct *conn,
98 int snum, char **dst, char *src, int *p_space_remaining)
100 TALLOC_CTX *ctx = talloc_tos();
101 char *buf = NULL;
102 int l;
104 if (!src || !dst || !p_space_remaining || !(*dst) ||
105 *p_space_remaining <= 0) {
106 return 0;
109 buf = talloc_strdup(ctx, src);
110 if (!buf) {
111 *p_space_remaining = 0;
112 return 0;
114 buf = talloc_string_sub(ctx, buf,"%S",lp_servicename(snum));
115 if (!buf) {
116 *p_space_remaining = 0;
117 return 0;
119 buf = talloc_sub_advanced(ctx,
120 lp_servicename(SNUM(conn)),
121 conn->session_info->unix_name,
122 conn->connectpath,
123 conn->session_info->utok.gid,
124 conn->session_info->sanitized_username,
125 conn->session_info->info3->base.domain.string,
126 buf);
127 if (!buf) {
128 *p_space_remaining = 0;
129 return 0;
131 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
132 if (l == -1) {
133 return 0;
135 (*dst) += l;
136 (*p_space_remaining) -= l;
137 return l;
140 static int CopyAndAdvance(char **dst, char *src, int *n)
142 int l;
143 if (!src || !dst || !n || !(*dst)) {
144 return 0;
146 l = push_ascii(*dst,src,*n, STR_TERMINATE);
147 if (l == -1) {
148 return 0;
150 (*dst) += l;
151 (*n) -= l;
152 return l;
155 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
157 TALLOC_CTX *ctx = talloc_tos();
158 char *buf = NULL;
159 if (!s) {
160 return 0;
162 buf = talloc_strdup(ctx,s);
163 if (!buf) {
164 return 0;
166 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
167 if (!buf) {
168 return 0;
170 buf = talloc_sub_advanced(ctx,
171 lp_servicename(SNUM(conn)),
172 conn->session_info->unix_name,
173 conn->connectpath,
174 conn->session_info->utok.gid,
175 conn->session_info->sanitized_username,
176 conn->session_info->info3->base.domain.string,
177 buf);
178 if (!buf) {
179 return 0;
181 return strlen(buf) + 1;
184 /*******************************************************************
185 Check a API string for validity when we only need to check the prefix.
186 ******************************************************************/
188 static bool prefix_ok(const char *str, const char *prefix)
190 return(strncmp(str,prefix,strlen(prefix)) == 0);
193 struct pack_desc {
194 const char *format; /* formatstring for structure */
195 const char *subformat; /* subformat for structure */
196 char *base; /* baseaddress of buffer */
197 int buflen; /* remaining size for fixed part; on init: length of base */
198 int subcount; /* count of substructures */
199 char *structbuf; /* pointer into buffer for remaining fixed part */
200 int stringlen; /* remaining size for variable part */
201 char *stringbuf; /* pointer into buffer for remaining variable part */
202 int neededlen; /* total needed size */
203 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
204 const char *curpos; /* current position; pointer into format or subformat */
205 int errcode;
208 static int get_counter(const char **p)
210 int i, n;
211 if (!p || !(*p)) {
212 return 1;
214 if (!isdigit((int)**p)) {
215 return 1;
217 for (n = 0;;) {
218 i = **p;
219 if (isdigit(i)) {
220 n = 10 * n + (i - '0');
221 } else {
222 return n;
224 (*p)++;
228 static int getlen(const char *p)
230 int n = 0;
231 if (!p) {
232 return 0;
235 while (*p) {
236 switch( *p++ ) {
237 case 'W': /* word (2 byte) */
238 n += 2;
239 break;
240 case 'K': /* status word? (2 byte) */
241 n += 2;
242 break;
243 case 'N': /* count of substructures (word) at end */
244 n += 2;
245 break;
246 case 'D': /* double word (4 byte) */
247 case 'z': /* offset to zero terminated string (4 byte) */
248 case 'l': /* offset to user data (4 byte) */
249 n += 4;
250 break;
251 case 'b': /* offset to data (with counter) (4 byte) */
252 n += 4;
253 get_counter(&p);
254 break;
255 case 'B': /* byte (with optional counter) */
256 n += get_counter(&p);
257 break;
260 return n;
263 static bool init_package(struct pack_desc *p, int count, int subcount)
265 int n = p->buflen;
266 int i;
268 if (!p->format || !p->base) {
269 return False;
272 i = count * getlen(p->format);
273 if (p->subformat) {
274 i += subcount * getlen(p->subformat);
276 p->structbuf = p->base;
277 p->neededlen = 0;
278 p->usedlen = 0;
279 p->subcount = 0;
280 p->curpos = p->format;
281 if (i > n) {
282 p->neededlen = i;
283 i = n = 0;
284 #if 0
286 * This is the old error code we used. Aparently
287 * WinNT/2k systems return ERRbuftoosmall (2123) and
288 * OS/2 needs this. I'm leaving this here so we can revert
289 * if needed. JRA.
291 p->errcode = ERRmoredata;
292 #else
293 p->errcode = ERRbuftoosmall;
294 #endif
295 } else {
296 p->errcode = NERR_Success;
298 p->buflen = i;
299 n -= i;
300 p->stringbuf = p->base + i;
301 p->stringlen = n;
302 return (p->errcode == NERR_Success);
305 static int package(struct pack_desc *p, ...)
307 va_list args;
308 int needed=0, stringneeded;
309 const char *str=NULL;
310 int is_string=0, stringused;
311 int32 temp;
313 va_start(args,p);
315 if (!*p->curpos) {
316 if (!p->subcount) {
317 p->curpos = p->format;
318 } else {
319 p->curpos = p->subformat;
320 p->subcount--;
323 #if CHECK_TYPES
324 str = va_arg(args,char*);
325 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
326 #endif
327 stringneeded = -1;
329 if (!p->curpos) {
330 va_end(args);
331 return 0;
334 switch( *p->curpos++ ) {
335 case 'W': /* word (2 byte) */
336 needed = 2;
337 temp = va_arg(args,int);
338 if (p->buflen >= needed) {
339 SSVAL(p->structbuf,0,temp);
341 break;
342 case 'K': /* status word? (2 byte) */
343 needed = 2;
344 temp = va_arg(args,int);
345 if (p->buflen >= needed) {
346 SSVAL(p->structbuf,0,temp);
348 break;
349 case 'N': /* count of substructures (word) at end */
350 needed = 2;
351 p->subcount = va_arg(args,int);
352 if (p->buflen >= needed) {
353 SSVAL(p->structbuf,0,p->subcount);
355 break;
356 case 'D': /* double word (4 byte) */
357 needed = 4;
358 temp = va_arg(args,int);
359 if (p->buflen >= needed) {
360 SIVAL(p->structbuf,0,temp);
362 break;
363 case 'B': /* byte (with optional counter) */
364 needed = get_counter(&p->curpos);
366 char *s = va_arg(args,char*);
367 if (p->buflen >= needed) {
368 StrnCpy(p->structbuf,s?s:"",needed-1);
371 break;
372 case 'z': /* offset to zero terminated string (4 byte) */
373 str = va_arg(args,char*);
374 stringneeded = (str ? strlen(str)+1 : 0);
375 is_string = 1;
376 break;
377 case 'l': /* offset to user data (4 byte) */
378 str = va_arg(args,char*);
379 stringneeded = va_arg(args,int);
380 is_string = 0;
381 break;
382 case 'b': /* offset to data (with counter) (4 byte) */
383 str = va_arg(args,char*);
384 stringneeded = get_counter(&p->curpos);
385 is_string = 0;
386 break;
389 va_end(args);
390 if (stringneeded >= 0) {
391 needed = 4;
392 if (p->buflen >= needed) {
393 stringused = stringneeded;
394 if (stringused > p->stringlen) {
395 stringused = (is_string ? p->stringlen : 0);
396 if (p->errcode == NERR_Success) {
397 p->errcode = ERRmoredata;
400 if (!stringused) {
401 SIVAL(p->structbuf,0,0);
402 } else {
403 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
404 memcpy(p->stringbuf,str?str:"",stringused);
405 if (is_string) {
406 p->stringbuf[stringused-1] = '\0';
408 p->stringbuf += stringused;
409 p->stringlen -= stringused;
410 p->usedlen += stringused;
413 p->neededlen += stringneeded;
416 p->neededlen += needed;
417 if (p->buflen >= needed) {
418 p->structbuf += needed;
419 p->buflen -= needed;
420 p->usedlen += needed;
421 } else {
422 if (p->errcode == NERR_Success) {
423 p->errcode = ERRmoredata;
426 return 1;
429 #if CHECK_TYPES
430 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
431 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
432 #else
433 #define PACK(desc,t,v) package(desc,v)
434 #define PACKl(desc,t,v,l) package(desc,v,l)
435 #endif
437 static void PACKI(struct pack_desc* desc, const char *t,int v)
439 PACK(desc,t,v);
442 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
444 PACK(desc,t,v);
447 /****************************************************************************
448 Get a print queue.
449 ****************************************************************************/
451 static void PackDriverData(struct pack_desc* desc)
453 char drivdata[4+4+32];
454 SIVAL(drivdata,0,sizeof drivdata); /* cb */
455 SIVAL(drivdata,4,1000); /* lVersion */
456 memset(drivdata+8,0,32); /* szDeviceName */
457 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
458 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
461 static int check_printq_info(struct pack_desc* desc,
462 unsigned int uLevel, char *id1, char *id2)
464 desc->subformat = NULL;
465 switch( uLevel ) {
466 case 0:
467 desc->format = "B13";
468 break;
469 case 1:
470 desc->format = "B13BWWWzzzzzWW";
471 break;
472 case 2:
473 desc->format = "B13BWWWzzzzzWN";
474 desc->subformat = "WB21BB16B10zWWzDDz";
475 break;
476 case 3:
477 desc->format = "zWWWWzzzzWWzzl";
478 break;
479 case 4:
480 desc->format = "zWWWWzzzzWNzzl";
481 desc->subformat = "WWzWWDDzz";
482 break;
483 case 5:
484 desc->format = "z";
485 break;
486 case 51:
487 desc->format = "K";
488 break;
489 case 52:
490 desc->format = "WzzzzzzzzN";
491 desc->subformat = "z";
492 break;
493 default:
494 DEBUG(0,("check_printq_info: invalid level %d\n",
495 uLevel ));
496 return False;
498 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
499 DEBUG(0,("check_printq_info: invalid format %s\n",
500 id1 ? id1 : "<NULL>" ));
501 return False;
503 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
504 DEBUG(0,("check_printq_info: invalid subformat %s\n",
505 id2 ? id2 : "<NULL>" ));
506 return False;
508 return True;
512 #define RAP_JOB_STATUS_QUEUED 0
513 #define RAP_JOB_STATUS_PAUSED 1
514 #define RAP_JOB_STATUS_SPOOLING 2
515 #define RAP_JOB_STATUS_PRINTING 3
516 #define RAP_JOB_STATUS_PRINTED 4
518 #define RAP_QUEUE_STATUS_PAUSED 1
519 #define RAP_QUEUE_STATUS_ERROR 2
521 /* turn a print job status into a on the wire status
523 static int printj_spoolss_status(int v)
525 if (v == JOB_STATUS_QUEUED)
526 return RAP_JOB_STATUS_QUEUED;
527 if (v & JOB_STATUS_PAUSED)
528 return RAP_JOB_STATUS_PAUSED;
529 if (v & JOB_STATUS_SPOOLING)
530 return RAP_JOB_STATUS_SPOOLING;
531 if (v & JOB_STATUS_PRINTING)
532 return RAP_JOB_STATUS_PRINTING;
533 return 0;
536 /* turn a print queue status into a on the wire status
538 static int printq_spoolss_status(int v)
540 if (v == PRINTER_STATUS_OK)
541 return 0;
542 if (v & PRINTER_STATUS_PAUSED)
543 return RAP_QUEUE_STATUS_PAUSED;
544 return RAP_QUEUE_STATUS_ERROR;
547 static void fill_spoolss_printjob_info(int uLevel,
548 struct pack_desc *desc,
549 struct spoolss_JobInfo2 *info2,
550 int n)
552 time_t t = spoolss_Time_to_time_t(&info2->submitted);
554 /* the client expects localtime */
555 t -= get_time_zone(t);
557 PACKI(desc,"W",pjobid_to_rap(info2->printer_name, info2->job_id)); /* uJobId */
558 if (uLevel == 1) {
559 PACKS(desc,"B21", info2->user_name); /* szUserName */
560 PACKS(desc,"B",""); /* pad */
561 PACKS(desc,"B16",""); /* szNotifyName */
562 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
563 PACKS(desc,"z",""); /* pszParms */
564 PACKI(desc,"W",n+1); /* uPosition */
565 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
566 PACKS(desc,"z",""); /* pszStatus */
567 PACKI(desc,"D", t); /* ulSubmitted */
568 PACKI(desc,"D", info2->size); /* ulSize */
569 PACKS(desc,"z", info2->document_name); /* pszComment */
571 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
572 PACKI(desc,"W", info2->priority); /* uPriority */
573 PACKS(desc,"z", info2->user_name); /* pszUserName */
574 PACKI(desc,"W",n+1); /* uPosition */
575 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
576 PACKI(desc,"D",t); /* ulSubmitted */
577 PACKI(desc,"D", info2->size); /* ulSize */
578 PACKS(desc,"z","Samba"); /* pszComment */
579 PACKS(desc,"z", info2->document_name); /* pszDocument */
580 if (uLevel == 3) {
581 PACKS(desc,"z",""); /* pszNotifyName */
582 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
583 PACKS(desc,"z",""); /* pszParms */
584 PACKS(desc,"z",""); /* pszStatus */
585 PACKS(desc,"z", info2->printer_name); /* pszQueue */
586 PACKS(desc,"z","lpd"); /* pszQProcName */
587 PACKS(desc,"z",""); /* pszQProcParms */
588 PACKS(desc,"z","NULL"); /* pszDriverName */
589 PackDriverData(desc); /* pDriverData */
590 PACKS(desc,"z",""); /* pszPrinterName */
591 } else if (uLevel == 4) { /* OS2 */
592 PACKS(desc,"z",""); /* pszSpoolFileName */
593 PACKS(desc,"z",""); /* pszPortName */
594 PACKS(desc,"z",""); /* pszStatus */
595 PACKI(desc,"D",0); /* ulPagesSpooled */
596 PACKI(desc,"D",0); /* ulPagesSent */
597 PACKI(desc,"D",0); /* ulPagesPrinted */
598 PACKI(desc,"D",0); /* ulTimePrinted */
599 PACKI(desc,"D",0); /* ulExtendJobStatus */
600 PACKI(desc,"D",0); /* ulStartPage */
601 PACKI(desc,"D",0); /* ulEndPage */
606 /********************************************************************
607 Respond to the DosPrintQInfo command with a level of 52
608 This is used to get printer driver information for Win9x clients
609 ********************************************************************/
610 static void fill_printq_info_52(struct spoolss_DriverInfo3 *driver,
611 struct pack_desc* desc, int count,
612 const char *printer_name)
614 int i;
615 fstring location;
616 trim_string((char *)driver->driver_path, "\\print$\\WIN40\\0\\", 0);
617 trim_string((char *)driver->data_file, "\\print$\\WIN40\\0\\", 0);
618 trim_string((char *)driver->help_file, "\\print$\\WIN40\\0\\", 0);
620 PACKI(desc, "W", 0x0400); /* don't know */
621 PACKS(desc, "z", driver->driver_name); /* long printer name */
622 PACKS(desc, "z", driver->driver_path); /* Driverfile Name */
623 PACKS(desc, "z", driver->data_file); /* Datafile name */
624 PACKS(desc, "z", driver->monitor_name); /* language monitor */
626 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
627 standard_sub_basic( "", "", location, sizeof(location)-1 );
628 PACKS(desc,"z", location); /* share to retrieve files */
630 PACKS(desc,"z", driver->default_datatype); /* default data type */
631 PACKS(desc,"z", driver->help_file); /* helpfile name */
632 PACKS(desc,"z", driver->driver_path); /* driver name */
634 DEBUG(3,("Printer Driver Name: %s:\n",driver->driver_name));
635 DEBUG(3,("Driver: %s:\n",driver->driver_path));
636 DEBUG(3,("Data File: %s:\n",driver->data_file));
637 DEBUG(3,("Language Monitor: %s:\n",driver->monitor_name));
638 DEBUG(3,("Driver Location: %s:\n",location));
639 DEBUG(3,("Data Type: %s:\n",driver->default_datatype));
640 DEBUG(3,("Help File: %s:\n",driver->help_file));
641 PACKI(desc,"N",count); /* number of files to copy */
643 for ( i=0; i<count && driver->dependent_files && *driver->dependent_files[i]; i++)
645 trim_string((char *)driver->dependent_files[i], "\\print$\\WIN40\\0\\", 0);
646 PACKS(desc,"z",driver->dependent_files[i]); /* driver files to copy */
647 DEBUG(3,("Dependent File: %s:\n", driver->dependent_files[i]));
650 /* sanity check */
651 if ( i != count )
652 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
653 count, i));
655 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", printer_name, i));
657 desc->errcode=NERR_Success;
661 static const char *strip_unc(const char *unc)
663 char *p;
665 if (unc == NULL) {
666 return NULL;
669 if ((p = strrchr(unc, '\\')) != NULL) {
670 return p+1;
673 return unc;
676 static void fill_printq_info(int uLevel,
677 struct pack_desc* desc,
678 int count,
679 union spoolss_JobInfo *job_info,
680 struct spoolss_DriverInfo3 *driver_info,
681 struct spoolss_PrinterInfo2 *printer_info)
683 switch (uLevel) {
684 case 0:
685 case 1:
686 case 2:
687 PACKS(desc,"B13", strip_unc(printer_info->printername));
688 break;
689 case 3:
690 case 4:
691 case 5:
692 PACKS(desc,"z", strip_unc(printer_info->printername));
693 break;
694 case 51:
695 PACKI(desc,"K", printq_spoolss_status(printer_info->status));
696 break;
699 if (uLevel == 1 || uLevel == 2) {
700 PACKS(desc,"B",""); /* alignment */
701 PACKI(desc,"W",5); /* priority */
702 PACKI(desc,"W",0); /* start time */
703 PACKI(desc,"W",0); /* until time */
704 PACKS(desc,"z",""); /* pSepFile */
705 PACKS(desc,"z","lpd"); /* pPrProc */
706 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pDestinations */
707 PACKS(desc,"z",""); /* pParms */
708 if (printer_info->printername == NULL) {
709 PACKS(desc,"z","UNKNOWN PRINTER");
710 PACKI(desc,"W",LPSTAT_ERROR);
711 } else {
712 PACKS(desc,"z", printer_info->comment);
713 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* status */
715 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
718 if (uLevel == 3 || uLevel == 4) {
719 PACKI(desc,"W",5); /* uPriority */
720 PACKI(desc,"W",0); /* uStarttime */
721 PACKI(desc,"W",0); /* uUntiltime */
722 PACKI(desc,"W",5); /* pad1 */
723 PACKS(desc,"z",""); /* pszSepFile */
724 PACKS(desc,"z","WinPrint"); /* pszPrProc */
725 PACKS(desc,"z",NULL); /* pszParms */
726 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
727 /* "don't ask" that it's done this way to fix corrupted
728 Win9X/ME printer comments. */
729 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* fsStatus */
730 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
731 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pszPrinters */
732 PACKS(desc,"z", printer_info->drivername); /* pszDriverName */
733 PackDriverData(desc); /* pDriverData */
736 if (uLevel == 2 || uLevel == 4) {
737 int i;
738 for (i = 0; i < count; i++) {
739 fill_spoolss_printjob_info(uLevel == 2 ? 1 : 2, desc, &job_info[i].info2, i);
743 if (uLevel==52)
744 fill_printq_info_52(driver_info, desc, count, printer_info->printername);
747 /* This function returns the number of files for a given driver */
748 static int get_printerdrivernumber(const struct spoolss_DriverInfo3 *driver)
750 int result = 0;
752 /* count the number of files */
753 while (driver->dependent_files && *driver->dependent_files[result])
754 result++;
756 return result;
759 static bool api_DosPrintQGetInfo(struct smbd_server_connection *sconn,
760 connection_struct *conn, uint16 vuid,
761 char *param, int tpscnt,
762 char *data, int tdscnt,
763 int mdrcnt,int mprcnt,
764 char **rdata,char **rparam,
765 int *rdata_len,int *rparam_len)
767 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
768 char *str2 = skip_string(param,tpscnt,str1);
769 char *p = skip_string(param,tpscnt,str2);
770 char *QueueName = p;
771 unsigned int uLevel;
772 uint32_t count = 0;
773 char *str3;
774 struct pack_desc desc;
775 char* tmpdata=NULL;
777 WERROR werr = WERR_OK;
778 TALLOC_CTX *mem_ctx = talloc_tos();
779 NTSTATUS status;
780 struct rpc_pipe_client *cli = NULL;
781 struct dcerpc_binding_handle *b = NULL;
782 struct policy_handle handle;
783 struct spoolss_DevmodeContainer devmode_ctr;
784 union spoolss_DriverInfo driver_info;
785 union spoolss_JobInfo *job_info = NULL;
786 union spoolss_PrinterInfo printer_info;
788 if (!str1 || !str2 || !p) {
789 return False;
791 memset((char *)&desc,'\0',sizeof(desc));
793 p = skip_string(param,tpscnt,p);
794 if (!p) {
795 return False;
797 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
798 str3 = get_safe_str_ptr(param,tpscnt,p,4);
799 /* str3 may be null here and is checked in check_printq_info(). */
801 /* remove any trailing username */
802 if ((p = strchr_m(QueueName,'%')))
803 *p = 0;
805 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
807 /* check it's a supported varient */
808 if (!prefix_ok(str1,"zWrLh"))
809 return False;
810 if (!check_printq_info(&desc,uLevel,str2,str3)) {
812 * Patch from Scott Moomaw <scott@bridgewater.edu>
813 * to return the 'invalid info level' error if an
814 * unknown level was requested.
816 *rdata_len = 0;
817 *rparam_len = 6;
818 *rparam = smb_realloc_limit(*rparam,*rparam_len);
819 if (!*rparam) {
820 return False;
822 SSVALS(*rparam,0,ERRunknownlevel);
823 SSVAL(*rparam,2,0);
824 SSVAL(*rparam,4,0);
825 return(True);
828 ZERO_STRUCT(handle);
830 if (QueueName == NULL || (strlen(QueueName) < 1)) {
831 desc.errcode = W_ERROR_V(WERR_INVALID_PARAM);
832 goto out;
835 status = rpc_pipe_open_interface(conn,
836 &ndr_table_spoolss.syntax_id,
837 conn->session_info,
838 &conn->sconn->client_id,
839 conn->sconn->msg_ctx,
840 &cli);
841 if (!NT_STATUS_IS_OK(status)) {
842 DEBUG(0,("api_DosPrintQGetInfo: could not connect to spoolss: %s\n",
843 nt_errstr(status)));
844 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
845 goto out;
847 b = cli->binding_handle;
849 ZERO_STRUCT(devmode_ctr);
851 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
852 QueueName,
853 "RAW",
854 devmode_ctr,
855 PRINTER_ACCESS_USE,
856 &handle,
857 &werr);
858 if (!NT_STATUS_IS_OK(status)) {
859 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
860 goto out;
862 if (!W_ERROR_IS_OK(werr)) {
863 desc.errcode = W_ERROR_V(werr);
864 goto out;
867 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
868 &handle,
871 &printer_info);
872 if (!W_ERROR_IS_OK(werr)) {
873 desc.errcode = W_ERROR_V(werr);
874 goto out;
877 if (uLevel==52) {
878 uint32_t server_major_version;
879 uint32_t server_minor_version;
881 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
882 &handle,
883 "Windows 4.0",
884 3, /* level */
886 0, /* version */
888 &driver_info,
889 &server_major_version,
890 &server_minor_version);
891 if (!W_ERROR_IS_OK(werr)) {
892 desc.errcode = W_ERROR_V(werr);
893 goto out;
896 count = get_printerdrivernumber(&driver_info.info3);
897 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
898 } else {
899 uint32_t num_jobs;
900 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
901 &handle,
902 0, /* firstjob */
903 0xff, /* numjobs */
904 2, /* level */
905 0, /* offered */
906 &num_jobs,
907 &job_info);
908 if (!W_ERROR_IS_OK(werr)) {
909 desc.errcode = W_ERROR_V(werr);
910 goto out;
913 count = num_jobs;
916 if (mdrcnt > 0) {
917 *rdata = smb_realloc_limit(*rdata,mdrcnt);
918 if (!*rdata) {
919 return False;
921 desc.base = *rdata;
922 desc.buflen = mdrcnt;
923 } else {
925 * Don't return data but need to get correct length
926 * init_package will return wrong size if buflen=0
928 desc.buflen = getlen(desc.format);
929 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
932 if (init_package(&desc,1,count)) {
933 desc.subcount = count;
934 fill_printq_info(uLevel,&desc,count, job_info, &driver_info.info3, &printer_info.info2);
937 *rdata_len = desc.usedlen;
940 * We must set the return code to ERRbuftoosmall
941 * in order to support lanman style printing with Win NT/2k
942 * clients --jerry
944 if (!mdrcnt && lp_disable_spoolss())
945 desc.errcode = ERRbuftoosmall;
947 out:
948 if (b && is_valid_policy_hnd(&handle)) {
949 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
952 *rdata_len = desc.usedlen;
953 *rparam_len = 6;
954 *rparam = smb_realloc_limit(*rparam,*rparam_len);
955 if (!*rparam) {
956 SAFE_FREE(tmpdata);
957 return False;
959 SSVALS(*rparam,0,desc.errcode);
960 SSVAL(*rparam,2,0);
961 SSVAL(*rparam,4,desc.neededlen);
963 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
965 SAFE_FREE(tmpdata);
967 return(True);
970 /****************************************************************************
971 View list of all print jobs on all queues.
972 ****************************************************************************/
974 static bool api_DosPrintQEnum(struct smbd_server_connection *sconn,
975 connection_struct *conn, uint16 vuid,
976 char *param, int tpscnt,
977 char *data, int tdscnt,
978 int mdrcnt, int mprcnt,
979 char **rdata, char** rparam,
980 int *rdata_len, int *rparam_len)
982 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
983 char *output_format1 = skip_string(param,tpscnt,param_format);
984 char *p = skip_string(param,tpscnt,output_format1);
985 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
986 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
987 int i;
988 struct pack_desc desc;
989 int *subcntarr = NULL;
990 int queuecnt = 0, subcnt = 0, succnt = 0;
992 WERROR werr = WERR_OK;
993 TALLOC_CTX *mem_ctx = talloc_tos();
994 NTSTATUS status;
995 struct rpc_pipe_client *cli = NULL;
996 struct dcerpc_binding_handle *b = NULL;
997 struct spoolss_DevmodeContainer devmode_ctr;
998 uint32_t num_printers;
999 union spoolss_PrinterInfo *printer_info;
1000 union spoolss_DriverInfo *driver_info;
1001 union spoolss_JobInfo **job_info;
1003 if (!param_format || !output_format1 || !p) {
1004 return False;
1007 memset((char *)&desc,'\0',sizeof(desc));
1009 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
1011 if (!prefix_ok(param_format,"WrLeh")) {
1012 return False;
1014 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
1016 * Patch from Scott Moomaw <scott@bridgewater.edu>
1017 * to return the 'invalid info level' error if an
1018 * unknown level was requested.
1020 *rdata_len = 0;
1021 *rparam_len = 6;
1022 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1023 if (!*rparam) {
1024 return False;
1026 SSVALS(*rparam,0,ERRunknownlevel);
1027 SSVAL(*rparam,2,0);
1028 SSVAL(*rparam,4,0);
1029 return(True);
1032 status = rpc_pipe_open_interface(conn,
1033 &ndr_table_spoolss.syntax_id,
1034 conn->session_info,
1035 &conn->sconn->client_id,
1036 conn->sconn->msg_ctx,
1037 &cli);
1038 if (!NT_STATUS_IS_OK(status)) {
1039 DEBUG(0,("api_DosPrintQEnum: could not connect to spoolss: %s\n",
1040 nt_errstr(status)));
1041 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1042 goto out;
1044 b = cli->binding_handle;
1046 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
1047 PRINTER_ENUM_LOCAL,
1048 cli->srv_name_slash,
1051 &num_printers,
1052 &printer_info);
1053 if (!W_ERROR_IS_OK(werr)) {
1054 desc.errcode = W_ERROR_V(werr);
1055 goto out;
1058 queuecnt = num_printers;
1060 job_info = talloc_array(mem_ctx, union spoolss_JobInfo *, num_printers);
1061 if (job_info == NULL) {
1062 goto err;
1065 driver_info = talloc_array(mem_ctx, union spoolss_DriverInfo, num_printers);
1066 if (driver_info == NULL) {
1067 goto err;
1070 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1071 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1072 goto err;
1075 if (mdrcnt > 0) {
1076 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1077 if (!*rdata) {
1078 goto err;
1081 desc.base = *rdata;
1082 desc.buflen = mdrcnt;
1084 subcnt = 0;
1085 for (i = 0; i < num_printers; i++) {
1087 uint32_t num_jobs;
1088 struct policy_handle handle;
1089 const char *printername;
1091 printername = talloc_strdup(mem_ctx, printer_info[i].info2.printername);
1092 if (printername == NULL) {
1093 goto err;
1096 ZERO_STRUCT(handle);
1097 ZERO_STRUCT(devmode_ctr);
1099 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
1100 printername,
1101 "RAW",
1102 devmode_ctr,
1103 PRINTER_ACCESS_USE,
1104 &handle,
1105 &werr);
1106 if (!NT_STATUS_IS_OK(status)) {
1107 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1108 goto out;
1110 if (!W_ERROR_IS_OK(werr)) {
1111 desc.errcode = W_ERROR_V(werr);
1112 goto out;
1115 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
1116 &handle,
1117 0, /* firstjob */
1118 0xff, /* numjobs */
1119 2, /* level */
1120 0, /* offered */
1121 &num_jobs,
1122 &job_info[i]);
1123 if (!W_ERROR_IS_OK(werr)) {
1124 desc.errcode = W_ERROR_V(werr);
1125 goto out;
1128 if (uLevel==52) {
1129 uint32_t server_major_version;
1130 uint32_t server_minor_version;
1132 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1133 &handle,
1134 "Windows 4.0",
1135 3, /* level */
1137 0, /* version */
1139 &driver_info[i],
1140 &server_major_version,
1141 &server_minor_version);
1142 if (!W_ERROR_IS_OK(werr)) {
1143 desc.errcode = W_ERROR_V(werr);
1144 goto out;
1148 subcntarr[i] = num_jobs;
1149 subcnt += subcntarr[i];
1151 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
1154 if (init_package(&desc,queuecnt,subcnt)) {
1155 for (i = 0; i < num_printers; i++) {
1156 fill_printq_info(uLevel,&desc,subcntarr[i], job_info[i], &driver_info[i].info3, &printer_info[i].info2);
1157 if (desc.errcode == NERR_Success) {
1158 succnt = i;
1163 SAFE_FREE(subcntarr);
1164 out:
1165 *rdata_len = desc.usedlen;
1166 *rparam_len = 8;
1167 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1168 if (!*rparam) {
1169 goto err;
1171 SSVALS(*rparam,0,desc.errcode);
1172 SSVAL(*rparam,2,0);
1173 SSVAL(*rparam,4,succnt);
1174 SSVAL(*rparam,6,queuecnt);
1176 return True;
1178 err:
1180 SAFE_FREE(subcntarr);
1182 return False;
1185 /****************************************************************************
1186 Get info level for a server list query.
1187 ****************************************************************************/
1189 static bool check_session_info(int uLevel, char* id)
1191 switch( uLevel ) {
1192 case 0:
1193 if (strcmp(id,"B16") != 0) {
1194 return False;
1196 break;
1197 case 1:
1198 if (strcmp(id,"B16BBDz") != 0) {
1199 return False;
1201 break;
1202 default:
1203 return False;
1205 return True;
1208 struct srv_info_struct {
1209 fstring name;
1210 uint32 type;
1211 fstring comment;
1212 fstring domain;
1213 bool server_added;
1216 /*******************************************************************
1217 Get server info lists from the files saved by nmbd. Return the
1218 number of entries.
1219 ******************************************************************/
1221 static int get_session_info(uint32 servertype,
1222 struct srv_info_struct **servers,
1223 const char *domain)
1225 int count=0;
1226 int alloced=0;
1227 char **lines;
1228 bool local_list_only;
1229 int i;
1231 lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
1232 if (!lines) {
1233 DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
1234 return 0;
1237 /* request for everything is code for request all servers */
1238 if (servertype == SV_TYPE_ALL) {
1239 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1242 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1244 DEBUG(4,("Servertype search: %8x\n",servertype));
1246 for (i=0;lines[i];i++) {
1247 fstring stype;
1248 struct srv_info_struct *s;
1249 const char *ptr = lines[i];
1250 bool ok = True;
1251 TALLOC_CTX *frame = NULL;
1252 char *p;
1254 if (!*ptr) {
1255 continue;
1258 if (count == alloced) {
1259 alloced += 10;
1260 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1261 if (!*servers) {
1262 DEBUG(0,("get_session_info: failed to enlarge servers info struct!\n"));
1263 TALLOC_FREE(lines);
1264 return 0;
1266 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1268 s = &(*servers)[count];
1270 frame = talloc_stackframe();
1271 s->name[0] = '\0';
1272 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1273 TALLOC_FREE(frame);
1274 continue;
1276 fstrcpy(s->name, p);
1278 stype[0] = '\0';
1279 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1280 TALLOC_FREE(frame);
1281 continue;
1283 fstrcpy(stype, p);
1285 s->comment[0] = '\0';
1286 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1287 TALLOC_FREE(frame);
1288 continue;
1290 fstrcpy(s->comment, p);
1291 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1293 s->domain[0] = '\0';
1294 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1295 /* this allows us to cope with an old nmbd */
1296 fstrcpy(s->domain,lp_workgroup());
1297 } else {
1298 fstrcpy(s->domain, p);
1300 TALLOC_FREE(frame);
1302 if (sscanf(stype,"%X",&s->type) != 1) {
1303 DEBUG(4,("r:host file "));
1304 ok = False;
1307 /* Filter the servers/domains we return based on what was asked for. */
1309 /* Check to see if we are being asked for a local list only. */
1310 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1311 DEBUG(4,("r: local list only"));
1312 ok = False;
1315 /* doesn't match up: don't want it */
1316 if (!(servertype & s->type)) {
1317 DEBUG(4,("r:serv type "));
1318 ok = False;
1321 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1322 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1323 DEBUG(4,("s: dom mismatch "));
1324 ok = False;
1327 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1328 ok = False;
1331 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1332 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1334 if (ok) {
1335 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1336 s->name, s->type, s->comment, s->domain));
1337 s->server_added = True;
1338 count++;
1339 } else {
1340 DEBUG(4,("%20s %8x %25s %15s\n",
1341 s->name, s->type, s->comment, s->domain));
1345 TALLOC_FREE(lines);
1346 return count;
1349 /*******************************************************************
1350 Fill in a server info structure.
1351 ******************************************************************/
1353 static int fill_srv_info(struct srv_info_struct *service,
1354 int uLevel, char **buf, int *buflen,
1355 char **stringbuf, int *stringspace, char *baseaddr)
1357 int struct_len;
1358 char* p;
1359 char* p2;
1360 int l2;
1361 int len;
1363 switch (uLevel) {
1364 case 0:
1365 struct_len = 16;
1366 break;
1367 case 1:
1368 struct_len = 26;
1369 break;
1370 default:
1371 return -1;
1374 if (!buf) {
1375 len = 0;
1376 switch (uLevel) {
1377 case 1:
1378 len = strlen(service->comment)+1;
1379 break;
1382 *buflen = struct_len;
1383 *stringspace = len;
1384 return struct_len + len;
1387 len = struct_len;
1388 p = *buf;
1389 if (*buflen < struct_len) {
1390 return -1;
1392 if (stringbuf) {
1393 p2 = *stringbuf;
1394 l2 = *stringspace;
1395 } else {
1396 p2 = p + struct_len;
1397 l2 = *buflen - struct_len;
1399 if (!baseaddr) {
1400 baseaddr = p;
1403 switch (uLevel) {
1404 case 0:
1405 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1406 break;
1408 case 1:
1409 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1410 SIVAL(p,18,service->type);
1411 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1412 len += CopyAndAdvance(&p2,service->comment,&l2);
1413 break;
1416 if (stringbuf) {
1417 *buf = p + struct_len;
1418 *buflen -= struct_len;
1419 *stringbuf = p2;
1420 *stringspace = l2;
1421 } else {
1422 *buf = p2;
1423 *buflen -= len;
1425 return len;
1429 static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1431 return StrCaseCmp(s1->name,s2->name);
1434 /****************************************************************************
1435 View list of servers available (or possibly domains). The info is
1436 extracted from lists saved by nmbd on the local host.
1437 ****************************************************************************/
1439 static bool api_RNetServerEnum2(struct smbd_server_connection *sconn,
1440 connection_struct *conn, uint16 vuid,
1441 char *param, int tpscnt,
1442 char *data, int tdscnt,
1443 int mdrcnt, int mprcnt, char **rdata,
1444 char **rparam, int *rdata_len, int *rparam_len)
1446 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1447 char *str2 = skip_string(param,tpscnt,str1);
1448 char *p = skip_string(param,tpscnt,str2);
1449 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1450 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1451 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1452 char *p2;
1453 int data_len, fixed_len, string_len;
1454 int f_len = 0, s_len = 0;
1455 struct srv_info_struct *servers=NULL;
1456 int counted=0,total=0;
1457 int i,missed;
1458 fstring domain;
1459 bool domain_request;
1460 bool local_request;
1462 if (!str1 || !str2 || !p) {
1463 return False;
1466 /* If someone sets all the bits they don't really mean to set
1467 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1468 known servers. */
1470 if (servertype == SV_TYPE_ALL) {
1471 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1474 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1475 any other bit (they may just set this bit on its own) they
1476 want all the locally seen servers. However this bit can be
1477 set on its own so set the requested servers to be
1478 ALL - DOMAIN_ENUM. */
1480 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1481 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1484 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1485 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1487 p += 8;
1489 if (!prefix_ok(str1,"WrLehD")) {
1490 return False;
1492 if (!check_session_info(uLevel,str2)) {
1493 return False;
1496 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1497 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1498 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1500 if (strcmp(str1, "WrLehDz") == 0) {
1501 if (skip_string(param,tpscnt,p) == NULL) {
1502 return False;
1504 pull_ascii_fstring(domain, p);
1505 } else {
1506 fstrcpy(domain, lp_workgroup());
1509 DEBUG(4, ("domain [%s]\n", domain));
1511 if (lp_browse_list()) {
1512 total = get_session_info(servertype,&servers,domain);
1515 data_len = fixed_len = string_len = 0;
1516 missed = 0;
1518 TYPESAFE_QSORT(servers, total, srv_comp);
1521 char *lastname=NULL;
1523 for (i=0;i<total;i++) {
1524 struct srv_info_struct *s = &servers[i];
1526 if (lastname && strequal(lastname,s->name)) {
1527 continue;
1529 lastname = s->name;
1530 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1531 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1532 i, s->name, s->type, s->comment, s->domain));
1534 if (data_len < buf_len) {
1535 counted++;
1536 fixed_len += f_len;
1537 string_len += s_len;
1538 } else {
1539 missed++;
1544 *rdata_len = fixed_len + string_len;
1545 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1546 if (!*rdata) {
1547 return False;
1550 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1551 p = *rdata;
1552 f_len = fixed_len;
1553 s_len = string_len;
1556 char *lastname=NULL;
1557 int count2 = counted;
1559 for (i = 0; i < total && count2;i++) {
1560 struct srv_info_struct *s = &servers[i];
1562 if (lastname && strequal(lastname,s->name)) {
1563 continue;
1565 lastname = s->name;
1566 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1567 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1568 i, s->name, s->type, s->comment, s->domain));
1569 count2--;
1573 *rparam_len = 8;
1574 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1575 if (!*rparam) {
1576 return False;
1578 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1579 SSVAL(*rparam,2,0);
1580 SSVAL(*rparam,4,counted);
1581 SSVAL(*rparam,6,counted+missed);
1583 SAFE_FREE(servers);
1585 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1586 domain,uLevel,counted,counted+missed));
1588 return True;
1591 static int srv_name_match(const char *n1, const char *n2)
1594 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1596 * In Windows, FirstNameToReturn need not be an exact match:
1597 * the server will return a list of servers that exist on
1598 * the network greater than or equal to the FirstNameToReturn.
1600 int ret = StrCaseCmp(n1, n2);
1602 if (ret <= 0) {
1603 return 0;
1606 return ret;
1609 static bool api_RNetServerEnum3(struct smbd_server_connection *sconn,
1610 connection_struct *conn, uint16 vuid,
1611 char *param, int tpscnt,
1612 char *data, int tdscnt,
1613 int mdrcnt, int mprcnt, char **rdata,
1614 char **rparam, int *rdata_len, int *rparam_len)
1616 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1617 char *str2 = skip_string(param,tpscnt,str1);
1618 char *p = skip_string(param,tpscnt,str2);
1619 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1620 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1621 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1622 char *p2;
1623 int data_len, fixed_len, string_len;
1624 int f_len = 0, s_len = 0;
1625 struct srv_info_struct *servers=NULL;
1626 int counted=0,first=0,total=0;
1627 int i,missed;
1628 fstring domain;
1629 fstring first_name;
1630 bool domain_request;
1631 bool local_request;
1633 if (!str1 || !str2 || !p) {
1634 return False;
1637 /* If someone sets all the bits they don't really mean to set
1638 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1639 known servers. */
1641 if (servertype == SV_TYPE_ALL) {
1642 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1645 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1646 any other bit (they may just set this bit on its own) they
1647 want all the locally seen servers. However this bit can be
1648 set on its own so set the requested servers to be
1649 ALL - DOMAIN_ENUM. */
1651 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1652 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1655 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1656 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1658 p += 8;
1660 if (strcmp(str1, "WrLehDzz") != 0) {
1661 return false;
1663 if (!check_session_info(uLevel,str2)) {
1664 return False;
1667 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1668 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1669 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1671 if (skip_string(param,tpscnt,p) == NULL) {
1672 return False;
1674 pull_ascii_fstring(domain, p);
1675 if (domain[0] == '\0') {
1676 fstrcpy(domain, lp_workgroup());
1678 p = skip_string(param,tpscnt,p);
1679 if (skip_string(param,tpscnt,p) == NULL) {
1680 return False;
1682 pull_ascii_fstring(first_name, p);
1684 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1685 domain, first_name));
1687 if (lp_browse_list()) {
1688 total = get_session_info(servertype,&servers,domain);
1691 data_len = fixed_len = string_len = 0;
1692 missed = 0;
1694 TYPESAFE_QSORT(servers, total, srv_comp);
1696 if (first_name[0] != '\0') {
1697 struct srv_info_struct *first_server = NULL;
1699 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1700 srv_name_match, first_server);
1701 if (first_server) {
1702 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1704 * The binary search may not find the exact match
1705 * so we need to search backward to find the first match
1707 * This implements the strange matching windows
1708 * implements. (see the comment in srv_name_match().
1710 for (;first > 0;) {
1711 int ret;
1712 ret = StrCaseCmp(first_name,
1713 servers[first-1].name);
1714 if (ret > 0) {
1715 break;
1717 first--;
1719 } else {
1720 /* we should return no entries */
1721 first = total;
1726 char *lastname=NULL;
1728 for (i=first;i<total;i++) {
1729 struct srv_info_struct *s = &servers[i];
1731 if (lastname && strequal(lastname,s->name)) {
1732 continue;
1734 lastname = s->name;
1735 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1736 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1737 i, s->name, s->type, s->comment, s->domain));
1739 if (data_len < buf_len) {
1740 counted++;
1741 fixed_len += f_len;
1742 string_len += s_len;
1743 } else {
1744 missed++;
1749 *rdata_len = fixed_len + string_len;
1750 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1751 if (!*rdata) {
1752 return False;
1755 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1756 p = *rdata;
1757 f_len = fixed_len;
1758 s_len = string_len;
1761 char *lastname=NULL;
1762 int count2 = counted;
1764 for (i = first; i < total && count2;i++) {
1765 struct srv_info_struct *s = &servers[i];
1767 if (lastname && strequal(lastname,s->name)) {
1768 continue;
1770 lastname = s->name;
1771 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1772 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1773 i, s->name, s->type, s->comment, s->domain));
1774 count2--;
1778 *rparam_len = 8;
1779 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1780 if (!*rparam) {
1781 return False;
1783 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1784 SSVAL(*rparam,2,0);
1785 SSVAL(*rparam,4,counted);
1786 SSVAL(*rparam,6,counted+missed);
1788 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1789 domain,uLevel,first,first_name,
1790 first < total ? servers[first].name : "",
1791 counted,counted+missed));
1793 SAFE_FREE(servers);
1795 return True;
1798 /****************************************************************************
1799 command 0x34 - suspected of being a "Lookup Names" stub api
1800 ****************************************************************************/
1802 static bool api_RNetGroupGetUsers(struct smbd_server_connection *sconn,
1803 connection_struct *conn, uint16 vuid,
1804 char *param, int tpscnt,
1805 char *data, int tdscnt,
1806 int mdrcnt, int mprcnt, char **rdata,
1807 char **rparam, int *rdata_len, int *rparam_len)
1809 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1810 char *str2 = skip_string(param,tpscnt,str1);
1811 char *p = skip_string(param,tpscnt,str2);
1812 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1813 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1814 int counted=0;
1815 int missed=0;
1817 if (!str1 || !str2 || !p) {
1818 return False;
1821 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1822 str1, str2, p, uLevel, buf_len));
1824 if (!prefix_ok(str1,"zWrLeh")) {
1825 return False;
1828 *rdata_len = 0;
1830 *rparam_len = 8;
1831 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1832 if (!*rparam) {
1833 return False;
1836 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1837 SSVAL(*rparam,2,0);
1838 SSVAL(*rparam,4,counted);
1839 SSVAL(*rparam,6,counted+missed);
1841 return True;
1844 /****************************************************************************
1845 get info about a share
1846 ****************************************************************************/
1848 static bool check_share_info(int uLevel, char* id)
1850 switch( uLevel ) {
1851 case 0:
1852 if (strcmp(id,"B13") != 0) {
1853 return False;
1855 break;
1856 case 1:
1857 /* Level-2 descriptor is allowed (and ignored) */
1858 if (strcmp(id,"B13BWz") != 0 &&
1859 strcmp(id,"B13BWzWWWzB9B") != 0) {
1860 return False;
1862 break;
1863 case 2:
1864 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1865 return False;
1867 break;
1868 case 91:
1869 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1870 return False;
1872 break;
1873 default:
1874 return False;
1876 return True;
1879 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1880 char** buf, int* buflen,
1881 char** stringbuf, int* stringspace, char* baseaddr)
1883 int struct_len;
1884 char* p;
1885 char* p2;
1886 int l2;
1887 int len;
1889 switch( uLevel ) {
1890 case 0:
1891 struct_len = 13;
1892 break;
1893 case 1:
1894 struct_len = 20;
1895 break;
1896 case 2:
1897 struct_len = 40;
1898 break;
1899 case 91:
1900 struct_len = 68;
1901 break;
1902 default:
1903 return -1;
1906 if (!buf) {
1907 len = 0;
1909 if (uLevel > 0) {
1910 len += StrlenExpanded(conn,snum,lp_comment(snum));
1912 if (uLevel > 1) {
1913 len += strlen(lp_pathname(snum)) + 1;
1915 if (buflen) {
1916 *buflen = struct_len;
1918 if (stringspace) {
1919 *stringspace = len;
1921 return struct_len + len;
1924 len = struct_len;
1925 p = *buf;
1926 if ((*buflen) < struct_len) {
1927 return -1;
1930 if (stringbuf) {
1931 p2 = *stringbuf;
1932 l2 = *stringspace;
1933 } else {
1934 p2 = p + struct_len;
1935 l2 = (*buflen) - struct_len;
1938 if (!baseaddr) {
1939 baseaddr = p;
1942 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1944 if (uLevel > 0) {
1945 int type;
1947 SCVAL(p,13,0);
1948 type = STYPE_DISKTREE;
1949 if (lp_print_ok(snum)) {
1950 type = STYPE_PRINTQ;
1952 if (strequal("IPC",lp_fstype(snum))) {
1953 type = STYPE_IPC;
1955 SSVAL(p,14,type); /* device type */
1956 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1957 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1960 if (uLevel > 1) {
1961 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1962 SSVALS(p,22,-1); /* max uses */
1963 SSVAL(p,24,1); /* current uses */
1964 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1965 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1966 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1969 if (uLevel > 2) {
1970 memset(p+40,0,SHPWLEN+2);
1971 SSVAL(p,50,0);
1972 SIVAL(p,52,0);
1973 SSVAL(p,56,0);
1974 SSVAL(p,58,0);
1975 SIVAL(p,60,0);
1976 SSVAL(p,64,0);
1977 SSVAL(p,66,0);
1980 if (stringbuf) {
1981 (*buf) = p + struct_len;
1982 (*buflen) -= struct_len;
1983 (*stringbuf) = p2;
1984 (*stringspace) = l2;
1985 } else {
1986 (*buf) = p2;
1987 (*buflen) -= len;
1990 return len;
1993 static bool api_RNetShareGetInfo(struct smbd_server_connection *sconn,
1994 connection_struct *conn,uint16 vuid,
1995 char *param, int tpscnt,
1996 char *data, int tdscnt,
1997 int mdrcnt,int mprcnt,
1998 char **rdata,char **rparam,
1999 int *rdata_len,int *rparam_len)
2001 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2002 char *str2 = skip_string(param,tpscnt,str1);
2003 char *netname_in = skip_string(param,tpscnt,str2);
2004 char *netname = NULL;
2005 char *p = skip_string(param,tpscnt,netname);
2006 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2007 int snum;
2009 if (!str1 || !str2 || !netname || !p) {
2010 return False;
2013 snum = find_service(talloc_tos(), netname_in, &netname);
2014 if (snum < 0 || !netname) {
2015 return False;
2018 /* check it's a supported varient */
2019 if (!prefix_ok(str1,"zWrLh")) {
2020 return False;
2022 if (!check_share_info(uLevel,str2)) {
2023 return False;
2026 *rdata = smb_realloc_limit(*rdata,mdrcnt);
2027 if (!*rdata) {
2028 return False;
2030 p = *rdata;
2031 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
2032 if (*rdata_len < 0) {
2033 return False;
2036 *rparam_len = 6;
2037 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2038 if (!*rparam) {
2039 return False;
2041 SSVAL(*rparam,0,NERR_Success);
2042 SSVAL(*rparam,2,0); /* converter word */
2043 SSVAL(*rparam,4,*rdata_len);
2045 return True;
2048 /****************************************************************************
2049 View the list of available shares.
2051 This function is the server side of the NetShareEnum() RAP call.
2052 It fills the return buffer with share names and share comments.
2053 Note that the return buffer normally (in all known cases) allows only
2054 twelve byte strings for share names (plus one for a nul terminator).
2055 Share names longer than 12 bytes must be skipped.
2056 ****************************************************************************/
2058 static bool api_RNetShareEnum(struct smbd_server_connection *sconn,
2059 connection_struct *conn, uint16 vuid,
2060 char *param, int tpscnt,
2061 char *data, int tdscnt,
2062 int mdrcnt,
2063 int mprcnt,
2064 char **rdata,
2065 char **rparam,
2066 int *rdata_len,
2067 int *rparam_len )
2069 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2070 char *str2 = skip_string(param,tpscnt,str1);
2071 char *p = skip_string(param,tpscnt,str2);
2072 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2073 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
2074 char *p2;
2075 int count = 0;
2076 int total=0,counted=0;
2077 bool missed = False;
2078 int i;
2079 int data_len, fixed_len, string_len;
2080 int f_len = 0, s_len = 0;
2082 if (!str1 || !str2 || !p) {
2083 return False;
2086 if (!prefix_ok(str1,"WrLeh")) {
2087 return False;
2089 if (!check_share_info(uLevel,str2)) {
2090 return False;
2093 /* Ensure all the usershares are loaded. */
2094 become_root();
2095 load_registry_shares();
2096 count = load_usershare_shares();
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(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, lp_servicename(i));
2138 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2139 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2140 break;
2145 *rparam_len = 8;
2146 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2147 if (!*rparam) {
2148 return False;
2150 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2151 SSVAL(*rparam,2,0);
2152 SSVAL(*rparam,4,counted);
2153 SSVAL(*rparam,6,total);
2155 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2156 counted,total,uLevel,
2157 buf_len,*rdata_len,mdrcnt));
2159 return True;
2162 /****************************************************************************
2163 Add a share
2164 ****************************************************************************/
2166 static bool api_RNetShareAdd(struct smbd_server_connection *sconn,
2167 connection_struct *conn,uint16 vuid,
2168 char *param, int tpscnt,
2169 char *data, int tdscnt,
2170 int mdrcnt,int mprcnt,
2171 char **rdata,char **rparam,
2172 int *rdata_len,int *rparam_len)
2174 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2175 char *str2 = skip_string(param,tpscnt,str1);
2176 char *p = skip_string(param,tpscnt,str2);
2177 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2178 fstring sharename;
2179 fstring comment;
2180 char *pathname = NULL;
2181 unsigned int offset;
2182 int res = ERRunsup;
2183 size_t converted_size;
2185 WERROR werr = WERR_OK;
2186 TALLOC_CTX *mem_ctx = talloc_tos();
2187 NTSTATUS status;
2188 struct rpc_pipe_client *cli = NULL;
2189 union srvsvc_NetShareInfo info;
2190 struct srvsvc_NetShareInfo2 info2;
2191 struct dcerpc_binding_handle *b;
2193 if (!str1 || !str2 || !p) {
2194 return False;
2197 /* check it's a supported varient */
2198 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2199 return False;
2201 if (!check_share_info(uLevel,str2)) {
2202 return False;
2204 if (uLevel != 2) {
2205 return False;
2208 /* Do we have a string ? */
2209 if (skip_string(data,mdrcnt,data) == NULL) {
2210 return False;
2212 pull_ascii_fstring(sharename,data);
2214 if (mdrcnt < 28) {
2215 return False;
2218 /* only support disk share adds */
2219 if (SVAL(data,14)!=STYPE_DISKTREE) {
2220 return False;
2223 offset = IVAL(data, 16);
2224 if (offset >= mdrcnt) {
2225 res = ERRinvalidparam;
2226 goto out;
2229 /* Do we have a string ? */
2230 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2231 return False;
2233 pull_ascii_fstring(comment, offset? (data+offset) : "");
2235 offset = IVAL(data, 26);
2237 if (offset >= mdrcnt) {
2238 res = ERRinvalidparam;
2239 goto out;
2242 /* Do we have a string ? */
2243 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2244 return False;
2247 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2248 offset ? (data+offset) : "", &converted_size))
2250 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
2251 strerror(errno)));
2254 if (!pathname) {
2255 return false;
2258 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_srvsvc.syntax_id,
2259 conn->session_info,
2260 &conn->sconn->client_id,
2261 conn->sconn->msg_ctx,
2262 &cli);
2263 if (!NT_STATUS_IS_OK(status)) {
2264 DEBUG(0,("api_RNetShareAdd: could not connect to srvsvc: %s\n",
2265 nt_errstr(status)));
2266 res = W_ERROR_V(ntstatus_to_werror(status));
2267 goto out;
2270 b = cli->binding_handle;
2272 info2.name = sharename;
2273 info2.type = STYPE_DISKTREE;
2274 info2.comment = comment;
2275 info2.permissions = 0;
2276 info2.max_users = 0;
2277 info2.current_users = 0;
2278 info2.path = pathname;
2279 info2.password = NULL;
2281 info.info2 = &info2;
2283 status = dcerpc_srvsvc_NetShareAdd(b, mem_ctx,
2284 cli->srv_name_slash,
2286 &info,
2287 NULL,
2288 &werr);
2289 if (!NT_STATUS_IS_OK(status)) {
2290 res = W_ERROR_V(ntstatus_to_werror(status));
2291 goto out;
2293 if (!W_ERROR_IS_OK(werr)) {
2294 res = W_ERROR_V(werr);
2295 goto out;
2298 *rparam_len = 6;
2299 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2300 if (!*rparam) {
2301 return False;
2303 SSVAL(*rparam,0,NERR_Success);
2304 SSVAL(*rparam,2,0); /* converter word */
2305 SSVAL(*rparam,4,*rdata_len);
2306 *rdata_len = 0;
2308 return True;
2310 out:
2312 *rparam_len = 4;
2313 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2314 if (!*rparam) {
2315 return False;
2317 *rdata_len = 0;
2318 SSVAL(*rparam,0,res);
2319 SSVAL(*rparam,2,0);
2320 return True;
2323 /****************************************************************************
2324 view list of groups available
2325 ****************************************************************************/
2327 static bool api_RNetGroupEnum(struct smbd_server_connection *sconn,
2328 connection_struct *conn,uint16 vuid,
2329 char *param, int tpscnt,
2330 char *data, int tdscnt,
2331 int mdrcnt,int mprcnt,
2332 char **rdata,char **rparam,
2333 int *rdata_len,int *rparam_len)
2335 int i;
2336 int errflags=0;
2337 int resume_context, cli_buf_size;
2338 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2339 char *str2 = skip_string(param,tpscnt,str1);
2340 char *p = skip_string(param,tpscnt,str2);
2342 uint32_t num_groups;
2343 uint32_t resume_handle;
2344 struct rpc_pipe_client *samr_pipe;
2345 struct policy_handle samr_handle, domain_handle;
2346 NTSTATUS status, result;
2347 struct dcerpc_binding_handle *b;
2349 if (!str1 || !str2 || !p) {
2350 return False;
2353 if (strcmp(str1,"WrLeh") != 0) {
2354 return False;
2357 /* parameters
2358 * W-> resume context (number of users to skip)
2359 * r -> return parameter pointer to receive buffer
2360 * L -> length of receive buffer
2361 * e -> return parameter number of entries
2362 * h -> return parameter total number of users
2365 if (strcmp("B21",str2) != 0) {
2366 return False;
2369 status = rpc_pipe_open_internal(
2370 talloc_tos(), &ndr_table_samr.syntax_id,
2371 conn->session_info, &conn->sconn->client_id,
2372 conn->sconn->msg_ctx, &samr_pipe);
2373 if (!NT_STATUS_IS_OK(status)) {
2374 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2375 nt_errstr(status)));
2376 return false;
2379 b = samr_pipe->binding_handle;
2381 status = dcerpc_samr_Connect2(b, talloc_tos(), global_myname(),
2382 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle,
2383 &result);
2384 if (!NT_STATUS_IS_OK(status)) {
2385 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2386 nt_errstr(status)));
2387 return false;
2389 if (!NT_STATUS_IS_OK(result)) {
2390 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2391 nt_errstr(result)));
2392 return false;
2395 status = dcerpc_samr_OpenDomain(b, talloc_tos(), &samr_handle,
2396 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2397 get_global_sam_sid(), &domain_handle,
2398 &result);
2399 if (!NT_STATUS_IS_OK(status)) {
2400 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2401 nt_errstr(status)));
2402 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2403 return false;
2405 if (!NT_STATUS_IS_OK(result)) {
2406 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2407 nt_errstr(result)));
2408 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2409 return false;
2412 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2413 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2414 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2415 "%d\n", resume_context, cli_buf_size));
2417 *rdata_len = cli_buf_size;
2418 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2419 if (!*rdata) {
2420 return False;
2423 p = *rdata;
2425 errflags = NERR_Success;
2426 num_groups = 0;
2427 resume_handle = 0;
2429 while (true) {
2430 struct samr_SamArray *sam_entries;
2431 uint32_t num_entries;
2433 status = dcerpc_samr_EnumDomainGroups(b, talloc_tos(),
2434 &domain_handle,
2435 &resume_handle,
2436 &sam_entries, 1,
2437 &num_entries,
2438 &result);
2439 if (!NT_STATUS_IS_OK(status)) {
2440 DEBUG(10, ("dcerpc_samr_EnumDomainGroups returned "
2441 "%s\n", nt_errstr(status)));
2442 break;
2444 if (!NT_STATUS_IS_OK(result)) {
2445 status = result;
2446 DEBUG(10, ("dcerpc_samr_EnumDomainGroups returned "
2447 "%s\n", nt_errstr(result)));
2448 break;
2451 if (num_entries == 0) {
2452 DEBUG(10, ("dcerpc_samr_EnumDomainGroups returned "
2453 "no entries -- done\n"));
2454 break;
2457 for(i=0; i<num_entries; i++) {
2458 const char *name;
2460 name = sam_entries->entries[i].name.string;
2462 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2463 /* set overflow error */
2464 DEBUG(3,("overflow on entry %d group %s\n", i,
2465 name));
2466 errflags=234;
2467 break;
2470 /* truncate the name at 21 chars. */
2471 memset(p, 0, 21);
2472 strlcpy(p, name, 21);
2473 DEBUG(10,("adding entry %d group %s\n", i, p));
2474 p += 21;
2475 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2476 * idea why... */
2477 num_groups += 1;
2480 if (errflags != NERR_Success) {
2481 break;
2484 TALLOC_FREE(sam_entries);
2487 dcerpc_samr_Close(b, talloc_tos(), &domain_handle, &result);
2488 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2490 *rdata_len = PTR_DIFF(p,*rdata);
2492 *rparam_len = 8;
2493 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2494 if (!*rparam) {
2495 return False;
2497 SSVAL(*rparam, 0, errflags);
2498 SSVAL(*rparam, 2, 0); /* converter word */
2499 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2500 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2502 return(True);
2505 /*******************************************************************
2506 Get groups that a user is a member of.
2507 ******************************************************************/
2509 static bool api_NetUserGetGroups(struct smbd_server_connection *sconn,
2510 connection_struct *conn,uint16 vuid,
2511 char *param, int tpscnt,
2512 char *data, int tdscnt,
2513 int mdrcnt,int mprcnt,
2514 char **rdata,char **rparam,
2515 int *rdata_len,int *rparam_len)
2517 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2518 char *str2 = skip_string(param,tpscnt,str1);
2519 char *UserName = skip_string(param,tpscnt,str2);
2520 char *p = skip_string(param,tpscnt,UserName);
2521 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2522 const char *level_string;
2523 int count=0;
2524 bool ret = False;
2525 uint32_t i;
2526 char *endp = NULL;
2528 struct rpc_pipe_client *samr_pipe;
2529 struct policy_handle samr_handle, domain_handle, user_handle;
2530 struct lsa_String name;
2531 struct lsa_Strings names;
2532 struct samr_Ids type, rid;
2533 struct samr_RidWithAttributeArray *rids;
2534 NTSTATUS status, result;
2535 struct dcerpc_binding_handle *b;
2537 if (!str1 || !str2 || !UserName || !p) {
2538 return False;
2541 *rparam_len = 8;
2542 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2543 if (!*rparam) {
2544 return False;
2547 /* check it's a supported varient */
2549 if ( strcmp(str1,"zWrLeh") != 0 )
2550 return False;
2552 switch( uLevel ) {
2553 case 0:
2554 level_string = "B21";
2555 break;
2556 default:
2557 return False;
2560 if (strcmp(level_string,str2) != 0)
2561 return False;
2563 *rdata_len = mdrcnt + 1024;
2564 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2565 if (!*rdata) {
2566 return False;
2569 SSVAL(*rparam,0,NERR_Success);
2570 SSVAL(*rparam,2,0); /* converter word */
2572 p = *rdata;
2573 endp = *rdata + *rdata_len;
2575 status = rpc_pipe_open_internal(
2576 talloc_tos(), &ndr_table_samr.syntax_id,
2577 conn->session_info, &conn->sconn->client_id,
2578 conn->sconn->msg_ctx, &samr_pipe);
2579 if (!NT_STATUS_IS_OK(status)) {
2580 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2581 nt_errstr(status)));
2582 return false;
2585 b = samr_pipe->binding_handle;
2587 status = dcerpc_samr_Connect2(b, talloc_tos(), global_myname(),
2588 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle,
2589 &result);
2590 if (!NT_STATUS_IS_OK(status)) {
2591 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2592 nt_errstr(status)));
2593 return false;
2595 if (!NT_STATUS_IS_OK(result)) {
2596 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2597 nt_errstr(result)));
2598 return false;
2601 status = dcerpc_samr_OpenDomain(b, talloc_tos(), &samr_handle,
2602 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2603 get_global_sam_sid(), &domain_handle,
2604 &result);
2605 if (!NT_STATUS_IS_OK(status)) {
2606 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2607 nt_errstr(status)));
2608 goto close_sam;
2610 if (!NT_STATUS_IS_OK(result)) {
2611 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2612 nt_errstr(result)));
2613 goto close_sam;
2616 name.string = UserName;
2618 status = dcerpc_samr_LookupNames(b, talloc_tos(),
2619 &domain_handle, 1, &name,
2620 &rid, &type,
2621 &result);
2622 if (!NT_STATUS_IS_OK(status)) {
2623 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2624 nt_errstr(status)));
2625 goto close_domain;
2627 if (!NT_STATUS_IS_OK(result)) {
2628 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2629 nt_errstr(result)));
2630 goto close_domain;
2633 if (type.ids[0] != SID_NAME_USER) {
2634 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2635 sid_type_lookup(type.ids[0])));
2636 goto close_domain;
2639 status = dcerpc_samr_OpenUser(b, talloc_tos(),
2640 &domain_handle,
2641 SAMR_USER_ACCESS_GET_GROUPS,
2642 rid.ids[0], &user_handle,
2643 &result);
2644 if (!NT_STATUS_IS_OK(status)) {
2645 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2646 nt_errstr(status)));
2647 goto close_domain;
2649 if (!NT_STATUS_IS_OK(result)) {
2650 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2651 nt_errstr(result)));
2652 goto close_domain;
2655 status = dcerpc_samr_GetGroupsForUser(b, talloc_tos(),
2656 &user_handle, &rids,
2657 &result);
2658 if (!NT_STATUS_IS_OK(status)) {
2659 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2660 nt_errstr(status)));
2661 goto close_user;
2663 if (!NT_STATUS_IS_OK(result)) {
2664 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2665 nt_errstr(result)));
2666 goto close_user;
2669 for (i=0; i<rids->count; i++) {
2671 status = dcerpc_samr_LookupRids(b, talloc_tos(),
2672 &domain_handle,
2673 1, &rids->rids[i].rid,
2674 &names, &type,
2675 &result);
2676 if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result) && (names.count == 1)) {
2677 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2678 p += 21;
2679 count++;
2683 *rdata_len = PTR_DIFF(p,*rdata);
2685 SSVAL(*rparam,4,count); /* is this right?? */
2686 SSVAL(*rparam,6,count); /* is this right?? */
2688 ret = True;
2690 close_user:
2691 dcerpc_samr_Close(b, talloc_tos(), &user_handle, &result);
2692 close_domain:
2693 dcerpc_samr_Close(b, talloc_tos(), &domain_handle, &result);
2694 close_sam:
2695 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2697 return ret;
2700 /*******************************************************************
2701 Get all users.
2702 ******************************************************************/
2704 static bool api_RNetUserEnum(struct smbd_server_connection *sconn,
2705 connection_struct *conn, uint16 vuid,
2706 char *param, int tpscnt,
2707 char *data, int tdscnt,
2708 int mdrcnt,int mprcnt,
2709 char **rdata,char **rparam,
2710 int *rdata_len,int *rparam_len)
2712 int count_sent=0;
2713 int num_users=0;
2714 int errflags=0;
2715 int i, resume_context, cli_buf_size;
2716 uint32_t resume_handle;
2718 struct rpc_pipe_client *samr_pipe;
2719 struct policy_handle samr_handle, domain_handle;
2720 NTSTATUS status, result;
2722 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2723 char *str2 = skip_string(param,tpscnt,str1);
2724 char *p = skip_string(param,tpscnt,str2);
2725 char *endp = NULL;
2727 struct dcerpc_binding_handle *b;
2729 if (!str1 || !str2 || !p) {
2730 return False;
2733 if (strcmp(str1,"WrLeh") != 0)
2734 return False;
2735 /* parameters
2736 * W-> resume context (number of users to skip)
2737 * r -> return parameter pointer to receive buffer
2738 * L -> length of receive buffer
2739 * e -> return parameter number of entries
2740 * h -> return parameter total number of users
2743 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2744 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2745 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2746 resume_context, cli_buf_size));
2748 *rparam_len = 8;
2749 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2750 if (!*rparam) {
2751 return False;
2754 /* check it's a supported varient */
2755 if (strcmp("B21",str2) != 0)
2756 return False;
2758 *rdata_len = cli_buf_size;
2759 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2760 if (!*rdata) {
2761 return False;
2764 p = *rdata;
2765 endp = *rdata + *rdata_len;
2767 status = rpc_pipe_open_internal(
2768 talloc_tos(), &ndr_table_samr.syntax_id,
2769 conn->session_info, &conn->sconn->client_id,
2770 conn->sconn->msg_ctx, &samr_pipe);
2771 if (!NT_STATUS_IS_OK(status)) {
2772 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2773 nt_errstr(status)));
2774 return false;
2777 b = samr_pipe->binding_handle;
2779 status = dcerpc_samr_Connect2(b, talloc_tos(), global_myname(),
2780 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle,
2781 &result);
2782 if (!NT_STATUS_IS_OK(status)) {
2783 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2784 nt_errstr(status)));
2785 return false;
2787 if (!NT_STATUS_IS_OK(result)) {
2788 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2789 nt_errstr(result)));
2790 return false;
2793 status = dcerpc_samr_OpenDomain(b, talloc_tos(), &samr_handle,
2794 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2795 get_global_sam_sid(), &domain_handle,
2796 &result);
2797 if (!NT_STATUS_IS_OK(status)) {
2798 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2799 nt_errstr(status)));
2800 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2801 return false;
2803 if (!NT_STATUS_IS_OK(result)) {
2804 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2805 nt_errstr(result)));
2806 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2807 return false;
2810 errflags=NERR_Success;
2812 resume_handle = 0;
2814 while (true) {
2815 struct samr_SamArray *sam_entries;
2816 uint32_t num_entries;
2818 status = dcerpc_samr_EnumDomainUsers(b, talloc_tos(),
2819 &domain_handle,
2820 &resume_handle,
2821 0, &sam_entries, 1,
2822 &num_entries,
2823 &result);
2825 if (!NT_STATUS_IS_OK(status)) {
2826 DEBUG(10, ("dcerpc_samr_EnumDomainUsers returned "
2827 "%s\n", nt_errstr(status)));
2828 break;
2830 if (!NT_STATUS_IS_OK(result)) {
2831 DEBUG(10, ("dcerpc_samr_EnumDomainUsers returned "
2832 "%s\n", nt_errstr(result)));
2833 break;
2836 if (num_entries == 0) {
2837 DEBUG(10, ("dcerpc_samr_EnumDomainUsers returned "
2838 "no entries -- done\n"));
2839 break;
2842 for (i=0; i<num_entries; i++) {
2843 const char *name;
2845 name = sam_entries->entries[i].name.string;
2847 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2848 &&(strlen(name)<=21)) {
2849 strlcpy(p,name,PTR_DIFF(endp,p));
2850 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2851 "username %s\n",count_sent,p));
2852 p += 21;
2853 count_sent++;
2854 } else {
2855 /* set overflow error */
2856 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2857 "username %s\n",count_sent,name));
2858 errflags=234;
2859 break;
2863 if (errflags != NERR_Success) {
2864 break;
2867 TALLOC_FREE(sam_entries);
2870 dcerpc_samr_Close(b, talloc_tos(), &domain_handle, &result);
2871 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2873 *rdata_len = PTR_DIFF(p,*rdata);
2875 SSVAL(*rparam,0,errflags);
2876 SSVAL(*rparam,2,0); /* converter word */
2877 SSVAL(*rparam,4,count_sent); /* is this right?? */
2878 SSVAL(*rparam,6,num_users); /* is this right?? */
2880 return True;
2883 /****************************************************************************
2884 Get the time of day info.
2885 ****************************************************************************/
2887 static bool api_NetRemoteTOD(struct smbd_server_connection *sconn,
2888 connection_struct *conn,uint16 vuid,
2889 char *param, int tpscnt,
2890 char *data, int tdscnt,
2891 int mdrcnt,int mprcnt,
2892 char **rdata,char **rparam,
2893 int *rdata_len,int *rparam_len)
2895 struct tm *t;
2896 time_t unixdate = time(NULL);
2897 char *p;
2899 *rparam_len = 4;
2900 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2901 if (!*rparam) {
2902 return False;
2905 *rdata_len = 21;
2906 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2907 if (!*rdata) {
2908 return False;
2911 SSVAL(*rparam,0,NERR_Success);
2912 SSVAL(*rparam,2,0); /* converter word */
2914 p = *rdata;
2916 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2917 by NT in a "net time" operation,
2918 it seems to ignore the one below */
2920 /* the client expects to get localtime, not GMT, in this bit
2921 (I think, this needs testing) */
2922 t = localtime(&unixdate);
2923 if (!t) {
2924 return False;
2927 SIVAL(p,4,0); /* msecs ? */
2928 SCVAL(p,8,t->tm_hour);
2929 SCVAL(p,9,t->tm_min);
2930 SCVAL(p,10,t->tm_sec);
2931 SCVAL(p,11,0); /* hundredths of seconds */
2932 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2933 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2934 SCVAL(p,16,t->tm_mday);
2935 SCVAL(p,17,t->tm_mon + 1);
2936 SSVAL(p,18,1900+t->tm_year);
2937 SCVAL(p,20,t->tm_wday);
2939 return True;
2942 /****************************************************************************
2943 Set the user password.
2944 *****************************************************************************/
2946 static bool api_SetUserPassword(struct smbd_server_connection *sconn,
2947 connection_struct *conn,uint16 vuid,
2948 char *param, int tpscnt,
2949 char *data, int tdscnt,
2950 int mdrcnt,int mprcnt,
2951 char **rdata,char **rparam,
2952 int *rdata_len,int *rparam_len)
2954 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2955 char *p = NULL;
2956 fstring user;
2957 fstring pass1,pass2;
2958 TALLOC_CTX *mem_ctx = talloc_tos();
2959 NTSTATUS status, result;
2960 struct rpc_pipe_client *cli = NULL;
2961 struct policy_handle connect_handle, domain_handle, user_handle;
2962 struct lsa_String domain_name;
2963 struct dom_sid2 *domain_sid;
2964 struct lsa_String names;
2965 struct samr_Ids rids;
2966 struct samr_Ids types;
2967 struct samr_Password old_lm_hash;
2968 struct samr_Password new_lm_hash;
2969 int errcode = NERR_badpass;
2970 uint32_t rid;
2971 int encrypted;
2972 int min_pwd_length;
2973 struct dcerpc_binding_handle *b = NULL;
2975 /* Skip 2 strings. */
2976 p = skip_string(param,tpscnt,np);
2977 p = skip_string(param,tpscnt,p);
2979 if (!np || !p) {
2980 return False;
2983 /* Do we have a string ? */
2984 if (skip_string(param,tpscnt,p) == NULL) {
2985 return False;
2987 pull_ascii_fstring(user,p);
2989 p = skip_string(param,tpscnt,p);
2990 if (!p) {
2991 return False;
2994 memset(pass1,'\0',sizeof(pass1));
2995 memset(pass2,'\0',sizeof(pass2));
2997 * We use 31 here not 32 as we're checking
2998 * the last byte we want to access is safe.
3000 if (!is_offset_safe(param,tpscnt,p,31)) {
3001 return False;
3003 memcpy(pass1,p,16);
3004 memcpy(pass2,p+16,16);
3006 encrypted = get_safe_SVAL(param,tpscnt,p+32,0,-1);
3007 if (encrypted == -1) {
3008 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3009 goto out;
3012 min_pwd_length = get_safe_SVAL(param,tpscnt,p+34,0,-1);
3013 if (min_pwd_length == -1) {
3014 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3015 goto out;
3018 *rparam_len = 4;
3019 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3020 if (!*rparam) {
3021 return False;
3024 *rdata_len = 0;
3026 DEBUG(3,("Set password for <%s> (encrypted: %d, min_pwd_length: %d)\n",
3027 user, encrypted, min_pwd_length));
3029 ZERO_STRUCT(connect_handle);
3030 ZERO_STRUCT(domain_handle);
3031 ZERO_STRUCT(user_handle);
3033 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_samr.syntax_id,
3034 conn->session_info,
3035 &conn->sconn->client_id,
3036 conn->sconn->msg_ctx,
3037 &cli);
3038 if (!NT_STATUS_IS_OK(status)) {
3039 DEBUG(0,("api_SetUserPassword: could not connect to samr: %s\n",
3040 nt_errstr(status)));
3041 errcode = W_ERROR_V(ntstatus_to_werror(status));
3042 goto out;
3045 b = cli->binding_handle;
3047 status = dcerpc_samr_Connect2(b, mem_ctx,
3048 global_myname(),
3049 SAMR_ACCESS_CONNECT_TO_SERVER |
3050 SAMR_ACCESS_ENUM_DOMAINS |
3051 SAMR_ACCESS_LOOKUP_DOMAIN,
3052 &connect_handle,
3053 &result);
3054 if (!NT_STATUS_IS_OK(status)) {
3055 errcode = W_ERROR_V(ntstatus_to_werror(status));
3056 goto out;
3058 if (!NT_STATUS_IS_OK(result)) {
3059 errcode = W_ERROR_V(ntstatus_to_werror(result));
3060 goto out;
3063 init_lsa_String(&domain_name, get_global_sam_name());
3065 status = dcerpc_samr_LookupDomain(b, mem_ctx,
3066 &connect_handle,
3067 &domain_name,
3068 &domain_sid,
3069 &result);
3070 if (!NT_STATUS_IS_OK(status)) {
3071 errcode = W_ERROR_V(ntstatus_to_werror(status));
3072 goto out;
3074 if (!NT_STATUS_IS_OK(result)) {
3075 errcode = W_ERROR_V(ntstatus_to_werror(result));
3076 goto out;
3079 status = dcerpc_samr_OpenDomain(b, mem_ctx,
3080 &connect_handle,
3081 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
3082 domain_sid,
3083 &domain_handle,
3084 &result);
3085 if (!NT_STATUS_IS_OK(status)) {
3086 errcode = W_ERROR_V(ntstatus_to_werror(status));
3087 goto out;
3089 if (!NT_STATUS_IS_OK(result)) {
3090 errcode = W_ERROR_V(ntstatus_to_werror(result));
3091 goto out;
3094 init_lsa_String(&names, user);
3096 status = dcerpc_samr_LookupNames(b, mem_ctx,
3097 &domain_handle,
3099 &names,
3100 &rids,
3101 &types,
3102 &result);
3103 if (!NT_STATUS_IS_OK(status)) {
3104 errcode = W_ERROR_V(ntstatus_to_werror(status));
3105 goto out;
3107 if (!NT_STATUS_IS_OK(result)) {
3108 errcode = W_ERROR_V(ntstatus_to_werror(result));
3109 goto out;
3112 if (rids.count != 1) {
3113 errcode = W_ERROR_V(WERR_NO_SUCH_USER);
3114 goto out;
3116 if (rids.count != types.count) {
3117 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3118 goto out;
3120 if (types.ids[0] != SID_NAME_USER) {
3121 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3122 goto out;
3125 rid = rids.ids[0];
3127 status = dcerpc_samr_OpenUser(b, mem_ctx,
3128 &domain_handle,
3129 SAMR_USER_ACCESS_CHANGE_PASSWORD,
3130 rid,
3131 &user_handle,
3132 &result);
3133 if (!NT_STATUS_IS_OK(status)) {
3134 errcode = W_ERROR_V(ntstatus_to_werror(status));
3135 goto out;
3137 if (!NT_STATUS_IS_OK(result)) {
3138 errcode = W_ERROR_V(ntstatus_to_werror(result));
3139 goto out;
3142 if (encrypted == 0) {
3143 E_deshash(pass1, old_lm_hash.hash);
3144 E_deshash(pass2, new_lm_hash.hash);
3145 } else {
3146 ZERO_STRUCT(old_lm_hash);
3147 ZERO_STRUCT(new_lm_hash);
3148 memcpy(old_lm_hash.hash, pass1, MIN(strlen(pass1), 16));
3149 memcpy(new_lm_hash.hash, pass1, MIN(strlen(pass2), 16));
3152 status = dcerpc_samr_ChangePasswordUser(b, mem_ctx,
3153 &user_handle,
3154 true, /* lm_present */
3155 &old_lm_hash,
3156 &new_lm_hash,
3157 false, /* nt_present */
3158 NULL, /* old_nt_crypted */
3159 NULL, /* new_nt_crypted */
3160 false, /* cross1_present */
3161 NULL, /* nt_cross */
3162 false, /* cross2_present */
3163 NULL, /* lm_cross */
3164 &result);
3165 if (!NT_STATUS_IS_OK(status)) {
3166 errcode = W_ERROR_V(ntstatus_to_werror(status));
3167 goto out;
3169 if (!NT_STATUS_IS_OK(result)) {
3170 errcode = W_ERROR_V(ntstatus_to_werror(result));
3171 goto out;
3174 errcode = NERR_Success;
3175 out:
3177 if (b && is_valid_policy_hnd(&user_handle)) {
3178 dcerpc_samr_Close(b, mem_ctx, &user_handle, &result);
3180 if (b && is_valid_policy_hnd(&domain_handle)) {
3181 dcerpc_samr_Close(b, mem_ctx, &domain_handle, &result);
3183 if (b && is_valid_policy_hnd(&connect_handle)) {
3184 dcerpc_samr_Close(b, mem_ctx, &connect_handle, &result);
3187 memset((char *)pass1,'\0',sizeof(fstring));
3188 memset((char *)pass2,'\0',sizeof(fstring));
3190 SSVAL(*rparam,0,errcode);
3191 SSVAL(*rparam,2,0); /* converter word */
3192 return(True);
3195 /****************************************************************************
3196 Set the user password (SamOEM version - gets plaintext).
3197 ****************************************************************************/
3199 static bool api_SamOEMChangePassword(struct smbd_server_connection *sconn,
3200 connection_struct *conn,uint16 vuid,
3201 char *param, int tpscnt,
3202 char *data, int tdscnt,
3203 int mdrcnt,int mprcnt,
3204 char **rdata,char **rparam,
3205 int *rdata_len,int *rparam_len)
3207 fstring user;
3208 char *p = get_safe_str_ptr(param,tpscnt,param,2);
3210 TALLOC_CTX *mem_ctx = talloc_tos();
3211 NTSTATUS status, result;
3212 struct rpc_pipe_client *cli = NULL;
3213 struct lsa_AsciiString server, account;
3214 struct samr_CryptPassword password;
3215 struct samr_Password hash;
3216 int errcode = NERR_badpass;
3217 int bufsize;
3218 struct dcerpc_binding_handle *b;
3220 *rparam_len = 4;
3221 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3222 if (!*rparam) {
3223 return False;
3226 if (!p) {
3227 return False;
3229 *rdata_len = 0;
3231 SSVAL(*rparam,0,NERR_badpass);
3234 * Check the parameter definition is correct.
3237 /* Do we have a string ? */
3238 if (skip_string(param,tpscnt,p) == 0) {
3239 return False;
3241 if(!strequal(p, "zsT")) {
3242 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
3243 return False;
3245 p = skip_string(param, tpscnt, p);
3246 if (!p) {
3247 return False;
3250 /* Do we have a string ? */
3251 if (skip_string(param,tpscnt,p) == 0) {
3252 return False;
3254 if(!strequal(p, "B516B16")) {
3255 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
3256 return False;
3258 p = skip_string(param,tpscnt,p);
3259 if (!p) {
3260 return False;
3262 /* Do we have a string ? */
3263 if (skip_string(param,tpscnt,p) == 0) {
3264 return False;
3266 p += pull_ascii_fstring(user,p);
3268 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
3270 if (tdscnt != 532) {
3271 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3272 goto out;
3275 bufsize = get_safe_SVAL(param,tpscnt,p,0,-1);
3276 if (bufsize != 532) {
3277 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3278 goto out;
3281 memcpy(password.data, data, 516);
3282 memcpy(hash.hash, data+516, 16);
3284 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_samr.syntax_id,
3285 conn->session_info,
3286 &conn->sconn->client_id,
3287 conn->sconn->msg_ctx,
3288 &cli);
3289 if (!NT_STATUS_IS_OK(status)) {
3290 DEBUG(0,("api_SamOEMChangePassword: could not connect to samr: %s\n",
3291 nt_errstr(status)));
3292 errcode = W_ERROR_V(ntstatus_to_werror(status));
3293 goto out;
3296 b = cli->binding_handle;
3298 init_lsa_AsciiString(&server, global_myname());
3299 init_lsa_AsciiString(&account, user);
3301 status = dcerpc_samr_OemChangePasswordUser2(b, mem_ctx,
3302 &server,
3303 &account,
3304 &password,
3305 &hash,
3306 &result);
3307 if (!NT_STATUS_IS_OK(status)) {
3308 errcode = W_ERROR_V(ntstatus_to_werror(status));
3309 goto out;
3311 if (!NT_STATUS_IS_OK(result)) {
3312 errcode = W_ERROR_V(ntstatus_to_werror(result));
3313 goto out;
3316 errcode = NERR_Success;
3317 out:
3318 SSVAL(*rparam,0,errcode);
3319 SSVAL(*rparam,2,0); /* converter word */
3321 return(True);
3324 /****************************************************************************
3325 delete a print job
3326 Form: <W> <>
3327 ****************************************************************************/
3329 static bool api_RDosPrintJobDel(struct smbd_server_connection *sconn,
3330 connection_struct *conn,uint16 vuid,
3331 char *param, int tpscnt,
3332 char *data, int tdscnt,
3333 int mdrcnt,int mprcnt,
3334 char **rdata,char **rparam,
3335 int *rdata_len,int *rparam_len)
3337 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3338 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3339 char *str2 = skip_string(param,tpscnt,str1);
3340 char *p = skip_string(param,tpscnt,str2);
3341 uint32 jobid;
3342 fstring sharename;
3343 int errcode;
3344 WERROR werr = WERR_OK;
3346 TALLOC_CTX *mem_ctx = talloc_tos();
3347 NTSTATUS status;
3348 struct rpc_pipe_client *cli = NULL;
3349 struct dcerpc_binding_handle *b = NULL;
3350 struct policy_handle handle;
3351 struct spoolss_DevmodeContainer devmode_ctr;
3352 enum spoolss_JobControl command;
3354 if (!str1 || !str2 || !p) {
3355 return False;
3358 * We use 1 here not 2 as we're checking
3359 * the last byte we want to access is safe.
3361 if (!is_offset_safe(param,tpscnt,p,1)) {
3362 return False;
3364 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3365 return False;
3367 /* check it's a supported varient */
3368 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
3369 return(False);
3371 *rparam_len = 4;
3372 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3373 if (!*rparam) {
3374 return False;
3376 *rdata_len = 0;
3378 ZERO_STRUCT(handle);
3380 status = rpc_pipe_open_interface(conn,
3381 &ndr_table_spoolss.syntax_id,
3382 conn->session_info,
3383 &conn->sconn->client_id,
3384 conn->sconn->msg_ctx,
3385 &cli);
3386 if (!NT_STATUS_IS_OK(status)) {
3387 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
3388 nt_errstr(status)));
3389 errcode = W_ERROR_V(ntstatus_to_werror(status));
3390 goto out;
3392 b = cli->binding_handle;
3394 ZERO_STRUCT(devmode_ctr);
3396 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
3397 sharename,
3398 "RAW",
3399 devmode_ctr,
3400 JOB_ACCESS_ADMINISTER,
3401 &handle,
3402 &werr);
3403 if (!NT_STATUS_IS_OK(status)) {
3404 errcode = W_ERROR_V(ntstatus_to_werror(status));
3405 goto out;
3407 if (!W_ERROR_IS_OK(werr)) {
3408 errcode = W_ERROR_V(werr);
3409 goto out;
3412 /* FIXME: formerly NERR_JobNotFound was returned if job did not exist
3413 * and NERR_DestNotFound if share did not exist */
3415 errcode = NERR_Success;
3417 switch (function) {
3418 case 81: /* delete */
3419 command = SPOOLSS_JOB_CONTROL_DELETE;
3420 break;
3421 case 82: /* pause */
3422 command = SPOOLSS_JOB_CONTROL_PAUSE;
3423 break;
3424 case 83: /* resume */
3425 command = SPOOLSS_JOB_CONTROL_RESUME;
3426 break;
3427 default:
3428 errcode = NERR_notsupported;
3429 goto out;
3432 status = dcerpc_spoolss_SetJob(b, mem_ctx,
3433 &handle,
3434 jobid,
3435 NULL, /* unique ptr ctr */
3436 command,
3437 &werr);
3438 if (!NT_STATUS_IS_OK(status)) {
3439 errcode = W_ERROR_V(ntstatus_to_werror(status));
3440 goto out;
3442 if (!W_ERROR_IS_OK(werr)) {
3443 errcode = W_ERROR_V(werr);
3444 goto out;
3447 out:
3448 if (b && is_valid_policy_hnd(&handle)) {
3449 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
3452 SSVAL(*rparam,0,errcode);
3453 SSVAL(*rparam,2,0); /* converter word */
3455 return(True);
3458 /****************************************************************************
3459 Purge a print queue - or pause or resume it.
3460 ****************************************************************************/
3462 static bool api_WPrintQueueCtrl(struct smbd_server_connection *sconn,
3463 connection_struct *conn,uint16 vuid,
3464 char *param, int tpscnt,
3465 char *data, int tdscnt,
3466 int mdrcnt,int mprcnt,
3467 char **rdata,char **rparam,
3468 int *rdata_len,int *rparam_len)
3470 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3471 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3472 char *str2 = skip_string(param,tpscnt,str1);
3473 char *QueueName = skip_string(param,tpscnt,str2);
3474 int errcode = NERR_notsupported;
3475 WERROR werr = WERR_OK;
3476 NTSTATUS status;
3478 TALLOC_CTX *mem_ctx = talloc_tos();
3479 struct rpc_pipe_client *cli = NULL;
3480 struct dcerpc_binding_handle *b = NULL;
3481 struct policy_handle handle;
3482 struct spoolss_SetPrinterInfoCtr info_ctr;
3483 struct spoolss_DevmodeContainer devmode_ctr;
3484 struct sec_desc_buf secdesc_ctr;
3485 enum spoolss_PrinterControl command;
3487 if (!str1 || !str2 || !QueueName) {
3488 return False;
3491 /* check it's a supported varient */
3492 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3493 return(False);
3495 *rparam_len = 4;
3496 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3497 if (!*rparam) {
3498 return False;
3500 *rdata_len = 0;
3502 if (skip_string(param,tpscnt,QueueName) == NULL) {
3503 return False;
3506 ZERO_STRUCT(handle);
3508 status = rpc_pipe_open_interface(conn,
3509 &ndr_table_spoolss.syntax_id,
3510 conn->session_info,
3511 &conn->sconn->client_id,
3512 conn->sconn->msg_ctx,
3513 &cli);
3514 if (!NT_STATUS_IS_OK(status)) {
3515 DEBUG(0,("api_WPrintQueueCtrl: could not connect to spoolss: %s\n",
3516 nt_errstr(status)));
3517 errcode = W_ERROR_V(ntstatus_to_werror(status));
3518 goto out;
3520 b = cli->binding_handle;
3522 ZERO_STRUCT(devmode_ctr);
3524 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
3525 QueueName,
3526 NULL,
3527 devmode_ctr,
3528 SEC_FLAG_MAXIMUM_ALLOWED,
3529 &handle,
3530 &werr);
3531 if (!NT_STATUS_IS_OK(status)) {
3532 errcode = W_ERROR_V(ntstatus_to_werror(status));
3533 goto out;
3535 if (!W_ERROR_IS_OK(werr)) {
3536 errcode = W_ERROR_V(werr);
3537 goto out;
3540 switch (function) {
3541 case 74: /* Pause queue */
3542 command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3543 break;
3544 case 75: /* Resume queue */
3545 command = SPOOLSS_PRINTER_CONTROL_RESUME;
3546 break;
3547 case 103: /* Purge */
3548 command = SPOOLSS_PRINTER_CONTROL_PURGE;
3549 break;
3550 default:
3551 werr = WERR_NOT_SUPPORTED;
3552 break;
3555 if (!W_ERROR_IS_OK(werr)) {
3556 errcode = W_ERROR_V(werr);
3557 goto out;
3560 ZERO_STRUCT(info_ctr);
3561 ZERO_STRUCT(secdesc_ctr);
3563 status = dcerpc_spoolss_SetPrinter(b, mem_ctx,
3564 &handle,
3565 &info_ctr,
3566 &devmode_ctr,
3567 &secdesc_ctr,
3568 command,
3569 &werr);
3570 if (!NT_STATUS_IS_OK(status)) {
3571 errcode = W_ERROR_V(ntstatus_to_werror(status));
3572 goto out;
3574 if (!W_ERROR_IS_OK(werr)) {
3575 errcode = W_ERROR_V(werr);
3576 goto out;
3579 errcode = W_ERROR_V(werr);
3581 out:
3583 if (b && is_valid_policy_hnd(&handle)) {
3584 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
3587 SSVAL(*rparam,0,errcode);
3588 SSVAL(*rparam,2,0); /* converter word */
3590 return(True);
3593 /****************************************************************************
3594 set the property of a print job (undocumented?)
3595 ? function = 0xb -> set name of print job
3596 ? function = 0x6 -> move print job up/down
3597 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3598 or <WWsTP> <WB21BB16B10zWWzDDz>
3599 ****************************************************************************/
3601 static int check_printjob_info(struct pack_desc* desc,
3602 int uLevel, char* id)
3604 desc->subformat = NULL;
3605 switch( uLevel ) {
3606 case 0: desc->format = "W"; break;
3607 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3608 case 2: desc->format = "WWzWWDDzz"; break;
3609 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3610 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3611 default:
3612 DEBUG(0,("check_printjob_info: invalid level %d\n",
3613 uLevel ));
3614 return False;
3616 if (id == NULL || strcmp(desc->format,id) != 0) {
3617 DEBUG(0,("check_printjob_info: invalid format %s\n",
3618 id ? id : "<NULL>" ));
3619 return False;
3621 return True;
3624 static bool api_PrintJobInfo(struct smbd_server_connection *sconn,
3625 connection_struct *conn, uint16 vuid,
3626 char *param, int tpscnt,
3627 char *data, int tdscnt,
3628 int mdrcnt,int mprcnt,
3629 char **rdata,char **rparam,
3630 int *rdata_len,int *rparam_len)
3632 struct pack_desc desc;
3633 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3634 char *str2 = skip_string(param,tpscnt,str1);
3635 char *p = skip_string(param,tpscnt,str2);
3636 uint32 jobid;
3637 fstring sharename;
3638 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3639 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3640 int errcode;
3642 TALLOC_CTX *mem_ctx = talloc_tos();
3643 WERROR werr;
3644 NTSTATUS status;
3645 struct rpc_pipe_client *cli = NULL;
3646 struct dcerpc_binding_handle *b = NULL;
3647 struct policy_handle handle;
3648 struct spoolss_DevmodeContainer devmode_ctr;
3649 struct spoolss_JobInfoContainer ctr;
3650 union spoolss_JobInfo info;
3651 struct spoolss_SetJobInfo1 info1;
3653 if (!str1 || !str2 || !p) {
3654 return False;
3657 * We use 1 here not 2 as we're checking
3658 * the last byte we want to access is safe.
3660 if (!is_offset_safe(param,tpscnt,p,1)) {
3661 return False;
3663 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3664 return False;
3665 *rparam_len = 4;
3666 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3667 if (!*rparam) {
3668 return False;
3671 *rdata_len = 0;
3673 /* check it's a supported varient */
3674 if ((strcmp(str1,"WWsTP")) ||
3675 (!check_printjob_info(&desc,uLevel,str2)))
3676 return(False);
3678 errcode = NERR_notsupported;
3680 switch (function) {
3681 case 0xb:
3682 /* change print job name, data gives the name */
3683 break;
3684 default:
3685 goto out;
3688 ZERO_STRUCT(handle);
3690 status = rpc_pipe_open_interface(conn,
3691 &ndr_table_spoolss.syntax_id,
3692 conn->session_info,
3693 &conn->sconn->client_id,
3694 conn->sconn->msg_ctx,
3695 &cli);
3696 if (!NT_STATUS_IS_OK(status)) {
3697 DEBUG(0,("api_PrintJobInfo: could not connect to spoolss: %s\n",
3698 nt_errstr(status)));
3699 errcode = W_ERROR_V(ntstatus_to_werror(status));
3700 goto out;
3702 b = cli->binding_handle;
3704 ZERO_STRUCT(devmode_ctr);
3706 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
3707 sharename,
3708 "RAW",
3709 devmode_ctr,
3710 PRINTER_ACCESS_USE,
3711 &handle,
3712 &werr);
3713 if (!NT_STATUS_IS_OK(status)) {
3714 errcode = W_ERROR_V(ntstatus_to_werror(status));
3715 goto out;
3717 if (!W_ERROR_IS_OK(werr)) {
3718 errcode = W_ERROR_V(werr);
3719 goto out;
3722 werr = rpccli_spoolss_getjob(cli, mem_ctx,
3723 &handle,
3724 jobid,
3725 1, /* level */
3726 0, /* offered */
3727 &info);
3728 if (!W_ERROR_IS_OK(werr)) {
3729 errcode = W_ERROR_V(werr);
3730 goto out;
3733 ZERO_STRUCT(ctr);
3735 info1.job_id = info.info1.job_id;
3736 info1.printer_name = info.info1.printer_name;
3737 info1.user_name = info.info1.user_name;
3738 info1.document_name = data;
3739 info1.data_type = info.info1.data_type;
3740 info1.text_status = info.info1.text_status;
3741 info1.status = info.info1.status;
3742 info1.priority = info.info1.priority;
3743 info1.position = info.info1.position;
3744 info1.total_pages = info.info1.total_pages;
3745 info1.pages_printed = info.info1.pages_printed;
3746 info1.submitted = info.info1.submitted;
3748 ctr.level = 1;
3749 ctr.info.info1 = &info1;
3751 status = dcerpc_spoolss_SetJob(b, mem_ctx,
3752 &handle,
3753 jobid,
3754 &ctr,
3756 &werr);
3757 if (!NT_STATUS_IS_OK(status)) {
3758 errcode = W_ERROR_V(ntstatus_to_werror(status));
3759 goto out;
3761 if (!W_ERROR_IS_OK(werr)) {
3762 errcode = W_ERROR_V(werr);
3763 goto out;
3766 errcode = NERR_Success;
3767 out:
3769 if (b && is_valid_policy_hnd(&handle)) {
3770 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
3773 SSVALS(*rparam,0,errcode);
3774 SSVAL(*rparam,2,0); /* converter word */
3776 return(True);
3780 /****************************************************************************
3781 Get info about the server.
3782 ****************************************************************************/
3784 static bool api_RNetServerGetInfo(struct smbd_server_connection *sconn,
3785 connection_struct *conn,uint16 vuid,
3786 char *param, int tpscnt,
3787 char *data, int tdscnt,
3788 int mdrcnt,int mprcnt,
3789 char **rdata,char **rparam,
3790 int *rdata_len,int *rparam_len)
3792 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3793 char *str2 = skip_string(param,tpscnt,str1);
3794 char *p = skip_string(param,tpscnt,str2);
3795 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3796 char *p2;
3797 int struct_len;
3799 NTSTATUS status;
3800 WERROR werr;
3801 TALLOC_CTX *mem_ctx = talloc_tos();
3802 struct rpc_pipe_client *cli = NULL;
3803 union srvsvc_NetSrvInfo info;
3804 int errcode;
3805 struct dcerpc_binding_handle *b;
3807 if (!str1 || !str2 || !p) {
3808 return False;
3811 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3813 /* check it's a supported varient */
3814 if (!prefix_ok(str1,"WrLh")) {
3815 return False;
3818 switch( uLevel ) {
3819 case 0:
3820 if (strcmp(str2,"B16") != 0) {
3821 return False;
3823 struct_len = 16;
3824 break;
3825 case 1:
3826 if (strcmp(str2,"B16BBDz") != 0) {
3827 return False;
3829 struct_len = 26;
3830 break;
3831 case 2:
3832 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3833 return False;
3835 struct_len = 134;
3836 break;
3837 case 3:
3838 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3839 return False;
3841 struct_len = 144;
3842 break;
3843 case 20:
3844 if (strcmp(str2,"DN") != 0) {
3845 return False;
3847 struct_len = 6;
3848 break;
3849 case 50:
3850 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3851 return False;
3853 struct_len = 42;
3854 break;
3855 default:
3856 return False;
3859 *rdata_len = mdrcnt;
3860 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3861 if (!*rdata) {
3862 return False;
3865 p = *rdata;
3866 p2 = p + struct_len;
3868 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_srvsvc.syntax_id,
3869 conn->session_info,
3870 &conn->sconn->client_id,
3871 conn->sconn->msg_ctx,
3872 &cli);
3873 if (!NT_STATUS_IS_OK(status)) {
3874 DEBUG(0,("api_RNetServerGetInfo: could not connect to srvsvc: %s\n",
3875 nt_errstr(status)));
3876 errcode = W_ERROR_V(ntstatus_to_werror(status));
3877 goto out;
3880 b = cli->binding_handle;
3882 status = dcerpc_srvsvc_NetSrvGetInfo(b, mem_ctx,
3883 NULL,
3884 101,
3885 &info,
3886 &werr);
3887 if (!NT_STATUS_IS_OK(status)) {
3888 errcode = W_ERROR_V(ntstatus_to_werror(status));
3889 goto out;
3891 if (!W_ERROR_IS_OK(werr)) {
3892 errcode = W_ERROR_V(werr);
3893 goto out;
3896 if (info.info101 == NULL) {
3897 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3898 goto out;
3901 if (uLevel != 20) {
3902 srvstr_push(NULL, 0, p, info.info101->server_name, 16,
3903 STR_ASCII|STR_UPPER|STR_TERMINATE);
3905 p += 16;
3906 if (uLevel > 0) {
3907 SCVAL(p,0,info.info101->version_major);
3908 SCVAL(p,1,info.info101->version_minor);
3909 SIVAL(p,2,info.info101->server_type);
3911 if (mdrcnt == struct_len) {
3912 SIVAL(p,6,0);
3913 } else {
3914 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3915 if (mdrcnt - struct_len <= 0) {
3916 return false;
3918 push_ascii(p2,
3919 info.info101->comment,
3920 MIN(mdrcnt - struct_len,
3921 MAX_SERVER_STRING_LENGTH),
3922 STR_TERMINATE);
3923 p2 = skip_string(*rdata,*rdata_len,p2);
3924 if (!p2) {
3925 return False;
3930 if (uLevel > 1) {
3931 return False; /* not yet implemented */
3934 errcode = NERR_Success;
3936 out:
3938 *rdata_len = PTR_DIFF(p2,*rdata);
3940 *rparam_len = 6;
3941 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3942 if (!*rparam) {
3943 return False;
3945 SSVAL(*rparam,0,errcode);
3946 SSVAL(*rparam,2,0); /* converter word */
3947 SSVAL(*rparam,4,*rdata_len);
3949 return True;
3952 /****************************************************************************
3953 Get info about the server.
3954 ****************************************************************************/
3956 static bool api_NetWkstaGetInfo(struct smbd_server_connection *sconn,
3957 connection_struct *conn,uint16 vuid,
3958 char *param, int tpscnt,
3959 char *data, int tdscnt,
3960 int mdrcnt,int mprcnt,
3961 char **rdata,char **rparam,
3962 int *rdata_len,int *rparam_len)
3964 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3965 char *str2 = skip_string(param,tpscnt,str1);
3966 char *p = skip_string(param,tpscnt,str2);
3967 char *p2;
3968 char *endp;
3969 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3971 if (!str1 || !str2 || !p) {
3972 return False;
3975 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3977 *rparam_len = 6;
3978 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3979 if (!*rparam) {
3980 return False;
3983 /* check it's a supported varient */
3984 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3985 return False;
3988 *rdata_len = mdrcnt + 1024;
3989 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3990 if (!*rdata) {
3991 return False;
3994 SSVAL(*rparam,0,NERR_Success);
3995 SSVAL(*rparam,2,0); /* converter word */
3997 p = *rdata;
3998 endp = *rdata + *rdata_len;
4000 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
4001 if (!p2) {
4002 return False;
4005 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
4006 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
4007 strupper_m(p2);
4008 p2 = skip_string(*rdata,*rdata_len,p2);
4009 if (!p2) {
4010 return False;
4012 p += 4;
4014 SIVAL(p,0,PTR_DIFF(p2,*rdata));
4015 strlcpy(p2,conn->session_info->sanitized_username,PTR_DIFF(endp,p2));
4016 p2 = skip_string(*rdata,*rdata_len,p2);
4017 if (!p2) {
4018 return False;
4020 p += 4;
4022 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
4023 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
4024 strupper_m(p2);
4025 p2 = skip_string(*rdata,*rdata_len,p2);
4026 if (!p2) {
4027 return False;
4029 p += 4;
4031 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
4032 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
4033 p += 2;
4035 SIVAL(p,0,PTR_DIFF(p2,*rdata));
4036 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
4037 p2 = skip_string(*rdata,*rdata_len,p2);
4038 if (!p2) {
4039 return False;
4041 p += 4;
4043 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
4044 strlcpy(p2,"",PTR_DIFF(endp,p2));
4045 p2 = skip_string(*rdata,*rdata_len,p2);
4046 if (!p2) {
4047 return False;
4049 p += 4;
4051 *rdata_len = PTR_DIFF(p2,*rdata);
4053 SSVAL(*rparam,4,*rdata_len);
4055 return True;
4058 /****************************************************************************
4059 get info about a user
4061 struct user_info_11 {
4062 char usri11_name[21]; 0-20
4063 char usri11_pad; 21
4064 char *usri11_comment; 22-25
4065 char *usri11_usr_comment; 26-29
4066 unsigned short usri11_priv; 30-31
4067 unsigned long usri11_auth_flags; 32-35
4068 long usri11_password_age; 36-39
4069 char *usri11_homedir; 40-43
4070 char *usri11_parms; 44-47
4071 long usri11_last_logon; 48-51
4072 long usri11_last_logoff; 52-55
4073 unsigned short usri11_bad_pw_count; 56-57
4074 unsigned short usri11_num_logons; 58-59
4075 char *usri11_logon_server; 60-63
4076 unsigned short usri11_country_code; 64-65
4077 char *usri11_workstations; 66-69
4078 unsigned long usri11_max_storage; 70-73
4079 unsigned short usri11_units_per_week; 74-75
4080 unsigned char *usri11_logon_hours; 76-79
4081 unsigned short usri11_code_page; 80-81
4084 where:
4086 usri11_name specifies the user name for which information is retrieved
4088 usri11_pad aligns the next data structure element to a word boundary
4090 usri11_comment is a null terminated ASCII comment
4092 usri11_user_comment is a null terminated ASCII comment about the user
4094 usri11_priv specifies the level of the privilege assigned to the user.
4095 The possible values are:
4097 Name Value Description
4098 USER_PRIV_GUEST 0 Guest privilege
4099 USER_PRIV_USER 1 User privilege
4100 USER_PRV_ADMIN 2 Administrator privilege
4102 usri11_auth_flags specifies the account operator privileges. The
4103 possible values are:
4105 Name Value Description
4106 AF_OP_PRINT 0 Print operator
4109 Leach, Naik [Page 28]
4113 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
4116 AF_OP_COMM 1 Communications operator
4117 AF_OP_SERVER 2 Server operator
4118 AF_OP_ACCOUNTS 3 Accounts operator
4121 usri11_password_age specifies how many seconds have elapsed since the
4122 password was last changed.
4124 usri11_home_dir points to a null terminated ASCII string that contains
4125 the path name of the user's home directory.
4127 usri11_parms points to a null terminated ASCII string that is set
4128 aside for use by applications.
4130 usri11_last_logon specifies the time when the user last logged on.
4131 This value is stored as the number of seconds elapsed since
4132 00:00:00, January 1, 1970.
4134 usri11_last_logoff specifies the time when the user last logged off.
4135 This value is stored as the number of seconds elapsed since
4136 00:00:00, January 1, 1970. A value of 0 means the last logoff
4137 time is unknown.
4139 usri11_bad_pw_count specifies the number of incorrect passwords
4140 entered since the last successful logon.
4142 usri11_log1_num_logons specifies the number of times this user has
4143 logged on. A value of -1 means the number of logons is unknown.
4145 usri11_logon_server points to a null terminated ASCII string that
4146 contains the name of the server to which logon requests are sent.
4147 A null string indicates logon requests should be sent to the
4148 domain controller.
4150 usri11_country_code specifies the country code for the user's language
4151 of choice.
4153 usri11_workstations points to a null terminated ASCII string that
4154 contains the names of workstations the user may log on from.
4155 There may be up to 8 workstations, with the names separated by
4156 commas. A null strings indicates there are no restrictions.
4158 usri11_max_storage specifies the maximum amount of disk space the user
4159 can occupy. A value of 0xffffffff indicates there are no
4160 restrictions.
4162 usri11_units_per_week specifies the equal number of time units into
4163 which a week is divided. This value must be equal to 168.
4165 usri11_logon_hours points to a 21 byte (168 bits) string that
4166 specifies the time during which the user can log on. Each bit
4167 represents one unique hour in a week. The first bit (bit 0, word
4168 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
4172 Leach, Naik [Page 29]
4176 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
4179 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
4180 are no restrictions.
4182 usri11_code_page specifies the code page for the user's language of
4183 choice
4185 All of the pointers in this data structure need to be treated
4186 specially. The pointer is a 32 bit pointer. The higher 16 bits need
4187 to be ignored. The converter word returned in the parameters section
4188 needs to be subtracted from the lower 16 bits to calculate an offset
4189 into the return buffer where this ASCII string resides.
4191 There is no auxiliary data in the response.
4193 ****************************************************************************/
4195 #define usri11_name 0
4196 #define usri11_pad 21
4197 #define usri11_comment 22
4198 #define usri11_usr_comment 26
4199 #define usri11_full_name 30
4200 #define usri11_priv 34
4201 #define usri11_auth_flags 36
4202 #define usri11_password_age 40
4203 #define usri11_homedir 44
4204 #define usri11_parms 48
4205 #define usri11_last_logon 52
4206 #define usri11_last_logoff 56
4207 #define usri11_bad_pw_count 60
4208 #define usri11_num_logons 62
4209 #define usri11_logon_server 64
4210 #define usri11_country_code 68
4211 #define usri11_workstations 70
4212 #define usri11_max_storage 74
4213 #define usri11_units_per_week 78
4214 #define usri11_logon_hours 80
4215 #define usri11_code_page 84
4216 #define usri11_end 86
4218 static bool api_RNetUserGetInfo(struct smbd_server_connection *sconn,
4219 connection_struct *conn, uint16 vuid,
4220 char *param, int tpscnt,
4221 char *data, int tdscnt,
4222 int mdrcnt,int mprcnt,
4223 char **rdata,char **rparam,
4224 int *rdata_len,int *rparam_len)
4226 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4227 char *str2 = skip_string(param,tpscnt,str1);
4228 char *UserName = skip_string(param,tpscnt,str2);
4229 char *p = skip_string(param,tpscnt,UserName);
4230 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4231 char *p2;
4232 char *endp;
4233 const char *level_string;
4235 TALLOC_CTX *mem_ctx = talloc_tos();
4236 NTSTATUS status, result;
4237 struct rpc_pipe_client *cli = NULL;
4238 struct policy_handle connect_handle, domain_handle, user_handle;
4239 struct lsa_String domain_name;
4240 struct dom_sid2 *domain_sid;
4241 struct lsa_String names;
4242 struct samr_Ids rids;
4243 struct samr_Ids types;
4244 int errcode = W_ERROR_V(WERR_USER_NOT_FOUND);
4245 uint32_t rid;
4246 union samr_UserInfo *info;
4247 struct dcerpc_binding_handle *b = NULL;
4249 if (!str1 || !str2 || !UserName || !p) {
4250 return False;
4253 *rparam_len = 6;
4254 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4255 if (!*rparam) {
4256 return False;
4259 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
4261 /* check it's a supported variant */
4262 if (strcmp(str1,"zWrLh") != 0) {
4263 return False;
4265 switch( uLevel ) {
4266 case 0: level_string = "B21"; break;
4267 case 1: level_string = "B21BB16DWzzWz"; break;
4268 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
4269 case 10: level_string = "B21Bzzz"; break;
4270 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
4271 default: return False;
4274 if (strcmp(level_string,str2) != 0) {
4275 return False;
4278 *rdata_len = mdrcnt + 1024;
4279 *rdata = smb_realloc_limit(*rdata,*rdata_len);
4280 if (!*rdata) {
4281 return False;
4284 p = *rdata;
4285 endp = *rdata + *rdata_len;
4286 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
4287 if (!p2) {
4288 return False;
4291 ZERO_STRUCT(connect_handle);
4292 ZERO_STRUCT(domain_handle);
4293 ZERO_STRUCT(user_handle);
4295 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_samr.syntax_id,
4296 conn->session_info,
4297 &conn->sconn->client_id,
4298 conn->sconn->msg_ctx,
4299 &cli);
4300 if (!NT_STATUS_IS_OK(status)) {
4301 DEBUG(0,("api_RNetUserGetInfo: could not connect to samr: %s\n",
4302 nt_errstr(status)));
4303 errcode = W_ERROR_V(ntstatus_to_werror(status));
4304 goto out;
4307 b = cli->binding_handle;
4309 status = dcerpc_samr_Connect2(b, mem_ctx,
4310 global_myname(),
4311 SAMR_ACCESS_CONNECT_TO_SERVER |
4312 SAMR_ACCESS_ENUM_DOMAINS |
4313 SAMR_ACCESS_LOOKUP_DOMAIN,
4314 &connect_handle,
4315 &result);
4316 if (!NT_STATUS_IS_OK(status)) {
4317 errcode = W_ERROR_V(ntstatus_to_werror(status));
4318 goto out;
4320 if (!NT_STATUS_IS_OK(result)) {
4321 errcode = W_ERROR_V(ntstatus_to_werror(result));
4322 goto out;
4325 init_lsa_String(&domain_name, get_global_sam_name());
4327 status = dcerpc_samr_LookupDomain(b, mem_ctx,
4328 &connect_handle,
4329 &domain_name,
4330 &domain_sid,
4331 &result);
4332 if (!NT_STATUS_IS_OK(status)) {
4333 errcode = W_ERROR_V(ntstatus_to_werror(status));
4334 goto out;
4336 if (!NT_STATUS_IS_OK(result)) {
4337 errcode = W_ERROR_V(ntstatus_to_werror(result));
4338 goto out;
4341 status = dcerpc_samr_OpenDomain(b, mem_ctx,
4342 &connect_handle,
4343 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
4344 domain_sid,
4345 &domain_handle,
4346 &result);
4347 if (!NT_STATUS_IS_OK(status)) {
4348 errcode = W_ERROR_V(ntstatus_to_werror(status));
4349 goto out;
4351 if (!NT_STATUS_IS_OK(result)) {
4352 errcode = W_ERROR_V(ntstatus_to_werror(result));
4353 goto out;
4356 init_lsa_String(&names, UserName);
4358 status = dcerpc_samr_LookupNames(b, mem_ctx,
4359 &domain_handle,
4361 &names,
4362 &rids,
4363 &types,
4364 &result);
4365 if (!NT_STATUS_IS_OK(status)) {
4366 errcode = W_ERROR_V(ntstatus_to_werror(status));
4367 goto out;
4369 if (!NT_STATUS_IS_OK(result)) {
4370 errcode = W_ERROR_V(ntstatus_to_werror(result));
4371 goto out;
4374 if (rids.count != 1) {
4375 errcode = W_ERROR_V(WERR_NO_SUCH_USER);
4376 goto out;
4378 if (rids.count != types.count) {
4379 errcode = W_ERROR_V(WERR_INVALID_PARAM);
4380 goto out;
4382 if (types.ids[0] != SID_NAME_USER) {
4383 errcode = W_ERROR_V(WERR_INVALID_PARAM);
4384 goto out;
4387 rid = rids.ids[0];
4389 status = dcerpc_samr_OpenUser(b, mem_ctx,
4390 &domain_handle,
4391 SAMR_USER_ACCESS_GET_LOCALE |
4392 SAMR_USER_ACCESS_GET_LOGONINFO |
4393 SAMR_USER_ACCESS_GET_ATTRIBUTES |
4394 SAMR_USER_ACCESS_GET_GROUPS |
4395 SAMR_USER_ACCESS_GET_GROUP_MEMBERSHIP |
4396 SEC_STD_READ_CONTROL,
4397 rid,
4398 &user_handle,
4399 &result);
4400 if (!NT_STATUS_IS_OK(status)) {
4401 errcode = W_ERROR_V(ntstatus_to_werror(status));
4402 goto out;
4404 if (!NT_STATUS_IS_OK(result)) {
4405 errcode = W_ERROR_V(ntstatus_to_werror(result));
4406 goto out;
4409 status = dcerpc_samr_QueryUserInfo2(b, mem_ctx,
4410 &user_handle,
4411 UserAllInformation,
4412 &info,
4413 &result);
4414 if (!NT_STATUS_IS_OK(status)) {
4415 errcode = W_ERROR_V(ntstatus_to_werror(status));
4416 goto out;
4418 if (!NT_STATUS_IS_OK(result)) {
4419 errcode = W_ERROR_V(ntstatus_to_werror(result));
4420 goto out;
4423 memset(p,0,21);
4424 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
4426 if (uLevel > 0) {
4427 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
4428 *p2 = 0;
4431 if (uLevel >= 10) {
4432 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
4433 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
4434 p2 = skip_string(*rdata,*rdata_len,p2);
4435 if (!p2) {
4436 return False;
4439 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
4440 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
4441 p2 = skip_string(*rdata,*rdata_len,p2);
4442 if (!p2) {
4443 return False;
4446 /* EEK! the cifsrap.txt doesn't have this in!!!! */
4447 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
4448 strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4449 p2 = skip_string(*rdata,*rdata_len,p2);
4450 if (!p2) {
4451 return False;
4455 if (uLevel == 11) {
4456 const char *homedir = info->info21.home_directory.string;
4457 /* modelled after NTAS 3.51 reply */
4458 SSVAL(p,usri11_priv,
4459 (get_current_uid(conn) == sec_initial_uid())?
4460 USER_PRIV_ADMIN:USER_PRIV_USER);
4461 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
4462 SIVALS(p,usri11_password_age,-1); /* password age */
4463 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
4464 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
4465 p2 = skip_string(*rdata,*rdata_len,p2);
4466 if (!p2) {
4467 return False;
4469 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
4470 strlcpy(p2,"",PTR_DIFF(endp,p2));
4471 p2 = skip_string(*rdata,*rdata_len,p2);
4472 if (!p2) {
4473 return False;
4475 SIVAL(p,usri11_last_logon,0); /* last logon */
4476 SIVAL(p,usri11_last_logoff,0); /* last logoff */
4477 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
4478 SSVALS(p,usri11_num_logons,-1); /* num logons */
4479 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
4480 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
4481 p2 = skip_string(*rdata,*rdata_len,p2);
4482 if (!p2) {
4483 return False;
4485 SSVAL(p,usri11_country_code,0); /* country code */
4487 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
4488 strlcpy(p2,"",PTR_DIFF(endp,p2));
4489 p2 = skip_string(*rdata,*rdata_len,p2);
4490 if (!p2) {
4491 return False;
4494 SIVALS(p,usri11_max_storage,-1); /* max storage */
4495 SSVAL(p,usri11_units_per_week,168); /* units per week */
4496 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
4498 /* a simple way to get logon hours at all times. */
4499 memset(p2,0xff,21);
4500 SCVAL(p2,21,0); /* fix zero termination */
4501 p2 = skip_string(*rdata,*rdata_len,p2);
4502 if (!p2) {
4503 return False;
4506 SSVAL(p,usri11_code_page,0); /* code page */
4509 if (uLevel == 1 || uLevel == 2) {
4510 memset(p+22,' ',16); /* password */
4511 SIVALS(p,38,-1); /* password age */
4512 SSVAL(p,42,
4513 (get_current_uid(conn) == sec_initial_uid())?
4514 USER_PRIV_ADMIN:USER_PRIV_USER);
4515 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
4516 strlcpy(p2, info->info21.home_directory.string,
4517 PTR_DIFF(endp,p2));
4518 p2 = skip_string(*rdata,*rdata_len,p2);
4519 if (!p2) {
4520 return False;
4522 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
4523 *p2++ = 0;
4524 SSVAL(p,52,0); /* flags */
4525 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
4526 strlcpy(p2, info->info21.logon_script.string,
4527 PTR_DIFF(endp,p2));
4528 p2 = skip_string(*rdata,*rdata_len,p2);
4529 if (!p2) {
4530 return False;
4532 if (uLevel == 2) {
4533 SIVAL(p,58,0); /* auth_flags */
4534 SIVAL(p,62,PTR_DIFF(p2,*rdata)); /* full_name */
4535 strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4536 p2 = skip_string(*rdata,*rdata_len,p2);
4537 if (!p2) {
4538 return False;
4540 SIVAL(p,66,0); /* urs_comment */
4541 SIVAL(p,70,PTR_DIFF(p2,*rdata)); /* parms */
4542 strlcpy(p2,"",PTR_DIFF(endp,p2));
4543 p2 = skip_string(*rdata,*rdata_len,p2);
4544 if (!p2) {
4545 return False;
4547 SIVAL(p,74,0); /* workstations */
4548 SIVAL(p,78,0); /* last_logon */
4549 SIVAL(p,82,0); /* last_logoff */
4550 SIVALS(p,86,-1); /* acct_expires */
4551 SIVALS(p,90,-1); /* max_storage */
4552 SSVAL(p,94,168); /* units_per_week */
4553 SIVAL(p,96,PTR_DIFF(p2,*rdata)); /* logon_hours */
4554 memset(p2,-1,21);
4555 p2 += 21;
4556 SSVALS(p,100,-1); /* bad_pw_count */
4557 SSVALS(p,102,-1); /* num_logons */
4558 SIVAL(p,104,PTR_DIFF(p2,*rdata)); /* logon_server */
4560 TALLOC_CTX *ctx = talloc_tos();
4561 int space_rem = *rdata_len - (p2 - *rdata);
4562 char *tmp;
4564 if (space_rem <= 0) {
4565 return false;
4567 tmp = talloc_strdup(ctx, "\\\\%L");
4568 if (!tmp) {
4569 return false;
4571 tmp = talloc_sub_basic(ctx,
4574 tmp);
4575 if (!tmp) {
4576 return false;
4579 push_ascii(p2,
4580 tmp,
4581 space_rem,
4582 STR_TERMINATE);
4584 p2 = skip_string(*rdata,*rdata_len,p2);
4585 if (!p2) {
4586 return False;
4588 SSVAL(p,108,49); /* country_code */
4589 SSVAL(p,110,860); /* code page */
4593 errcode = NERR_Success;
4595 out:
4596 *rdata_len = PTR_DIFF(p2,*rdata);
4598 if (b && is_valid_policy_hnd(&user_handle)) {
4599 dcerpc_samr_Close(b, mem_ctx, &user_handle, &result);
4601 if (b && is_valid_policy_hnd(&domain_handle)) {
4602 dcerpc_samr_Close(b, mem_ctx, &domain_handle, &result);
4604 if (b && is_valid_policy_hnd(&connect_handle)) {
4605 dcerpc_samr_Close(b, mem_ctx, &connect_handle, &result);
4608 SSVAL(*rparam,0,errcode);
4609 SSVAL(*rparam,2,0); /* converter word */
4610 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
4612 return(True);
4615 static bool api_WWkstaUserLogon(struct smbd_server_connection *sconn,
4616 connection_struct *conn,uint16 vuid,
4617 char *param, int tpscnt,
4618 char *data, int tdscnt,
4619 int mdrcnt,int mprcnt,
4620 char **rdata,char **rparam,
4621 int *rdata_len,int *rparam_len)
4623 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4624 char *str2 = skip_string(param,tpscnt,str1);
4625 char *p = skip_string(param,tpscnt,str2);
4626 int uLevel;
4627 struct pack_desc desc;
4628 char* name;
4629 /* With share level security vuid will always be zero.
4630 Don't depend on vuser being non-null !!. JRA */
4631 user_struct *vuser = get_valid_user_struct(sconn, vuid);
4633 if (!str1 || !str2 || !p) {
4634 return False;
4637 if(vuser != NULL) {
4638 DEBUG(3,(" Username of UID %d is %s\n",
4639 (int)vuser->session_info->utok.uid,
4640 vuser->session_info->unix_name));
4643 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4644 name = get_safe_str_ptr(param,tpscnt,p,2);
4645 if (!name) {
4646 return False;
4649 memset((char *)&desc,'\0',sizeof(desc));
4651 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
4653 /* check it's a supported varient */
4654 if (strcmp(str1,"OOWb54WrLh") != 0) {
4655 return False;
4657 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
4658 return False;
4660 if (mdrcnt > 0) {
4661 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4662 if (!*rdata) {
4663 return False;
4667 desc.base = *rdata;
4668 desc.buflen = mdrcnt;
4669 desc.subformat = NULL;
4670 desc.format = str2;
4672 if (init_package(&desc,1,0)) {
4673 PACKI(&desc,"W",0); /* code */
4674 PACKS(&desc,"B21",name); /* eff. name */
4675 PACKS(&desc,"B",""); /* pad */
4676 PACKI(&desc,"W",
4677 (get_current_uid(conn) == sec_initial_uid())?
4678 USER_PRIV_ADMIN:USER_PRIV_USER);
4679 PACKI(&desc,"D",0); /* auth flags XXX */
4680 PACKI(&desc,"W",0); /* num logons */
4681 PACKI(&desc,"W",0); /* bad pw count */
4682 PACKI(&desc,"D",0); /* last logon */
4683 PACKI(&desc,"D",-1); /* last logoff */
4684 PACKI(&desc,"D",-1); /* logoff time */
4685 PACKI(&desc,"D",-1); /* kickoff time */
4686 PACKI(&desc,"D",0); /* password age */
4687 PACKI(&desc,"D",0); /* password can change */
4688 PACKI(&desc,"D",-1); /* password must change */
4691 fstring mypath;
4692 fstrcpy(mypath,"\\\\");
4693 fstrcat(mypath,get_local_machine_name());
4694 strupper_m(mypath);
4695 PACKS(&desc,"z",mypath); /* computer */
4698 PACKS(&desc,"z",lp_workgroup());/* domain */
4699 PACKS(&desc,"z", vuser ?
4700 vuser->session_info->info3->base.logon_script.string
4701 : ""); /* script path */
4702 PACKI(&desc,"D",0x00000000); /* reserved */
4705 *rdata_len = desc.usedlen;
4706 *rparam_len = 6;
4707 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4708 if (!*rparam) {
4709 return False;
4711 SSVALS(*rparam,0,desc.errcode);
4712 SSVAL(*rparam,2,0);
4713 SSVAL(*rparam,4,desc.neededlen);
4715 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4717 return True;
4720 /****************************************************************************
4721 api_WAccessGetUserPerms
4722 ****************************************************************************/
4724 static bool api_WAccessGetUserPerms(struct smbd_server_connection *sconn,
4725 connection_struct *conn,uint16 vuid,
4726 char *param, int tpscnt,
4727 char *data, int tdscnt,
4728 int mdrcnt,int mprcnt,
4729 char **rdata,char **rparam,
4730 int *rdata_len,int *rparam_len)
4732 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4733 char *str2 = skip_string(param,tpscnt,str1);
4734 char *user = skip_string(param,tpscnt,str2);
4735 char *resource = skip_string(param,tpscnt,user);
4737 if (!str1 || !str2 || !user || !resource) {
4738 return False;
4741 if (skip_string(param,tpscnt,resource) == NULL) {
4742 return False;
4744 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4746 /* check it's a supported varient */
4747 if (strcmp(str1,"zzh") != 0) {
4748 return False;
4750 if (strcmp(str2,"") != 0) {
4751 return False;
4754 *rparam_len = 6;
4755 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4756 if (!*rparam) {
4757 return False;
4759 SSVALS(*rparam,0,0); /* errorcode */
4760 SSVAL(*rparam,2,0); /* converter word */
4761 SSVAL(*rparam,4,0x7f); /* permission flags */
4763 return True;
4766 /****************************************************************************
4767 api_WPrintJobEnumerate
4768 ****************************************************************************/
4770 static bool api_WPrintJobGetInfo(struct smbd_server_connection *sconn,
4771 connection_struct *conn, uint16 vuid,
4772 char *param, int tpscnt,
4773 char *data, int tdscnt,
4774 int mdrcnt,int mprcnt,
4775 char **rdata,char **rparam,
4776 int *rdata_len,int *rparam_len)
4778 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4779 char *str2 = skip_string(param,tpscnt,str1);
4780 char *p = skip_string(param,tpscnt,str2);
4781 int uLevel;
4782 fstring sharename;
4783 uint32 jobid;
4784 struct pack_desc desc;
4785 char *tmpdata=NULL;
4787 TALLOC_CTX *mem_ctx = talloc_tos();
4788 WERROR werr;
4789 NTSTATUS status;
4790 struct rpc_pipe_client *cli = NULL;
4791 struct dcerpc_binding_handle *b = NULL;
4792 struct policy_handle handle;
4793 struct spoolss_DevmodeContainer devmode_ctr;
4794 union spoolss_JobInfo info;
4796 if (!str1 || !str2 || !p) {
4797 return False;
4800 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4802 memset((char *)&desc,'\0',sizeof(desc));
4803 memset((char *)&status,'\0',sizeof(status));
4805 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4807 /* check it's a supported varient */
4808 if (strcmp(str1,"WWrLh") != 0) {
4809 return False;
4811 if (!check_printjob_info(&desc,uLevel,str2)) {
4812 return False;
4815 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4816 return False;
4819 ZERO_STRUCT(handle);
4821 status = rpc_pipe_open_interface(conn,
4822 &ndr_table_spoolss.syntax_id,
4823 conn->session_info,
4824 &conn->sconn->client_id,
4825 conn->sconn->msg_ctx,
4826 &cli);
4827 if (!NT_STATUS_IS_OK(status)) {
4828 DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n",
4829 nt_errstr(status)));
4830 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4831 goto out;
4833 b = cli->binding_handle;
4835 ZERO_STRUCT(devmode_ctr);
4837 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
4838 sharename,
4839 "RAW",
4840 devmode_ctr,
4841 PRINTER_ACCESS_USE,
4842 &handle,
4843 &werr);
4844 if (!NT_STATUS_IS_OK(status)) {
4845 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4846 goto out;
4848 if (!W_ERROR_IS_OK(werr)) {
4849 desc.errcode = W_ERROR_V(werr);
4850 goto out;
4853 werr = rpccli_spoolss_getjob(cli, mem_ctx,
4854 &handle,
4855 jobid,
4856 2, /* level */
4857 0, /* offered */
4858 &info);
4859 if (!W_ERROR_IS_OK(werr)) {
4860 desc.errcode = W_ERROR_V(werr);
4861 goto out;
4864 if (mdrcnt > 0) {
4865 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4866 if (!*rdata) {
4867 return False;
4869 desc.base = *rdata;
4870 desc.buflen = mdrcnt;
4871 } else {
4873 * Don't return data but need to get correct length
4874 * init_package will return wrong size if buflen=0
4876 desc.buflen = getlen(desc.format);
4877 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4880 if (init_package(&desc,1,0)) {
4881 fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position);
4882 *rdata_len = desc.usedlen;
4883 } else {
4884 desc.errcode = NERR_JobNotFound;
4885 *rdata_len = 0;
4887 out:
4888 if (b && is_valid_policy_hnd(&handle)) {
4889 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
4892 *rparam_len = 6;
4893 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4894 if (!*rparam) {
4895 return False;
4897 SSVALS(*rparam,0,desc.errcode);
4898 SSVAL(*rparam,2,0);
4899 SSVAL(*rparam,4,desc.neededlen);
4901 SAFE_FREE(tmpdata);
4903 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4905 return True;
4908 static bool api_WPrintJobEnumerate(struct smbd_server_connection *sconn,
4909 connection_struct *conn, uint16 vuid,
4910 char *param, int tpscnt,
4911 char *data, int tdscnt,
4912 int mdrcnt,int mprcnt,
4913 char **rdata,char **rparam,
4914 int *rdata_len,int *rparam_len)
4916 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4917 char *str2 = skip_string(param,tpscnt,str1);
4918 char *p = skip_string(param,tpscnt,str2);
4919 char *name = p;
4920 int uLevel;
4921 int i, succnt=0;
4922 struct pack_desc desc;
4924 TALLOC_CTX *mem_ctx = talloc_tos();
4925 WERROR werr;
4926 NTSTATUS status;
4927 struct rpc_pipe_client *cli = NULL;
4928 struct dcerpc_binding_handle *b = NULL;
4929 struct policy_handle handle;
4930 struct spoolss_DevmodeContainer devmode_ctr;
4931 uint32_t count = 0;
4932 union spoolss_JobInfo *info;
4934 if (!str1 || !str2 || !p) {
4935 return False;
4938 memset((char *)&desc,'\0',sizeof(desc));
4940 p = skip_string(param,tpscnt,p);
4941 if (!p) {
4942 return False;
4944 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4946 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4948 /* check it's a supported variant */
4949 if (strcmp(str1,"zWrLeh") != 0) {
4950 return False;
4953 if (uLevel > 2) {
4954 return False; /* defined only for uLevel 0,1,2 */
4957 if (!check_printjob_info(&desc,uLevel,str2)) {
4958 return False;
4961 ZERO_STRUCT(handle);
4963 status = rpc_pipe_open_interface(conn,
4964 &ndr_table_spoolss.syntax_id,
4965 conn->session_info,
4966 &conn->sconn->client_id,
4967 conn->sconn->msg_ctx,
4968 &cli);
4969 if (!NT_STATUS_IS_OK(status)) {
4970 DEBUG(0,("api_WPrintJobEnumerate: could not connect to spoolss: %s\n",
4971 nt_errstr(status)));
4972 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4973 goto out;
4975 b = cli->binding_handle;
4977 ZERO_STRUCT(devmode_ctr);
4979 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
4980 name,
4981 NULL,
4982 devmode_ctr,
4983 SEC_FLAG_MAXIMUM_ALLOWED,
4984 &handle,
4985 &werr);
4986 if (!NT_STATUS_IS_OK(status)) {
4987 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4988 goto out;
4990 if (!W_ERROR_IS_OK(werr)) {
4991 desc.errcode = W_ERROR_V(werr);
4992 goto out;
4995 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
4996 &handle,
4997 0, /* firstjob */
4998 0xff, /* numjobs */
4999 2, /* level */
5000 0, /* offered */
5001 &count,
5002 &info);
5003 if (!W_ERROR_IS_OK(werr)) {
5004 desc.errcode = W_ERROR_V(werr);
5005 goto out;
5008 if (mdrcnt > 0) {
5009 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5010 if (!*rdata) {
5011 return False;
5014 desc.base = *rdata;
5015 desc.buflen = mdrcnt;
5017 if (init_package(&desc,count,0)) {
5018 succnt = 0;
5019 for (i = 0; i < count; i++) {
5020 fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i);
5021 if (desc.errcode == NERR_Success) {
5022 succnt = i+1;
5026 out:
5027 if (b && is_valid_policy_hnd(&handle)) {
5028 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5031 *rdata_len = desc.usedlen;
5033 *rparam_len = 8;
5034 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5035 if (!*rparam) {
5036 return False;
5038 SSVALS(*rparam,0,desc.errcode);
5039 SSVAL(*rparam,2,0);
5040 SSVAL(*rparam,4,succnt);
5041 SSVAL(*rparam,6,count);
5043 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
5045 return True;
5048 static int check_printdest_info(struct pack_desc* desc,
5049 int uLevel, char* id)
5051 desc->subformat = NULL;
5052 switch( uLevel ) {
5053 case 0:
5054 desc->format = "B9";
5055 break;
5056 case 1:
5057 desc->format = "B9B21WWzW";
5058 break;
5059 case 2:
5060 desc->format = "z";
5061 break;
5062 case 3:
5063 desc->format = "zzzWWzzzWW";
5064 break;
5065 default:
5066 DEBUG(0,("check_printdest_info: invalid level %d\n",
5067 uLevel));
5068 return False;
5070 if (id == NULL || strcmp(desc->format,id) != 0) {
5071 DEBUG(0,("check_printdest_info: invalid string %s\n",
5072 id ? id : "<NULL>" ));
5073 return False;
5075 return True;
5078 static void fill_printdest_info(struct spoolss_PrinterInfo2 *info2, int uLevel,
5079 struct pack_desc* desc)
5081 char buf[100];
5083 strncpy(buf, info2->printername, sizeof(buf)-1);
5084 buf[sizeof(buf)-1] = 0;
5085 strupper_m(buf);
5087 if (uLevel <= 1) {
5088 PACKS(desc,"B9",buf); /* szName */
5089 if (uLevel == 1) {
5090 PACKS(desc,"B21",""); /* szUserName */
5091 PACKI(desc,"W",0); /* uJobId */
5092 PACKI(desc,"W",0); /* fsStatus */
5093 PACKS(desc,"z",""); /* pszStatus */
5094 PACKI(desc,"W",0); /* time */
5098 if (uLevel == 2 || uLevel == 3) {
5099 PACKS(desc,"z",buf); /* pszPrinterName */
5100 if (uLevel == 3) {
5101 PACKS(desc,"z",""); /* pszUserName */
5102 PACKS(desc,"z",""); /* pszLogAddr */
5103 PACKI(desc,"W",0); /* uJobId */
5104 PACKI(desc,"W",0); /* fsStatus */
5105 PACKS(desc,"z",""); /* pszStatus */
5106 PACKS(desc,"z",""); /* pszComment */
5107 PACKS(desc,"z","NULL"); /* pszDrivers */
5108 PACKI(desc,"W",0); /* time */
5109 PACKI(desc,"W",0); /* pad1 */
5114 static bool api_WPrintDestGetInfo(struct smbd_server_connection *sconn,
5115 connection_struct *conn, uint16 vuid,
5116 char *param, int tpscnt,
5117 char *data, int tdscnt,
5118 int mdrcnt,int mprcnt,
5119 char **rdata,char **rparam,
5120 int *rdata_len,int *rparam_len)
5122 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5123 char *str2 = skip_string(param,tpscnt,str1);
5124 char *p = skip_string(param,tpscnt,str2);
5125 char* PrinterName = p;
5126 int uLevel;
5127 struct pack_desc desc;
5128 char *tmpdata=NULL;
5130 TALLOC_CTX *mem_ctx = talloc_tos();
5131 WERROR werr;
5132 NTSTATUS status;
5133 struct rpc_pipe_client *cli = NULL;
5134 struct dcerpc_binding_handle *b = NULL;
5135 struct policy_handle handle;
5136 struct spoolss_DevmodeContainer devmode_ctr;
5137 union spoolss_PrinterInfo info;
5139 if (!str1 || !str2 || !p) {
5140 return False;
5143 memset((char *)&desc,'\0',sizeof(desc));
5145 p = skip_string(param,tpscnt,p);
5146 if (!p) {
5147 return False;
5149 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5151 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
5153 /* check it's a supported varient */
5154 if (strcmp(str1,"zWrLh") != 0) {
5155 return False;
5157 if (!check_printdest_info(&desc,uLevel,str2)) {
5158 return False;
5161 ZERO_STRUCT(handle);
5163 status = rpc_pipe_open_interface(conn,
5164 &ndr_table_spoolss.syntax_id,
5165 conn->session_info,
5166 &conn->sconn->client_id,
5167 conn->sconn->msg_ctx,
5168 &cli);
5169 if (!NT_STATUS_IS_OK(status)) {
5170 DEBUG(0,("api_WPrintDestGetInfo: could not connect to spoolss: %s\n",
5171 nt_errstr(status)));
5172 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5173 goto out;
5175 b = cli->binding_handle;
5177 ZERO_STRUCT(devmode_ctr);
5179 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5180 PrinterName,
5181 NULL,
5182 devmode_ctr,
5183 SEC_FLAG_MAXIMUM_ALLOWED,
5184 &handle,
5185 &werr);
5186 if (!NT_STATUS_IS_OK(status)) {
5187 *rdata_len = 0;
5188 desc.errcode = NERR_DestNotFound;
5189 desc.neededlen = 0;
5190 goto out;
5192 if (!W_ERROR_IS_OK(werr)) {
5193 *rdata_len = 0;
5194 desc.errcode = NERR_DestNotFound;
5195 desc.neededlen = 0;
5196 goto out;
5199 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
5200 &handle,
5203 &info);
5204 if (!W_ERROR_IS_OK(werr)) {
5205 *rdata_len = 0;
5206 desc.errcode = NERR_DestNotFound;
5207 desc.neededlen = 0;
5208 goto out;
5211 if (mdrcnt > 0) {
5212 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5213 if (!*rdata) {
5214 return False;
5216 desc.base = *rdata;
5217 desc.buflen = mdrcnt;
5218 } else {
5220 * Don't return data but need to get correct length
5221 * init_package will return wrong size if buflen=0
5223 desc.buflen = getlen(desc.format);
5224 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
5226 if (init_package(&desc,1,0)) {
5227 fill_printdest_info(&info.info2, uLevel,&desc);
5230 out:
5231 if (b && is_valid_policy_hnd(&handle)) {
5232 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5235 *rdata_len = desc.usedlen;
5237 *rparam_len = 6;
5238 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5239 if (!*rparam) {
5240 return False;
5242 SSVALS(*rparam,0,desc.errcode);
5243 SSVAL(*rparam,2,0);
5244 SSVAL(*rparam,4,desc.neededlen);
5246 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
5247 SAFE_FREE(tmpdata);
5249 return True;
5252 static bool api_WPrintDestEnum(struct smbd_server_connection *sconn,
5253 connection_struct *conn, uint16 vuid,
5254 char *param, int tpscnt,
5255 char *data, int tdscnt,
5256 int mdrcnt,int mprcnt,
5257 char **rdata,char **rparam,
5258 int *rdata_len,int *rparam_len)
5260 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5261 char *str2 = skip_string(param,tpscnt,str1);
5262 char *p = skip_string(param,tpscnt,str2);
5263 int uLevel;
5264 int queuecnt;
5265 int i, n, succnt=0;
5266 struct pack_desc desc;
5268 TALLOC_CTX *mem_ctx = talloc_tos();
5269 WERROR werr;
5270 NTSTATUS status;
5271 struct rpc_pipe_client *cli = NULL;
5272 union spoolss_PrinterInfo *info;
5273 uint32_t count;
5275 if (!str1 || !str2 || !p) {
5276 return False;
5279 memset((char *)&desc,'\0',sizeof(desc));
5281 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5283 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
5285 /* check it's a supported varient */
5286 if (strcmp(str1,"WrLeh") != 0) {
5287 return False;
5289 if (!check_printdest_info(&desc,uLevel,str2)) {
5290 return False;
5293 queuecnt = 0;
5295 status = rpc_pipe_open_interface(conn,
5296 &ndr_table_spoolss.syntax_id,
5297 conn->session_info,
5298 &conn->sconn->client_id,
5299 conn->sconn->msg_ctx,
5300 &cli);
5301 if (!NT_STATUS_IS_OK(status)) {
5302 DEBUG(0,("api_WPrintDestEnum: could not connect to spoolss: %s\n",
5303 nt_errstr(status)));
5304 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5305 goto out;
5308 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
5309 PRINTER_ENUM_LOCAL,
5310 cli->srv_name_slash,
5313 &count,
5314 &info);
5315 if (!W_ERROR_IS_OK(werr)) {
5316 desc.errcode = W_ERROR_V(werr);
5317 *rdata_len = 0;
5318 desc.errcode = NERR_DestNotFound;
5319 desc.neededlen = 0;
5320 goto out;
5323 queuecnt = count;
5325 if (mdrcnt > 0) {
5326 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5327 if (!*rdata) {
5328 return False;
5332 desc.base = *rdata;
5333 desc.buflen = mdrcnt;
5334 if (init_package(&desc,queuecnt,0)) {
5335 succnt = 0;
5336 n = 0;
5337 for (i = 0; i < count; i++) {
5338 fill_printdest_info(&info[i].info2, uLevel,&desc);
5339 n++;
5340 if (desc.errcode == NERR_Success) {
5341 succnt = n;
5345 out:
5346 *rdata_len = desc.usedlen;
5348 *rparam_len = 8;
5349 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5350 if (!*rparam) {
5351 return False;
5353 SSVALS(*rparam,0,desc.errcode);
5354 SSVAL(*rparam,2,0);
5355 SSVAL(*rparam,4,succnt);
5356 SSVAL(*rparam,6,queuecnt);
5358 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
5360 return True;
5363 static bool api_WPrintDriverEnum(struct smbd_server_connection *sconn,
5364 connection_struct *conn, uint16 vuid,
5365 char *param, int tpscnt,
5366 char *data, int tdscnt,
5367 int mdrcnt,int mprcnt,
5368 char **rdata,char **rparam,
5369 int *rdata_len,int *rparam_len)
5371 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5372 char *str2 = skip_string(param,tpscnt,str1);
5373 char *p = skip_string(param,tpscnt,str2);
5374 int uLevel;
5375 int succnt;
5376 struct pack_desc desc;
5378 if (!str1 || !str2 || !p) {
5379 return False;
5382 memset((char *)&desc,'\0',sizeof(desc));
5384 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5386 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
5388 /* check it's a supported varient */
5389 if (strcmp(str1,"WrLeh") != 0) {
5390 return False;
5392 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
5393 return False;
5396 if (mdrcnt > 0) {
5397 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5398 if (!*rdata) {
5399 return False;
5402 desc.base = *rdata;
5403 desc.buflen = mdrcnt;
5404 if (init_package(&desc,1,0)) {
5405 PACKS(&desc,"B41","NULL");
5408 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5410 *rdata_len = desc.usedlen;
5412 *rparam_len = 8;
5413 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5414 if (!*rparam) {
5415 return False;
5417 SSVALS(*rparam,0,desc.errcode);
5418 SSVAL(*rparam,2,0);
5419 SSVAL(*rparam,4,succnt);
5420 SSVAL(*rparam,6,1);
5422 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
5424 return True;
5427 static bool api_WPrintQProcEnum(struct smbd_server_connection *sconn,
5428 connection_struct *conn, uint16 vuid,
5429 char *param, int tpscnt,
5430 char *data, int tdscnt,
5431 int mdrcnt,int mprcnt,
5432 char **rdata,char **rparam,
5433 int *rdata_len,int *rparam_len)
5435 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5436 char *str2 = skip_string(param,tpscnt,str1);
5437 char *p = skip_string(param,tpscnt,str2);
5438 int uLevel;
5439 int succnt;
5440 struct pack_desc desc;
5442 if (!str1 || !str2 || !p) {
5443 return False;
5445 memset((char *)&desc,'\0',sizeof(desc));
5447 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5449 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
5451 /* check it's a supported varient */
5452 if (strcmp(str1,"WrLeh") != 0) {
5453 return False;
5455 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
5456 return False;
5459 if (mdrcnt > 0) {
5460 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5461 if (!*rdata) {
5462 return False;
5465 desc.base = *rdata;
5466 desc.buflen = mdrcnt;
5467 desc.format = str2;
5468 if (init_package(&desc,1,0)) {
5469 PACKS(&desc,"B13","lpd");
5472 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5474 *rdata_len = desc.usedlen;
5476 *rparam_len = 8;
5477 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5478 if (!*rparam) {
5479 return False;
5481 SSVALS(*rparam,0,desc.errcode);
5482 SSVAL(*rparam,2,0);
5483 SSVAL(*rparam,4,succnt);
5484 SSVAL(*rparam,6,1);
5486 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
5488 return True;
5491 static bool api_WPrintPortEnum(struct smbd_server_connection *sconn,
5492 connection_struct *conn, uint16 vuid,
5493 char *param, int tpscnt,
5494 char *data, int tdscnt,
5495 int mdrcnt,int mprcnt,
5496 char **rdata,char **rparam,
5497 int *rdata_len,int *rparam_len)
5499 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5500 char *str2 = skip_string(param,tpscnt,str1);
5501 char *p = skip_string(param,tpscnt,str2);
5502 int uLevel;
5503 int succnt;
5504 struct pack_desc desc;
5506 if (!str1 || !str2 || !p) {
5507 return False;
5510 memset((char *)&desc,'\0',sizeof(desc));
5512 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5514 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
5516 /* check it's a supported varient */
5517 if (strcmp(str1,"WrLeh") != 0) {
5518 return False;
5520 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
5521 return False;
5524 if (mdrcnt > 0) {
5525 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5526 if (!*rdata) {
5527 return False;
5530 memset((char *)&desc,'\0',sizeof(desc));
5531 desc.base = *rdata;
5532 desc.buflen = mdrcnt;
5533 desc.format = str2;
5534 if (init_package(&desc,1,0)) {
5535 PACKS(&desc,"B13","lp0");
5538 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5540 *rdata_len = desc.usedlen;
5542 *rparam_len = 8;
5543 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5544 if (!*rparam) {
5545 return False;
5547 SSVALS(*rparam,0,desc.errcode);
5548 SSVAL(*rparam,2,0);
5549 SSVAL(*rparam,4,succnt);
5550 SSVAL(*rparam,6,1);
5552 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
5554 return True;
5557 /****************************************************************************
5558 List open sessions
5559 ****************************************************************************/
5561 static bool api_RNetSessionEnum(struct smbd_server_connection *sconn,
5562 connection_struct *conn, uint16 vuid,
5563 char *param, int tpscnt,
5564 char *data, int tdscnt,
5565 int mdrcnt,int mprcnt,
5566 char **rdata,char **rparam,
5567 int *rdata_len,int *rparam_len)
5570 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5571 char *str2 = skip_string(param,tpscnt,str1);
5572 char *p = skip_string(param,tpscnt,str2);
5573 int uLevel;
5574 struct pack_desc desc;
5575 int i;
5577 TALLOC_CTX *mem_ctx = talloc_tos();
5578 WERROR werr;
5579 NTSTATUS status;
5580 struct rpc_pipe_client *cli = NULL;
5581 struct dcerpc_binding_handle *b = NULL;
5582 struct srvsvc_NetSessInfoCtr info_ctr;
5583 uint32_t totalentries, resume_handle = 0;
5584 uint32_t count = 0;
5586 if (!str1 || !str2 || !p) {
5587 return False;
5590 ZERO_STRUCT(desc);
5592 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5594 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
5595 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
5596 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
5598 /* check it's a supported varient */
5599 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
5600 return False;
5602 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
5603 return False;
5606 status = rpc_pipe_open_interface(conn,
5607 &ndr_table_srvsvc.syntax_id,
5608 conn->session_info,
5609 &conn->sconn->client_id,
5610 conn->sconn->msg_ctx,
5611 &cli);
5612 if (!NT_STATUS_IS_OK(status)) {
5613 DEBUG(0,("RNetSessionEnum: could not connect to srvsvc: %s\n",
5614 nt_errstr(status)));
5615 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5616 goto out;
5618 b = cli->binding_handle;
5620 info_ctr.level = 1;
5621 info_ctr.ctr.ctr1 = talloc_zero(talloc_tos(), struct srvsvc_NetSessCtr1);
5622 if (info_ctr.ctr.ctr1 == NULL) {
5623 desc.errcode = W_ERROR_V(WERR_NOMEM);
5624 goto out;
5627 status = dcerpc_srvsvc_NetSessEnum(b, mem_ctx,
5628 cli->srv_name_slash,
5629 NULL, /* client */
5630 NULL, /* user */
5631 &info_ctr,
5632 (uint32_t)-1, /* max_buffer */
5633 &totalentries,
5634 &resume_handle,
5635 &werr);
5636 if (!NT_STATUS_IS_OK(status)) {
5637 DEBUG(0,("RNetSessionEnum: dcerpc_srvsvc_NetSessEnum failed: %s\n",
5638 nt_errstr(status)));
5639 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5640 goto out;
5643 if (!W_ERROR_IS_OK(werr)) {
5644 DEBUG(0,("RNetSessionEnum: dcerpc_srvsvc_NetSessEnum failed: %s\n",
5645 win_errstr(werr)));
5646 desc.errcode = W_ERROR_V(werr);
5647 goto out;
5650 count = info_ctr.ctr.ctr1->count;
5652 out:
5653 if (mdrcnt > 0) {
5654 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5655 if (!*rdata) {
5656 return False;
5660 desc.base = *rdata;
5661 desc.buflen = mdrcnt;
5662 desc.format = str2;
5663 if (!init_package(&desc, count,0)) {
5664 return False;
5667 for(i=0; i < count; i++) {
5668 PACKS(&desc, "z", info_ctr.ctr.ctr1->array[i].client);
5669 PACKS(&desc, "z", info_ctr.ctr.ctr1->array[i].user);
5670 PACKI(&desc, "W", 1); /* num conns */
5671 PACKI(&desc, "W", info_ctr.ctr.ctr1->array[i].num_open);
5672 PACKI(&desc, "W", 1); /* num users */
5673 PACKI(&desc, "D", 0); /* session time */
5674 PACKI(&desc, "D", 0); /* idle time */
5675 PACKI(&desc, "D", 0); /* flags */
5676 PACKS(&desc, "z", "Unknown Client"); /* client type string */
5679 *rdata_len = desc.usedlen;
5681 *rparam_len = 8;
5682 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5683 if (!*rparam) {
5684 return False;
5686 SSVALS(*rparam,0,desc.errcode);
5687 SSVAL(*rparam,2,0); /* converter */
5688 SSVAL(*rparam,4, count); /* count */
5690 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
5692 return True;
5696 /****************************************************************************
5697 The buffer was too small.
5698 ****************************************************************************/
5700 static bool api_TooSmall(struct smbd_server_connection *sconn,
5701 connection_struct *conn,uint16 vuid, char *param, char *data,
5702 int mdrcnt, int mprcnt,
5703 char **rdata, char **rparam,
5704 int *rdata_len, int *rparam_len)
5706 *rparam_len = MIN(*rparam_len,mprcnt);
5707 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5708 if (!*rparam) {
5709 return False;
5712 *rdata_len = 0;
5714 SSVAL(*rparam,0,NERR_BufTooSmall);
5716 DEBUG(3,("Supplied buffer too small in API command\n"));
5718 return True;
5721 /****************************************************************************
5722 The request is not supported.
5723 ****************************************************************************/
5725 static bool api_Unsupported(struct smbd_server_connection *sconn,
5726 connection_struct *conn, uint16 vuid,
5727 char *param, int tpscnt,
5728 char *data, int tdscnt,
5729 int mdrcnt, int mprcnt,
5730 char **rdata, char **rparam,
5731 int *rdata_len, int *rparam_len)
5733 *rparam_len = 4;
5734 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5735 if (!*rparam) {
5736 return False;
5739 *rdata_len = 0;
5741 SSVAL(*rparam,0,NERR_notsupported);
5742 SSVAL(*rparam,2,0); /* converter word */
5744 DEBUG(3,("Unsupported API command\n"));
5746 return True;
5749 static const struct {
5750 const char *name;
5751 int id;
5752 bool (*fn)(struct smbd_server_connection *sconn,
5753 connection_struct *, uint16,
5754 char *, int,
5755 char *, int,
5756 int,int,char **,char **,int *,int *);
5757 bool auth_user; /* Deny anonymous access? */
5758 } api_commands[] = {
5759 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
5760 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
5761 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
5762 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
5763 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
5764 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
5765 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
5766 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
5767 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
5768 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
5769 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
5770 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
5771 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
5772 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
5773 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
5774 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
5775 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
5776 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
5777 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
5778 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
5779 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
5780 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
5781 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
5782 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
5783 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
5784 {"NetServerEnum3", RAP_NetServerEnum3, api_RNetServerEnum3}, /* anon OK */
5785 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
5786 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
5787 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
5788 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
5789 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
5790 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
5791 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
5792 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
5793 {NULL, -1, api_Unsupported}
5794 /* The following RAP calls are not implemented by Samba:
5796 RAP_WFileEnum2 - anon not OK
5801 /****************************************************************************
5802 Handle remote api calls.
5803 ****************************************************************************/
5805 void api_reply(connection_struct *conn, uint16 vuid,
5806 struct smb_request *req,
5807 char *data, char *params,
5808 int tdscnt, int tpscnt,
5809 int mdrcnt, int mprcnt)
5811 int api_command;
5812 char *rdata = NULL;
5813 char *rparam = NULL;
5814 const char *name1 = NULL;
5815 const char *name2 = NULL;
5816 int rdata_len = 0;
5817 int rparam_len = 0;
5818 bool reply=False;
5819 int i;
5821 if (!params) {
5822 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
5823 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5824 return;
5827 if (tpscnt < 2) {
5828 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5829 return;
5831 api_command = SVAL(params,0);
5832 /* Is there a string at position params+2 ? */
5833 if (skip_string(params,tpscnt,params+2)) {
5834 name1 = params + 2;
5835 } else {
5836 name1 = "";
5838 name2 = skip_string(params,tpscnt,params+2);
5839 if (!name2) {
5840 name2 = "";
5843 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
5844 api_command,
5845 name1,
5846 name2,
5847 tdscnt,tpscnt,mdrcnt,mprcnt));
5849 for (i=0;api_commands[i].name;i++) {
5850 if (api_commands[i].id == api_command && api_commands[i].fn) {
5851 DEBUG(3,("Doing %s\n",api_commands[i].name));
5852 break;
5856 /* Check whether this api call can be done anonymously */
5858 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
5859 user_struct *user = get_valid_user_struct(req->sconn, vuid);
5861 if (!user || user->session_info->guest) {
5862 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5863 return;
5867 rdata = (char *)SMB_MALLOC(1024);
5868 if (rdata) {
5869 memset(rdata,'\0',1024);
5872 rparam = (char *)SMB_MALLOC(1024);
5873 if (rparam) {
5874 memset(rparam,'\0',1024);
5877 if(!rdata || !rparam) {
5878 DEBUG(0,("api_reply: malloc fail !\n"));
5879 SAFE_FREE(rdata);
5880 SAFE_FREE(rparam);
5881 reply_nterror(req, NT_STATUS_NO_MEMORY);
5882 return;
5885 reply = api_commands[i].fn(req->sconn, conn,
5886 vuid,
5887 params,tpscnt, /* params + length */
5888 data,tdscnt, /* data + length */
5889 mdrcnt,mprcnt,
5890 &rdata,&rparam,&rdata_len,&rparam_len);
5893 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
5894 reply = api_TooSmall(req->sconn,conn,vuid,params,data,
5895 mdrcnt,mprcnt,
5896 &rdata,&rparam,&rdata_len,&rparam_len);
5899 /* if we get False back then it's actually unsupported */
5900 if (!reply) {
5901 reply = api_Unsupported(req->sconn,conn,vuid,params,tpscnt,
5902 data,
5903 tdscnt,mdrcnt,mprcnt,
5904 &rdata,&rparam,&rdata_len,&rparam_len);
5907 /* If api_Unsupported returns false we can't return anything. */
5908 if (reply) {
5909 send_trans_reply(conn, req, rparam, rparam_len,
5910 rdata, rdata_len, False);
5913 SAFE_FREE(rdata);
5914 SAFE_FREE(rparam);
5915 return;