s3: Fix Coverity ID 2236: REVERSE_INULL
[Samba.git] / source3 / smbd / lanman.c
blob1749eb01079ade49e2e346903a6c0dbb7c22cb80
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/globals.h"
30 #include "../librpc/gen_ndr/ndr_samr_c.h"
31 #include "../librpc/gen_ndr/ndr_spoolss_c.h"
32 #include "rpc_client/cli_spoolss.h"
33 #include "rpc_client/init_spoolss.h"
34 #include "../librpc/gen_ndr/ndr_srvsvc_c.h"
35 #include "../librpc/gen_ndr/srv_samr.h"
36 #include "../librpc/gen_ndr/srv_srvsvc.h"
37 #include "../librpc/gen_ndr/rap.h"
38 #include "../lib/util/binsearch.h"
39 #include "../libcli/auth/libcli_auth.h"
40 #include "rpc_client/init_lsa.h"
41 #include "rpc_server/rpc_ncacn_np.h"
42 #include "../libcli/security/security.h"
43 #include "printing.h"
45 #ifdef CHECK_TYPES
46 #undef CHECK_TYPES
47 #endif
48 #define CHECK_TYPES 0
50 #define NERR_Success 0
51 #define NERR_badpass 86
52 #define NERR_notsupported 50
54 #define NERR_BASE (2100)
55 #define NERR_BufTooSmall (NERR_BASE+23)
56 #define NERR_JobNotFound (NERR_BASE+51)
57 #define NERR_DestNotFound (NERR_BASE+52)
59 #define ACCESS_READ 0x01
60 #define ACCESS_WRITE 0x02
61 #define ACCESS_CREATE 0x04
63 #define SHPWLEN 8 /* share password length */
65 /* Limit size of ipc replies */
67 static char *smb_realloc_limit(void *ptr, size_t size)
69 char *val;
71 size = MAX((size),4*1024);
72 val = (char *)SMB_REALLOC(ptr,size);
73 if (val) {
74 memset(val,'\0',size);
76 return val;
79 static bool api_Unsupported(struct smbd_server_connection *sconn,
80 connection_struct *conn, uint16 vuid,
81 char *param, int tpscnt,
82 char *data, int tdscnt,
83 int mdrcnt, int mprcnt,
84 char **rdata, char **rparam,
85 int *rdata_len, int *rparam_len);
87 static bool api_TooSmall(struct smbd_server_connection *sconn,
88 connection_struct *conn, uint16 vuid, char *param, char *data,
89 int mdrcnt, int mprcnt,
90 char **rdata, char **rparam,
91 int *rdata_len, int *rparam_len);
94 static int CopyExpanded(connection_struct *conn,
95 int snum, char **dst, char *src, int *p_space_remaining)
97 TALLOC_CTX *ctx = talloc_tos();
98 char *buf = NULL;
99 int l;
101 if (!src || !dst || !p_space_remaining || !(*dst) ||
102 *p_space_remaining <= 0) {
103 return 0;
106 buf = talloc_strdup(ctx, src);
107 if (!buf) {
108 *p_space_remaining = 0;
109 return 0;
111 buf = talloc_string_sub(ctx, buf,"%S",lp_servicename(snum));
112 if (!buf) {
113 *p_space_remaining = 0;
114 return 0;
116 buf = talloc_sub_advanced(ctx,
117 lp_servicename(SNUM(conn)),
118 conn->session_info->unix_name,
119 conn->connectpath,
120 conn->session_info->utok.gid,
121 conn->session_info->sanitized_username,
122 conn->session_info->info3->base.domain.string,
123 buf);
124 if (!buf) {
125 *p_space_remaining = 0;
126 return 0;
128 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
129 if (l == -1) {
130 return 0;
132 (*dst) += l;
133 (*p_space_remaining) -= l;
134 return l;
137 static int CopyAndAdvance(char **dst, char *src, int *n)
139 int l;
140 if (!src || !dst || !n || !(*dst)) {
141 return 0;
143 l = push_ascii(*dst,src,*n, STR_TERMINATE);
144 if (l == -1) {
145 return 0;
147 (*dst) += l;
148 (*n) -= l;
149 return l;
152 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
154 TALLOC_CTX *ctx = talloc_tos();
155 char *buf = NULL;
156 if (!s) {
157 return 0;
159 buf = talloc_strdup(ctx,s);
160 if (!buf) {
161 return 0;
163 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
164 if (!buf) {
165 return 0;
167 buf = talloc_sub_advanced(ctx,
168 lp_servicename(SNUM(conn)),
169 conn->session_info->unix_name,
170 conn->connectpath,
171 conn->session_info->utok.gid,
172 conn->session_info->sanitized_username,
173 conn->session_info->info3->base.domain.string,
174 buf);
175 if (!buf) {
176 return 0;
178 return strlen(buf) + 1;
181 /*******************************************************************
182 Check a API string for validity when we only need to check the prefix.
183 ******************************************************************/
185 static bool prefix_ok(const char *str, const char *prefix)
187 return(strncmp(str,prefix,strlen(prefix)) == 0);
190 struct pack_desc {
191 const char *format; /* formatstring for structure */
192 const char *subformat; /* subformat for structure */
193 char *base; /* baseaddress of buffer */
194 int buflen; /* remaining size for fixed part; on init: length of base */
195 int subcount; /* count of substructures */
196 char *structbuf; /* pointer into buffer for remaining fixed part */
197 int stringlen; /* remaining size for variable part */
198 char *stringbuf; /* pointer into buffer for remaining variable part */
199 int neededlen; /* total needed size */
200 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
201 const char *curpos; /* current position; pointer into format or subformat */
202 int errcode;
205 static int get_counter(const char **p)
207 int i, n;
208 if (!p || !(*p)) {
209 return 1;
211 if (!isdigit((int)**p)) {
212 return 1;
214 for (n = 0;;) {
215 i = **p;
216 if (isdigit(i)) {
217 n = 10 * n + (i - '0');
218 } else {
219 return n;
221 (*p)++;
225 static int getlen(const char *p)
227 int n = 0;
228 if (!p) {
229 return 0;
232 while (*p) {
233 switch( *p++ ) {
234 case 'W': /* word (2 byte) */
235 n += 2;
236 break;
237 case 'K': /* status word? (2 byte) */
238 n += 2;
239 break;
240 case 'N': /* count of substructures (word) at end */
241 n += 2;
242 break;
243 case 'D': /* double word (4 byte) */
244 case 'z': /* offset to zero terminated string (4 byte) */
245 case 'l': /* offset to user data (4 byte) */
246 n += 4;
247 break;
248 case 'b': /* offset to data (with counter) (4 byte) */
249 n += 4;
250 get_counter(&p);
251 break;
252 case 'B': /* byte (with optional counter) */
253 n += get_counter(&p);
254 break;
257 return n;
260 static bool init_package(struct pack_desc *p, int count, int subcount)
262 int n = p->buflen;
263 int i;
265 if (!p->format || !p->base) {
266 return False;
269 i = count * getlen(p->format);
270 if (p->subformat) {
271 i += subcount * getlen(p->subformat);
273 p->structbuf = p->base;
274 p->neededlen = 0;
275 p->usedlen = 0;
276 p->subcount = 0;
277 p->curpos = p->format;
278 if (i > n) {
279 p->neededlen = i;
280 i = n = 0;
281 #if 0
283 * This is the old error code we used. Aparently
284 * WinNT/2k systems return ERRbuftoosmall (2123) and
285 * OS/2 needs this. I'm leaving this here so we can revert
286 * if needed. JRA.
288 p->errcode = ERRmoredata;
289 #else
290 p->errcode = ERRbuftoosmall;
291 #endif
292 } else {
293 p->errcode = NERR_Success;
295 p->buflen = i;
296 n -= i;
297 p->stringbuf = p->base + i;
298 p->stringlen = n;
299 return (p->errcode == NERR_Success);
302 static int package(struct pack_desc *p, ...)
304 va_list args;
305 int needed=0, stringneeded;
306 const char *str=NULL;
307 int is_string=0, stringused;
308 int32 temp;
310 va_start(args,p);
312 if (!*p->curpos) {
313 if (!p->subcount) {
314 p->curpos = p->format;
315 } else {
316 p->curpos = p->subformat;
317 p->subcount--;
320 #if CHECK_TYPES
321 str = va_arg(args,char*);
322 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
323 #endif
324 stringneeded = -1;
326 if (!p->curpos) {
327 va_end(args);
328 return 0;
331 switch( *p->curpos++ ) {
332 case 'W': /* word (2 byte) */
333 needed = 2;
334 temp = va_arg(args,int);
335 if (p->buflen >= needed) {
336 SSVAL(p->structbuf,0,temp);
338 break;
339 case 'K': /* status word? (2 byte) */
340 needed = 2;
341 temp = va_arg(args,int);
342 if (p->buflen >= needed) {
343 SSVAL(p->structbuf,0,temp);
345 break;
346 case 'N': /* count of substructures (word) at end */
347 needed = 2;
348 p->subcount = va_arg(args,int);
349 if (p->buflen >= needed) {
350 SSVAL(p->structbuf,0,p->subcount);
352 break;
353 case 'D': /* double word (4 byte) */
354 needed = 4;
355 temp = va_arg(args,int);
356 if (p->buflen >= needed) {
357 SIVAL(p->structbuf,0,temp);
359 break;
360 case 'B': /* byte (with optional counter) */
361 needed = get_counter(&p->curpos);
363 char *s = va_arg(args,char*);
364 if (p->buflen >= needed) {
365 StrnCpy(p->structbuf,s?s:"",needed-1);
368 break;
369 case 'z': /* offset to zero terminated string (4 byte) */
370 str = va_arg(args,char*);
371 stringneeded = (str ? strlen(str)+1 : 0);
372 is_string = 1;
373 break;
374 case 'l': /* offset to user data (4 byte) */
375 str = va_arg(args,char*);
376 stringneeded = va_arg(args,int);
377 is_string = 0;
378 break;
379 case 'b': /* offset to data (with counter) (4 byte) */
380 str = va_arg(args,char*);
381 stringneeded = get_counter(&p->curpos);
382 is_string = 0;
383 break;
386 va_end(args);
387 if (stringneeded >= 0) {
388 needed = 4;
389 if (p->buflen >= needed) {
390 stringused = stringneeded;
391 if (stringused > p->stringlen) {
392 stringused = (is_string ? p->stringlen : 0);
393 if (p->errcode == NERR_Success) {
394 p->errcode = ERRmoredata;
397 if (!stringused) {
398 SIVAL(p->structbuf,0,0);
399 } else {
400 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
401 memcpy(p->stringbuf,str?str:"",stringused);
402 if (is_string) {
403 p->stringbuf[stringused-1] = '\0';
405 p->stringbuf += stringused;
406 p->stringlen -= stringused;
407 p->usedlen += stringused;
410 p->neededlen += stringneeded;
413 p->neededlen += needed;
414 if (p->buflen >= needed) {
415 p->structbuf += needed;
416 p->buflen -= needed;
417 p->usedlen += needed;
418 } else {
419 if (p->errcode == NERR_Success) {
420 p->errcode = ERRmoredata;
423 return 1;
426 #if CHECK_TYPES
427 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
428 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
429 #else
430 #define PACK(desc,t,v) package(desc,v)
431 #define PACKl(desc,t,v,l) package(desc,v,l)
432 #endif
434 static void PACKI(struct pack_desc* desc, const char *t,int v)
436 PACK(desc,t,v);
439 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
441 PACK(desc,t,v);
444 /****************************************************************************
445 Get a print queue.
446 ****************************************************************************/
448 static void PackDriverData(struct pack_desc* desc)
450 char drivdata[4+4+32];
451 SIVAL(drivdata,0,sizeof drivdata); /* cb */
452 SIVAL(drivdata,4,1000); /* lVersion */
453 memset(drivdata+8,0,32); /* szDeviceName */
454 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
455 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
458 static int check_printq_info(struct pack_desc* desc,
459 unsigned int uLevel, char *id1, char *id2)
461 desc->subformat = NULL;
462 switch( uLevel ) {
463 case 0:
464 desc->format = "B13";
465 break;
466 case 1:
467 desc->format = "B13BWWWzzzzzWW";
468 break;
469 case 2:
470 desc->format = "B13BWWWzzzzzWN";
471 desc->subformat = "WB21BB16B10zWWzDDz";
472 break;
473 case 3:
474 desc->format = "zWWWWzzzzWWzzl";
475 break;
476 case 4:
477 desc->format = "zWWWWzzzzWNzzl";
478 desc->subformat = "WWzWWDDzz";
479 break;
480 case 5:
481 desc->format = "z";
482 break;
483 case 51:
484 desc->format = "K";
485 break;
486 case 52:
487 desc->format = "WzzzzzzzzN";
488 desc->subformat = "z";
489 break;
490 default:
491 DEBUG(0,("check_printq_info: invalid level %d\n",
492 uLevel ));
493 return False;
495 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
496 DEBUG(0,("check_printq_info: invalid format %s\n",
497 id1 ? id1 : "<NULL>" ));
498 return False;
500 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
501 DEBUG(0,("check_printq_info: invalid subformat %s\n",
502 id2 ? id2 : "<NULL>" ));
503 return False;
505 return True;
509 #define RAP_JOB_STATUS_QUEUED 0
510 #define RAP_JOB_STATUS_PAUSED 1
511 #define RAP_JOB_STATUS_SPOOLING 2
512 #define RAP_JOB_STATUS_PRINTING 3
513 #define RAP_JOB_STATUS_PRINTED 4
515 #define RAP_QUEUE_STATUS_PAUSED 1
516 #define RAP_QUEUE_STATUS_ERROR 2
518 /* turn a print job status into a on the wire status
520 static int printj_spoolss_status(int v)
522 if (v == JOB_STATUS_QUEUED)
523 return RAP_JOB_STATUS_QUEUED;
524 if (v & JOB_STATUS_PAUSED)
525 return RAP_JOB_STATUS_PAUSED;
526 if (v & JOB_STATUS_SPOOLING)
527 return RAP_JOB_STATUS_SPOOLING;
528 if (v & JOB_STATUS_PRINTING)
529 return RAP_JOB_STATUS_PRINTING;
530 return 0;
533 /* turn a print queue status into a on the wire status
535 static int printq_spoolss_status(int v)
537 if (v == PRINTER_STATUS_OK)
538 return 0;
539 if (v & PRINTER_STATUS_PAUSED)
540 return RAP_QUEUE_STATUS_PAUSED;
541 return RAP_QUEUE_STATUS_ERROR;
544 static void fill_spoolss_printjob_info(int uLevel,
545 struct pack_desc *desc,
546 struct spoolss_JobInfo2 *info2,
547 int n)
549 time_t t = spoolss_Time_to_time_t(&info2->submitted);
551 /* the client expects localtime */
552 t -= get_time_zone(t);
554 PACKI(desc,"W",pjobid_to_rap(info2->printer_name, info2->job_id)); /* uJobId */
555 if (uLevel == 1) {
556 PACKS(desc,"B21", info2->user_name); /* szUserName */
557 PACKS(desc,"B",""); /* pad */
558 PACKS(desc,"B16",""); /* szNotifyName */
559 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
560 PACKS(desc,"z",""); /* pszParms */
561 PACKI(desc,"W",n+1); /* uPosition */
562 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
563 PACKS(desc,"z",""); /* pszStatus */
564 PACKI(desc,"D", t); /* ulSubmitted */
565 PACKI(desc,"D", info2->size); /* ulSize */
566 PACKS(desc,"z", info2->document_name); /* pszComment */
568 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
569 PACKI(desc,"W", info2->priority); /* uPriority */
570 PACKS(desc,"z", info2->user_name); /* pszUserName */
571 PACKI(desc,"W",n+1); /* uPosition */
572 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
573 PACKI(desc,"D",t); /* ulSubmitted */
574 PACKI(desc,"D", info2->size); /* ulSize */
575 PACKS(desc,"z","Samba"); /* pszComment */
576 PACKS(desc,"z", info2->document_name); /* pszDocument */
577 if (uLevel == 3) {
578 PACKS(desc,"z",""); /* pszNotifyName */
579 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
580 PACKS(desc,"z",""); /* pszParms */
581 PACKS(desc,"z",""); /* pszStatus */
582 PACKS(desc,"z", info2->printer_name); /* pszQueue */
583 PACKS(desc,"z","lpd"); /* pszQProcName */
584 PACKS(desc,"z",""); /* pszQProcParms */
585 PACKS(desc,"z","NULL"); /* pszDriverName */
586 PackDriverData(desc); /* pDriverData */
587 PACKS(desc,"z",""); /* pszPrinterName */
588 } else if (uLevel == 4) { /* OS2 */
589 PACKS(desc,"z",""); /* pszSpoolFileName */
590 PACKS(desc,"z",""); /* pszPortName */
591 PACKS(desc,"z",""); /* pszStatus */
592 PACKI(desc,"D",0); /* ulPagesSpooled */
593 PACKI(desc,"D",0); /* ulPagesSent */
594 PACKI(desc,"D",0); /* ulPagesPrinted */
595 PACKI(desc,"D",0); /* ulTimePrinted */
596 PACKI(desc,"D",0); /* ulExtendJobStatus */
597 PACKI(desc,"D",0); /* ulStartPage */
598 PACKI(desc,"D",0); /* ulEndPage */
603 /********************************************************************
604 Respond to the DosPrintQInfo command with a level of 52
605 This is used to get printer driver information for Win9x clients
606 ********************************************************************/
607 static void fill_printq_info_52(struct spoolss_DriverInfo3 *driver,
608 struct pack_desc* desc, int count,
609 const char *printer_name)
611 int i;
612 fstring location;
613 trim_string((char *)driver->driver_path, "\\print$\\WIN40\\0\\", 0);
614 trim_string((char *)driver->data_file, "\\print$\\WIN40\\0\\", 0);
615 trim_string((char *)driver->help_file, "\\print$\\WIN40\\0\\", 0);
617 PACKI(desc, "W", 0x0400); /* don't know */
618 PACKS(desc, "z", driver->driver_name); /* long printer name */
619 PACKS(desc, "z", driver->driver_path); /* Driverfile Name */
620 PACKS(desc, "z", driver->data_file); /* Datafile name */
621 PACKS(desc, "z", driver->monitor_name); /* language monitor */
623 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
624 standard_sub_basic( "", "", location, sizeof(location)-1 );
625 PACKS(desc,"z", location); /* share to retrieve files */
627 PACKS(desc,"z", driver->default_datatype); /* default data type */
628 PACKS(desc,"z", driver->help_file); /* helpfile name */
629 PACKS(desc,"z", driver->driver_path); /* driver name */
631 DEBUG(3,("Printer Driver Name: %s:\n",driver->driver_name));
632 DEBUG(3,("Driver: %s:\n",driver->driver_path));
633 DEBUG(3,("Data File: %s:\n",driver->data_file));
634 DEBUG(3,("Language Monitor: %s:\n",driver->monitor_name));
635 DEBUG(3,("Driver Location: %s:\n",location));
636 DEBUG(3,("Data Type: %s:\n",driver->default_datatype));
637 DEBUG(3,("Help File: %s:\n",driver->help_file));
638 PACKI(desc,"N",count); /* number of files to copy */
640 for ( i=0; i<count && driver->dependent_files && *driver->dependent_files[i]; i++)
642 trim_string((char *)driver->dependent_files[i], "\\print$\\WIN40\\0\\", 0);
643 PACKS(desc,"z",driver->dependent_files[i]); /* driver files to copy */
644 DEBUG(3,("Dependent File: %s:\n", driver->dependent_files[i]));
647 /* sanity check */
648 if ( i != count )
649 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
650 count, i));
652 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", printer_name, i));
654 desc->errcode=NERR_Success;
658 static const char *strip_unc(const char *unc)
660 char *p;
662 if (unc == NULL) {
663 return NULL;
666 if ((p = strrchr(unc, '\\')) != NULL) {
667 return p+1;
670 return unc;
673 static void fill_printq_info(int uLevel,
674 struct pack_desc* desc,
675 int count,
676 union spoolss_JobInfo *job_info,
677 struct spoolss_DriverInfo3 *driver_info,
678 struct spoolss_PrinterInfo2 *printer_info)
680 switch (uLevel) {
681 case 0:
682 case 1:
683 case 2:
684 PACKS(desc,"B13", strip_unc(printer_info->printername));
685 break;
686 case 3:
687 case 4:
688 case 5:
689 PACKS(desc,"z", strip_unc(printer_info->printername));
690 break;
691 case 51:
692 PACKI(desc,"K", printq_spoolss_status(printer_info->status));
693 break;
696 if (uLevel == 1 || uLevel == 2) {
697 PACKS(desc,"B",""); /* alignment */
698 PACKI(desc,"W",5); /* priority */
699 PACKI(desc,"W",0); /* start time */
700 PACKI(desc,"W",0); /* until time */
701 PACKS(desc,"z",""); /* pSepFile */
702 PACKS(desc,"z","lpd"); /* pPrProc */
703 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pDestinations */
704 PACKS(desc,"z",""); /* pParms */
705 if (printer_info->printername == NULL) {
706 PACKS(desc,"z","UNKNOWN PRINTER");
707 PACKI(desc,"W",LPSTAT_ERROR);
708 } else {
709 PACKS(desc,"z", printer_info->comment);
710 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* status */
712 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
715 if (uLevel == 3 || uLevel == 4) {
716 PACKI(desc,"W",5); /* uPriority */
717 PACKI(desc,"W",0); /* uStarttime */
718 PACKI(desc,"W",0); /* uUntiltime */
719 PACKI(desc,"W",5); /* pad1 */
720 PACKS(desc,"z",""); /* pszSepFile */
721 PACKS(desc,"z","WinPrint"); /* pszPrProc */
722 PACKS(desc,"z",NULL); /* pszParms */
723 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
724 /* "don't ask" that it's done this way to fix corrupted
725 Win9X/ME printer comments. */
726 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* fsStatus */
727 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
728 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pszPrinters */
729 PACKS(desc,"z", printer_info->drivername); /* pszDriverName */
730 PackDriverData(desc); /* pDriverData */
733 if (uLevel == 2 || uLevel == 4) {
734 int i;
735 for (i = 0; i < count; i++) {
736 fill_spoolss_printjob_info(uLevel == 2 ? 1 : 2, desc, &job_info[i].info2, i);
740 if (uLevel==52)
741 fill_printq_info_52(driver_info, desc, count, printer_info->printername);
744 /* This function returns the number of files for a given driver */
745 static int get_printerdrivernumber(const struct spoolss_DriverInfo3 *driver)
747 int result = 0;
749 /* count the number of files */
750 while (driver->dependent_files && *driver->dependent_files[result])
751 result++;
753 return result;
756 static bool api_DosPrintQGetInfo(struct smbd_server_connection *sconn,
757 connection_struct *conn, uint16 vuid,
758 char *param, int tpscnt,
759 char *data, int tdscnt,
760 int mdrcnt,int mprcnt,
761 char **rdata,char **rparam,
762 int *rdata_len,int *rparam_len)
764 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
765 char *str2 = skip_string(param,tpscnt,str1);
766 char *p = skip_string(param,tpscnt,str2);
767 char *QueueName = p;
768 unsigned int uLevel;
769 uint32_t count = 0;
770 char *str3;
771 struct pack_desc desc;
772 char* tmpdata=NULL;
774 WERROR werr = WERR_OK;
775 TALLOC_CTX *mem_ctx = talloc_tos();
776 NTSTATUS status;
777 struct rpc_pipe_client *cli = NULL;
778 struct dcerpc_binding_handle *b = NULL;
779 struct policy_handle handle;
780 struct spoolss_DevmodeContainer devmode_ctr;
781 union spoolss_DriverInfo driver_info;
782 union spoolss_JobInfo *job_info = NULL;
783 union spoolss_PrinterInfo printer_info;
785 if (!str1 || !str2 || !p) {
786 return False;
788 memset((char *)&desc,'\0',sizeof(desc));
790 p = skip_string(param,tpscnt,p);
791 if (!p) {
792 return False;
794 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
795 str3 = get_safe_str_ptr(param,tpscnt,p,4);
796 /* str3 may be null here and is checked in check_printq_info(). */
798 /* remove any trailing username */
799 if ((p = strchr_m(QueueName,'%')))
800 *p = 0;
802 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
804 /* check it's a supported varient */
805 if (!prefix_ok(str1,"zWrLh"))
806 return False;
807 if (!check_printq_info(&desc,uLevel,str2,str3)) {
809 * Patch from Scott Moomaw <scott@bridgewater.edu>
810 * to return the 'invalid info level' error if an
811 * unknown level was requested.
813 *rdata_len = 0;
814 *rparam_len = 6;
815 *rparam = smb_realloc_limit(*rparam,*rparam_len);
816 if (!*rparam) {
817 return False;
819 SSVALS(*rparam,0,ERRunknownlevel);
820 SSVAL(*rparam,2,0);
821 SSVAL(*rparam,4,0);
822 return(True);
825 ZERO_STRUCT(handle);
827 if (QueueName == NULL || (strlen(QueueName) < 1)) {
828 desc.errcode = W_ERROR_V(WERR_INVALID_PARAM);
829 goto out;
832 status = rpc_pipe_open_interface(conn,
833 &ndr_table_spoolss.syntax_id,
834 conn->session_info,
835 &conn->sconn->client_id,
836 conn->sconn->msg_ctx,
837 &cli);
838 if (!NT_STATUS_IS_OK(status)) {
839 DEBUG(0,("api_DosPrintQGetInfo: could not connect to spoolss: %s\n",
840 nt_errstr(status)));
841 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
842 goto out;
844 b = cli->binding_handle;
846 ZERO_STRUCT(devmode_ctr);
848 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
849 QueueName,
850 "RAW",
851 devmode_ctr,
852 PRINTER_ACCESS_USE,
853 &handle,
854 &werr);
855 if (!NT_STATUS_IS_OK(status)) {
856 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
857 goto out;
859 if (!W_ERROR_IS_OK(werr)) {
860 desc.errcode = W_ERROR_V(werr);
861 goto out;
864 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
865 &handle,
868 &printer_info);
869 if (!W_ERROR_IS_OK(werr)) {
870 desc.errcode = W_ERROR_V(werr);
871 goto out;
874 if (uLevel==52) {
875 uint32_t server_major_version;
876 uint32_t server_minor_version;
878 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
879 &handle,
880 "Windows 4.0",
881 3, /* level */
883 0, /* version */
885 &driver_info,
886 &server_major_version,
887 &server_minor_version);
888 if (!W_ERROR_IS_OK(werr)) {
889 desc.errcode = W_ERROR_V(werr);
890 goto out;
893 count = get_printerdrivernumber(&driver_info.info3);
894 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
895 } else {
896 uint32_t num_jobs;
897 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
898 &handle,
899 0, /* firstjob */
900 0xff, /* numjobs */
901 2, /* level */
902 0, /* offered */
903 &num_jobs,
904 &job_info);
905 if (!W_ERROR_IS_OK(werr)) {
906 desc.errcode = W_ERROR_V(werr);
907 goto out;
910 count = num_jobs;
913 if (mdrcnt > 0) {
914 *rdata = smb_realloc_limit(*rdata,mdrcnt);
915 if (!*rdata) {
916 return False;
918 desc.base = *rdata;
919 desc.buflen = mdrcnt;
920 } else {
922 * Don't return data but need to get correct length
923 * init_package will return wrong size if buflen=0
925 desc.buflen = getlen(desc.format);
926 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
929 if (init_package(&desc,1,count)) {
930 desc.subcount = count;
931 fill_printq_info(uLevel,&desc,count, job_info, &driver_info.info3, &printer_info.info2);
934 *rdata_len = desc.usedlen;
937 * We must set the return code to ERRbuftoosmall
938 * in order to support lanman style printing with Win NT/2k
939 * clients --jerry
941 if (!mdrcnt && lp_disable_spoolss())
942 desc.errcode = ERRbuftoosmall;
944 out:
945 if (b && is_valid_policy_hnd(&handle)) {
946 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
949 *rdata_len = desc.usedlen;
950 *rparam_len = 6;
951 *rparam = smb_realloc_limit(*rparam,*rparam_len);
952 if (!*rparam) {
953 SAFE_FREE(tmpdata);
954 return False;
956 SSVALS(*rparam,0,desc.errcode);
957 SSVAL(*rparam,2,0);
958 SSVAL(*rparam,4,desc.neededlen);
960 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
962 SAFE_FREE(tmpdata);
964 return(True);
967 /****************************************************************************
968 View list of all print jobs on all queues.
969 ****************************************************************************/
971 static bool api_DosPrintQEnum(struct smbd_server_connection *sconn,
972 connection_struct *conn, uint16 vuid,
973 char *param, int tpscnt,
974 char *data, int tdscnt,
975 int mdrcnt, int mprcnt,
976 char **rdata, char** rparam,
977 int *rdata_len, int *rparam_len)
979 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
980 char *output_format1 = skip_string(param,tpscnt,param_format);
981 char *p = skip_string(param,tpscnt,output_format1);
982 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
983 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
984 int i;
985 struct pack_desc desc;
986 int *subcntarr = NULL;
987 int queuecnt = 0, subcnt = 0, succnt = 0;
989 WERROR werr = WERR_OK;
990 TALLOC_CTX *mem_ctx = talloc_tos();
991 NTSTATUS status;
992 struct rpc_pipe_client *cli = NULL;
993 struct dcerpc_binding_handle *b = NULL;
994 struct spoolss_DevmodeContainer devmode_ctr;
995 uint32_t num_printers;
996 union spoolss_PrinterInfo *printer_info;
997 union spoolss_DriverInfo *driver_info;
998 union spoolss_JobInfo **job_info;
1000 if (!param_format || !output_format1 || !p) {
1001 return False;
1004 memset((char *)&desc,'\0',sizeof(desc));
1006 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
1008 if (!prefix_ok(param_format,"WrLeh")) {
1009 return False;
1011 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
1013 * Patch from Scott Moomaw <scott@bridgewater.edu>
1014 * to return the 'invalid info level' error if an
1015 * unknown level was requested.
1017 *rdata_len = 0;
1018 *rparam_len = 6;
1019 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1020 if (!*rparam) {
1021 return False;
1023 SSVALS(*rparam,0,ERRunknownlevel);
1024 SSVAL(*rparam,2,0);
1025 SSVAL(*rparam,4,0);
1026 return(True);
1029 status = rpc_pipe_open_interface(conn,
1030 &ndr_table_spoolss.syntax_id,
1031 conn->session_info,
1032 &conn->sconn->client_id,
1033 conn->sconn->msg_ctx,
1034 &cli);
1035 if (!NT_STATUS_IS_OK(status)) {
1036 DEBUG(0,("api_DosPrintQEnum: could not connect to spoolss: %s\n",
1037 nt_errstr(status)));
1038 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1039 goto out;
1041 b = cli->binding_handle;
1043 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
1044 PRINTER_ENUM_LOCAL,
1045 cli->srv_name_slash,
1048 &num_printers,
1049 &printer_info);
1050 if (!W_ERROR_IS_OK(werr)) {
1051 desc.errcode = W_ERROR_V(werr);
1052 goto out;
1055 queuecnt = num_printers;
1057 job_info = talloc_array(mem_ctx, union spoolss_JobInfo *, num_printers);
1058 if (job_info == NULL) {
1059 goto err;
1062 driver_info = talloc_array(mem_ctx, union spoolss_DriverInfo, num_printers);
1063 if (driver_info == NULL) {
1064 goto err;
1067 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1068 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1069 goto err;
1072 if (mdrcnt > 0) {
1073 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1074 if (!*rdata) {
1075 goto err;
1078 desc.base = *rdata;
1079 desc.buflen = mdrcnt;
1081 subcnt = 0;
1082 for (i = 0; i < num_printers; i++) {
1084 uint32_t num_jobs;
1085 struct policy_handle handle;
1086 const char *printername;
1088 printername = talloc_strdup(mem_ctx, printer_info[i].info2.printername);
1089 if (printername == NULL) {
1090 goto err;
1093 ZERO_STRUCT(handle);
1094 ZERO_STRUCT(devmode_ctr);
1096 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
1097 printername,
1098 "RAW",
1099 devmode_ctr,
1100 PRINTER_ACCESS_USE,
1101 &handle,
1102 &werr);
1103 if (!NT_STATUS_IS_OK(status)) {
1104 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1105 goto out;
1107 if (!W_ERROR_IS_OK(werr)) {
1108 desc.errcode = W_ERROR_V(werr);
1109 goto out;
1112 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
1113 &handle,
1114 0, /* firstjob */
1115 0xff, /* numjobs */
1116 2, /* level */
1117 0, /* offered */
1118 &num_jobs,
1119 &job_info[i]);
1120 if (!W_ERROR_IS_OK(werr)) {
1121 desc.errcode = W_ERROR_V(werr);
1122 goto out;
1125 if (uLevel==52) {
1126 uint32_t server_major_version;
1127 uint32_t server_minor_version;
1129 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1130 &handle,
1131 "Windows 4.0",
1132 3, /* level */
1134 0, /* version */
1136 &driver_info[i],
1137 &server_major_version,
1138 &server_minor_version);
1139 if (!W_ERROR_IS_OK(werr)) {
1140 desc.errcode = W_ERROR_V(werr);
1141 goto out;
1145 subcntarr[i] = num_jobs;
1146 subcnt += subcntarr[i];
1148 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
1151 if (init_package(&desc,queuecnt,subcnt)) {
1152 for (i = 0; i < num_printers; i++) {
1153 fill_printq_info(uLevel,&desc,subcntarr[i], job_info[i], &driver_info[i].info3, &printer_info[i].info2);
1154 if (desc.errcode == NERR_Success) {
1155 succnt = i;
1160 SAFE_FREE(subcntarr);
1161 out:
1162 *rdata_len = desc.usedlen;
1163 *rparam_len = 8;
1164 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1165 if (!*rparam) {
1166 goto err;
1168 SSVALS(*rparam,0,desc.errcode);
1169 SSVAL(*rparam,2,0);
1170 SSVAL(*rparam,4,succnt);
1171 SSVAL(*rparam,6,queuecnt);
1173 return True;
1175 err:
1177 SAFE_FREE(subcntarr);
1179 return False;
1182 /****************************************************************************
1183 Get info level for a server list query.
1184 ****************************************************************************/
1186 static bool check_session_info(int uLevel, char* id)
1188 switch( uLevel ) {
1189 case 0:
1190 if (strcmp(id,"B16") != 0) {
1191 return False;
1193 break;
1194 case 1:
1195 if (strcmp(id,"B16BBDz") != 0) {
1196 return False;
1198 break;
1199 default:
1200 return False;
1202 return True;
1205 struct srv_info_struct {
1206 fstring name;
1207 uint32 type;
1208 fstring comment;
1209 fstring domain;
1210 bool server_added;
1213 /*******************************************************************
1214 Get server info lists from the files saved by nmbd. Return the
1215 number of entries.
1216 ******************************************************************/
1218 static int get_session_info(uint32 servertype,
1219 struct srv_info_struct **servers,
1220 const char *domain)
1222 int count=0;
1223 int alloced=0;
1224 char **lines;
1225 bool local_list_only;
1226 int i;
1228 lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
1229 if (!lines) {
1230 DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
1231 return 0;
1234 /* request for everything is code for request all servers */
1235 if (servertype == SV_TYPE_ALL) {
1236 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1239 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1241 DEBUG(4,("Servertype search: %8x\n",servertype));
1243 for (i=0;lines[i];i++) {
1244 fstring stype;
1245 struct srv_info_struct *s;
1246 const char *ptr = lines[i];
1247 bool ok = True;
1248 TALLOC_CTX *frame = NULL;
1249 char *p;
1251 if (!*ptr) {
1252 continue;
1255 if (count == alloced) {
1256 alloced += 10;
1257 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1258 if (!*servers) {
1259 DEBUG(0,("get_session_info: failed to enlarge servers info struct!\n"));
1260 TALLOC_FREE(lines);
1261 return 0;
1263 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1265 s = &(*servers)[count];
1267 frame = talloc_stackframe();
1268 s->name[0] = '\0';
1269 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1270 TALLOC_FREE(frame);
1271 continue;
1273 fstrcpy(s->name, p);
1275 stype[0] = '\0';
1276 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1277 TALLOC_FREE(frame);
1278 continue;
1280 fstrcpy(stype, p);
1282 s->comment[0] = '\0';
1283 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1284 TALLOC_FREE(frame);
1285 continue;
1287 fstrcpy(s->comment, p);
1288 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1290 s->domain[0] = '\0';
1291 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1292 /* this allows us to cope with an old nmbd */
1293 fstrcpy(s->domain,lp_workgroup());
1294 } else {
1295 fstrcpy(s->domain, p);
1297 TALLOC_FREE(frame);
1299 if (sscanf(stype,"%X",&s->type) != 1) {
1300 DEBUG(4,("r:host file "));
1301 ok = False;
1304 /* Filter the servers/domains we return based on what was asked for. */
1306 /* Check to see if we are being asked for a local list only. */
1307 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1308 DEBUG(4,("r: local list only"));
1309 ok = False;
1312 /* doesn't match up: don't want it */
1313 if (!(servertype & s->type)) {
1314 DEBUG(4,("r:serv type "));
1315 ok = False;
1318 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1319 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1320 DEBUG(4,("s: dom mismatch "));
1321 ok = False;
1324 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1325 ok = False;
1328 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1329 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1331 if (ok) {
1332 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1333 s->name, s->type, s->comment, s->domain));
1334 s->server_added = True;
1335 count++;
1336 } else {
1337 DEBUG(4,("%20s %8x %25s %15s\n",
1338 s->name, s->type, s->comment, s->domain));
1342 TALLOC_FREE(lines);
1343 return count;
1346 /*******************************************************************
1347 Fill in a server info structure.
1348 ******************************************************************/
1350 static int fill_srv_info(struct srv_info_struct *service,
1351 int uLevel, char **buf, int *buflen,
1352 char **stringbuf, int *stringspace, char *baseaddr)
1354 int struct_len;
1355 char* p;
1356 char* p2;
1357 int l2;
1358 int len;
1360 switch (uLevel) {
1361 case 0:
1362 struct_len = 16;
1363 break;
1364 case 1:
1365 struct_len = 26;
1366 break;
1367 default:
1368 return -1;
1371 if (!buf) {
1372 len = 0;
1373 switch (uLevel) {
1374 case 1:
1375 len = strlen(service->comment)+1;
1376 break;
1379 *buflen = struct_len;
1380 *stringspace = len;
1381 return struct_len + len;
1384 len = struct_len;
1385 p = *buf;
1386 if (*buflen < struct_len) {
1387 return -1;
1389 if (stringbuf) {
1390 p2 = *stringbuf;
1391 l2 = *stringspace;
1392 } else {
1393 p2 = p + struct_len;
1394 l2 = *buflen - struct_len;
1396 if (!baseaddr) {
1397 baseaddr = p;
1400 switch (uLevel) {
1401 case 0:
1402 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1403 break;
1405 case 1:
1406 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1407 SIVAL(p,18,service->type);
1408 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1409 len += CopyAndAdvance(&p2,service->comment,&l2);
1410 break;
1413 if (stringbuf) {
1414 *buf = p + struct_len;
1415 *buflen -= struct_len;
1416 *stringbuf = p2;
1417 *stringspace = l2;
1418 } else {
1419 *buf = p2;
1420 *buflen -= len;
1422 return len;
1426 static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1428 return StrCaseCmp(s1->name,s2->name);
1431 /****************************************************************************
1432 View list of servers available (or possibly domains). The info is
1433 extracted from lists saved by nmbd on the local host.
1434 ****************************************************************************/
1436 static bool api_RNetServerEnum2(struct smbd_server_connection *sconn,
1437 connection_struct *conn, uint16 vuid,
1438 char *param, int tpscnt,
1439 char *data, int tdscnt,
1440 int mdrcnt, int mprcnt, char **rdata,
1441 char **rparam, int *rdata_len, int *rparam_len)
1443 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1444 char *str2 = skip_string(param,tpscnt,str1);
1445 char *p = skip_string(param,tpscnt,str2);
1446 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1447 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1448 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1449 char *p2;
1450 int data_len, fixed_len, string_len;
1451 int f_len = 0, s_len = 0;
1452 struct srv_info_struct *servers=NULL;
1453 int counted=0,total=0;
1454 int i,missed;
1455 fstring domain;
1456 bool domain_request;
1457 bool local_request;
1459 if (!str1 || !str2 || !p) {
1460 return False;
1463 /* If someone sets all the bits they don't really mean to set
1464 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1465 known servers. */
1467 if (servertype == SV_TYPE_ALL) {
1468 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1471 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1472 any other bit (they may just set this bit on its own) they
1473 want all the locally seen servers. However this bit can be
1474 set on its own so set the requested servers to be
1475 ALL - DOMAIN_ENUM. */
1477 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1478 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1481 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1482 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1484 p += 8;
1486 if (!prefix_ok(str1,"WrLehD")) {
1487 return False;
1489 if (!check_session_info(uLevel,str2)) {
1490 return False;
1493 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1494 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1495 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1497 if (strcmp(str1, "WrLehDz") == 0) {
1498 if (skip_string(param,tpscnt,p) == NULL) {
1499 return False;
1501 pull_ascii_fstring(domain, p);
1502 } else {
1503 fstrcpy(domain, lp_workgroup());
1506 DEBUG(4, ("domain [%s]\n", domain));
1508 if (lp_browse_list()) {
1509 total = get_session_info(servertype,&servers,domain);
1512 data_len = fixed_len = string_len = 0;
1513 missed = 0;
1515 TYPESAFE_QSORT(servers, total, srv_comp);
1518 char *lastname=NULL;
1520 for (i=0;i<total;i++) {
1521 struct srv_info_struct *s = &servers[i];
1523 if (lastname && strequal(lastname,s->name)) {
1524 continue;
1526 lastname = s->name;
1527 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1528 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1529 i, s->name, s->type, s->comment, s->domain));
1531 if (data_len < buf_len) {
1532 counted++;
1533 fixed_len += f_len;
1534 string_len += s_len;
1535 } else {
1536 missed++;
1541 *rdata_len = fixed_len + string_len;
1542 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1543 if (!*rdata) {
1544 return False;
1547 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1548 p = *rdata;
1549 f_len = fixed_len;
1550 s_len = string_len;
1553 char *lastname=NULL;
1554 int count2 = counted;
1556 for (i = 0; i < total && count2;i++) {
1557 struct srv_info_struct *s = &servers[i];
1559 if (lastname && strequal(lastname,s->name)) {
1560 continue;
1562 lastname = s->name;
1563 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1564 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1565 i, s->name, s->type, s->comment, s->domain));
1566 count2--;
1570 *rparam_len = 8;
1571 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1572 if (!*rparam) {
1573 return False;
1575 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1576 SSVAL(*rparam,2,0);
1577 SSVAL(*rparam,4,counted);
1578 SSVAL(*rparam,6,counted+missed);
1580 SAFE_FREE(servers);
1582 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1583 domain,uLevel,counted,counted+missed));
1585 return True;
1588 static int srv_name_match(const char *n1, const char *n2)
1591 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1593 * In Windows, FirstNameToReturn need not be an exact match:
1594 * the server will return a list of servers that exist on
1595 * the network greater than or equal to the FirstNameToReturn.
1597 int ret = StrCaseCmp(n1, n2);
1599 if (ret <= 0) {
1600 return 0;
1603 return ret;
1606 static bool api_RNetServerEnum3(struct smbd_server_connection *sconn,
1607 connection_struct *conn, uint16 vuid,
1608 char *param, int tpscnt,
1609 char *data, int tdscnt,
1610 int mdrcnt, int mprcnt, char **rdata,
1611 char **rparam, int *rdata_len, int *rparam_len)
1613 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1614 char *str2 = skip_string(param,tpscnt,str1);
1615 char *p = skip_string(param,tpscnt,str2);
1616 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1617 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1618 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1619 char *p2;
1620 int data_len, fixed_len, string_len;
1621 int f_len = 0, s_len = 0;
1622 struct srv_info_struct *servers=NULL;
1623 int counted=0,first=0,total=0;
1624 int i,missed;
1625 fstring domain;
1626 fstring first_name;
1627 bool domain_request;
1628 bool local_request;
1630 if (!str1 || !str2 || !p) {
1631 return False;
1634 /* If someone sets all the bits they don't really mean to set
1635 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1636 known servers. */
1638 if (servertype == SV_TYPE_ALL) {
1639 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1642 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1643 any other bit (they may just set this bit on its own) they
1644 want all the locally seen servers. However this bit can be
1645 set on its own so set the requested servers to be
1646 ALL - DOMAIN_ENUM. */
1648 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1649 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1652 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1653 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1655 p += 8;
1657 if (strcmp(str1, "WrLehDzz") != 0) {
1658 return false;
1660 if (!check_session_info(uLevel,str2)) {
1661 return False;
1664 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1665 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1666 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1668 if (skip_string(param,tpscnt,p) == NULL) {
1669 return False;
1671 pull_ascii_fstring(domain, p);
1672 if (domain[0] == '\0') {
1673 fstrcpy(domain, lp_workgroup());
1675 p = skip_string(param,tpscnt,p);
1676 if (skip_string(param,tpscnt,p) == NULL) {
1677 return False;
1679 pull_ascii_fstring(first_name, p);
1681 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1682 domain, first_name));
1684 if (lp_browse_list()) {
1685 total = get_session_info(servertype,&servers,domain);
1688 data_len = fixed_len = string_len = 0;
1689 missed = 0;
1691 TYPESAFE_QSORT(servers, total, srv_comp);
1693 if (first_name[0] != '\0') {
1694 struct srv_info_struct *first_server = NULL;
1696 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1697 srv_name_match, first_server);
1698 if (first_server) {
1699 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1701 * The binary search may not find the exact match
1702 * so we need to search backward to find the first match
1704 * This implements the strange matching windows
1705 * implements. (see the comment in srv_name_match().
1707 for (;first > 0;) {
1708 int ret;
1709 ret = StrCaseCmp(first_name,
1710 servers[first-1].name);
1711 if (ret > 0) {
1712 break;
1714 first--;
1716 } else {
1717 /* we should return no entries */
1718 first = total;
1723 char *lastname=NULL;
1725 for (i=first;i<total;i++) {
1726 struct srv_info_struct *s = &servers[i];
1728 if (lastname && strequal(lastname,s->name)) {
1729 continue;
1731 lastname = s->name;
1732 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1733 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1734 i, s->name, s->type, s->comment, s->domain));
1736 if (data_len < buf_len) {
1737 counted++;
1738 fixed_len += f_len;
1739 string_len += s_len;
1740 } else {
1741 missed++;
1746 *rdata_len = fixed_len + string_len;
1747 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1748 if (!*rdata) {
1749 return False;
1752 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1753 p = *rdata;
1754 f_len = fixed_len;
1755 s_len = string_len;
1758 char *lastname=NULL;
1759 int count2 = counted;
1761 for (i = first; i < total && count2;i++) {
1762 struct srv_info_struct *s = &servers[i];
1764 if (lastname && strequal(lastname,s->name)) {
1765 continue;
1767 lastname = s->name;
1768 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1769 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1770 i, s->name, s->type, s->comment, s->domain));
1771 count2--;
1775 *rparam_len = 8;
1776 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1777 if (!*rparam) {
1778 return False;
1780 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1781 SSVAL(*rparam,2,0);
1782 SSVAL(*rparam,4,counted);
1783 SSVAL(*rparam,6,counted+missed);
1785 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1786 domain,uLevel,first,first_name,
1787 first < total ? servers[first].name : "",
1788 counted,counted+missed));
1790 SAFE_FREE(servers);
1792 return True;
1795 /****************************************************************************
1796 command 0x34 - suspected of being a "Lookup Names" stub api
1797 ****************************************************************************/
1799 static bool api_RNetGroupGetUsers(struct smbd_server_connection *sconn,
1800 connection_struct *conn, uint16 vuid,
1801 char *param, int tpscnt,
1802 char *data, int tdscnt,
1803 int mdrcnt, int mprcnt, char **rdata,
1804 char **rparam, int *rdata_len, int *rparam_len)
1806 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1807 char *str2 = skip_string(param,tpscnt,str1);
1808 char *p = skip_string(param,tpscnt,str2);
1809 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1810 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1811 int counted=0;
1812 int missed=0;
1814 if (!str1 || !str2 || !p) {
1815 return False;
1818 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1819 str1, str2, p, uLevel, buf_len));
1821 if (!prefix_ok(str1,"zWrLeh")) {
1822 return False;
1825 *rdata_len = 0;
1827 *rparam_len = 8;
1828 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1829 if (!*rparam) {
1830 return False;
1833 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1834 SSVAL(*rparam,2,0);
1835 SSVAL(*rparam,4,counted);
1836 SSVAL(*rparam,6,counted+missed);
1838 return True;
1841 /****************************************************************************
1842 get info about a share
1843 ****************************************************************************/
1845 static bool check_share_info(int uLevel, char* id)
1847 switch( uLevel ) {
1848 case 0:
1849 if (strcmp(id,"B13") != 0) {
1850 return False;
1852 break;
1853 case 1:
1854 /* Level-2 descriptor is allowed (and ignored) */
1855 if (strcmp(id,"B13BWz") != 0 &&
1856 strcmp(id,"B13BWzWWWzB9B") != 0) {
1857 return False;
1859 break;
1860 case 2:
1861 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1862 return False;
1864 break;
1865 case 91:
1866 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1867 return False;
1869 break;
1870 default:
1871 return False;
1873 return True;
1876 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1877 char** buf, int* buflen,
1878 char** stringbuf, int* stringspace, char* baseaddr)
1880 int struct_len;
1881 char* p;
1882 char* p2;
1883 int l2;
1884 int len;
1886 switch( uLevel ) {
1887 case 0:
1888 struct_len = 13;
1889 break;
1890 case 1:
1891 struct_len = 20;
1892 break;
1893 case 2:
1894 struct_len = 40;
1895 break;
1896 case 91:
1897 struct_len = 68;
1898 break;
1899 default:
1900 return -1;
1903 if (!buf) {
1904 len = 0;
1906 if (uLevel > 0) {
1907 len += StrlenExpanded(conn,snum,lp_comment(snum));
1909 if (uLevel > 1) {
1910 len += strlen(lp_pathname(snum)) + 1;
1912 if (buflen) {
1913 *buflen = struct_len;
1915 if (stringspace) {
1916 *stringspace = len;
1918 return struct_len + len;
1921 len = struct_len;
1922 p = *buf;
1923 if ((*buflen) < struct_len) {
1924 return -1;
1927 if (stringbuf) {
1928 p2 = *stringbuf;
1929 l2 = *stringspace;
1930 } else {
1931 p2 = p + struct_len;
1932 l2 = (*buflen) - struct_len;
1935 if (!baseaddr) {
1936 baseaddr = p;
1939 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1941 if (uLevel > 0) {
1942 int type;
1944 SCVAL(p,13,0);
1945 type = STYPE_DISKTREE;
1946 if (lp_print_ok(snum)) {
1947 type = STYPE_PRINTQ;
1949 if (strequal("IPC",lp_fstype(snum))) {
1950 type = STYPE_IPC;
1952 SSVAL(p,14,type); /* device type */
1953 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1954 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1957 if (uLevel > 1) {
1958 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1959 SSVALS(p,22,-1); /* max uses */
1960 SSVAL(p,24,1); /* current uses */
1961 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1962 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1963 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1966 if (uLevel > 2) {
1967 memset(p+40,0,SHPWLEN+2);
1968 SSVAL(p,50,0);
1969 SIVAL(p,52,0);
1970 SSVAL(p,56,0);
1971 SSVAL(p,58,0);
1972 SIVAL(p,60,0);
1973 SSVAL(p,64,0);
1974 SSVAL(p,66,0);
1977 if (stringbuf) {
1978 (*buf) = p + struct_len;
1979 (*buflen) -= struct_len;
1980 (*stringbuf) = p2;
1981 (*stringspace) = l2;
1982 } else {
1983 (*buf) = p2;
1984 (*buflen) -= len;
1987 return len;
1990 static bool api_RNetShareGetInfo(struct smbd_server_connection *sconn,
1991 connection_struct *conn,uint16 vuid,
1992 char *param, int tpscnt,
1993 char *data, int tdscnt,
1994 int mdrcnt,int mprcnt,
1995 char **rdata,char **rparam,
1996 int *rdata_len,int *rparam_len)
1998 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1999 char *str2 = skip_string(param,tpscnt,str1);
2000 char *netname_in = skip_string(param,tpscnt,str2);
2001 char *netname = NULL;
2002 char *p = skip_string(param,tpscnt,netname);
2003 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2004 int snum;
2006 if (!str1 || !str2 || !netname || !p) {
2007 return False;
2010 snum = find_service(talloc_tos(), netname_in, &netname);
2011 if (snum < 0 || !netname) {
2012 return False;
2015 /* check it's a supported varient */
2016 if (!prefix_ok(str1,"zWrLh")) {
2017 return False;
2019 if (!check_share_info(uLevel,str2)) {
2020 return False;
2023 *rdata = smb_realloc_limit(*rdata,mdrcnt);
2024 if (!*rdata) {
2025 return False;
2027 p = *rdata;
2028 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
2029 if (*rdata_len < 0) {
2030 return False;
2033 *rparam_len = 6;
2034 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2035 if (!*rparam) {
2036 return False;
2038 SSVAL(*rparam,0,NERR_Success);
2039 SSVAL(*rparam,2,0); /* converter word */
2040 SSVAL(*rparam,4,*rdata_len);
2042 return True;
2045 /****************************************************************************
2046 View the list of available shares.
2048 This function is the server side of the NetShareEnum() RAP call.
2049 It fills the return buffer with share names and share comments.
2050 Note that the return buffer normally (in all known cases) allows only
2051 twelve byte strings for share names (plus one for a nul terminator).
2052 Share names longer than 12 bytes must be skipped.
2053 ****************************************************************************/
2055 static bool api_RNetShareEnum(struct smbd_server_connection *sconn,
2056 connection_struct *conn, uint16 vuid,
2057 char *param, int tpscnt,
2058 char *data, int tdscnt,
2059 int mdrcnt,
2060 int mprcnt,
2061 char **rdata,
2062 char **rparam,
2063 int *rdata_len,
2064 int *rparam_len )
2066 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2067 char *str2 = skip_string(param,tpscnt,str1);
2068 char *p = skip_string(param,tpscnt,str2);
2069 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2070 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
2071 char *p2;
2072 int count = 0;
2073 int total=0,counted=0;
2074 bool missed = False;
2075 int i;
2076 int data_len, fixed_len, string_len;
2077 int f_len = 0, s_len = 0;
2079 if (!str1 || !str2 || !p) {
2080 return False;
2083 if (!prefix_ok(str1,"WrLeh")) {
2084 return False;
2086 if (!check_share_info(uLevel,str2)) {
2087 return False;
2090 /* Ensure all the usershares are loaded. */
2091 become_root();
2092 load_registry_shares();
2093 count = load_usershare_shares();
2094 unbecome_root();
2096 data_len = fixed_len = string_len = 0;
2097 for (i=0;i<count;i++) {
2098 fstring servicename_dos;
2099 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2100 continue;
2102 push_ascii_fstring(servicename_dos, lp_servicename(i));
2103 /* Maximum name length = 13. */
2104 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
2105 total++;
2106 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
2107 if (data_len < buf_len) {
2108 counted++;
2109 fixed_len += f_len;
2110 string_len += s_len;
2111 } else {
2112 missed = True;
2117 *rdata_len = fixed_len + string_len;
2118 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2119 if (!*rdata) {
2120 return False;
2123 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
2124 p = *rdata;
2125 f_len = fixed_len;
2126 s_len = string_len;
2128 for( i = 0; i < count; i++ ) {
2129 fstring servicename_dos;
2130 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2131 continue;
2134 push_ascii_fstring(servicename_dos, lp_servicename(i));
2135 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2136 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2137 break;
2142 *rparam_len = 8;
2143 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2144 if (!*rparam) {
2145 return False;
2147 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2148 SSVAL(*rparam,2,0);
2149 SSVAL(*rparam,4,counted);
2150 SSVAL(*rparam,6,total);
2152 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2153 counted,total,uLevel,
2154 buf_len,*rdata_len,mdrcnt));
2156 return True;
2159 /****************************************************************************
2160 Add a share
2161 ****************************************************************************/
2163 static bool api_RNetShareAdd(struct smbd_server_connection *sconn,
2164 connection_struct *conn,uint16 vuid,
2165 char *param, int tpscnt,
2166 char *data, int tdscnt,
2167 int mdrcnt,int mprcnt,
2168 char **rdata,char **rparam,
2169 int *rdata_len,int *rparam_len)
2171 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2172 char *str2 = skip_string(param,tpscnt,str1);
2173 char *p = skip_string(param,tpscnt,str2);
2174 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2175 fstring sharename;
2176 fstring comment;
2177 char *pathname = NULL;
2178 unsigned int offset;
2179 int res = ERRunsup;
2180 size_t converted_size;
2182 WERROR werr = WERR_OK;
2183 TALLOC_CTX *mem_ctx = talloc_tos();
2184 NTSTATUS status;
2185 struct rpc_pipe_client *cli = NULL;
2186 union srvsvc_NetShareInfo info;
2187 struct srvsvc_NetShareInfo2 info2;
2188 struct dcerpc_binding_handle *b;
2190 if (!str1 || !str2 || !p) {
2191 return False;
2194 /* check it's a supported varient */
2195 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2196 return False;
2198 if (!check_share_info(uLevel,str2)) {
2199 return False;
2201 if (uLevel != 2) {
2202 return False;
2205 /* Do we have a string ? */
2206 if (skip_string(data,mdrcnt,data) == NULL) {
2207 return False;
2209 pull_ascii_fstring(sharename,data);
2211 if (mdrcnt < 28) {
2212 return False;
2215 /* only support disk share adds */
2216 if (SVAL(data,14)!=STYPE_DISKTREE) {
2217 return False;
2220 offset = IVAL(data, 16);
2221 if (offset >= mdrcnt) {
2222 res = ERRinvalidparam;
2223 goto out;
2226 /* Do we have a string ? */
2227 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2228 return False;
2230 pull_ascii_fstring(comment, offset? (data+offset) : "");
2232 offset = IVAL(data, 26);
2234 if (offset >= mdrcnt) {
2235 res = ERRinvalidparam;
2236 goto out;
2239 /* Do we have a string ? */
2240 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2241 return False;
2244 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2245 offset ? (data+offset) : "", &converted_size))
2247 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
2248 strerror(errno)));
2251 if (!pathname) {
2252 return false;
2255 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_srvsvc.syntax_id,
2256 conn->session_info,
2257 &conn->sconn->client_id,
2258 conn->sconn->msg_ctx,
2259 &cli);
2260 if (!NT_STATUS_IS_OK(status)) {
2261 DEBUG(0,("api_RNetShareAdd: could not connect to srvsvc: %s\n",
2262 nt_errstr(status)));
2263 res = W_ERROR_V(ntstatus_to_werror(status));
2264 goto out;
2267 b = cli->binding_handle;
2269 info2.name = sharename;
2270 info2.type = STYPE_DISKTREE;
2271 info2.comment = comment;
2272 info2.permissions = 0;
2273 info2.max_users = 0;
2274 info2.current_users = 0;
2275 info2.path = pathname;
2276 info2.password = NULL;
2278 info.info2 = &info2;
2280 status = dcerpc_srvsvc_NetShareAdd(b, mem_ctx,
2281 cli->srv_name_slash,
2283 &info,
2284 NULL,
2285 &werr);
2286 if (!NT_STATUS_IS_OK(status)) {
2287 res = W_ERROR_V(ntstatus_to_werror(status));
2288 goto out;
2290 if (!W_ERROR_IS_OK(werr)) {
2291 res = W_ERROR_V(werr);
2292 goto out;
2295 *rparam_len = 6;
2296 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2297 if (!*rparam) {
2298 return False;
2300 SSVAL(*rparam,0,NERR_Success);
2301 SSVAL(*rparam,2,0); /* converter word */
2302 SSVAL(*rparam,4,*rdata_len);
2303 *rdata_len = 0;
2305 return True;
2307 out:
2309 *rparam_len = 4;
2310 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2311 if (!*rparam) {
2312 return False;
2314 *rdata_len = 0;
2315 SSVAL(*rparam,0,res);
2316 SSVAL(*rparam,2,0);
2317 return True;
2320 /****************************************************************************
2321 view list of groups available
2322 ****************************************************************************/
2324 static bool api_RNetGroupEnum(struct smbd_server_connection *sconn,
2325 connection_struct *conn,uint16 vuid,
2326 char *param, int tpscnt,
2327 char *data, int tdscnt,
2328 int mdrcnt,int mprcnt,
2329 char **rdata,char **rparam,
2330 int *rdata_len,int *rparam_len)
2332 int i;
2333 int errflags=0;
2334 int resume_context, cli_buf_size;
2335 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2336 char *str2 = skip_string(param,tpscnt,str1);
2337 char *p = skip_string(param,tpscnt,str2);
2339 uint32_t num_groups;
2340 uint32_t resume_handle;
2341 struct rpc_pipe_client *samr_pipe;
2342 struct policy_handle samr_handle, domain_handle;
2343 NTSTATUS status, result;
2344 struct dcerpc_binding_handle *b;
2346 if (!str1 || !str2 || !p) {
2347 return False;
2350 if (strcmp(str1,"WrLeh") != 0) {
2351 return False;
2354 /* parameters
2355 * W-> resume context (number of users to skip)
2356 * r -> return parameter pointer to receive buffer
2357 * L -> length of receive buffer
2358 * e -> return parameter number of entries
2359 * h -> return parameter total number of users
2362 if (strcmp("B21",str2) != 0) {
2363 return False;
2366 status = rpc_pipe_open_internal(
2367 talloc_tos(), &ndr_table_samr.syntax_id,
2368 conn->session_info, &conn->sconn->client_id,
2369 conn->sconn->msg_ctx, &samr_pipe);
2370 if (!NT_STATUS_IS_OK(status)) {
2371 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2372 nt_errstr(status)));
2373 return false;
2376 b = samr_pipe->binding_handle;
2378 status = dcerpc_samr_Connect2(b, talloc_tos(), global_myname(),
2379 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle,
2380 &result);
2381 if (!NT_STATUS_IS_OK(status)) {
2382 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2383 nt_errstr(status)));
2384 return false;
2386 if (!NT_STATUS_IS_OK(result)) {
2387 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2388 nt_errstr(result)));
2389 return false;
2392 status = dcerpc_samr_OpenDomain(b, talloc_tos(), &samr_handle,
2393 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2394 get_global_sam_sid(), &domain_handle,
2395 &result);
2396 if (!NT_STATUS_IS_OK(status)) {
2397 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2398 nt_errstr(status)));
2399 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2400 return false;
2402 if (!NT_STATUS_IS_OK(result)) {
2403 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2404 nt_errstr(result)));
2405 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2406 return false;
2409 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2410 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2411 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2412 "%d\n", resume_context, cli_buf_size));
2414 *rdata_len = cli_buf_size;
2415 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2416 if (!*rdata) {
2417 return False;
2420 p = *rdata;
2422 errflags = NERR_Success;
2423 num_groups = 0;
2424 resume_handle = 0;
2426 while (true) {
2427 struct samr_SamArray *sam_entries;
2428 uint32_t num_entries;
2430 status = dcerpc_samr_EnumDomainGroups(b, talloc_tos(),
2431 &domain_handle,
2432 &resume_handle,
2433 &sam_entries, 1,
2434 &num_entries,
2435 &result);
2436 if (!NT_STATUS_IS_OK(status)) {
2437 DEBUG(10, ("dcerpc_samr_EnumDomainGroups returned "
2438 "%s\n", nt_errstr(status)));
2439 break;
2441 if (!NT_STATUS_IS_OK(result)) {
2442 status = result;
2443 DEBUG(10, ("dcerpc_samr_EnumDomainGroups returned "
2444 "%s\n", nt_errstr(result)));
2445 break;
2448 if (num_entries == 0) {
2449 DEBUG(10, ("dcerpc_samr_EnumDomainGroups returned "
2450 "no entries -- done\n"));
2451 break;
2454 for(i=0; i<num_entries; i++) {
2455 const char *name;
2457 name = sam_entries->entries[i].name.string;
2459 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2460 /* set overflow error */
2461 DEBUG(3,("overflow on entry %d group %s\n", i,
2462 name));
2463 errflags=234;
2464 break;
2467 /* truncate the name at 21 chars. */
2468 memset(p, 0, 21);
2469 strlcpy(p, name, 21);
2470 DEBUG(10,("adding entry %d group %s\n", i, p));
2471 p += 21;
2472 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2473 * idea why... */
2474 num_groups += 1;
2477 if (errflags != NERR_Success) {
2478 break;
2481 TALLOC_FREE(sam_entries);
2484 dcerpc_samr_Close(b, talloc_tos(), &domain_handle, &result);
2485 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2487 *rdata_len = PTR_DIFF(p,*rdata);
2489 *rparam_len = 8;
2490 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2491 if (!*rparam) {
2492 return False;
2494 SSVAL(*rparam, 0, errflags);
2495 SSVAL(*rparam, 2, 0); /* converter word */
2496 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2497 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2499 return(True);
2502 /*******************************************************************
2503 Get groups that a user is a member of.
2504 ******************************************************************/
2506 static bool api_NetUserGetGroups(struct smbd_server_connection *sconn,
2507 connection_struct *conn,uint16 vuid,
2508 char *param, int tpscnt,
2509 char *data, int tdscnt,
2510 int mdrcnt,int mprcnt,
2511 char **rdata,char **rparam,
2512 int *rdata_len,int *rparam_len)
2514 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2515 char *str2 = skip_string(param,tpscnt,str1);
2516 char *UserName = skip_string(param,tpscnt,str2);
2517 char *p = skip_string(param,tpscnt,UserName);
2518 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2519 const char *level_string;
2520 int count=0;
2521 bool ret = False;
2522 uint32_t i;
2523 char *endp = NULL;
2525 struct rpc_pipe_client *samr_pipe;
2526 struct policy_handle samr_handle, domain_handle, user_handle;
2527 struct lsa_String name;
2528 struct lsa_Strings names;
2529 struct samr_Ids type, rid;
2530 struct samr_RidWithAttributeArray *rids;
2531 NTSTATUS status, result;
2532 struct dcerpc_binding_handle *b;
2534 if (!str1 || !str2 || !UserName || !p) {
2535 return False;
2538 *rparam_len = 8;
2539 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2540 if (!*rparam) {
2541 return False;
2544 /* check it's a supported varient */
2546 if ( strcmp(str1,"zWrLeh") != 0 )
2547 return False;
2549 switch( uLevel ) {
2550 case 0:
2551 level_string = "B21";
2552 break;
2553 default:
2554 return False;
2557 if (strcmp(level_string,str2) != 0)
2558 return False;
2560 *rdata_len = mdrcnt + 1024;
2561 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2562 if (!*rdata) {
2563 return False;
2566 SSVAL(*rparam,0,NERR_Success);
2567 SSVAL(*rparam,2,0); /* converter word */
2569 p = *rdata;
2570 endp = *rdata + *rdata_len;
2572 status = rpc_pipe_open_internal(
2573 talloc_tos(), &ndr_table_samr.syntax_id,
2574 conn->session_info, &conn->sconn->client_id,
2575 conn->sconn->msg_ctx, &samr_pipe);
2576 if (!NT_STATUS_IS_OK(status)) {
2577 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2578 nt_errstr(status)));
2579 return false;
2582 b = samr_pipe->binding_handle;
2584 status = dcerpc_samr_Connect2(b, talloc_tos(), global_myname(),
2585 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle,
2586 &result);
2587 if (!NT_STATUS_IS_OK(status)) {
2588 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2589 nt_errstr(status)));
2590 return false;
2592 if (!NT_STATUS_IS_OK(result)) {
2593 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2594 nt_errstr(result)));
2595 return false;
2598 status = dcerpc_samr_OpenDomain(b, talloc_tos(), &samr_handle,
2599 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2600 get_global_sam_sid(), &domain_handle,
2601 &result);
2602 if (!NT_STATUS_IS_OK(status)) {
2603 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2604 nt_errstr(status)));
2605 goto close_sam;
2607 if (!NT_STATUS_IS_OK(result)) {
2608 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2609 nt_errstr(result)));
2610 goto close_sam;
2613 name.string = UserName;
2615 status = dcerpc_samr_LookupNames(b, talloc_tos(),
2616 &domain_handle, 1, &name,
2617 &rid, &type,
2618 &result);
2619 if (!NT_STATUS_IS_OK(status)) {
2620 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2621 nt_errstr(status)));
2622 goto close_domain;
2624 if (!NT_STATUS_IS_OK(result)) {
2625 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2626 nt_errstr(result)));
2627 goto close_domain;
2630 if (type.ids[0] != SID_NAME_USER) {
2631 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2632 sid_type_lookup(type.ids[0])));
2633 goto close_domain;
2636 status = dcerpc_samr_OpenUser(b, talloc_tos(),
2637 &domain_handle,
2638 SAMR_USER_ACCESS_GET_GROUPS,
2639 rid.ids[0], &user_handle,
2640 &result);
2641 if (!NT_STATUS_IS_OK(status)) {
2642 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2643 nt_errstr(status)));
2644 goto close_domain;
2646 if (!NT_STATUS_IS_OK(result)) {
2647 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2648 nt_errstr(result)));
2649 goto close_domain;
2652 status = dcerpc_samr_GetGroupsForUser(b, talloc_tos(),
2653 &user_handle, &rids,
2654 &result);
2655 if (!NT_STATUS_IS_OK(status)) {
2656 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2657 nt_errstr(status)));
2658 goto close_user;
2660 if (!NT_STATUS_IS_OK(result)) {
2661 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2662 nt_errstr(result)));
2663 goto close_user;
2666 for (i=0; i<rids->count; i++) {
2668 status = dcerpc_samr_LookupRids(b, talloc_tos(),
2669 &domain_handle,
2670 1, &rids->rids[i].rid,
2671 &names, &type,
2672 &result);
2673 if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result) && (names.count == 1)) {
2674 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2675 p += 21;
2676 count++;
2680 *rdata_len = PTR_DIFF(p,*rdata);
2682 SSVAL(*rparam,4,count); /* is this right?? */
2683 SSVAL(*rparam,6,count); /* is this right?? */
2685 ret = True;
2687 close_user:
2688 dcerpc_samr_Close(b, talloc_tos(), &user_handle, &result);
2689 close_domain:
2690 dcerpc_samr_Close(b, talloc_tos(), &domain_handle, &result);
2691 close_sam:
2692 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2694 return ret;
2697 /*******************************************************************
2698 Get all users.
2699 ******************************************************************/
2701 static bool api_RNetUserEnum(struct smbd_server_connection *sconn,
2702 connection_struct *conn, uint16 vuid,
2703 char *param, int tpscnt,
2704 char *data, int tdscnt,
2705 int mdrcnt,int mprcnt,
2706 char **rdata,char **rparam,
2707 int *rdata_len,int *rparam_len)
2709 int count_sent=0;
2710 int num_users=0;
2711 int errflags=0;
2712 int i, resume_context, cli_buf_size;
2713 uint32_t resume_handle;
2715 struct rpc_pipe_client *samr_pipe;
2716 struct policy_handle samr_handle, domain_handle;
2717 NTSTATUS status, result;
2719 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2720 char *str2 = skip_string(param,tpscnt,str1);
2721 char *p = skip_string(param,tpscnt,str2);
2722 char *endp = NULL;
2724 struct dcerpc_binding_handle *b;
2726 if (!str1 || !str2 || !p) {
2727 return False;
2730 if (strcmp(str1,"WrLeh") != 0)
2731 return False;
2732 /* parameters
2733 * W-> resume context (number of users to skip)
2734 * r -> return parameter pointer to receive buffer
2735 * L -> length of receive buffer
2736 * e -> return parameter number of entries
2737 * h -> return parameter total number of users
2740 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2741 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2742 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2743 resume_context, cli_buf_size));
2745 *rparam_len = 8;
2746 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2747 if (!*rparam) {
2748 return False;
2751 /* check it's a supported varient */
2752 if (strcmp("B21",str2) != 0)
2753 return False;
2755 *rdata_len = cli_buf_size;
2756 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2757 if (!*rdata) {
2758 return False;
2761 p = *rdata;
2762 endp = *rdata + *rdata_len;
2764 status = rpc_pipe_open_internal(
2765 talloc_tos(), &ndr_table_samr.syntax_id,
2766 conn->session_info, &conn->sconn->client_id,
2767 conn->sconn->msg_ctx, &samr_pipe);
2768 if (!NT_STATUS_IS_OK(status)) {
2769 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2770 nt_errstr(status)));
2771 return false;
2774 b = samr_pipe->binding_handle;
2776 status = dcerpc_samr_Connect2(b, talloc_tos(), global_myname(),
2777 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle,
2778 &result);
2779 if (!NT_STATUS_IS_OK(status)) {
2780 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2781 nt_errstr(status)));
2782 return false;
2784 if (!NT_STATUS_IS_OK(result)) {
2785 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2786 nt_errstr(result)));
2787 return false;
2790 status = dcerpc_samr_OpenDomain(b, talloc_tos(), &samr_handle,
2791 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2792 get_global_sam_sid(), &domain_handle,
2793 &result);
2794 if (!NT_STATUS_IS_OK(status)) {
2795 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2796 nt_errstr(status)));
2797 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2798 return false;
2800 if (!NT_STATUS_IS_OK(result)) {
2801 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2802 nt_errstr(result)));
2803 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2804 return false;
2807 errflags=NERR_Success;
2809 resume_handle = 0;
2811 while (true) {
2812 struct samr_SamArray *sam_entries;
2813 uint32_t num_entries;
2815 status = dcerpc_samr_EnumDomainUsers(b, talloc_tos(),
2816 &domain_handle,
2817 &resume_handle,
2818 0, &sam_entries, 1,
2819 &num_entries,
2820 &result);
2822 if (!NT_STATUS_IS_OK(status)) {
2823 DEBUG(10, ("dcerpc_samr_EnumDomainUsers returned "
2824 "%s\n", nt_errstr(status)));
2825 break;
2827 if (!NT_STATUS_IS_OK(result)) {
2828 DEBUG(10, ("dcerpc_samr_EnumDomainUsers returned "
2829 "%s\n", nt_errstr(result)));
2830 break;
2833 if (num_entries == 0) {
2834 DEBUG(10, ("dcerpc_samr_EnumDomainUsers returned "
2835 "no entries -- done\n"));
2836 break;
2839 for (i=0; i<num_entries; i++) {
2840 const char *name;
2842 name = sam_entries->entries[i].name.string;
2844 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2845 &&(strlen(name)<=21)) {
2846 strlcpy(p,name,PTR_DIFF(endp,p));
2847 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2848 "username %s\n",count_sent,p));
2849 p += 21;
2850 count_sent++;
2851 } else {
2852 /* set overflow error */
2853 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2854 "username %s\n",count_sent,name));
2855 errflags=234;
2856 break;
2860 if (errflags != NERR_Success) {
2861 break;
2864 TALLOC_FREE(sam_entries);
2867 dcerpc_samr_Close(b, talloc_tos(), &domain_handle, &result);
2868 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2870 *rdata_len = PTR_DIFF(p,*rdata);
2872 SSVAL(*rparam,0,errflags);
2873 SSVAL(*rparam,2,0); /* converter word */
2874 SSVAL(*rparam,4,count_sent); /* is this right?? */
2875 SSVAL(*rparam,6,num_users); /* is this right?? */
2877 return True;
2880 /****************************************************************************
2881 Get the time of day info.
2882 ****************************************************************************/
2884 static bool api_NetRemoteTOD(struct smbd_server_connection *sconn,
2885 connection_struct *conn,uint16 vuid,
2886 char *param, int tpscnt,
2887 char *data, int tdscnt,
2888 int mdrcnt,int mprcnt,
2889 char **rdata,char **rparam,
2890 int *rdata_len,int *rparam_len)
2892 struct tm *t;
2893 time_t unixdate = time(NULL);
2894 char *p;
2896 *rparam_len = 4;
2897 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2898 if (!*rparam) {
2899 return False;
2902 *rdata_len = 21;
2903 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2904 if (!*rdata) {
2905 return False;
2908 SSVAL(*rparam,0,NERR_Success);
2909 SSVAL(*rparam,2,0); /* converter word */
2911 p = *rdata;
2913 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2914 by NT in a "net time" operation,
2915 it seems to ignore the one below */
2917 /* the client expects to get localtime, not GMT, in this bit
2918 (I think, this needs testing) */
2919 t = localtime(&unixdate);
2920 if (!t) {
2921 return False;
2924 SIVAL(p,4,0); /* msecs ? */
2925 SCVAL(p,8,t->tm_hour);
2926 SCVAL(p,9,t->tm_min);
2927 SCVAL(p,10,t->tm_sec);
2928 SCVAL(p,11,0); /* hundredths of seconds */
2929 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2930 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2931 SCVAL(p,16,t->tm_mday);
2932 SCVAL(p,17,t->tm_mon + 1);
2933 SSVAL(p,18,1900+t->tm_year);
2934 SCVAL(p,20,t->tm_wday);
2936 return True;
2939 /****************************************************************************
2940 Set the user password.
2941 *****************************************************************************/
2943 static bool api_SetUserPassword(struct smbd_server_connection *sconn,
2944 connection_struct *conn,uint16 vuid,
2945 char *param, int tpscnt,
2946 char *data, int tdscnt,
2947 int mdrcnt,int mprcnt,
2948 char **rdata,char **rparam,
2949 int *rdata_len,int *rparam_len)
2951 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2952 char *p = NULL;
2953 fstring user;
2954 fstring pass1,pass2;
2955 TALLOC_CTX *mem_ctx = talloc_tos();
2956 NTSTATUS status, result;
2957 struct rpc_pipe_client *cli = NULL;
2958 struct policy_handle connect_handle, domain_handle, user_handle;
2959 struct lsa_String domain_name;
2960 struct dom_sid2 *domain_sid;
2961 struct lsa_String names;
2962 struct samr_Ids rids;
2963 struct samr_Ids types;
2964 struct samr_Password old_lm_hash;
2965 struct samr_Password new_lm_hash;
2966 int errcode = NERR_badpass;
2967 uint32_t rid;
2968 int encrypted;
2969 int min_pwd_length;
2970 struct dcerpc_binding_handle *b = NULL;
2972 /* Skip 2 strings. */
2973 p = skip_string(param,tpscnt,np);
2974 p = skip_string(param,tpscnt,p);
2976 if (!np || !p) {
2977 return False;
2980 /* Do we have a string ? */
2981 if (skip_string(param,tpscnt,p) == NULL) {
2982 return False;
2984 pull_ascii_fstring(user,p);
2986 p = skip_string(param,tpscnt,p);
2987 if (!p) {
2988 return False;
2991 memset(pass1,'\0',sizeof(pass1));
2992 memset(pass2,'\0',sizeof(pass2));
2994 * We use 31 here not 32 as we're checking
2995 * the last byte we want to access is safe.
2997 if (!is_offset_safe(param,tpscnt,p,31)) {
2998 return False;
3000 memcpy(pass1,p,16);
3001 memcpy(pass2,p+16,16);
3003 encrypted = get_safe_SVAL(param,tpscnt,p+32,0,-1);
3004 if (encrypted == -1) {
3005 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3006 goto out;
3009 min_pwd_length = get_safe_SVAL(param,tpscnt,p+34,0,-1);
3010 if (min_pwd_length == -1) {
3011 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3012 goto out;
3015 *rparam_len = 4;
3016 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3017 if (!*rparam) {
3018 return False;
3021 *rdata_len = 0;
3023 DEBUG(3,("Set password for <%s> (encrypted: %d, min_pwd_length: %d)\n",
3024 user, encrypted, min_pwd_length));
3026 ZERO_STRUCT(connect_handle);
3027 ZERO_STRUCT(domain_handle);
3028 ZERO_STRUCT(user_handle);
3030 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_samr.syntax_id,
3031 conn->session_info,
3032 &conn->sconn->client_id,
3033 conn->sconn->msg_ctx,
3034 &cli);
3035 if (!NT_STATUS_IS_OK(status)) {
3036 DEBUG(0,("api_SetUserPassword: could not connect to samr: %s\n",
3037 nt_errstr(status)));
3038 errcode = W_ERROR_V(ntstatus_to_werror(status));
3039 goto out;
3042 b = cli->binding_handle;
3044 status = dcerpc_samr_Connect2(b, mem_ctx,
3045 global_myname(),
3046 SAMR_ACCESS_CONNECT_TO_SERVER |
3047 SAMR_ACCESS_ENUM_DOMAINS |
3048 SAMR_ACCESS_LOOKUP_DOMAIN,
3049 &connect_handle,
3050 &result);
3051 if (!NT_STATUS_IS_OK(status)) {
3052 errcode = W_ERROR_V(ntstatus_to_werror(status));
3053 goto out;
3055 if (!NT_STATUS_IS_OK(result)) {
3056 errcode = W_ERROR_V(ntstatus_to_werror(result));
3057 goto out;
3060 init_lsa_String(&domain_name, get_global_sam_name());
3062 status = dcerpc_samr_LookupDomain(b, mem_ctx,
3063 &connect_handle,
3064 &domain_name,
3065 &domain_sid,
3066 &result);
3067 if (!NT_STATUS_IS_OK(status)) {
3068 errcode = W_ERROR_V(ntstatus_to_werror(status));
3069 goto out;
3071 if (!NT_STATUS_IS_OK(result)) {
3072 errcode = W_ERROR_V(ntstatus_to_werror(result));
3073 goto out;
3076 status = dcerpc_samr_OpenDomain(b, mem_ctx,
3077 &connect_handle,
3078 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
3079 domain_sid,
3080 &domain_handle,
3081 &result);
3082 if (!NT_STATUS_IS_OK(status)) {
3083 errcode = W_ERROR_V(ntstatus_to_werror(status));
3084 goto out;
3086 if (!NT_STATUS_IS_OK(result)) {
3087 errcode = W_ERROR_V(ntstatus_to_werror(result));
3088 goto out;
3091 init_lsa_String(&names, user);
3093 status = dcerpc_samr_LookupNames(b, mem_ctx,
3094 &domain_handle,
3096 &names,
3097 &rids,
3098 &types,
3099 &result);
3100 if (!NT_STATUS_IS_OK(status)) {
3101 errcode = W_ERROR_V(ntstatus_to_werror(status));
3102 goto out;
3104 if (!NT_STATUS_IS_OK(result)) {
3105 errcode = W_ERROR_V(ntstatus_to_werror(result));
3106 goto out;
3109 if (rids.count != 1) {
3110 errcode = W_ERROR_V(WERR_NO_SUCH_USER);
3111 goto out;
3113 if (rids.count != types.count) {
3114 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3115 goto out;
3117 if (types.ids[0] != SID_NAME_USER) {
3118 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3119 goto out;
3122 rid = rids.ids[0];
3124 status = dcerpc_samr_OpenUser(b, mem_ctx,
3125 &domain_handle,
3126 SAMR_USER_ACCESS_CHANGE_PASSWORD,
3127 rid,
3128 &user_handle,
3129 &result);
3130 if (!NT_STATUS_IS_OK(status)) {
3131 errcode = W_ERROR_V(ntstatus_to_werror(status));
3132 goto out;
3134 if (!NT_STATUS_IS_OK(result)) {
3135 errcode = W_ERROR_V(ntstatus_to_werror(result));
3136 goto out;
3139 if (encrypted == 0) {
3140 E_deshash(pass1, old_lm_hash.hash);
3141 E_deshash(pass2, new_lm_hash.hash);
3142 } else {
3143 ZERO_STRUCT(old_lm_hash);
3144 ZERO_STRUCT(new_lm_hash);
3145 memcpy(old_lm_hash.hash, pass1, MIN(strlen(pass1), 16));
3146 memcpy(new_lm_hash.hash, pass1, MIN(strlen(pass2), 16));
3149 status = dcerpc_samr_ChangePasswordUser(b, mem_ctx,
3150 &user_handle,
3151 true, /* lm_present */
3152 &old_lm_hash,
3153 &new_lm_hash,
3154 false, /* nt_present */
3155 NULL, /* old_nt_crypted */
3156 NULL, /* new_nt_crypted */
3157 false, /* cross1_present */
3158 NULL, /* nt_cross */
3159 false, /* cross2_present */
3160 NULL, /* lm_cross */
3161 &result);
3162 if (!NT_STATUS_IS_OK(status)) {
3163 errcode = W_ERROR_V(ntstatus_to_werror(status));
3164 goto out;
3166 if (!NT_STATUS_IS_OK(result)) {
3167 errcode = W_ERROR_V(ntstatus_to_werror(result));
3168 goto out;
3171 errcode = NERR_Success;
3172 out:
3174 if (b && is_valid_policy_hnd(&user_handle)) {
3175 dcerpc_samr_Close(b, mem_ctx, &user_handle, &result);
3177 if (b && is_valid_policy_hnd(&domain_handle)) {
3178 dcerpc_samr_Close(b, mem_ctx, &domain_handle, &result);
3180 if (b && is_valid_policy_hnd(&connect_handle)) {
3181 dcerpc_samr_Close(b, mem_ctx, &connect_handle, &result);
3184 memset((char *)pass1,'\0',sizeof(fstring));
3185 memset((char *)pass2,'\0',sizeof(fstring));
3187 SSVAL(*rparam,0,errcode);
3188 SSVAL(*rparam,2,0); /* converter word */
3189 return(True);
3192 /****************************************************************************
3193 Set the user password (SamOEM version - gets plaintext).
3194 ****************************************************************************/
3196 static bool api_SamOEMChangePassword(struct smbd_server_connection *sconn,
3197 connection_struct *conn,uint16 vuid,
3198 char *param, int tpscnt,
3199 char *data, int tdscnt,
3200 int mdrcnt,int mprcnt,
3201 char **rdata,char **rparam,
3202 int *rdata_len,int *rparam_len)
3204 fstring user;
3205 char *p = get_safe_str_ptr(param,tpscnt,param,2);
3207 TALLOC_CTX *mem_ctx = talloc_tos();
3208 NTSTATUS status, result;
3209 struct rpc_pipe_client *cli = NULL;
3210 struct lsa_AsciiString server, account;
3211 struct samr_CryptPassword password;
3212 struct samr_Password hash;
3213 int errcode = NERR_badpass;
3214 int bufsize;
3215 struct dcerpc_binding_handle *b;
3217 *rparam_len = 4;
3218 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3219 if (!*rparam) {
3220 return False;
3223 if (!p) {
3224 return False;
3226 *rdata_len = 0;
3228 SSVAL(*rparam,0,NERR_badpass);
3231 * Check the parameter definition is correct.
3234 /* Do we have a string ? */
3235 if (skip_string(param,tpscnt,p) == 0) {
3236 return False;
3238 if(!strequal(p, "zsT")) {
3239 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
3240 return False;
3242 p = skip_string(param, tpscnt, p);
3243 if (!p) {
3244 return False;
3247 /* Do we have a string ? */
3248 if (skip_string(param,tpscnt,p) == 0) {
3249 return False;
3251 if(!strequal(p, "B516B16")) {
3252 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
3253 return False;
3255 p = skip_string(param,tpscnt,p);
3256 if (!p) {
3257 return False;
3259 /* Do we have a string ? */
3260 if (skip_string(param,tpscnt,p) == 0) {
3261 return False;
3263 p += pull_ascii_fstring(user,p);
3265 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
3267 if (tdscnt != 532) {
3268 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3269 goto out;
3272 bufsize = get_safe_SVAL(param,tpscnt,p,0,-1);
3273 if (bufsize != 532) {
3274 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3275 goto out;
3278 memcpy(password.data, data, 516);
3279 memcpy(hash.hash, data+516, 16);
3281 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_samr.syntax_id,
3282 conn->session_info,
3283 &conn->sconn->client_id,
3284 conn->sconn->msg_ctx,
3285 &cli);
3286 if (!NT_STATUS_IS_OK(status)) {
3287 DEBUG(0,("api_SamOEMChangePassword: could not connect to samr: %s\n",
3288 nt_errstr(status)));
3289 errcode = W_ERROR_V(ntstatus_to_werror(status));
3290 goto out;
3293 b = cli->binding_handle;
3295 init_lsa_AsciiString(&server, global_myname());
3296 init_lsa_AsciiString(&account, user);
3298 status = dcerpc_samr_OemChangePasswordUser2(b, mem_ctx,
3299 &server,
3300 &account,
3301 &password,
3302 &hash,
3303 &result);
3304 if (!NT_STATUS_IS_OK(status)) {
3305 errcode = W_ERROR_V(ntstatus_to_werror(status));
3306 goto out;
3308 if (!NT_STATUS_IS_OK(result)) {
3309 errcode = W_ERROR_V(ntstatus_to_werror(result));
3310 goto out;
3313 errcode = NERR_Success;
3314 out:
3315 SSVAL(*rparam,0,errcode);
3316 SSVAL(*rparam,2,0); /* converter word */
3318 return(True);
3321 /****************************************************************************
3322 delete a print job
3323 Form: <W> <>
3324 ****************************************************************************/
3326 static bool api_RDosPrintJobDel(struct smbd_server_connection *sconn,
3327 connection_struct *conn,uint16 vuid,
3328 char *param, int tpscnt,
3329 char *data, int tdscnt,
3330 int mdrcnt,int mprcnt,
3331 char **rdata,char **rparam,
3332 int *rdata_len,int *rparam_len)
3334 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3335 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3336 char *str2 = skip_string(param,tpscnt,str1);
3337 char *p = skip_string(param,tpscnt,str2);
3338 uint32 jobid;
3339 fstring sharename;
3340 int errcode;
3341 WERROR werr = WERR_OK;
3343 TALLOC_CTX *mem_ctx = talloc_tos();
3344 NTSTATUS status;
3345 struct rpc_pipe_client *cli = NULL;
3346 struct dcerpc_binding_handle *b = NULL;
3347 struct policy_handle handle;
3348 struct spoolss_DevmodeContainer devmode_ctr;
3349 enum spoolss_JobControl command;
3351 if (!str1 || !str2 || !p) {
3352 return False;
3355 * We use 1 here not 2 as we're checking
3356 * the last byte we want to access is safe.
3358 if (!is_offset_safe(param,tpscnt,p,1)) {
3359 return False;
3361 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3362 return False;
3364 /* check it's a supported varient */
3365 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
3366 return(False);
3368 *rparam_len = 4;
3369 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3370 if (!*rparam) {
3371 return False;
3373 *rdata_len = 0;
3375 ZERO_STRUCT(handle);
3377 status = rpc_pipe_open_interface(conn,
3378 &ndr_table_spoolss.syntax_id,
3379 conn->session_info,
3380 &conn->sconn->client_id,
3381 conn->sconn->msg_ctx,
3382 &cli);
3383 if (!NT_STATUS_IS_OK(status)) {
3384 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
3385 nt_errstr(status)));
3386 errcode = W_ERROR_V(ntstatus_to_werror(status));
3387 goto out;
3389 b = cli->binding_handle;
3391 ZERO_STRUCT(devmode_ctr);
3393 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
3394 sharename,
3395 "RAW",
3396 devmode_ctr,
3397 JOB_ACCESS_ADMINISTER,
3398 &handle,
3399 &werr);
3400 if (!NT_STATUS_IS_OK(status)) {
3401 errcode = W_ERROR_V(ntstatus_to_werror(status));
3402 goto out;
3404 if (!W_ERROR_IS_OK(werr)) {
3405 errcode = W_ERROR_V(werr);
3406 goto out;
3409 /* FIXME: formerly NERR_JobNotFound was returned if job did not exist
3410 * and NERR_DestNotFound if share did not exist */
3412 errcode = NERR_Success;
3414 switch (function) {
3415 case 81: /* delete */
3416 command = SPOOLSS_JOB_CONTROL_DELETE;
3417 break;
3418 case 82: /* pause */
3419 command = SPOOLSS_JOB_CONTROL_PAUSE;
3420 break;
3421 case 83: /* resume */
3422 command = SPOOLSS_JOB_CONTROL_RESUME;
3423 break;
3424 default:
3425 errcode = NERR_notsupported;
3426 goto out;
3429 status = dcerpc_spoolss_SetJob(b, mem_ctx,
3430 &handle,
3431 jobid,
3432 NULL, /* unique ptr ctr */
3433 command,
3434 &werr);
3435 if (!NT_STATUS_IS_OK(status)) {
3436 errcode = W_ERROR_V(ntstatus_to_werror(status));
3437 goto out;
3439 if (!W_ERROR_IS_OK(werr)) {
3440 errcode = W_ERROR_V(werr);
3441 goto out;
3444 out:
3445 if (b && is_valid_policy_hnd(&handle)) {
3446 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
3449 SSVAL(*rparam,0,errcode);
3450 SSVAL(*rparam,2,0); /* converter word */
3452 return(True);
3455 /****************************************************************************
3456 Purge a print queue - or pause or resume it.
3457 ****************************************************************************/
3459 static bool api_WPrintQueueCtrl(struct smbd_server_connection *sconn,
3460 connection_struct *conn,uint16 vuid,
3461 char *param, int tpscnt,
3462 char *data, int tdscnt,
3463 int mdrcnt,int mprcnt,
3464 char **rdata,char **rparam,
3465 int *rdata_len,int *rparam_len)
3467 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3468 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3469 char *str2 = skip_string(param,tpscnt,str1);
3470 char *QueueName = skip_string(param,tpscnt,str2);
3471 int errcode = NERR_notsupported;
3472 WERROR werr = WERR_OK;
3473 NTSTATUS status;
3475 TALLOC_CTX *mem_ctx = talloc_tos();
3476 struct rpc_pipe_client *cli = NULL;
3477 struct dcerpc_binding_handle *b = NULL;
3478 struct policy_handle handle;
3479 struct spoolss_SetPrinterInfoCtr info_ctr;
3480 struct spoolss_DevmodeContainer devmode_ctr;
3481 struct sec_desc_buf secdesc_ctr;
3482 enum spoolss_PrinterControl command;
3484 if (!str1 || !str2 || !QueueName) {
3485 return False;
3488 /* check it's a supported varient */
3489 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3490 return(False);
3492 *rparam_len = 4;
3493 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3494 if (!*rparam) {
3495 return False;
3497 *rdata_len = 0;
3499 if (skip_string(param,tpscnt,QueueName) == NULL) {
3500 return False;
3503 ZERO_STRUCT(handle);
3505 status = rpc_pipe_open_interface(conn,
3506 &ndr_table_spoolss.syntax_id,
3507 conn->session_info,
3508 &conn->sconn->client_id,
3509 conn->sconn->msg_ctx,
3510 &cli);
3511 if (!NT_STATUS_IS_OK(status)) {
3512 DEBUG(0,("api_WPrintQueueCtrl: could not connect to spoolss: %s\n",
3513 nt_errstr(status)));
3514 errcode = W_ERROR_V(ntstatus_to_werror(status));
3515 goto out;
3517 b = cli->binding_handle;
3519 ZERO_STRUCT(devmode_ctr);
3521 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
3522 QueueName,
3523 NULL,
3524 devmode_ctr,
3525 SEC_FLAG_MAXIMUM_ALLOWED,
3526 &handle,
3527 &werr);
3528 if (!NT_STATUS_IS_OK(status)) {
3529 errcode = W_ERROR_V(ntstatus_to_werror(status));
3530 goto out;
3532 if (!W_ERROR_IS_OK(werr)) {
3533 errcode = W_ERROR_V(werr);
3534 goto out;
3537 switch (function) {
3538 case 74: /* Pause queue */
3539 command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3540 break;
3541 case 75: /* Resume queue */
3542 command = SPOOLSS_PRINTER_CONTROL_RESUME;
3543 break;
3544 case 103: /* Purge */
3545 command = SPOOLSS_PRINTER_CONTROL_PURGE;
3546 break;
3547 default:
3548 werr = WERR_NOT_SUPPORTED;
3549 break;
3552 if (!W_ERROR_IS_OK(werr)) {
3553 errcode = W_ERROR_V(werr);
3554 goto out;
3557 ZERO_STRUCT(info_ctr);
3558 ZERO_STRUCT(secdesc_ctr);
3560 status = dcerpc_spoolss_SetPrinter(b, mem_ctx,
3561 &handle,
3562 &info_ctr,
3563 &devmode_ctr,
3564 &secdesc_ctr,
3565 command,
3566 &werr);
3567 if (!NT_STATUS_IS_OK(status)) {
3568 errcode = W_ERROR_V(ntstatus_to_werror(status));
3569 goto out;
3571 if (!W_ERROR_IS_OK(werr)) {
3572 errcode = W_ERROR_V(werr);
3573 goto out;
3576 errcode = W_ERROR_V(werr);
3578 out:
3580 if (b && is_valid_policy_hnd(&handle)) {
3581 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
3584 SSVAL(*rparam,0,errcode);
3585 SSVAL(*rparam,2,0); /* converter word */
3587 return(True);
3590 /****************************************************************************
3591 set the property of a print job (undocumented?)
3592 ? function = 0xb -> set name of print job
3593 ? function = 0x6 -> move print job up/down
3594 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3595 or <WWsTP> <WB21BB16B10zWWzDDz>
3596 ****************************************************************************/
3598 static int check_printjob_info(struct pack_desc* desc,
3599 int uLevel, char* id)
3601 desc->subformat = NULL;
3602 switch( uLevel ) {
3603 case 0: desc->format = "W"; break;
3604 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3605 case 2: desc->format = "WWzWWDDzz"; break;
3606 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3607 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3608 default:
3609 DEBUG(0,("check_printjob_info: invalid level %d\n",
3610 uLevel ));
3611 return False;
3613 if (id == NULL || strcmp(desc->format,id) != 0) {
3614 DEBUG(0,("check_printjob_info: invalid format %s\n",
3615 id ? id : "<NULL>" ));
3616 return False;
3618 return True;
3621 static bool api_PrintJobInfo(struct smbd_server_connection *sconn,
3622 connection_struct *conn, uint16 vuid,
3623 char *param, int tpscnt,
3624 char *data, int tdscnt,
3625 int mdrcnt,int mprcnt,
3626 char **rdata,char **rparam,
3627 int *rdata_len,int *rparam_len)
3629 struct pack_desc desc;
3630 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3631 char *str2 = skip_string(param,tpscnt,str1);
3632 char *p = skip_string(param,tpscnt,str2);
3633 uint32 jobid;
3634 fstring sharename;
3635 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3636 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3637 int errcode;
3639 TALLOC_CTX *mem_ctx = talloc_tos();
3640 WERROR werr;
3641 NTSTATUS status;
3642 struct rpc_pipe_client *cli = NULL;
3643 struct dcerpc_binding_handle *b = NULL;
3644 struct policy_handle handle;
3645 struct spoolss_DevmodeContainer devmode_ctr;
3646 struct spoolss_JobInfoContainer ctr;
3647 union spoolss_JobInfo info;
3648 struct spoolss_SetJobInfo1 info1;
3650 if (!str1 || !str2 || !p) {
3651 return False;
3654 * We use 1 here not 2 as we're checking
3655 * the last byte we want to access is safe.
3657 if (!is_offset_safe(param,tpscnt,p,1)) {
3658 return False;
3660 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3661 return False;
3662 *rparam_len = 4;
3663 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3664 if (!*rparam) {
3665 return False;
3668 *rdata_len = 0;
3670 /* check it's a supported varient */
3671 if ((strcmp(str1,"WWsTP")) ||
3672 (!check_printjob_info(&desc,uLevel,str2)))
3673 return(False);
3675 errcode = NERR_notsupported;
3677 switch (function) {
3678 case 0xb:
3679 /* change print job name, data gives the name */
3680 break;
3681 default:
3682 goto out;
3685 ZERO_STRUCT(handle);
3687 status = rpc_pipe_open_interface(conn,
3688 &ndr_table_spoolss.syntax_id,
3689 conn->session_info,
3690 &conn->sconn->client_id,
3691 conn->sconn->msg_ctx,
3692 &cli);
3693 if (!NT_STATUS_IS_OK(status)) {
3694 DEBUG(0,("api_PrintJobInfo: could not connect to spoolss: %s\n",
3695 nt_errstr(status)));
3696 errcode = W_ERROR_V(ntstatus_to_werror(status));
3697 goto out;
3699 b = cli->binding_handle;
3701 ZERO_STRUCT(devmode_ctr);
3703 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
3704 sharename,
3705 "RAW",
3706 devmode_ctr,
3707 PRINTER_ACCESS_USE,
3708 &handle,
3709 &werr);
3710 if (!NT_STATUS_IS_OK(status)) {
3711 errcode = W_ERROR_V(ntstatus_to_werror(status));
3712 goto out;
3714 if (!W_ERROR_IS_OK(werr)) {
3715 errcode = W_ERROR_V(werr);
3716 goto out;
3719 werr = rpccli_spoolss_getjob(cli, mem_ctx,
3720 &handle,
3721 jobid,
3722 1, /* level */
3723 0, /* offered */
3724 &info);
3725 if (!W_ERROR_IS_OK(werr)) {
3726 errcode = W_ERROR_V(werr);
3727 goto out;
3730 ZERO_STRUCT(ctr);
3732 info1.job_id = info.info1.job_id;
3733 info1.printer_name = info.info1.printer_name;
3734 info1.user_name = info.info1.user_name;
3735 info1.document_name = data;
3736 info1.data_type = info.info1.data_type;
3737 info1.text_status = info.info1.text_status;
3738 info1.status = info.info1.status;
3739 info1.priority = info.info1.priority;
3740 info1.position = info.info1.position;
3741 info1.total_pages = info.info1.total_pages;
3742 info1.pages_printed = info.info1.pages_printed;
3743 info1.submitted = info.info1.submitted;
3745 ctr.level = 1;
3746 ctr.info.info1 = &info1;
3748 status = dcerpc_spoolss_SetJob(b, mem_ctx,
3749 &handle,
3750 jobid,
3751 &ctr,
3753 &werr);
3754 if (!NT_STATUS_IS_OK(status)) {
3755 errcode = W_ERROR_V(ntstatus_to_werror(status));
3756 goto out;
3758 if (!W_ERROR_IS_OK(werr)) {
3759 errcode = W_ERROR_V(werr);
3760 goto out;
3763 errcode = NERR_Success;
3764 out:
3766 if (b && is_valid_policy_hnd(&handle)) {
3767 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
3770 SSVALS(*rparam,0,errcode);
3771 SSVAL(*rparam,2,0); /* converter word */
3773 return(True);
3777 /****************************************************************************
3778 Get info about the server.
3779 ****************************************************************************/
3781 static bool api_RNetServerGetInfo(struct smbd_server_connection *sconn,
3782 connection_struct *conn,uint16 vuid,
3783 char *param, int tpscnt,
3784 char *data, int tdscnt,
3785 int mdrcnt,int mprcnt,
3786 char **rdata,char **rparam,
3787 int *rdata_len,int *rparam_len)
3789 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3790 char *str2 = skip_string(param,tpscnt,str1);
3791 char *p = skip_string(param,tpscnt,str2);
3792 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3793 char *p2;
3794 int struct_len;
3796 NTSTATUS status;
3797 WERROR werr;
3798 TALLOC_CTX *mem_ctx = talloc_tos();
3799 struct rpc_pipe_client *cli = NULL;
3800 union srvsvc_NetSrvInfo info;
3801 int errcode;
3802 struct dcerpc_binding_handle *b;
3804 if (!str1 || !str2 || !p) {
3805 return False;
3808 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3810 /* check it's a supported varient */
3811 if (!prefix_ok(str1,"WrLh")) {
3812 return False;
3815 switch( uLevel ) {
3816 case 0:
3817 if (strcmp(str2,"B16") != 0) {
3818 return False;
3820 struct_len = 16;
3821 break;
3822 case 1:
3823 if (strcmp(str2,"B16BBDz") != 0) {
3824 return False;
3826 struct_len = 26;
3827 break;
3828 case 2:
3829 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3830 return False;
3832 struct_len = 134;
3833 break;
3834 case 3:
3835 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3836 return False;
3838 struct_len = 144;
3839 break;
3840 case 20:
3841 if (strcmp(str2,"DN") != 0) {
3842 return False;
3844 struct_len = 6;
3845 break;
3846 case 50:
3847 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3848 return False;
3850 struct_len = 42;
3851 break;
3852 default:
3853 return False;
3856 *rdata_len = mdrcnt;
3857 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3858 if (!*rdata) {
3859 return False;
3862 p = *rdata;
3863 p2 = p + struct_len;
3865 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_srvsvc.syntax_id,
3866 conn->session_info,
3867 &conn->sconn->client_id,
3868 conn->sconn->msg_ctx,
3869 &cli);
3870 if (!NT_STATUS_IS_OK(status)) {
3871 DEBUG(0,("api_RNetServerGetInfo: could not connect to srvsvc: %s\n",
3872 nt_errstr(status)));
3873 errcode = W_ERROR_V(ntstatus_to_werror(status));
3874 goto out;
3877 b = cli->binding_handle;
3879 status = dcerpc_srvsvc_NetSrvGetInfo(b, mem_ctx,
3880 NULL,
3881 101,
3882 &info,
3883 &werr);
3884 if (!NT_STATUS_IS_OK(status)) {
3885 errcode = W_ERROR_V(ntstatus_to_werror(status));
3886 goto out;
3888 if (!W_ERROR_IS_OK(werr)) {
3889 errcode = W_ERROR_V(werr);
3890 goto out;
3893 if (info.info101 == NULL) {
3894 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3895 goto out;
3898 if (uLevel != 20) {
3899 srvstr_push(NULL, 0, p, info.info101->server_name, 16,
3900 STR_ASCII|STR_UPPER|STR_TERMINATE);
3902 p += 16;
3903 if (uLevel > 0) {
3904 SCVAL(p,0,info.info101->version_major);
3905 SCVAL(p,1,info.info101->version_minor);
3906 SIVAL(p,2,info.info101->server_type);
3908 if (mdrcnt == struct_len) {
3909 SIVAL(p,6,0);
3910 } else {
3911 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3912 if (mdrcnt - struct_len <= 0) {
3913 return false;
3915 push_ascii(p2,
3916 info.info101->comment,
3917 MIN(mdrcnt - struct_len,
3918 MAX_SERVER_STRING_LENGTH),
3919 STR_TERMINATE);
3920 p2 = skip_string(*rdata,*rdata_len,p2);
3921 if (!p2) {
3922 return False;
3927 if (uLevel > 1) {
3928 return False; /* not yet implemented */
3931 errcode = NERR_Success;
3933 out:
3935 *rdata_len = PTR_DIFF(p2,*rdata);
3937 *rparam_len = 6;
3938 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3939 if (!*rparam) {
3940 return False;
3942 SSVAL(*rparam,0,errcode);
3943 SSVAL(*rparam,2,0); /* converter word */
3944 SSVAL(*rparam,4,*rdata_len);
3946 return True;
3949 /****************************************************************************
3950 Get info about the server.
3951 ****************************************************************************/
3953 static bool api_NetWkstaGetInfo(struct smbd_server_connection *sconn,
3954 connection_struct *conn,uint16 vuid,
3955 char *param, int tpscnt,
3956 char *data, int tdscnt,
3957 int mdrcnt,int mprcnt,
3958 char **rdata,char **rparam,
3959 int *rdata_len,int *rparam_len)
3961 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3962 char *str2 = skip_string(param,tpscnt,str1);
3963 char *p = skip_string(param,tpscnt,str2);
3964 char *p2;
3965 char *endp;
3966 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3968 if (!str1 || !str2 || !p) {
3969 return False;
3972 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3974 *rparam_len = 6;
3975 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3976 if (!*rparam) {
3977 return False;
3980 /* check it's a supported varient */
3981 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3982 return False;
3985 *rdata_len = mdrcnt + 1024;
3986 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3987 if (!*rdata) {
3988 return False;
3991 SSVAL(*rparam,0,NERR_Success);
3992 SSVAL(*rparam,2,0); /* converter word */
3994 p = *rdata;
3995 endp = *rdata + *rdata_len;
3997 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3998 if (!p2) {
3999 return False;
4002 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
4003 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
4004 strupper_m(p2);
4005 p2 = skip_string(*rdata,*rdata_len,p2);
4006 if (!p2) {
4007 return False;
4009 p += 4;
4011 SIVAL(p,0,PTR_DIFF(p2,*rdata));
4012 strlcpy(p2,conn->session_info->sanitized_username,PTR_DIFF(endp,p2));
4013 p2 = skip_string(*rdata,*rdata_len,p2);
4014 if (!p2) {
4015 return False;
4017 p += 4;
4019 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
4020 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
4021 strupper_m(p2);
4022 p2 = skip_string(*rdata,*rdata_len,p2);
4023 if (!p2) {
4024 return False;
4026 p += 4;
4028 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
4029 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
4030 p += 2;
4032 SIVAL(p,0,PTR_DIFF(p2,*rdata));
4033 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
4034 p2 = skip_string(*rdata,*rdata_len,p2);
4035 if (!p2) {
4036 return False;
4038 p += 4;
4040 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
4041 strlcpy(p2,"",PTR_DIFF(endp,p2));
4042 p2 = skip_string(*rdata,*rdata_len,p2);
4043 if (!p2) {
4044 return False;
4046 p += 4;
4048 *rdata_len = PTR_DIFF(p2,*rdata);
4050 SSVAL(*rparam,4,*rdata_len);
4052 return True;
4055 /****************************************************************************
4056 get info about a user
4058 struct user_info_11 {
4059 char usri11_name[21]; 0-20
4060 char usri11_pad; 21
4061 char *usri11_comment; 22-25
4062 char *usri11_usr_comment; 26-29
4063 unsigned short usri11_priv; 30-31
4064 unsigned long usri11_auth_flags; 32-35
4065 long usri11_password_age; 36-39
4066 char *usri11_homedir; 40-43
4067 char *usri11_parms; 44-47
4068 long usri11_last_logon; 48-51
4069 long usri11_last_logoff; 52-55
4070 unsigned short usri11_bad_pw_count; 56-57
4071 unsigned short usri11_num_logons; 58-59
4072 char *usri11_logon_server; 60-63
4073 unsigned short usri11_country_code; 64-65
4074 char *usri11_workstations; 66-69
4075 unsigned long usri11_max_storage; 70-73
4076 unsigned short usri11_units_per_week; 74-75
4077 unsigned char *usri11_logon_hours; 76-79
4078 unsigned short usri11_code_page; 80-81
4081 where:
4083 usri11_name specifies the user name for which information is retrieved
4085 usri11_pad aligns the next data structure element to a word boundary
4087 usri11_comment is a null terminated ASCII comment
4089 usri11_user_comment is a null terminated ASCII comment about the user
4091 usri11_priv specifies the level of the privilege assigned to the user.
4092 The possible values are:
4094 Name Value Description
4095 USER_PRIV_GUEST 0 Guest privilege
4096 USER_PRIV_USER 1 User privilege
4097 USER_PRV_ADMIN 2 Administrator privilege
4099 usri11_auth_flags specifies the account operator privileges. The
4100 possible values are:
4102 Name Value Description
4103 AF_OP_PRINT 0 Print operator
4106 Leach, Naik [Page 28]
4110 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
4113 AF_OP_COMM 1 Communications operator
4114 AF_OP_SERVER 2 Server operator
4115 AF_OP_ACCOUNTS 3 Accounts operator
4118 usri11_password_age specifies how many seconds have elapsed since the
4119 password was last changed.
4121 usri11_home_dir points to a null terminated ASCII string that contains
4122 the path name of the user's home directory.
4124 usri11_parms points to a null terminated ASCII string that is set
4125 aside for use by applications.
4127 usri11_last_logon specifies the time when the user last logged on.
4128 This value is stored as the number of seconds elapsed since
4129 00:00:00, January 1, 1970.
4131 usri11_last_logoff specifies the time when the user last logged off.
4132 This value is stored as the number of seconds elapsed since
4133 00:00:00, January 1, 1970. A value of 0 means the last logoff
4134 time is unknown.
4136 usri11_bad_pw_count specifies the number of incorrect passwords
4137 entered since the last successful logon.
4139 usri11_log1_num_logons specifies the number of times this user has
4140 logged on. A value of -1 means the number of logons is unknown.
4142 usri11_logon_server points to a null terminated ASCII string that
4143 contains the name of the server to which logon requests are sent.
4144 A null string indicates logon requests should be sent to the
4145 domain controller.
4147 usri11_country_code specifies the country code for the user's language
4148 of choice.
4150 usri11_workstations points to a null terminated ASCII string that
4151 contains the names of workstations the user may log on from.
4152 There may be up to 8 workstations, with the names separated by
4153 commas. A null strings indicates there are no restrictions.
4155 usri11_max_storage specifies the maximum amount of disk space the user
4156 can occupy. A value of 0xffffffff indicates there are no
4157 restrictions.
4159 usri11_units_per_week specifies the equal number of time units into
4160 which a week is divided. This value must be equal to 168.
4162 usri11_logon_hours points to a 21 byte (168 bits) string that
4163 specifies the time during which the user can log on. Each bit
4164 represents one unique hour in a week. The first bit (bit 0, word
4165 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
4169 Leach, Naik [Page 29]
4173 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
4176 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
4177 are no restrictions.
4179 usri11_code_page specifies the code page for the user's language of
4180 choice
4182 All of the pointers in this data structure need to be treated
4183 specially. The pointer is a 32 bit pointer. The higher 16 bits need
4184 to be ignored. The converter word returned in the parameters section
4185 needs to be subtracted from the lower 16 bits to calculate an offset
4186 into the return buffer where this ASCII string resides.
4188 There is no auxiliary data in the response.
4190 ****************************************************************************/
4192 #define usri11_name 0
4193 #define usri11_pad 21
4194 #define usri11_comment 22
4195 #define usri11_usr_comment 26
4196 #define usri11_full_name 30
4197 #define usri11_priv 34
4198 #define usri11_auth_flags 36
4199 #define usri11_password_age 40
4200 #define usri11_homedir 44
4201 #define usri11_parms 48
4202 #define usri11_last_logon 52
4203 #define usri11_last_logoff 56
4204 #define usri11_bad_pw_count 60
4205 #define usri11_num_logons 62
4206 #define usri11_logon_server 64
4207 #define usri11_country_code 68
4208 #define usri11_workstations 70
4209 #define usri11_max_storage 74
4210 #define usri11_units_per_week 78
4211 #define usri11_logon_hours 80
4212 #define usri11_code_page 84
4213 #define usri11_end 86
4215 static bool api_RNetUserGetInfo(struct smbd_server_connection *sconn,
4216 connection_struct *conn, uint16 vuid,
4217 char *param, int tpscnt,
4218 char *data, int tdscnt,
4219 int mdrcnt,int mprcnt,
4220 char **rdata,char **rparam,
4221 int *rdata_len,int *rparam_len)
4223 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4224 char *str2 = skip_string(param,tpscnt,str1);
4225 char *UserName = skip_string(param,tpscnt,str2);
4226 char *p = skip_string(param,tpscnt,UserName);
4227 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4228 char *p2;
4229 char *endp;
4230 const char *level_string;
4232 TALLOC_CTX *mem_ctx = talloc_tos();
4233 NTSTATUS status, result;
4234 struct rpc_pipe_client *cli = NULL;
4235 struct policy_handle connect_handle, domain_handle, user_handle;
4236 struct lsa_String domain_name;
4237 struct dom_sid2 *domain_sid;
4238 struct lsa_String names;
4239 struct samr_Ids rids;
4240 struct samr_Ids types;
4241 int errcode = W_ERROR_V(WERR_USER_NOT_FOUND);
4242 uint32_t rid;
4243 union samr_UserInfo *info;
4244 struct dcerpc_binding_handle *b = NULL;
4246 if (!str1 || !str2 || !UserName || !p) {
4247 return False;
4250 *rparam_len = 6;
4251 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4252 if (!*rparam) {
4253 return False;
4256 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
4258 /* check it's a supported variant */
4259 if (strcmp(str1,"zWrLh") != 0) {
4260 return False;
4262 switch( uLevel ) {
4263 case 0: level_string = "B21"; break;
4264 case 1: level_string = "B21BB16DWzzWz"; break;
4265 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
4266 case 10: level_string = "B21Bzzz"; break;
4267 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
4268 default: return False;
4271 if (strcmp(level_string,str2) != 0) {
4272 return False;
4275 *rdata_len = mdrcnt + 1024;
4276 *rdata = smb_realloc_limit(*rdata,*rdata_len);
4277 if (!*rdata) {
4278 return False;
4281 p = *rdata;
4282 endp = *rdata + *rdata_len;
4283 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
4284 if (!p2) {
4285 return False;
4288 ZERO_STRUCT(connect_handle);
4289 ZERO_STRUCT(domain_handle);
4290 ZERO_STRUCT(user_handle);
4292 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_samr.syntax_id,
4293 conn->session_info,
4294 &conn->sconn->client_id,
4295 conn->sconn->msg_ctx,
4296 &cli);
4297 if (!NT_STATUS_IS_OK(status)) {
4298 DEBUG(0,("api_RNetUserGetInfo: could not connect to samr: %s\n",
4299 nt_errstr(status)));
4300 errcode = W_ERROR_V(ntstatus_to_werror(status));
4301 goto out;
4304 b = cli->binding_handle;
4306 status = dcerpc_samr_Connect2(b, mem_ctx,
4307 global_myname(),
4308 SAMR_ACCESS_CONNECT_TO_SERVER |
4309 SAMR_ACCESS_ENUM_DOMAINS |
4310 SAMR_ACCESS_LOOKUP_DOMAIN,
4311 &connect_handle,
4312 &result);
4313 if (!NT_STATUS_IS_OK(status)) {
4314 errcode = W_ERROR_V(ntstatus_to_werror(status));
4315 goto out;
4317 if (!NT_STATUS_IS_OK(result)) {
4318 errcode = W_ERROR_V(ntstatus_to_werror(result));
4319 goto out;
4322 init_lsa_String(&domain_name, get_global_sam_name());
4324 status = dcerpc_samr_LookupDomain(b, mem_ctx,
4325 &connect_handle,
4326 &domain_name,
4327 &domain_sid,
4328 &result);
4329 if (!NT_STATUS_IS_OK(status)) {
4330 errcode = W_ERROR_V(ntstatus_to_werror(status));
4331 goto out;
4333 if (!NT_STATUS_IS_OK(result)) {
4334 errcode = W_ERROR_V(ntstatus_to_werror(result));
4335 goto out;
4338 status = dcerpc_samr_OpenDomain(b, mem_ctx,
4339 &connect_handle,
4340 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
4341 domain_sid,
4342 &domain_handle,
4343 &result);
4344 if (!NT_STATUS_IS_OK(status)) {
4345 errcode = W_ERROR_V(ntstatus_to_werror(status));
4346 goto out;
4348 if (!NT_STATUS_IS_OK(result)) {
4349 errcode = W_ERROR_V(ntstatus_to_werror(result));
4350 goto out;
4353 init_lsa_String(&names, UserName);
4355 status = dcerpc_samr_LookupNames(b, mem_ctx,
4356 &domain_handle,
4358 &names,
4359 &rids,
4360 &types,
4361 &result);
4362 if (!NT_STATUS_IS_OK(status)) {
4363 errcode = W_ERROR_V(ntstatus_to_werror(status));
4364 goto out;
4366 if (!NT_STATUS_IS_OK(result)) {
4367 errcode = W_ERROR_V(ntstatus_to_werror(result));
4368 goto out;
4371 if (rids.count != 1) {
4372 errcode = W_ERROR_V(WERR_NO_SUCH_USER);
4373 goto out;
4375 if (rids.count != types.count) {
4376 errcode = W_ERROR_V(WERR_INVALID_PARAM);
4377 goto out;
4379 if (types.ids[0] != SID_NAME_USER) {
4380 errcode = W_ERROR_V(WERR_INVALID_PARAM);
4381 goto out;
4384 rid = rids.ids[0];
4386 status = dcerpc_samr_OpenUser(b, mem_ctx,
4387 &domain_handle,
4388 SAMR_USER_ACCESS_GET_LOCALE |
4389 SAMR_USER_ACCESS_GET_LOGONINFO |
4390 SAMR_USER_ACCESS_GET_ATTRIBUTES |
4391 SAMR_USER_ACCESS_GET_GROUPS |
4392 SAMR_USER_ACCESS_GET_GROUP_MEMBERSHIP |
4393 SEC_STD_READ_CONTROL,
4394 rid,
4395 &user_handle,
4396 &result);
4397 if (!NT_STATUS_IS_OK(status)) {
4398 errcode = W_ERROR_V(ntstatus_to_werror(status));
4399 goto out;
4401 if (!NT_STATUS_IS_OK(result)) {
4402 errcode = W_ERROR_V(ntstatus_to_werror(result));
4403 goto out;
4406 status = dcerpc_samr_QueryUserInfo2(b, mem_ctx,
4407 &user_handle,
4408 UserAllInformation,
4409 &info,
4410 &result);
4411 if (!NT_STATUS_IS_OK(status)) {
4412 errcode = W_ERROR_V(ntstatus_to_werror(status));
4413 goto out;
4415 if (!NT_STATUS_IS_OK(result)) {
4416 errcode = W_ERROR_V(ntstatus_to_werror(result));
4417 goto out;
4420 memset(p,0,21);
4421 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
4423 if (uLevel > 0) {
4424 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
4425 *p2 = 0;
4428 if (uLevel >= 10) {
4429 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
4430 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
4431 p2 = skip_string(*rdata,*rdata_len,p2);
4432 if (!p2) {
4433 return False;
4436 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
4437 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
4438 p2 = skip_string(*rdata,*rdata_len,p2);
4439 if (!p2) {
4440 return False;
4443 /* EEK! the cifsrap.txt doesn't have this in!!!! */
4444 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
4445 strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4446 p2 = skip_string(*rdata,*rdata_len,p2);
4447 if (!p2) {
4448 return False;
4452 if (uLevel == 11) {
4453 const char *homedir = info->info21.home_directory.string;
4454 /* modelled after NTAS 3.51 reply */
4455 SSVAL(p,usri11_priv,
4456 (get_current_uid(conn) == sec_initial_uid())?
4457 USER_PRIV_ADMIN:USER_PRIV_USER);
4458 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
4459 SIVALS(p,usri11_password_age,-1); /* password age */
4460 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
4461 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
4462 p2 = skip_string(*rdata,*rdata_len,p2);
4463 if (!p2) {
4464 return False;
4466 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
4467 strlcpy(p2,"",PTR_DIFF(endp,p2));
4468 p2 = skip_string(*rdata,*rdata_len,p2);
4469 if (!p2) {
4470 return False;
4472 SIVAL(p,usri11_last_logon,0); /* last logon */
4473 SIVAL(p,usri11_last_logoff,0); /* last logoff */
4474 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
4475 SSVALS(p,usri11_num_logons,-1); /* num logons */
4476 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
4477 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
4478 p2 = skip_string(*rdata,*rdata_len,p2);
4479 if (!p2) {
4480 return False;
4482 SSVAL(p,usri11_country_code,0); /* country code */
4484 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
4485 strlcpy(p2,"",PTR_DIFF(endp,p2));
4486 p2 = skip_string(*rdata,*rdata_len,p2);
4487 if (!p2) {
4488 return False;
4491 SIVALS(p,usri11_max_storage,-1); /* max storage */
4492 SSVAL(p,usri11_units_per_week,168); /* units per week */
4493 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
4495 /* a simple way to get logon hours at all times. */
4496 memset(p2,0xff,21);
4497 SCVAL(p2,21,0); /* fix zero termination */
4498 p2 = skip_string(*rdata,*rdata_len,p2);
4499 if (!p2) {
4500 return False;
4503 SSVAL(p,usri11_code_page,0); /* code page */
4506 if (uLevel == 1 || uLevel == 2) {
4507 memset(p+22,' ',16); /* password */
4508 SIVALS(p,38,-1); /* password age */
4509 SSVAL(p,42,
4510 (get_current_uid(conn) == sec_initial_uid())?
4511 USER_PRIV_ADMIN:USER_PRIV_USER);
4512 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
4513 strlcpy(p2, info->info21.home_directory.string,
4514 PTR_DIFF(endp,p2));
4515 p2 = skip_string(*rdata,*rdata_len,p2);
4516 if (!p2) {
4517 return False;
4519 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
4520 *p2++ = 0;
4521 SSVAL(p,52,0); /* flags */
4522 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
4523 strlcpy(p2, info->info21.logon_script.string,
4524 PTR_DIFF(endp,p2));
4525 p2 = skip_string(*rdata,*rdata_len,p2);
4526 if (!p2) {
4527 return False;
4529 if (uLevel == 2) {
4530 SIVAL(p,58,0); /* auth_flags */
4531 SIVAL(p,62,PTR_DIFF(p2,*rdata)); /* full_name */
4532 strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4533 p2 = skip_string(*rdata,*rdata_len,p2);
4534 if (!p2) {
4535 return False;
4537 SIVAL(p,66,0); /* urs_comment */
4538 SIVAL(p,70,PTR_DIFF(p2,*rdata)); /* parms */
4539 strlcpy(p2,"",PTR_DIFF(endp,p2));
4540 p2 = skip_string(*rdata,*rdata_len,p2);
4541 if (!p2) {
4542 return False;
4544 SIVAL(p,74,0); /* workstations */
4545 SIVAL(p,78,0); /* last_logon */
4546 SIVAL(p,82,0); /* last_logoff */
4547 SIVALS(p,86,-1); /* acct_expires */
4548 SIVALS(p,90,-1); /* max_storage */
4549 SSVAL(p,94,168); /* units_per_week */
4550 SIVAL(p,96,PTR_DIFF(p2,*rdata)); /* logon_hours */
4551 memset(p2,-1,21);
4552 p2 += 21;
4553 SSVALS(p,100,-1); /* bad_pw_count */
4554 SSVALS(p,102,-1); /* num_logons */
4555 SIVAL(p,104,PTR_DIFF(p2,*rdata)); /* logon_server */
4557 TALLOC_CTX *ctx = talloc_tos();
4558 int space_rem = *rdata_len - (p2 - *rdata);
4559 char *tmp;
4561 if (space_rem <= 0) {
4562 return false;
4564 tmp = talloc_strdup(ctx, "\\\\%L");
4565 if (!tmp) {
4566 return false;
4568 tmp = talloc_sub_basic(ctx,
4571 tmp);
4572 if (!tmp) {
4573 return false;
4576 push_ascii(p2,
4577 tmp,
4578 space_rem,
4579 STR_TERMINATE);
4581 p2 = skip_string(*rdata,*rdata_len,p2);
4582 if (!p2) {
4583 return False;
4585 SSVAL(p,108,49); /* country_code */
4586 SSVAL(p,110,860); /* code page */
4590 errcode = NERR_Success;
4592 out:
4593 *rdata_len = PTR_DIFF(p2,*rdata);
4595 if (b && is_valid_policy_hnd(&user_handle)) {
4596 dcerpc_samr_Close(b, mem_ctx, &user_handle, &result);
4598 if (b && is_valid_policy_hnd(&domain_handle)) {
4599 dcerpc_samr_Close(b, mem_ctx, &domain_handle, &result);
4601 if (b && is_valid_policy_hnd(&connect_handle)) {
4602 dcerpc_samr_Close(b, mem_ctx, &connect_handle, &result);
4605 SSVAL(*rparam,0,errcode);
4606 SSVAL(*rparam,2,0); /* converter word */
4607 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
4609 return(True);
4612 static bool api_WWkstaUserLogon(struct smbd_server_connection *sconn,
4613 connection_struct *conn,uint16 vuid,
4614 char *param, int tpscnt,
4615 char *data, int tdscnt,
4616 int mdrcnt,int mprcnt,
4617 char **rdata,char **rparam,
4618 int *rdata_len,int *rparam_len)
4620 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4621 char *str2 = skip_string(param,tpscnt,str1);
4622 char *p = skip_string(param,tpscnt,str2);
4623 int uLevel;
4624 struct pack_desc desc;
4625 char* name;
4626 /* With share level security vuid will always be zero.
4627 Don't depend on vuser being non-null !!. JRA */
4628 user_struct *vuser = get_valid_user_struct(sconn, vuid);
4630 if (!str1 || !str2 || !p) {
4631 return False;
4634 if(vuser != NULL) {
4635 DEBUG(3,(" Username of UID %d is %s\n",
4636 (int)vuser->session_info->utok.uid,
4637 vuser->session_info->unix_name));
4640 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4641 name = get_safe_str_ptr(param,tpscnt,p,2);
4642 if (!name) {
4643 return False;
4646 memset((char *)&desc,'\0',sizeof(desc));
4648 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
4650 /* check it's a supported varient */
4651 if (strcmp(str1,"OOWb54WrLh") != 0) {
4652 return False;
4654 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
4655 return False;
4657 if (mdrcnt > 0) {
4658 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4659 if (!*rdata) {
4660 return False;
4664 desc.base = *rdata;
4665 desc.buflen = mdrcnt;
4666 desc.subformat = NULL;
4667 desc.format = str2;
4669 if (init_package(&desc,1,0)) {
4670 PACKI(&desc,"W",0); /* code */
4671 PACKS(&desc,"B21",name); /* eff. name */
4672 PACKS(&desc,"B",""); /* pad */
4673 PACKI(&desc,"W",
4674 (get_current_uid(conn) == sec_initial_uid())?
4675 USER_PRIV_ADMIN:USER_PRIV_USER);
4676 PACKI(&desc,"D",0); /* auth flags XXX */
4677 PACKI(&desc,"W",0); /* num logons */
4678 PACKI(&desc,"W",0); /* bad pw count */
4679 PACKI(&desc,"D",0); /* last logon */
4680 PACKI(&desc,"D",-1); /* last logoff */
4681 PACKI(&desc,"D",-1); /* logoff time */
4682 PACKI(&desc,"D",-1); /* kickoff time */
4683 PACKI(&desc,"D",0); /* password age */
4684 PACKI(&desc,"D",0); /* password can change */
4685 PACKI(&desc,"D",-1); /* password must change */
4688 fstring mypath;
4689 fstrcpy(mypath,"\\\\");
4690 fstrcat(mypath,get_local_machine_name());
4691 strupper_m(mypath);
4692 PACKS(&desc,"z",mypath); /* computer */
4695 PACKS(&desc,"z",lp_workgroup());/* domain */
4696 PACKS(&desc,"z", vuser ?
4697 vuser->session_info->info3->base.logon_script.string
4698 : ""); /* script path */
4699 PACKI(&desc,"D",0x00000000); /* reserved */
4702 *rdata_len = desc.usedlen;
4703 *rparam_len = 6;
4704 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4705 if (!*rparam) {
4706 return False;
4708 SSVALS(*rparam,0,desc.errcode);
4709 SSVAL(*rparam,2,0);
4710 SSVAL(*rparam,4,desc.neededlen);
4712 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4714 return True;
4717 /****************************************************************************
4718 api_WAccessGetUserPerms
4719 ****************************************************************************/
4721 static bool api_WAccessGetUserPerms(struct smbd_server_connection *sconn,
4722 connection_struct *conn,uint16 vuid,
4723 char *param, int tpscnt,
4724 char *data, int tdscnt,
4725 int mdrcnt,int mprcnt,
4726 char **rdata,char **rparam,
4727 int *rdata_len,int *rparam_len)
4729 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4730 char *str2 = skip_string(param,tpscnt,str1);
4731 char *user = skip_string(param,tpscnt,str2);
4732 char *resource = skip_string(param,tpscnt,user);
4734 if (!str1 || !str2 || !user || !resource) {
4735 return False;
4738 if (skip_string(param,tpscnt,resource) == NULL) {
4739 return False;
4741 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4743 /* check it's a supported varient */
4744 if (strcmp(str1,"zzh") != 0) {
4745 return False;
4747 if (strcmp(str2,"") != 0) {
4748 return False;
4751 *rparam_len = 6;
4752 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4753 if (!*rparam) {
4754 return False;
4756 SSVALS(*rparam,0,0); /* errorcode */
4757 SSVAL(*rparam,2,0); /* converter word */
4758 SSVAL(*rparam,4,0x7f); /* permission flags */
4760 return True;
4763 /****************************************************************************
4764 api_WPrintJobEnumerate
4765 ****************************************************************************/
4767 static bool api_WPrintJobGetInfo(struct smbd_server_connection *sconn,
4768 connection_struct *conn, uint16 vuid,
4769 char *param, int tpscnt,
4770 char *data, int tdscnt,
4771 int mdrcnt,int mprcnt,
4772 char **rdata,char **rparam,
4773 int *rdata_len,int *rparam_len)
4775 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4776 char *str2 = skip_string(param,tpscnt,str1);
4777 char *p = skip_string(param,tpscnt,str2);
4778 int uLevel;
4779 fstring sharename;
4780 uint32 jobid;
4781 struct pack_desc desc;
4782 char *tmpdata=NULL;
4784 TALLOC_CTX *mem_ctx = talloc_tos();
4785 WERROR werr;
4786 NTSTATUS status;
4787 struct rpc_pipe_client *cli = NULL;
4788 struct dcerpc_binding_handle *b = NULL;
4789 struct policy_handle handle;
4790 struct spoolss_DevmodeContainer devmode_ctr;
4791 union spoolss_JobInfo info;
4793 if (!str1 || !str2 || !p) {
4794 return False;
4797 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4799 memset((char *)&desc,'\0',sizeof(desc));
4800 memset((char *)&status,'\0',sizeof(status));
4802 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4804 /* check it's a supported varient */
4805 if (strcmp(str1,"WWrLh") != 0) {
4806 return False;
4808 if (!check_printjob_info(&desc,uLevel,str2)) {
4809 return False;
4812 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4813 return False;
4816 ZERO_STRUCT(handle);
4818 status = rpc_pipe_open_interface(conn,
4819 &ndr_table_spoolss.syntax_id,
4820 conn->session_info,
4821 &conn->sconn->client_id,
4822 conn->sconn->msg_ctx,
4823 &cli);
4824 if (!NT_STATUS_IS_OK(status)) {
4825 DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n",
4826 nt_errstr(status)));
4827 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4828 goto out;
4830 b = cli->binding_handle;
4832 ZERO_STRUCT(devmode_ctr);
4834 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
4835 sharename,
4836 "RAW",
4837 devmode_ctr,
4838 PRINTER_ACCESS_USE,
4839 &handle,
4840 &werr);
4841 if (!NT_STATUS_IS_OK(status)) {
4842 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4843 goto out;
4845 if (!W_ERROR_IS_OK(werr)) {
4846 desc.errcode = W_ERROR_V(werr);
4847 goto out;
4850 werr = rpccli_spoolss_getjob(cli, mem_ctx,
4851 &handle,
4852 jobid,
4853 2, /* level */
4854 0, /* offered */
4855 &info);
4856 if (!W_ERROR_IS_OK(werr)) {
4857 desc.errcode = W_ERROR_V(werr);
4858 goto out;
4861 if (mdrcnt > 0) {
4862 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4863 if (!*rdata) {
4864 return False;
4866 desc.base = *rdata;
4867 desc.buflen = mdrcnt;
4868 } else {
4870 * Don't return data but need to get correct length
4871 * init_package will return wrong size if buflen=0
4873 desc.buflen = getlen(desc.format);
4874 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4877 if (init_package(&desc,1,0)) {
4878 fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position);
4879 *rdata_len = desc.usedlen;
4880 } else {
4881 desc.errcode = NERR_JobNotFound;
4882 *rdata_len = 0;
4884 out:
4885 if (b && is_valid_policy_hnd(&handle)) {
4886 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
4889 *rparam_len = 6;
4890 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4891 if (!*rparam) {
4892 return False;
4894 SSVALS(*rparam,0,desc.errcode);
4895 SSVAL(*rparam,2,0);
4896 SSVAL(*rparam,4,desc.neededlen);
4898 SAFE_FREE(tmpdata);
4900 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4902 return True;
4905 static bool api_WPrintJobEnumerate(struct smbd_server_connection *sconn,
4906 connection_struct *conn, uint16 vuid,
4907 char *param, int tpscnt,
4908 char *data, int tdscnt,
4909 int mdrcnt,int mprcnt,
4910 char **rdata,char **rparam,
4911 int *rdata_len,int *rparam_len)
4913 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4914 char *str2 = skip_string(param,tpscnt,str1);
4915 char *p = skip_string(param,tpscnt,str2);
4916 char *name = p;
4917 int uLevel;
4918 int i, succnt=0;
4919 struct pack_desc desc;
4921 TALLOC_CTX *mem_ctx = talloc_tos();
4922 WERROR werr;
4923 NTSTATUS status;
4924 struct rpc_pipe_client *cli = NULL;
4925 struct dcerpc_binding_handle *b = NULL;
4926 struct policy_handle handle;
4927 struct spoolss_DevmodeContainer devmode_ctr;
4928 uint32_t count = 0;
4929 union spoolss_JobInfo *info;
4931 if (!str1 || !str2 || !p) {
4932 return False;
4935 memset((char *)&desc,'\0',sizeof(desc));
4937 p = skip_string(param,tpscnt,p);
4938 if (!p) {
4939 return False;
4941 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4943 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4945 /* check it's a supported variant */
4946 if (strcmp(str1,"zWrLeh") != 0) {
4947 return False;
4950 if (uLevel > 2) {
4951 return False; /* defined only for uLevel 0,1,2 */
4954 if (!check_printjob_info(&desc,uLevel,str2)) {
4955 return False;
4958 ZERO_STRUCT(handle);
4960 status = rpc_pipe_open_interface(conn,
4961 &ndr_table_spoolss.syntax_id,
4962 conn->session_info,
4963 &conn->sconn->client_id,
4964 conn->sconn->msg_ctx,
4965 &cli);
4966 if (!NT_STATUS_IS_OK(status)) {
4967 DEBUG(0,("api_WPrintJobEnumerate: could not connect to spoolss: %s\n",
4968 nt_errstr(status)));
4969 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4970 goto out;
4972 b = cli->binding_handle;
4974 ZERO_STRUCT(devmode_ctr);
4976 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
4977 name,
4978 NULL,
4979 devmode_ctr,
4980 SEC_FLAG_MAXIMUM_ALLOWED,
4981 &handle,
4982 &werr);
4983 if (!NT_STATUS_IS_OK(status)) {
4984 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4985 goto out;
4987 if (!W_ERROR_IS_OK(werr)) {
4988 desc.errcode = W_ERROR_V(werr);
4989 goto out;
4992 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
4993 &handle,
4994 0, /* firstjob */
4995 0xff, /* numjobs */
4996 2, /* level */
4997 0, /* offered */
4998 &count,
4999 &info);
5000 if (!W_ERROR_IS_OK(werr)) {
5001 desc.errcode = W_ERROR_V(werr);
5002 goto out;
5005 if (mdrcnt > 0) {
5006 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5007 if (!*rdata) {
5008 return False;
5011 desc.base = *rdata;
5012 desc.buflen = mdrcnt;
5014 if (init_package(&desc,count,0)) {
5015 succnt = 0;
5016 for (i = 0; i < count; i++) {
5017 fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i);
5018 if (desc.errcode == NERR_Success) {
5019 succnt = i+1;
5023 out:
5024 if (b && is_valid_policy_hnd(&handle)) {
5025 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5028 *rdata_len = desc.usedlen;
5030 *rparam_len = 8;
5031 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5032 if (!*rparam) {
5033 return False;
5035 SSVALS(*rparam,0,desc.errcode);
5036 SSVAL(*rparam,2,0);
5037 SSVAL(*rparam,4,succnt);
5038 SSVAL(*rparam,6,count);
5040 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
5042 return True;
5045 static int check_printdest_info(struct pack_desc* desc,
5046 int uLevel, char* id)
5048 desc->subformat = NULL;
5049 switch( uLevel ) {
5050 case 0:
5051 desc->format = "B9";
5052 break;
5053 case 1:
5054 desc->format = "B9B21WWzW";
5055 break;
5056 case 2:
5057 desc->format = "z";
5058 break;
5059 case 3:
5060 desc->format = "zzzWWzzzWW";
5061 break;
5062 default:
5063 DEBUG(0,("check_printdest_info: invalid level %d\n",
5064 uLevel));
5065 return False;
5067 if (id == NULL || strcmp(desc->format,id) != 0) {
5068 DEBUG(0,("check_printdest_info: invalid string %s\n",
5069 id ? id : "<NULL>" ));
5070 return False;
5072 return True;
5075 static void fill_printdest_info(struct spoolss_PrinterInfo2 *info2, int uLevel,
5076 struct pack_desc* desc)
5078 char buf[100];
5080 strncpy(buf, info2->printername, sizeof(buf)-1);
5081 buf[sizeof(buf)-1] = 0;
5082 strupper_m(buf);
5084 if (uLevel <= 1) {
5085 PACKS(desc,"B9",buf); /* szName */
5086 if (uLevel == 1) {
5087 PACKS(desc,"B21",""); /* szUserName */
5088 PACKI(desc,"W",0); /* uJobId */
5089 PACKI(desc,"W",0); /* fsStatus */
5090 PACKS(desc,"z",""); /* pszStatus */
5091 PACKI(desc,"W",0); /* time */
5095 if (uLevel == 2 || uLevel == 3) {
5096 PACKS(desc,"z",buf); /* pszPrinterName */
5097 if (uLevel == 3) {
5098 PACKS(desc,"z",""); /* pszUserName */
5099 PACKS(desc,"z",""); /* pszLogAddr */
5100 PACKI(desc,"W",0); /* uJobId */
5101 PACKI(desc,"W",0); /* fsStatus */
5102 PACKS(desc,"z",""); /* pszStatus */
5103 PACKS(desc,"z",""); /* pszComment */
5104 PACKS(desc,"z","NULL"); /* pszDrivers */
5105 PACKI(desc,"W",0); /* time */
5106 PACKI(desc,"W",0); /* pad1 */
5111 static bool api_WPrintDestGetInfo(struct smbd_server_connection *sconn,
5112 connection_struct *conn, uint16 vuid,
5113 char *param, int tpscnt,
5114 char *data, int tdscnt,
5115 int mdrcnt,int mprcnt,
5116 char **rdata,char **rparam,
5117 int *rdata_len,int *rparam_len)
5119 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5120 char *str2 = skip_string(param,tpscnt,str1);
5121 char *p = skip_string(param,tpscnt,str2);
5122 char* PrinterName = p;
5123 int uLevel;
5124 struct pack_desc desc;
5125 char *tmpdata=NULL;
5127 TALLOC_CTX *mem_ctx = talloc_tos();
5128 WERROR werr;
5129 NTSTATUS status;
5130 struct rpc_pipe_client *cli = NULL;
5131 struct dcerpc_binding_handle *b = NULL;
5132 struct policy_handle handle;
5133 struct spoolss_DevmodeContainer devmode_ctr;
5134 union spoolss_PrinterInfo info;
5136 if (!str1 || !str2 || !p) {
5137 return False;
5140 memset((char *)&desc,'\0',sizeof(desc));
5142 p = skip_string(param,tpscnt,p);
5143 if (!p) {
5144 return False;
5146 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5148 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
5150 /* check it's a supported varient */
5151 if (strcmp(str1,"zWrLh") != 0) {
5152 return False;
5154 if (!check_printdest_info(&desc,uLevel,str2)) {
5155 return False;
5158 ZERO_STRUCT(handle);
5160 status = rpc_pipe_open_interface(conn,
5161 &ndr_table_spoolss.syntax_id,
5162 conn->session_info,
5163 &conn->sconn->client_id,
5164 conn->sconn->msg_ctx,
5165 &cli);
5166 if (!NT_STATUS_IS_OK(status)) {
5167 DEBUG(0,("api_WPrintDestGetInfo: could not connect to spoolss: %s\n",
5168 nt_errstr(status)));
5169 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5170 goto out;
5172 b = cli->binding_handle;
5174 ZERO_STRUCT(devmode_ctr);
5176 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
5177 PrinterName,
5178 NULL,
5179 devmode_ctr,
5180 SEC_FLAG_MAXIMUM_ALLOWED,
5181 &handle,
5182 &werr);
5183 if (!NT_STATUS_IS_OK(status)) {
5184 *rdata_len = 0;
5185 desc.errcode = NERR_DestNotFound;
5186 desc.neededlen = 0;
5187 goto out;
5189 if (!W_ERROR_IS_OK(werr)) {
5190 *rdata_len = 0;
5191 desc.errcode = NERR_DestNotFound;
5192 desc.neededlen = 0;
5193 goto out;
5196 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
5197 &handle,
5200 &info);
5201 if (!W_ERROR_IS_OK(werr)) {
5202 *rdata_len = 0;
5203 desc.errcode = NERR_DestNotFound;
5204 desc.neededlen = 0;
5205 goto out;
5208 if (mdrcnt > 0) {
5209 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5210 if (!*rdata) {
5211 return False;
5213 desc.base = *rdata;
5214 desc.buflen = mdrcnt;
5215 } else {
5217 * Don't return data but need to get correct length
5218 * init_package will return wrong size if buflen=0
5220 desc.buflen = getlen(desc.format);
5221 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
5223 if (init_package(&desc,1,0)) {
5224 fill_printdest_info(&info.info2, uLevel,&desc);
5227 out:
5228 if (b && is_valid_policy_hnd(&handle)) {
5229 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5232 *rdata_len = desc.usedlen;
5234 *rparam_len = 6;
5235 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5236 if (!*rparam) {
5237 return False;
5239 SSVALS(*rparam,0,desc.errcode);
5240 SSVAL(*rparam,2,0);
5241 SSVAL(*rparam,4,desc.neededlen);
5243 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
5244 SAFE_FREE(tmpdata);
5246 return True;
5249 static bool api_WPrintDestEnum(struct smbd_server_connection *sconn,
5250 connection_struct *conn, uint16 vuid,
5251 char *param, int tpscnt,
5252 char *data, int tdscnt,
5253 int mdrcnt,int mprcnt,
5254 char **rdata,char **rparam,
5255 int *rdata_len,int *rparam_len)
5257 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5258 char *str2 = skip_string(param,tpscnt,str1);
5259 char *p = skip_string(param,tpscnt,str2);
5260 int uLevel;
5261 int queuecnt;
5262 int i, n, succnt=0;
5263 struct pack_desc desc;
5265 TALLOC_CTX *mem_ctx = talloc_tos();
5266 WERROR werr;
5267 NTSTATUS status;
5268 struct rpc_pipe_client *cli = NULL;
5269 union spoolss_PrinterInfo *info;
5270 uint32_t count;
5272 if (!str1 || !str2 || !p) {
5273 return False;
5276 memset((char *)&desc,'\0',sizeof(desc));
5278 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5280 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
5282 /* check it's a supported varient */
5283 if (strcmp(str1,"WrLeh") != 0) {
5284 return False;
5286 if (!check_printdest_info(&desc,uLevel,str2)) {
5287 return False;
5290 queuecnt = 0;
5292 status = rpc_pipe_open_interface(conn,
5293 &ndr_table_spoolss.syntax_id,
5294 conn->session_info,
5295 &conn->sconn->client_id,
5296 conn->sconn->msg_ctx,
5297 &cli);
5298 if (!NT_STATUS_IS_OK(status)) {
5299 DEBUG(0,("api_WPrintDestEnum: could not connect to spoolss: %s\n",
5300 nt_errstr(status)));
5301 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5302 goto out;
5305 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
5306 PRINTER_ENUM_LOCAL,
5307 cli->srv_name_slash,
5310 &count,
5311 &info);
5312 if (!W_ERROR_IS_OK(werr)) {
5313 desc.errcode = W_ERROR_V(werr);
5314 *rdata_len = 0;
5315 desc.errcode = NERR_DestNotFound;
5316 desc.neededlen = 0;
5317 goto out;
5320 queuecnt = count;
5322 if (mdrcnt > 0) {
5323 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5324 if (!*rdata) {
5325 return False;
5329 desc.base = *rdata;
5330 desc.buflen = mdrcnt;
5331 if (init_package(&desc,queuecnt,0)) {
5332 succnt = 0;
5333 n = 0;
5334 for (i = 0; i < count; i++) {
5335 fill_printdest_info(&info[i].info2, uLevel,&desc);
5336 n++;
5337 if (desc.errcode == NERR_Success) {
5338 succnt = n;
5342 out:
5343 *rdata_len = desc.usedlen;
5345 *rparam_len = 8;
5346 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5347 if (!*rparam) {
5348 return False;
5350 SSVALS(*rparam,0,desc.errcode);
5351 SSVAL(*rparam,2,0);
5352 SSVAL(*rparam,4,succnt);
5353 SSVAL(*rparam,6,queuecnt);
5355 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
5357 return True;
5360 static bool api_WPrintDriverEnum(struct smbd_server_connection *sconn,
5361 connection_struct *conn, uint16 vuid,
5362 char *param, int tpscnt,
5363 char *data, int tdscnt,
5364 int mdrcnt,int mprcnt,
5365 char **rdata,char **rparam,
5366 int *rdata_len,int *rparam_len)
5368 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5369 char *str2 = skip_string(param,tpscnt,str1);
5370 char *p = skip_string(param,tpscnt,str2);
5371 int uLevel;
5372 int succnt;
5373 struct pack_desc desc;
5375 if (!str1 || !str2 || !p) {
5376 return False;
5379 memset((char *)&desc,'\0',sizeof(desc));
5381 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5383 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
5385 /* check it's a supported varient */
5386 if (strcmp(str1,"WrLeh") != 0) {
5387 return False;
5389 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
5390 return False;
5393 if (mdrcnt > 0) {
5394 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5395 if (!*rdata) {
5396 return False;
5399 desc.base = *rdata;
5400 desc.buflen = mdrcnt;
5401 if (init_package(&desc,1,0)) {
5402 PACKS(&desc,"B41","NULL");
5405 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5407 *rdata_len = desc.usedlen;
5409 *rparam_len = 8;
5410 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5411 if (!*rparam) {
5412 return False;
5414 SSVALS(*rparam,0,desc.errcode);
5415 SSVAL(*rparam,2,0);
5416 SSVAL(*rparam,4,succnt);
5417 SSVAL(*rparam,6,1);
5419 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
5421 return True;
5424 static bool api_WPrintQProcEnum(struct smbd_server_connection *sconn,
5425 connection_struct *conn, uint16 vuid,
5426 char *param, int tpscnt,
5427 char *data, int tdscnt,
5428 int mdrcnt,int mprcnt,
5429 char **rdata,char **rparam,
5430 int *rdata_len,int *rparam_len)
5432 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5433 char *str2 = skip_string(param,tpscnt,str1);
5434 char *p = skip_string(param,tpscnt,str2);
5435 int uLevel;
5436 int succnt;
5437 struct pack_desc desc;
5439 if (!str1 || !str2 || !p) {
5440 return False;
5442 memset((char *)&desc,'\0',sizeof(desc));
5444 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5446 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
5448 /* check it's a supported varient */
5449 if (strcmp(str1,"WrLeh") != 0) {
5450 return False;
5452 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
5453 return False;
5456 if (mdrcnt > 0) {
5457 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5458 if (!*rdata) {
5459 return False;
5462 desc.base = *rdata;
5463 desc.buflen = mdrcnt;
5464 desc.format = str2;
5465 if (init_package(&desc,1,0)) {
5466 PACKS(&desc,"B13","lpd");
5469 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5471 *rdata_len = desc.usedlen;
5473 *rparam_len = 8;
5474 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5475 if (!*rparam) {
5476 return False;
5478 SSVALS(*rparam,0,desc.errcode);
5479 SSVAL(*rparam,2,0);
5480 SSVAL(*rparam,4,succnt);
5481 SSVAL(*rparam,6,1);
5483 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
5485 return True;
5488 static bool api_WPrintPortEnum(struct smbd_server_connection *sconn,
5489 connection_struct *conn, uint16 vuid,
5490 char *param, int tpscnt,
5491 char *data, int tdscnt,
5492 int mdrcnt,int mprcnt,
5493 char **rdata,char **rparam,
5494 int *rdata_len,int *rparam_len)
5496 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5497 char *str2 = skip_string(param,tpscnt,str1);
5498 char *p = skip_string(param,tpscnt,str2);
5499 int uLevel;
5500 int succnt;
5501 struct pack_desc desc;
5503 if (!str1 || !str2 || !p) {
5504 return False;
5507 memset((char *)&desc,'\0',sizeof(desc));
5509 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5511 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
5513 /* check it's a supported varient */
5514 if (strcmp(str1,"WrLeh") != 0) {
5515 return False;
5517 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
5518 return False;
5521 if (mdrcnt > 0) {
5522 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5523 if (!*rdata) {
5524 return False;
5527 memset((char *)&desc,'\0',sizeof(desc));
5528 desc.base = *rdata;
5529 desc.buflen = mdrcnt;
5530 desc.format = str2;
5531 if (init_package(&desc,1,0)) {
5532 PACKS(&desc,"B13","lp0");
5535 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5537 *rdata_len = desc.usedlen;
5539 *rparam_len = 8;
5540 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5541 if (!*rparam) {
5542 return False;
5544 SSVALS(*rparam,0,desc.errcode);
5545 SSVAL(*rparam,2,0);
5546 SSVAL(*rparam,4,succnt);
5547 SSVAL(*rparam,6,1);
5549 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
5551 return True;
5554 /****************************************************************************
5555 List open sessions
5556 ****************************************************************************/
5558 static bool api_RNetSessionEnum(struct smbd_server_connection *sconn,
5559 connection_struct *conn, uint16 vuid,
5560 char *param, int tpscnt,
5561 char *data, int tdscnt,
5562 int mdrcnt,int mprcnt,
5563 char **rdata,char **rparam,
5564 int *rdata_len,int *rparam_len)
5567 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5568 char *str2 = skip_string(param,tpscnt,str1);
5569 char *p = skip_string(param,tpscnt,str2);
5570 int uLevel;
5571 struct pack_desc desc;
5572 int i;
5574 TALLOC_CTX *mem_ctx = talloc_tos();
5575 WERROR werr;
5576 NTSTATUS status;
5577 struct rpc_pipe_client *cli = NULL;
5578 struct dcerpc_binding_handle *b = NULL;
5579 struct srvsvc_NetSessInfoCtr info_ctr;
5580 uint32_t totalentries, resume_handle = 0;
5581 uint32_t count = 0;
5583 if (!str1 || !str2 || !p) {
5584 return False;
5587 ZERO_STRUCT(desc);
5589 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5591 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
5592 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
5593 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
5595 /* check it's a supported varient */
5596 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
5597 return False;
5599 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
5600 return False;
5603 status = rpc_pipe_open_interface(conn,
5604 &ndr_table_srvsvc.syntax_id,
5605 conn->session_info,
5606 &conn->sconn->client_id,
5607 conn->sconn->msg_ctx,
5608 &cli);
5609 if (!NT_STATUS_IS_OK(status)) {
5610 DEBUG(0,("RNetSessionEnum: could not connect to srvsvc: %s\n",
5611 nt_errstr(status)));
5612 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5613 goto out;
5615 b = cli->binding_handle;
5617 info_ctr.level = 1;
5618 info_ctr.ctr.ctr1 = talloc_zero(talloc_tos(), struct srvsvc_NetSessCtr1);
5619 if (info_ctr.ctr.ctr1 == NULL) {
5620 desc.errcode = W_ERROR_V(WERR_NOMEM);
5621 goto out;
5624 status = dcerpc_srvsvc_NetSessEnum(b, mem_ctx,
5625 cli->srv_name_slash,
5626 NULL, /* client */
5627 NULL, /* user */
5628 &info_ctr,
5629 (uint32_t)-1, /* max_buffer */
5630 &totalentries,
5631 &resume_handle,
5632 &werr);
5633 if (!NT_STATUS_IS_OK(status)) {
5634 DEBUG(0,("RNetSessionEnum: dcerpc_srvsvc_NetSessEnum failed: %s\n",
5635 nt_errstr(status)));
5636 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5637 goto out;
5640 if (!W_ERROR_IS_OK(werr)) {
5641 DEBUG(0,("RNetSessionEnum: dcerpc_srvsvc_NetSessEnum failed: %s\n",
5642 win_errstr(werr)));
5643 desc.errcode = W_ERROR_V(werr);
5644 goto out;
5647 count = info_ctr.ctr.ctr1->count;
5649 out:
5650 if (mdrcnt > 0) {
5651 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5652 if (!*rdata) {
5653 return False;
5657 desc.base = *rdata;
5658 desc.buflen = mdrcnt;
5659 desc.format = str2;
5660 if (!init_package(&desc, count,0)) {
5661 return False;
5664 for(i=0; i < count; i++) {
5665 PACKS(&desc, "z", info_ctr.ctr.ctr1->array[i].client);
5666 PACKS(&desc, "z", info_ctr.ctr.ctr1->array[i].user);
5667 PACKI(&desc, "W", 1); /* num conns */
5668 PACKI(&desc, "W", info_ctr.ctr.ctr1->array[i].num_open);
5669 PACKI(&desc, "W", 1); /* num users */
5670 PACKI(&desc, "D", 0); /* session time */
5671 PACKI(&desc, "D", 0); /* idle time */
5672 PACKI(&desc, "D", 0); /* flags */
5673 PACKS(&desc, "z", "Unknown Client"); /* client type string */
5676 *rdata_len = desc.usedlen;
5678 *rparam_len = 8;
5679 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5680 if (!*rparam) {
5681 return False;
5683 SSVALS(*rparam,0,desc.errcode);
5684 SSVAL(*rparam,2,0); /* converter */
5685 SSVAL(*rparam,4, count); /* count */
5687 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
5689 return True;
5693 /****************************************************************************
5694 The buffer was too small.
5695 ****************************************************************************/
5697 static bool api_TooSmall(struct smbd_server_connection *sconn,
5698 connection_struct *conn,uint16 vuid, char *param, char *data,
5699 int mdrcnt, int mprcnt,
5700 char **rdata, char **rparam,
5701 int *rdata_len, int *rparam_len)
5703 *rparam_len = MIN(*rparam_len,mprcnt);
5704 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5705 if (!*rparam) {
5706 return False;
5709 *rdata_len = 0;
5711 SSVAL(*rparam,0,NERR_BufTooSmall);
5713 DEBUG(3,("Supplied buffer too small in API command\n"));
5715 return True;
5718 /****************************************************************************
5719 The request is not supported.
5720 ****************************************************************************/
5722 static bool api_Unsupported(struct smbd_server_connection *sconn,
5723 connection_struct *conn, uint16 vuid,
5724 char *param, int tpscnt,
5725 char *data, int tdscnt,
5726 int mdrcnt, int mprcnt,
5727 char **rdata, char **rparam,
5728 int *rdata_len, int *rparam_len)
5730 *rparam_len = 4;
5731 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5732 if (!*rparam) {
5733 return False;
5736 *rdata_len = 0;
5738 SSVAL(*rparam,0,NERR_notsupported);
5739 SSVAL(*rparam,2,0); /* converter word */
5741 DEBUG(3,("Unsupported API command\n"));
5743 return True;
5746 static const struct {
5747 const char *name;
5748 int id;
5749 bool (*fn)(struct smbd_server_connection *sconn,
5750 connection_struct *, uint16,
5751 char *, int,
5752 char *, int,
5753 int,int,char **,char **,int *,int *);
5754 bool auth_user; /* Deny anonymous access? */
5755 } api_commands[] = {
5756 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
5757 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
5758 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
5759 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
5760 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
5761 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
5762 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
5763 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
5764 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
5765 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
5766 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
5767 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
5768 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
5769 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
5770 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
5771 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
5772 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
5773 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
5774 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
5775 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
5776 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
5777 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
5778 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
5779 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
5780 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
5781 {"NetServerEnum3", RAP_NetServerEnum3, api_RNetServerEnum3}, /* anon OK */
5782 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
5783 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
5784 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
5785 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
5786 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
5787 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
5788 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
5789 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
5790 {NULL, -1, api_Unsupported}
5791 /* The following RAP calls are not implemented by Samba:
5793 RAP_WFileEnum2 - anon not OK
5798 /****************************************************************************
5799 Handle remote api calls.
5800 ****************************************************************************/
5802 void api_reply(connection_struct *conn, uint16 vuid,
5803 struct smb_request *req,
5804 char *data, char *params,
5805 int tdscnt, int tpscnt,
5806 int mdrcnt, int mprcnt)
5808 int api_command;
5809 char *rdata = NULL;
5810 char *rparam = NULL;
5811 const char *name1 = NULL;
5812 const char *name2 = NULL;
5813 int rdata_len = 0;
5814 int rparam_len = 0;
5815 bool reply=False;
5816 int i;
5818 if (!params) {
5819 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
5820 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5821 return;
5824 if (tpscnt < 2) {
5825 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5826 return;
5828 api_command = SVAL(params,0);
5829 /* Is there a string at position params+2 ? */
5830 if (skip_string(params,tpscnt,params+2)) {
5831 name1 = params + 2;
5832 } else {
5833 name1 = "";
5835 name2 = skip_string(params,tpscnt,params+2);
5836 if (!name2) {
5837 name2 = "";
5840 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
5841 api_command,
5842 name1,
5843 name2,
5844 tdscnt,tpscnt,mdrcnt,mprcnt));
5846 for (i=0;api_commands[i].name;i++) {
5847 if (api_commands[i].id == api_command && api_commands[i].fn) {
5848 DEBUG(3,("Doing %s\n",api_commands[i].name));
5849 break;
5853 /* Check whether this api call can be done anonymously */
5855 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
5856 user_struct *user = get_valid_user_struct(req->sconn, vuid);
5858 if (!user || user->session_info->guest) {
5859 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5860 return;
5864 rdata = (char *)SMB_MALLOC(1024);
5865 if (rdata) {
5866 memset(rdata,'\0',1024);
5869 rparam = (char *)SMB_MALLOC(1024);
5870 if (rparam) {
5871 memset(rparam,'\0',1024);
5874 if(!rdata || !rparam) {
5875 DEBUG(0,("api_reply: malloc fail !\n"));
5876 SAFE_FREE(rdata);
5877 SAFE_FREE(rparam);
5878 reply_nterror(req, NT_STATUS_NO_MEMORY);
5879 return;
5882 reply = api_commands[i].fn(req->sconn, conn,
5883 vuid,
5884 params,tpscnt, /* params + length */
5885 data,tdscnt, /* data + length */
5886 mdrcnt,mprcnt,
5887 &rdata,&rparam,&rdata_len,&rparam_len);
5890 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
5891 reply = api_TooSmall(req->sconn,conn,vuid,params,data,
5892 mdrcnt,mprcnt,
5893 &rdata,&rparam,&rdata_len,&rparam_len);
5896 /* if we get False back then it's actually unsupported */
5897 if (!reply) {
5898 reply = api_Unsupported(req->sconn,conn,vuid,params,tpscnt,
5899 data,
5900 tdscnt,mdrcnt,mprcnt,
5901 &rdata,&rparam,&rdata_len,&rparam_len);
5904 /* If api_Unsupported returns false we can't return anything. */
5905 if (reply) {
5906 send_trans_reply(conn, req, rparam, rparam_len,
5907 rdata, rdata_len, False);
5910 SAFE_FREE(rdata);
5911 SAFE_FREE(rparam);
5912 return;