auth4: avoid map_user_info() in auth_check_password_send()
[Samba.git] / source3 / smbd / lanman.c
blobc3e540ff8106994aa0f6bfa23d732ecb61670723
1 /*
2 Unix SMB/CIFS implementation.
3 Inter-process communication and named pipe handling
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Jeremy Allison 2007.
7 SMB Version handling
8 Copyright (C) John H Terpstra 1995-1998
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 This file handles the named pipe and mailslot calls
25 in the SMBtrans protocol
28 #include "includes.h"
29 #include "smbd/smbd.h"
30 #include "smbd/globals.h"
31 #include "rpc_client/rpc_client.h"
32 #include "../librpc/gen_ndr/ndr_samr_c.h"
33 #include "../librpc/gen_ndr/ndr_spoolss_c.h"
34 #include "rpc_client/cli_spoolss.h"
35 #include "rpc_client/init_spoolss.h"
36 #include "../librpc/gen_ndr/ndr_srvsvc_c.h"
37 #include "../librpc/gen_ndr/rap.h"
38 #include "../lib/util/binsearch.h"
39 #include "../libcli/auth/libcli_auth.h"
40 #include "rpc_client/init_lsa.h"
41 #include "../libcli/security/security.h"
42 #include "printing.h"
43 #include "passdb/machine_sid.h"
44 #include "auth.h"
45 #include "rpc_server/rpc_ncacn_np.h"
47 #ifdef CHECK_TYPES
48 #undef CHECK_TYPES
49 #endif
50 #define CHECK_TYPES 0
52 #define NERR_Success 0
53 #define NERR_badpass 86
54 #define NERR_notsupported 50
56 #define NERR_BASE (2100)
57 #define NERR_BufTooSmall (NERR_BASE+23)
58 #define NERR_JobNotFound (NERR_BASE+51)
59 #define NERR_DestNotFound (NERR_BASE+52)
61 #define ACCESS_READ 0x01
62 #define ACCESS_WRITE 0x02
63 #define ACCESS_CREATE 0x04
65 #define SHPWLEN 8 /* share password length */
67 /* Limit size of ipc replies */
69 static char *smb_realloc_limit(void *ptr, size_t size)
71 char *val;
73 size = MAX((size),4*1024);
74 val = (char *)SMB_REALLOC(ptr,size);
75 if (val) {
76 memset(val,'\0',size);
78 return val;
81 static bool api_Unsupported(struct smbd_server_connection *sconn,
82 connection_struct *conn, uint64_t vuid,
83 char *param, int tpscnt,
84 char *data, int tdscnt,
85 int mdrcnt, int mprcnt,
86 char **rdata, char **rparam,
87 int *rdata_len, int *rparam_len);
89 static bool api_TooSmall(struct smbd_server_connection *sconn,
90 connection_struct *conn, uint64_t vuid, char *param, char *data,
91 int mdrcnt, int mprcnt,
92 char **rdata, char **rparam,
93 int *rdata_len, int *rparam_len);
96 static int CopyExpanded(connection_struct *conn,
97 int snum, char **dst, char *src, int *p_space_remaining)
99 TALLOC_CTX *ctx = talloc_tos();
100 char *buf = NULL;
101 int l;
103 if (!src || !dst || !p_space_remaining || !(*dst) ||
104 *p_space_remaining <= 0) {
105 return 0;
108 buf = talloc_strdup(ctx, src);
109 if (!buf) {
110 *p_space_remaining = 0;
111 return 0;
113 buf = talloc_string_sub(ctx, buf,"%S", lp_servicename(ctx, snum));
114 if (!buf) {
115 *p_space_remaining = 0;
116 return 0;
118 buf = talloc_sub_advanced(ctx,
119 lp_servicename(ctx, SNUM(conn)),
120 conn->session_info->unix_info->unix_name,
121 conn->connectpath,
122 conn->session_info->unix_token->gid,
123 conn->session_info->unix_info->sanitized_username,
124 conn->session_info->info->domain_name,
125 buf);
126 if (!buf) {
127 *p_space_remaining = 0;
128 return 0;
130 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
131 if (l == 0) {
132 return 0;
134 (*dst) += l;
135 (*p_space_remaining) -= l;
136 return l;
139 static int CopyAndAdvance(char **dst, char *src, int *n)
141 int l;
142 if (!src || !dst || !n || !(*dst)) {
143 return 0;
145 l = push_ascii(*dst,src,*n, STR_TERMINATE);
146 if (l == 0) {
147 return 0;
149 (*dst) += l;
150 (*n) -= l;
151 return l;
154 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
156 TALLOC_CTX *ctx = talloc_tos();
157 char *buf = NULL;
158 if (!s) {
159 return 0;
161 buf = talloc_strdup(ctx,s);
162 if (!buf) {
163 return 0;
165 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(ctx, snum));
166 if (!buf) {
167 return 0;
169 buf = talloc_sub_advanced(ctx,
170 lp_servicename(ctx, SNUM(conn)),
171 conn->session_info->unix_info->unix_name,
172 conn->connectpath,
173 conn->session_info->unix_token->gid,
174 conn->session_info->unix_info->sanitized_username,
175 conn->session_info->info->domain_name,
176 buf);
177 if (!buf) {
178 return 0;
180 return strlen(buf) + 1;
183 /*******************************************************************
184 Check a API string for validity when we only need to check the prefix.
185 ******************************************************************/
187 static bool prefix_ok(const char *str, const char *prefix)
189 return(strncmp(str,prefix,strlen(prefix)) == 0);
192 struct pack_desc {
193 const char *format; /* formatstring for structure */
194 const char *subformat; /* subformat for structure */
195 char *base; /* baseaddress of buffer */
196 int buflen; /* remaining size for fixed part; on init: length of base */
197 int subcount; /* count of substructures */
198 char *structbuf; /* pointer into buffer for remaining fixed part */
199 int stringlen; /* remaining size for variable part */
200 char *stringbuf; /* pointer into buffer for remaining variable part */
201 int neededlen; /* total needed size */
202 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
203 const char *curpos; /* current position; pointer into format or subformat */
204 int errcode;
207 static int get_counter(const char **p)
209 int i, n;
210 if (!p || !(*p)) {
211 return 1;
213 if (!isdigit((int)**p)) {
214 return 1;
216 for (n = 0;;) {
217 i = **p;
218 if (isdigit(i)) {
219 n = 10 * n + (i - '0');
220 } else {
221 return n;
223 (*p)++;
227 static int getlen(const char *p)
229 int n = 0;
230 if (!p) {
231 return 0;
234 while (*p) {
235 switch( *p++ ) {
236 case 'W': /* word (2 byte) */
237 n += 2;
238 break;
239 case 'K': /* status word? (2 byte) */
240 n += 2;
241 break;
242 case 'N': /* count of substructures (word) at end */
243 n += 2;
244 break;
245 case 'D': /* double word (4 byte) */
246 case 'z': /* offset to zero terminated string (4 byte) */
247 case 'l': /* offset to user data (4 byte) */
248 n += 4;
249 break;
250 case 'b': /* offset to data (with counter) (4 byte) */
251 n += 4;
252 get_counter(&p);
253 break;
254 case 'B': /* byte (with optional counter) */
255 n += get_counter(&p);
256 break;
259 return n;
262 static bool init_package(struct pack_desc *p, int count, int subcount)
264 int n = p->buflen;
265 int i;
267 if (!p->format || !p->base) {
268 return False;
271 i = count * getlen(p->format);
272 if (p->subformat) {
273 i += subcount * getlen(p->subformat);
275 p->structbuf = p->base;
276 p->neededlen = 0;
277 p->usedlen = 0;
278 p->subcount = 0;
279 p->curpos = p->format;
280 if (i > n) {
281 p->neededlen = i;
282 i = n = 0;
283 #if 0
285 * This is the old error code we used. Aparently
286 * WinNT/2k systems return ERRbuftoosmall (2123) and
287 * OS/2 needs this. I'm leaving this here so we can revert
288 * if needed. JRA.
290 p->errcode = ERRmoredata;
291 #else
292 p->errcode = ERRbuftoosmall;
293 #endif
294 } else {
295 p->errcode = NERR_Success;
297 p->buflen = i;
298 n -= i;
299 p->stringbuf = p->base + i;
300 p->stringlen = n;
301 return (p->errcode == NERR_Success);
304 static int package(struct pack_desc *p, ...)
306 va_list args;
307 int needed=0, stringneeded;
308 const char *str=NULL;
309 int is_string=0, stringused;
310 int32_t temp;
312 va_start(args,p);
314 if (!*p->curpos) {
315 if (!p->subcount) {
316 p->curpos = p->format;
317 } else {
318 p->curpos = p->subformat;
319 p->subcount--;
322 #if CHECK_TYPES
323 str = va_arg(args,char*);
324 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
325 #endif
326 stringneeded = -1;
328 if (!p->curpos) {
329 va_end(args);
330 return 0;
333 switch( *p->curpos++ ) {
334 case 'W': /* word (2 byte) */
335 needed = 2;
336 temp = va_arg(args,int);
337 if (p->buflen >= needed) {
338 SSVAL(p->structbuf,0,temp);
340 break;
341 case 'K': /* status word? (2 byte) */
342 needed = 2;
343 temp = va_arg(args,int);
344 if (p->buflen >= needed) {
345 SSVAL(p->structbuf,0,temp);
347 break;
348 case 'N': /* count of substructures (word) at end */
349 needed = 2;
350 p->subcount = va_arg(args,int);
351 if (p->buflen >= needed) {
352 SSVAL(p->structbuf,0,p->subcount);
354 break;
355 case 'D': /* double word (4 byte) */
356 needed = 4;
357 temp = va_arg(args,int);
358 if (p->buflen >= needed) {
359 SIVAL(p->structbuf,0,temp);
361 break;
362 case 'B': /* byte (with optional counter) */
363 needed = get_counter(&p->curpos);
365 char *s = va_arg(args,char*);
366 if (p->buflen >= needed) {
367 StrnCpy(p->structbuf,s?s:"",needed-1);
370 break;
371 case 'z': /* offset to zero terminated string (4 byte) */
372 str = va_arg(args,char*);
373 stringneeded = (str ? strlen(str)+1 : 0);
374 is_string = 1;
375 break;
376 case 'l': /* offset to user data (4 byte) */
377 str = va_arg(args,char*);
378 stringneeded = va_arg(args,int);
379 is_string = 0;
380 break;
381 case 'b': /* offset to data (with counter) (4 byte) */
382 str = va_arg(args,char*);
383 stringneeded = get_counter(&p->curpos);
384 is_string = 0;
385 break;
388 va_end(args);
389 if (stringneeded >= 0) {
390 needed = 4;
391 if (p->buflen >= needed) {
392 stringused = stringneeded;
393 if (stringused > p->stringlen) {
394 stringused = (is_string ? p->stringlen : 0);
395 if (p->errcode == NERR_Success) {
396 p->errcode = ERRmoredata;
399 if (!stringused) {
400 SIVAL(p->structbuf,0,0);
401 } else {
402 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
403 memcpy(p->stringbuf,str?str:"",stringused);
404 if (is_string) {
405 p->stringbuf[stringused-1] = '\0';
407 p->stringbuf += stringused;
408 p->stringlen -= stringused;
409 p->usedlen += stringused;
412 p->neededlen += stringneeded;
415 p->neededlen += needed;
416 if (p->buflen >= needed) {
417 p->structbuf += needed;
418 p->buflen -= needed;
419 p->usedlen += needed;
420 } else {
421 if (p->errcode == NERR_Success) {
422 p->errcode = ERRmoredata;
425 return 1;
428 #if CHECK_TYPES
429 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
430 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
431 #else
432 #define PACK(desc,t,v) package(desc,v)
433 #define PACKl(desc,t,v,l) package(desc,v,l)
434 #endif
436 static void PACKI(struct pack_desc* desc, const char *t,int v)
438 PACK(desc,t,v);
441 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
443 PACK(desc,t,v);
446 /****************************************************************************
447 Get a print queue.
448 ****************************************************************************/
450 static void PackDriverData(struct pack_desc* desc)
452 char drivdata[4+4+32];
453 SIVAL(drivdata,0,sizeof drivdata); /* cb */
454 SIVAL(drivdata,4,1000); /* lVersion */
455 memset(drivdata+8,0,32); /* szDeviceName */
456 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
457 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
460 static int check_printq_info(struct pack_desc* desc,
461 unsigned int uLevel, char *id1, char *id2)
463 desc->subformat = NULL;
464 switch( uLevel ) {
465 case 0:
466 desc->format = "B13";
467 break;
468 case 1:
469 desc->format = "B13BWWWzzzzzWW";
470 break;
471 case 2:
472 desc->format = "B13BWWWzzzzzWN";
473 desc->subformat = "WB21BB16B10zWWzDDz";
474 break;
475 case 3:
476 desc->format = "zWWWWzzzzWWzzl";
477 break;
478 case 4:
479 desc->format = "zWWWWzzzzWNzzl";
480 desc->subformat = "WWzWWDDzz";
481 break;
482 case 5:
483 desc->format = "z";
484 break;
485 case 51:
486 desc->format = "K";
487 break;
488 case 52:
489 desc->format = "WzzzzzzzzN";
490 desc->subformat = "z";
491 break;
492 default:
493 DEBUG(0,("check_printq_info: invalid level %d\n",
494 uLevel ));
495 return False;
497 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
498 DEBUG(0,("check_printq_info: invalid format %s\n",
499 id1 ? id1 : "<NULL>" ));
500 return False;
502 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
503 DEBUG(0,("check_printq_info: invalid subformat %s\n",
504 id2 ? id2 : "<NULL>" ));
505 return False;
507 return True;
511 #define RAP_JOB_STATUS_QUEUED 0
512 #define RAP_JOB_STATUS_PAUSED 1
513 #define RAP_JOB_STATUS_SPOOLING 2
514 #define RAP_JOB_STATUS_PRINTING 3
515 #define RAP_JOB_STATUS_PRINTED 4
517 #define RAP_QUEUE_STATUS_PAUSED 1
518 #define RAP_QUEUE_STATUS_ERROR 2
520 /* turn a print job status into a on the wire status
522 static int printj_spoolss_status(int v)
524 if (v == JOB_STATUS_QUEUED)
525 return RAP_JOB_STATUS_QUEUED;
526 if (v & JOB_STATUS_PAUSED)
527 return RAP_JOB_STATUS_PAUSED;
528 if (v & JOB_STATUS_SPOOLING)
529 return RAP_JOB_STATUS_SPOOLING;
530 if (v & JOB_STATUS_PRINTING)
531 return RAP_JOB_STATUS_PRINTING;
532 return 0;
535 /* turn a print queue status into a on the wire status
537 static int printq_spoolss_status(int v)
539 if (v == PRINTER_STATUS_OK)
540 return 0;
541 if (v & PRINTER_STATUS_PAUSED)
542 return RAP_QUEUE_STATUS_PAUSED;
543 return RAP_QUEUE_STATUS_ERROR;
546 static void fill_spoolss_printjob_info(int uLevel,
547 struct pack_desc *desc,
548 struct spoolss_JobInfo2 *info2,
549 int n)
551 time_t t = spoolss_Time_to_time_t(&info2->submitted);
553 /* the client expects localtime */
554 t -= get_time_zone(t);
556 PACKI(desc,"W",pjobid_to_rap(info2->printer_name, info2->job_id)); /* uJobId */
557 if (uLevel == 1) {
558 PACKS(desc,"B21", info2->user_name); /* szUserName */
559 PACKS(desc,"B",""); /* pad */
560 PACKS(desc,"B16",""); /* szNotifyName */
561 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
562 PACKS(desc,"z",""); /* pszParms */
563 PACKI(desc,"W",n+1); /* uPosition */
564 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
565 PACKS(desc,"z",""); /* pszStatus */
566 PACKI(desc,"D", t); /* ulSubmitted */
567 PACKI(desc,"D", info2->size); /* ulSize */
568 PACKS(desc,"z", info2->document_name); /* pszComment */
570 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
571 PACKI(desc,"W", info2->priority); /* uPriority */
572 PACKS(desc,"z", info2->user_name); /* pszUserName */
573 PACKI(desc,"W",n+1); /* uPosition */
574 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
575 PACKI(desc,"D",t); /* ulSubmitted */
576 PACKI(desc,"D", info2->size); /* ulSize */
577 PACKS(desc,"z","Samba"); /* pszComment */
578 PACKS(desc,"z", info2->document_name); /* pszDocument */
579 if (uLevel == 3) {
580 PACKS(desc,"z",""); /* pszNotifyName */
581 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
582 PACKS(desc,"z",""); /* pszParms */
583 PACKS(desc,"z",""); /* pszStatus */
584 PACKS(desc,"z", info2->printer_name); /* pszQueue */
585 PACKS(desc,"z","lpd"); /* pszQProcName */
586 PACKS(desc,"z",""); /* pszQProcParms */
587 PACKS(desc,"z","NULL"); /* pszDriverName */
588 PackDriverData(desc); /* pDriverData */
589 PACKS(desc,"z",""); /* pszPrinterName */
590 } else if (uLevel == 4) { /* OS2 */
591 PACKS(desc,"z",""); /* pszSpoolFileName */
592 PACKS(desc,"z",""); /* pszPortName */
593 PACKS(desc,"z",""); /* pszStatus */
594 PACKI(desc,"D",0); /* ulPagesSpooled */
595 PACKI(desc,"D",0); /* ulPagesSent */
596 PACKI(desc,"D",0); /* ulPagesPrinted */
597 PACKI(desc,"D",0); /* ulTimePrinted */
598 PACKI(desc,"D",0); /* ulExtendJobStatus */
599 PACKI(desc,"D",0); /* ulStartPage */
600 PACKI(desc,"D",0); /* ulEndPage */
605 /********************************************************************
606 Respond to the DosPrintQInfo command with a level of 52
607 This is used to get printer driver information for Win9x clients
608 ********************************************************************/
609 static void fill_printq_info_52(struct spoolss_DriverInfo3 *driver,
610 struct pack_desc* desc, int count,
611 const char *printer_name)
613 int i;
614 fstring location;
615 trim_string(discard_const_p(char, driver->driver_path), "\\print$\\WIN40\\0\\", 0);
616 trim_string(discard_const_p(char, driver->data_file), "\\print$\\WIN40\\0\\", 0);
617 trim_string(discard_const_p(char, driver->help_file), "\\print$\\WIN40\\0\\", 0);
619 PACKI(desc, "W", 0x0400); /* don't know */
620 PACKS(desc, "z", driver->driver_name); /* long printer name */
621 PACKS(desc, "z", driver->driver_path); /* Driverfile Name */
622 PACKS(desc, "z", driver->data_file); /* Datafile name */
623 PACKS(desc, "z", driver->monitor_name); /* language monitor */
625 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
626 standard_sub_basic( "", "", location, sizeof(location)-1 );
627 PACKS(desc,"z", location); /* share to retrieve files */
629 PACKS(desc,"z", driver->default_datatype); /* default data type */
630 PACKS(desc,"z", driver->help_file); /* helpfile name */
631 PACKS(desc,"z", driver->driver_path); /* driver name */
633 DEBUG(3,("Printer Driver Name: %s:\n",driver->driver_name));
634 DEBUG(3,("Driver: %s:\n",driver->driver_path));
635 DEBUG(3,("Data File: %s:\n",driver->data_file));
636 DEBUG(3,("Language Monitor: %s:\n",driver->monitor_name));
637 DEBUG(3,("Driver Location: %s:\n",location));
638 DEBUG(3,("Data Type: %s:\n",driver->default_datatype));
639 DEBUG(3,("Help File: %s:\n",driver->help_file));
640 PACKI(desc,"N",count); /* number of files to copy */
642 for ( i=0; i<count && driver->dependent_files && *driver->dependent_files[i]; i++)
644 trim_string(discard_const_p(char, driver->dependent_files[i]), "\\print$\\WIN40\\0\\", 0);
645 PACKS(desc,"z",driver->dependent_files[i]); /* driver files to copy */
646 DEBUG(3,("Dependent File: %s:\n", driver->dependent_files[i]));
649 /* sanity check */
650 if ( i != count )
651 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
652 count, i));
654 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", printer_name, i));
656 desc->errcode=NERR_Success;
660 static const char *strip_unc(const char *unc)
662 char *p;
664 if (unc == NULL) {
665 return NULL;
668 if ((p = strrchr(unc, '\\')) != NULL) {
669 return p+1;
672 return unc;
675 static void fill_printq_info(int uLevel,
676 struct pack_desc* desc,
677 int count,
678 union spoolss_JobInfo *job_info,
679 struct spoolss_DriverInfo3 *driver_info,
680 struct spoolss_PrinterInfo2 *printer_info)
682 switch (uLevel) {
683 case 0:
684 case 1:
685 case 2:
686 PACKS(desc,"B13", strip_unc(printer_info->printername));
687 break;
688 case 3:
689 case 4:
690 case 5:
691 PACKS(desc,"z", strip_unc(printer_info->printername));
692 break;
693 case 51:
694 PACKI(desc,"K", printq_spoolss_status(printer_info->status));
695 break;
698 if (uLevel == 1 || uLevel == 2) {
699 PACKS(desc,"B",""); /* alignment */
700 PACKI(desc,"W",5); /* priority */
701 PACKI(desc,"W",0); /* start time */
702 PACKI(desc,"W",0); /* until time */
703 PACKS(desc,"z",""); /* pSepFile */
704 PACKS(desc,"z","lpd"); /* pPrProc */
705 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pDestinations */
706 PACKS(desc,"z",""); /* pParms */
707 if (printer_info->printername == NULL) {
708 PACKS(desc,"z","UNKNOWN PRINTER");
709 PACKI(desc,"W",LPSTAT_ERROR);
710 } else {
711 PACKS(desc,"z", printer_info->comment);
712 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* status */
714 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
717 if (uLevel == 3 || uLevel == 4) {
718 PACKI(desc,"W",5); /* uPriority */
719 PACKI(desc,"W",0); /* uStarttime */
720 PACKI(desc,"W",0); /* uUntiltime */
721 PACKI(desc,"W",5); /* pad1 */
722 PACKS(desc,"z",""); /* pszSepFile */
723 PACKS(desc,"z","WinPrint"); /* pszPrProc */
724 PACKS(desc,"z",NULL); /* pszParms */
725 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
726 /* "don't ask" that it's done this way to fix corrupted
727 Win9X/ME printer comments. */
728 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* fsStatus */
729 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
730 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pszPrinters */
731 PACKS(desc,"z", printer_info->drivername); /* pszDriverName */
732 PackDriverData(desc); /* pDriverData */
735 if (uLevel == 2 || uLevel == 4) {
736 int i;
737 for (i = 0; i < count; i++) {
738 fill_spoolss_printjob_info(uLevel == 2 ? 1 : 2, desc, &job_info[i].info2, i);
742 if (uLevel==52)
743 fill_printq_info_52(driver_info, desc, count, printer_info->printername);
746 /* This function returns the number of files for a given driver */
747 static int get_printerdrivernumber(const struct spoolss_DriverInfo3 *driver)
749 int result = 0;
751 /* count the number of files */
752 while (driver->dependent_files && *driver->dependent_files[result])
753 result++;
755 return result;
758 static bool api_DosPrintQGetInfo(struct smbd_server_connection *sconn,
759 connection_struct *conn, uint64_t vuid,
760 char *param, int tpscnt,
761 char *data, int tdscnt,
762 int mdrcnt,int mprcnt,
763 char **rdata,char **rparam,
764 int *rdata_len,int *rparam_len)
766 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
767 char *str2 = skip_string(param,tpscnt,str1);
768 char *p = skip_string(param,tpscnt,str2);
769 char *QueueName = p;
770 unsigned int uLevel;
771 uint32_t count = 0;
772 char *str3;
773 struct pack_desc desc;
774 char* tmpdata=NULL;
776 WERROR werr = WERR_OK;
777 TALLOC_CTX *mem_ctx = talloc_tos();
778 NTSTATUS status;
779 struct rpc_pipe_client *cli = NULL;
780 struct dcerpc_binding_handle *b = NULL;
781 struct policy_handle handle;
782 struct spoolss_DevmodeContainer devmode_ctr;
783 union spoolss_DriverInfo driver_info;
784 union spoolss_JobInfo *job_info = NULL;
785 union spoolss_PrinterInfo printer_info;
787 if (!str1 || !str2 || !p) {
788 return False;
790 memset((char *)&desc,'\0',sizeof(desc));
792 p = skip_string(param,tpscnt,p);
793 if (!p) {
794 return False;
796 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
797 str3 = get_safe_str_ptr(param,tpscnt,p,4);
798 /* str3 may be null here and is checked in check_printq_info(). */
800 /* remove any trailing username */
801 if ((p = strchr_m(QueueName,'%')))
802 *p = 0;
804 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
806 /* check it's a supported varient */
807 if (!prefix_ok(str1,"zWrLh"))
808 return False;
809 if (!check_printq_info(&desc,uLevel,str2,str3)) {
811 * Patch from Scott Moomaw <scott@bridgewater.edu>
812 * to return the 'invalid info level' error if an
813 * unknown level was requested.
815 *rdata_len = 0;
816 *rparam_len = 6;
817 *rparam = smb_realloc_limit(*rparam,*rparam_len);
818 if (!*rparam) {
819 return False;
821 SSVALS(*rparam,0,ERRunknownlevel);
822 SSVAL(*rparam,2,0);
823 SSVAL(*rparam,4,0);
824 return(True);
827 ZERO_STRUCT(handle);
829 if (QueueName == NULL || (strlen(QueueName) < 1)) {
830 desc.errcode = W_ERROR_V(WERR_INVALID_PARAMETER);
831 goto out;
834 status = rpc_pipe_open_interface(conn,
835 &ndr_table_spoolss,
836 conn->session_info,
837 conn->sconn->remote_address,
838 conn->sconn->local_address,
839 conn->sconn->msg_ctx,
840 &cli);
841 if (!NT_STATUS_IS_OK(status)) {
842 DEBUG(0,("api_DosPrintQGetInfo: could not connect to spoolss: %s\n",
843 nt_errstr(status)));
844 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
845 goto out;
847 b = cli->binding_handle;
849 ZERO_STRUCT(devmode_ctr);
851 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
852 QueueName,
853 "RAW",
854 devmode_ctr,
855 PRINTER_ACCESS_USE,
856 &handle,
857 &werr);
858 if (!NT_STATUS_IS_OK(status)) {
859 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
860 goto out;
862 if (!W_ERROR_IS_OK(werr)) {
863 desc.errcode = W_ERROR_V(werr);
864 goto out;
867 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
868 &handle,
871 &printer_info);
872 if (!W_ERROR_IS_OK(werr)) {
873 desc.errcode = W_ERROR_V(werr);
874 goto out;
877 if (uLevel==52) {
878 uint32_t server_major_version;
879 uint32_t server_minor_version;
881 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
882 &handle,
883 "Windows 4.0",
884 3, /* level */
886 0, /* version */
888 &driver_info,
889 &server_major_version,
890 &server_minor_version);
891 if (!W_ERROR_IS_OK(werr)) {
892 desc.errcode = W_ERROR_V(werr);
893 goto out;
896 count = get_printerdrivernumber(&driver_info.info3);
897 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
898 } else {
899 uint32_t num_jobs;
900 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
901 &handle,
902 0, /* firstjob */
903 0xff, /* numjobs */
904 2, /* level */
905 0, /* offered */
906 &num_jobs,
907 &job_info);
908 if (!W_ERROR_IS_OK(werr)) {
909 desc.errcode = W_ERROR_V(werr);
910 goto out;
913 count = num_jobs;
916 if (mdrcnt > 0) {
917 *rdata = smb_realloc_limit(*rdata,mdrcnt);
918 if (!*rdata) {
919 return False;
921 desc.base = *rdata;
922 desc.buflen = mdrcnt;
923 } else {
925 * Don't return data but need to get correct length
926 * init_package will return wrong size if buflen=0
928 desc.buflen = getlen(desc.format);
929 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
932 if (init_package(&desc,1,count)) {
933 desc.subcount = count;
934 fill_printq_info(uLevel,&desc,count, job_info, &driver_info.info3, &printer_info.info2);
937 *rdata_len = desc.usedlen;
940 * We must set the return code to ERRbuftoosmall
941 * in order to support lanman style printing with Win NT/2k
942 * clients --jerry
944 if (!mdrcnt && lp_disable_spoolss())
945 desc.errcode = ERRbuftoosmall;
947 out:
948 if (b && is_valid_policy_hnd(&handle)) {
949 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
952 *rdata_len = desc.usedlen;
953 *rparam_len = 6;
954 *rparam = smb_realloc_limit(*rparam,*rparam_len);
955 if (!*rparam) {
956 SAFE_FREE(tmpdata);
957 return False;
959 SSVALS(*rparam,0,desc.errcode);
960 SSVAL(*rparam,2,0);
961 SSVAL(*rparam,4,desc.neededlen);
963 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
965 SAFE_FREE(tmpdata);
967 return(True);
970 /****************************************************************************
971 View list of all print jobs on all queues.
972 ****************************************************************************/
974 static bool api_DosPrintQEnum(struct smbd_server_connection *sconn,
975 connection_struct *conn, uint64_t vuid,
976 char *param, int tpscnt,
977 char *data, int tdscnt,
978 int mdrcnt, int mprcnt,
979 char **rdata, char** rparam,
980 int *rdata_len, int *rparam_len)
982 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
983 char *output_format1 = skip_string(param,tpscnt,param_format);
984 char *p = skip_string(param,tpscnt,output_format1);
985 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
986 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
987 int i;
988 struct pack_desc desc;
989 int *subcntarr = NULL;
990 int queuecnt = 0, subcnt = 0, succnt = 0;
992 WERROR werr = WERR_OK;
993 TALLOC_CTX *mem_ctx = talloc_tos();
994 NTSTATUS status;
995 struct rpc_pipe_client *cli = NULL;
996 struct dcerpc_binding_handle *b = NULL;
997 struct spoolss_DevmodeContainer devmode_ctr;
998 uint32_t num_printers;
999 union spoolss_PrinterInfo *printer_info;
1000 union spoolss_DriverInfo *driver_info;
1001 union spoolss_JobInfo **job_info;
1003 if (!param_format || !output_format1 || !p) {
1004 return False;
1007 memset((char *)&desc,'\0',sizeof(desc));
1009 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
1011 if (!prefix_ok(param_format,"WrLeh")) {
1012 return False;
1014 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
1016 * Patch from Scott Moomaw <scott@bridgewater.edu>
1017 * to return the 'invalid info level' error if an
1018 * unknown level was requested.
1020 *rdata_len = 0;
1021 *rparam_len = 6;
1022 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1023 if (!*rparam) {
1024 return False;
1026 SSVALS(*rparam,0,ERRunknownlevel);
1027 SSVAL(*rparam,2,0);
1028 SSVAL(*rparam,4,0);
1029 return(True);
1032 status = rpc_pipe_open_interface(conn,
1033 &ndr_table_spoolss,
1034 conn->session_info,
1035 conn->sconn->remote_address,
1036 conn->sconn->local_address,
1037 conn->sconn->msg_ctx,
1038 &cli);
1039 if (!NT_STATUS_IS_OK(status)) {
1040 DEBUG(0,("api_DosPrintQEnum: could not connect to spoolss: %s\n",
1041 nt_errstr(status)));
1042 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1043 goto out;
1045 b = cli->binding_handle;
1047 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
1048 PRINTER_ENUM_LOCAL,
1049 cli->srv_name_slash,
1052 &num_printers,
1053 &printer_info);
1054 if (!W_ERROR_IS_OK(werr)) {
1055 desc.errcode = W_ERROR_V(werr);
1056 goto out;
1059 queuecnt = num_printers;
1061 job_info = talloc_array(mem_ctx, union spoolss_JobInfo *, num_printers);
1062 if (job_info == NULL) {
1063 goto err;
1066 driver_info = talloc_array(mem_ctx, union spoolss_DriverInfo, num_printers);
1067 if (driver_info == NULL) {
1068 goto err;
1071 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1072 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1073 goto err;
1076 if (mdrcnt > 0) {
1077 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1078 if (!*rdata) {
1079 goto err;
1082 desc.base = *rdata;
1083 desc.buflen = mdrcnt;
1085 subcnt = 0;
1086 for (i = 0; i < num_printers; i++) {
1088 uint32_t num_jobs;
1089 struct policy_handle handle;
1090 const char *printername;
1092 printername = talloc_strdup(mem_ctx, printer_info[i].info2.printername);
1093 if (printername == NULL) {
1094 goto err;
1097 ZERO_STRUCT(handle);
1098 ZERO_STRUCT(devmode_ctr);
1100 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
1101 printername,
1102 "RAW",
1103 devmode_ctr,
1104 PRINTER_ACCESS_USE,
1105 &handle,
1106 &werr);
1107 if (!NT_STATUS_IS_OK(status)) {
1108 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1109 goto out;
1111 if (!W_ERROR_IS_OK(werr)) {
1112 desc.errcode = W_ERROR_V(werr);
1113 goto out;
1116 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
1117 &handle,
1118 0, /* firstjob */
1119 0xff, /* numjobs */
1120 2, /* level */
1121 0, /* offered */
1122 &num_jobs,
1123 &job_info[i]);
1124 if (!W_ERROR_IS_OK(werr)) {
1125 desc.errcode = W_ERROR_V(werr);
1126 goto out;
1129 if (uLevel==52) {
1130 uint32_t server_major_version;
1131 uint32_t server_minor_version;
1133 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1134 &handle,
1135 "Windows 4.0",
1136 3, /* level */
1138 0, /* version */
1140 &driver_info[i],
1141 &server_major_version,
1142 &server_minor_version);
1143 if (!W_ERROR_IS_OK(werr)) {
1144 desc.errcode = W_ERROR_V(werr);
1145 goto out;
1149 subcntarr[i] = num_jobs;
1150 subcnt += subcntarr[i];
1152 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
1155 if (init_package(&desc,queuecnt,subcnt)) {
1156 for (i = 0; i < num_printers; i++) {
1157 fill_printq_info(uLevel,&desc,subcntarr[i], job_info[i], &driver_info[i].info3, &printer_info[i].info2);
1158 if (desc.errcode == NERR_Success) {
1159 succnt = i;
1164 out:
1165 SAFE_FREE(subcntarr);
1166 *rdata_len = desc.usedlen;
1167 *rparam_len = 8;
1168 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1169 if (!*rparam) {
1170 goto err;
1172 SSVALS(*rparam,0,desc.errcode);
1173 SSVAL(*rparam,2,0);
1174 SSVAL(*rparam,4,succnt);
1175 SSVAL(*rparam,6,queuecnt);
1177 return True;
1179 err:
1181 SAFE_FREE(subcntarr);
1183 return False;
1186 /****************************************************************************
1187 Get info level for a server list query.
1188 ****************************************************************************/
1190 static bool check_session_info(int uLevel, char* id)
1192 switch( uLevel ) {
1193 case 0:
1194 if (strcmp(id,"B16") != 0) {
1195 return False;
1197 break;
1198 case 1:
1199 if (strcmp(id,"B16BBDz") != 0) {
1200 return False;
1202 break;
1203 default:
1204 return False;
1206 return True;
1209 struct srv_info_struct {
1210 fstring name;
1211 uint32_t type;
1212 fstring comment;
1213 fstring domain;
1214 bool server_added;
1217 /*******************************************************************
1218 Get server info lists from the files saved by nmbd. Return the
1219 number of entries.
1220 ******************************************************************/
1222 static int get_session_info(uint32_t servertype,
1223 struct srv_info_struct **servers,
1224 const char *domain)
1226 int count=0;
1227 int alloced=0;
1228 char **lines;
1229 bool local_list_only;
1230 int i;
1231 char *slist_cache_path = cache_path(SERVER_LIST);
1232 if (slist_cache_path == NULL) {
1233 return 0;
1236 lines = file_lines_load(slist_cache_path, NULL, 0, NULL);
1237 if (!lines) {
1238 DEBUG(4, ("Can't open %s - %s\n",
1239 slist_cache_path, strerror(errno)));
1240 TALLOC_FREE(slist_cache_path);
1241 return 0;
1243 TALLOC_FREE(slist_cache_path);
1245 /* request for everything is code for request all servers */
1246 if (servertype == SV_TYPE_ALL) {
1247 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1250 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1252 DEBUG(4,("Servertype search: %8x\n",servertype));
1254 for (i=0;lines[i];i++) {
1255 fstring stype;
1256 struct srv_info_struct *s;
1257 const char *ptr = lines[i];
1258 bool ok = True;
1259 TALLOC_CTX *frame = NULL;
1260 char *p;
1262 if (!*ptr) {
1263 continue;
1266 if (count == alloced) {
1267 alloced += 10;
1268 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1269 if (!*servers) {
1270 DEBUG(0,("get_session_info: failed to enlarge servers info struct!\n"));
1271 TALLOC_FREE(lines);
1272 return 0;
1274 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1276 s = &(*servers)[count];
1278 frame = talloc_stackframe();
1279 s->name[0] = '\0';
1280 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1281 TALLOC_FREE(frame);
1282 continue;
1284 fstrcpy(s->name, p);
1286 stype[0] = '\0';
1287 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1288 TALLOC_FREE(frame);
1289 continue;
1291 fstrcpy(stype, p);
1293 s->comment[0] = '\0';
1294 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1295 TALLOC_FREE(frame);
1296 continue;
1298 fstrcpy(s->comment, p);
1299 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1301 s->domain[0] = '\0';
1302 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1303 /* this allows us to cope with an old nmbd */
1304 fstrcpy(s->domain,lp_workgroup());
1305 } else {
1306 fstrcpy(s->domain, p);
1308 TALLOC_FREE(frame);
1310 if (sscanf(stype,"%X",&s->type) != 1) {
1311 DEBUG(4,("r:host file "));
1312 ok = False;
1315 /* Filter the servers/domains we return based on what was asked for. */
1317 /* Check to see if we are being asked for a local list only. */
1318 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1319 DEBUG(4,("r: local list only"));
1320 ok = False;
1323 /* doesn't match up: don't want it */
1324 if (!(servertype & s->type)) {
1325 DEBUG(4,("r:serv type "));
1326 ok = False;
1329 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1330 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1331 DEBUG(4,("s: dom mismatch "));
1332 ok = False;
1335 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1336 ok = False;
1339 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1340 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1342 if (ok) {
1343 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1344 s->name, s->type, s->comment, s->domain));
1345 s->server_added = True;
1346 count++;
1347 } else {
1348 DEBUG(4,("%20s %8x %25s %15s\n",
1349 s->name, s->type, s->comment, s->domain));
1353 TALLOC_FREE(lines);
1354 return count;
1357 /*******************************************************************
1358 Fill in a server info structure.
1359 ******************************************************************/
1361 static int fill_srv_info(struct srv_info_struct *service,
1362 int uLevel, char **buf, int *buflen,
1363 char **stringbuf, int *stringspace, char *baseaddr)
1365 int struct_len;
1366 char* p;
1367 char* p2;
1368 int l2;
1369 int len;
1371 switch (uLevel) {
1372 case 0:
1373 struct_len = 16;
1374 break;
1375 case 1:
1376 struct_len = 26;
1377 break;
1378 default:
1379 return -1;
1382 if (!buf) {
1383 len = 0;
1384 switch (uLevel) {
1385 case 1:
1386 len = strlen(service->comment)+1;
1387 break;
1390 *buflen = struct_len;
1391 *stringspace = len;
1392 return struct_len + len;
1395 len = struct_len;
1396 p = *buf;
1397 if (*buflen < struct_len) {
1398 return -1;
1400 if (stringbuf) {
1401 p2 = *stringbuf;
1402 l2 = *stringspace;
1403 } else {
1404 p2 = p + struct_len;
1405 l2 = *buflen - struct_len;
1407 if (!baseaddr) {
1408 baseaddr = p;
1411 switch (uLevel) {
1412 case 0:
1413 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1414 break;
1416 case 1:
1417 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1418 SIVAL(p,18,service->type);
1419 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1420 len += CopyAndAdvance(&p2,service->comment,&l2);
1421 break;
1424 if (stringbuf) {
1425 *buf = p + struct_len;
1426 *buflen -= struct_len;
1427 *stringbuf = p2;
1428 *stringspace = l2;
1429 } else {
1430 *buf = p2;
1431 *buflen -= len;
1433 return len;
1437 static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1439 return strcasecmp_m(s1->name,s2->name);
1442 /****************************************************************************
1443 View list of servers available (or possibly domains). The info is
1444 extracted from lists saved by nmbd on the local host.
1445 ****************************************************************************/
1447 static bool api_RNetServerEnum2(struct smbd_server_connection *sconn,
1448 connection_struct *conn, uint64_t vuid,
1449 char *param, int tpscnt,
1450 char *data, int tdscnt,
1451 int mdrcnt, int mprcnt, char **rdata,
1452 char **rparam, int *rdata_len, int *rparam_len)
1454 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1455 char *str2 = skip_string(param,tpscnt,str1);
1456 char *p = skip_string(param,tpscnt,str2);
1457 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1458 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1459 uint32_t servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1460 char *p2;
1461 int data_len, fixed_len, string_len;
1462 int f_len = 0, s_len = 0;
1463 struct srv_info_struct *servers=NULL;
1464 int counted=0,total=0;
1465 int i,missed;
1466 fstring domain;
1467 bool domain_request;
1468 bool local_request;
1470 if (!str1 || !str2 || !p) {
1471 return False;
1474 /* If someone sets all the bits they don't really mean to set
1475 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1476 known servers. */
1478 if (servertype == SV_TYPE_ALL) {
1479 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1482 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1483 any other bit (they may just set this bit on its own) they
1484 want all the locally seen servers. However this bit can be
1485 set on its own so set the requested servers to be
1486 ALL - DOMAIN_ENUM. */
1488 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1489 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1492 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1493 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1495 p += 8;
1497 if (!prefix_ok(str1,"WrLehD")) {
1498 return False;
1500 if (!check_session_info(uLevel,str2)) {
1501 return False;
1504 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1505 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1506 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1508 if (strcmp(str1, "WrLehDz") == 0) {
1509 if (skip_string(param,tpscnt,p) == NULL) {
1510 return False;
1512 pull_ascii_fstring(domain, p);
1513 } else {
1514 fstrcpy(domain, lp_workgroup());
1517 DEBUG(4, ("domain [%s]\n", domain));
1519 if (lp_browse_list()) {
1520 total = get_session_info(servertype,&servers,domain);
1523 data_len = fixed_len = string_len = 0;
1524 missed = 0;
1526 TYPESAFE_QSORT(servers, total, srv_comp);
1529 char *lastname=NULL;
1531 for (i=0;i<total;i++) {
1532 struct srv_info_struct *s = &servers[i];
1534 if (lastname && strequal(lastname,s->name)) {
1535 continue;
1537 lastname = s->name;
1538 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1539 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1540 i, s->name, s->type, s->comment, s->domain));
1542 if (data_len < buf_len) {
1543 counted++;
1544 fixed_len += f_len;
1545 string_len += s_len;
1546 } else {
1547 missed++;
1552 *rdata_len = fixed_len + string_len;
1553 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1554 if (!*rdata) {
1555 return False;
1558 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1559 p = *rdata;
1560 f_len = fixed_len;
1561 s_len = string_len;
1564 char *lastname=NULL;
1565 int count2 = counted;
1567 for (i = 0; i < total && count2;i++) {
1568 struct srv_info_struct *s = &servers[i];
1570 if (lastname && strequal(lastname,s->name)) {
1571 continue;
1573 lastname = s->name;
1574 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1575 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1576 i, s->name, s->type, s->comment, s->domain));
1577 count2--;
1581 *rparam_len = 8;
1582 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1583 if (!*rparam) {
1584 return False;
1586 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1587 SSVAL(*rparam,2,0);
1588 SSVAL(*rparam,4,counted);
1589 SSVAL(*rparam,6,counted+missed);
1591 SAFE_FREE(servers);
1593 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1594 domain,uLevel,counted,counted+missed));
1596 return True;
1599 static int srv_name_match(const char *n1, const char *n2)
1602 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1604 * In Windows, FirstNameToReturn need not be an exact match:
1605 * the server will return a list of servers that exist on
1606 * the network greater than or equal to the FirstNameToReturn.
1608 int ret = strcasecmp_m(n1, n2);
1610 if (ret <= 0) {
1611 return 0;
1614 return ret;
1617 static bool api_RNetServerEnum3(struct smbd_server_connection *sconn,
1618 connection_struct *conn, uint64_t vuid,
1619 char *param, int tpscnt,
1620 char *data, int tdscnt,
1621 int mdrcnt, int mprcnt, char **rdata,
1622 char **rparam, int *rdata_len, int *rparam_len)
1624 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1625 char *str2 = skip_string(param,tpscnt,str1);
1626 char *p = skip_string(param,tpscnt,str2);
1627 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1628 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1629 uint32_t servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1630 char *p2;
1631 int data_len, fixed_len, string_len;
1632 int f_len = 0, s_len = 0;
1633 struct srv_info_struct *servers=NULL;
1634 int counted=0,first=0,total=0;
1635 int i,missed;
1636 fstring domain;
1637 fstring first_name;
1638 bool domain_request;
1639 bool local_request;
1641 if (!str1 || !str2 || !p) {
1642 return False;
1645 /* If someone sets all the bits they don't really mean to set
1646 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1647 known servers. */
1649 if (servertype == SV_TYPE_ALL) {
1650 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1653 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1654 any other bit (they may just set this bit on its own) they
1655 want all the locally seen servers. However this bit can be
1656 set on its own so set the requested servers to be
1657 ALL - DOMAIN_ENUM. */
1659 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1660 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1663 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1664 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1666 p += 8;
1668 if (strcmp(str1, "WrLehDzz") != 0) {
1669 return false;
1671 if (!check_session_info(uLevel,str2)) {
1672 return False;
1675 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1676 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1677 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1679 if (skip_string(param,tpscnt,p) == NULL) {
1680 return False;
1682 pull_ascii_fstring(domain, p);
1683 if (domain[0] == '\0') {
1684 fstrcpy(domain, lp_workgroup());
1686 p = skip_string(param,tpscnt,p);
1687 if (skip_string(param,tpscnt,p) == NULL) {
1688 return False;
1690 pull_ascii_fstring(first_name, p);
1692 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1693 domain, first_name));
1695 if (lp_browse_list()) {
1696 total = get_session_info(servertype,&servers,domain);
1699 data_len = fixed_len = string_len = 0;
1700 missed = 0;
1702 TYPESAFE_QSORT(servers, total, srv_comp);
1704 if (first_name[0] != '\0') {
1705 struct srv_info_struct *first_server = NULL;
1707 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1708 srv_name_match, first_server);
1709 if (first_server) {
1710 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1712 * The binary search may not find the exact match
1713 * so we need to search backward to find the first match
1715 * This implements the strange matching windows
1716 * implements. (see the comment in srv_name_match().
1718 for (;first > 0;) {
1719 int ret;
1720 ret = strcasecmp_m(first_name,
1721 servers[first-1].name);
1722 if (ret > 0) {
1723 break;
1725 first--;
1727 } else {
1728 /* we should return no entries */
1729 first = total;
1734 char *lastname=NULL;
1736 for (i=first;i<total;i++) {
1737 struct srv_info_struct *s = &servers[i];
1739 if (lastname && strequal(lastname,s->name)) {
1740 continue;
1742 lastname = s->name;
1743 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1744 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1745 i, s->name, s->type, s->comment, s->domain));
1747 if (data_len < buf_len) {
1748 counted++;
1749 fixed_len += f_len;
1750 string_len += s_len;
1751 } else {
1752 missed++;
1757 *rdata_len = fixed_len + string_len;
1758 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1759 if (!*rdata) {
1760 return False;
1763 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1764 p = *rdata;
1765 f_len = fixed_len;
1766 s_len = string_len;
1769 char *lastname=NULL;
1770 int count2 = counted;
1772 for (i = first; i < total && count2;i++) {
1773 struct srv_info_struct *s = &servers[i];
1775 if (lastname && strequal(lastname,s->name)) {
1776 continue;
1778 lastname = s->name;
1779 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1780 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1781 i, s->name, s->type, s->comment, s->domain));
1782 count2--;
1786 *rparam_len = 8;
1787 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1788 if (!*rparam) {
1789 return False;
1791 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1792 SSVAL(*rparam,2,0);
1793 SSVAL(*rparam,4,counted);
1794 SSVAL(*rparam,6,counted+missed);
1796 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1797 domain,uLevel,first,first_name,
1798 first < total ? servers[first].name : "",
1799 counted,counted+missed));
1801 SAFE_FREE(servers);
1803 return True;
1806 /****************************************************************************
1807 command 0x34 - suspected of being a "Lookup Names" stub api
1808 ****************************************************************************/
1810 static bool api_RNetGroupGetUsers(struct smbd_server_connection *sconn,
1811 connection_struct *conn, uint64_t vuid,
1812 char *param, int tpscnt,
1813 char *data, int tdscnt,
1814 int mdrcnt, int mprcnt, char **rdata,
1815 char **rparam, int *rdata_len, int *rparam_len)
1817 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1818 char *str2 = skip_string(param,tpscnt,str1);
1819 char *p = skip_string(param,tpscnt,str2);
1820 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1821 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1822 int counted=0;
1823 int missed=0;
1825 if (!str1 || !str2 || !p) {
1826 return False;
1829 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1830 str1, str2, p, uLevel, buf_len));
1832 if (!prefix_ok(str1,"zWrLeh")) {
1833 return False;
1836 *rdata_len = 0;
1838 *rparam_len = 8;
1839 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1840 if (!*rparam) {
1841 return False;
1844 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1845 SSVAL(*rparam,2,0);
1846 SSVAL(*rparam,4,counted);
1847 SSVAL(*rparam,6,counted+missed);
1849 return True;
1852 /****************************************************************************
1853 get info about a share
1854 ****************************************************************************/
1856 static bool check_share_info(int uLevel, char* id)
1858 switch( uLevel ) {
1859 case 0:
1860 if (strcmp(id,"B13") != 0) {
1861 return False;
1863 break;
1864 case 1:
1865 /* Level-2 descriptor is allowed (and ignored) */
1866 if (strcmp(id,"B13BWz") != 0 &&
1867 strcmp(id,"B13BWzWWWzB9B") != 0) {
1868 return False;
1870 break;
1871 case 2:
1872 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1873 return False;
1875 break;
1876 case 91:
1877 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1878 return False;
1880 break;
1881 default:
1882 return False;
1884 return True;
1887 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1888 char** buf, int* buflen,
1889 char** stringbuf, int* stringspace, char* baseaddr)
1891 int struct_len;
1892 char* p;
1893 char* p2;
1894 int l2;
1895 int len;
1897 switch( uLevel ) {
1898 case 0:
1899 struct_len = 13;
1900 break;
1901 case 1:
1902 struct_len = 20;
1903 break;
1904 case 2:
1905 struct_len = 40;
1906 break;
1907 case 91:
1908 struct_len = 68;
1909 break;
1910 default:
1911 return -1;
1914 if (!buf) {
1915 len = 0;
1917 if (uLevel > 0) {
1918 len += StrlenExpanded(conn,snum,lp_comment(talloc_tos(), snum));
1920 if (uLevel > 1) {
1921 len += strlen(lp_path(talloc_tos(), snum)) + 1;
1923 if (buflen) {
1924 *buflen = struct_len;
1926 if (stringspace) {
1927 *stringspace = len;
1929 return struct_len + len;
1932 len = struct_len;
1933 p = *buf;
1934 if ((*buflen) < struct_len) {
1935 return -1;
1938 if (stringbuf) {
1939 p2 = *stringbuf;
1940 l2 = *stringspace;
1941 } else {
1942 p2 = p + struct_len;
1943 l2 = (*buflen) - struct_len;
1946 if (!baseaddr) {
1947 baseaddr = p;
1950 push_ascii(p,lp_servicename(talloc_tos(), snum),13, STR_TERMINATE);
1952 if (uLevel > 0) {
1953 int type;
1955 SCVAL(p,13,0);
1956 type = STYPE_DISKTREE;
1957 if (lp_printable(snum)) {
1958 type = STYPE_PRINTQ;
1960 if (strequal("IPC",lp_fstype(snum))) {
1961 type = STYPE_IPC;
1963 SSVAL(p,14,type); /* device type */
1964 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1965 len += CopyExpanded(conn,snum,&p2,lp_comment(talloc_tos(),snum),&l2);
1968 if (uLevel > 1) {
1969 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1970 SSVALS(p,22,-1); /* max uses */
1971 SSVAL(p,24,1); /* current uses */
1972 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1973 len += CopyAndAdvance(&p2,lp_path(talloc_tos(),snum),&l2);
1974 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1977 if (uLevel > 2) {
1978 memset(p+40,0,SHPWLEN+2);
1979 SSVAL(p,50,0);
1980 SIVAL(p,52,0);
1981 SSVAL(p,56,0);
1982 SSVAL(p,58,0);
1983 SIVAL(p,60,0);
1984 SSVAL(p,64,0);
1985 SSVAL(p,66,0);
1988 if (stringbuf) {
1989 (*buf) = p + struct_len;
1990 (*buflen) -= struct_len;
1991 (*stringbuf) = p2;
1992 (*stringspace) = l2;
1993 } else {
1994 (*buf) = p2;
1995 (*buflen) -= len;
1998 return len;
2001 static bool api_RNetShareGetInfo(struct smbd_server_connection *sconn,
2002 connection_struct *conn,uint64_t vuid,
2003 char *param, int tpscnt,
2004 char *data, int tdscnt,
2005 int mdrcnt,int mprcnt,
2006 char **rdata,char **rparam,
2007 int *rdata_len,int *rparam_len)
2009 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2010 char *str2 = skip_string(param,tpscnt,str1);
2011 char *netname_in = skip_string(param,tpscnt,str2);
2012 char *netname = NULL;
2013 char *p = skip_string(param,tpscnt,netname);
2014 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2015 int snum;
2017 if (!str1 || !str2 || !netname_in || !p) {
2018 return False;
2021 snum = find_service(talloc_tos(), netname_in, &netname);
2022 if (snum < 0 || !netname) {
2023 return False;
2026 /* check it's a supported varient */
2027 if (!prefix_ok(str1,"zWrLh")) {
2028 return False;
2030 if (!check_share_info(uLevel,str2)) {
2031 return False;
2034 *rdata = smb_realloc_limit(*rdata,mdrcnt);
2035 if (!*rdata) {
2036 return False;
2038 p = *rdata;
2039 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
2040 if (*rdata_len < 0) {
2041 return False;
2044 *rparam_len = 6;
2045 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2046 if (!*rparam) {
2047 return False;
2049 SSVAL(*rparam,0,NERR_Success);
2050 SSVAL(*rparam,2,0); /* converter word */
2051 SSVAL(*rparam,4,*rdata_len);
2053 return True;
2056 /****************************************************************************
2057 View the list of available shares.
2059 This function is the server side of the NetShareEnum() RAP call.
2060 It fills the return buffer with share names and share comments.
2061 Note that the return buffer normally (in all known cases) allows only
2062 twelve byte strings for share names (plus one for a nul terminator).
2063 Share names longer than 12 bytes must be skipped.
2064 ****************************************************************************/
2066 static bool api_RNetShareEnum(struct smbd_server_connection *sconn,
2067 connection_struct *conn, uint64_t vuid,
2068 char *param, int tpscnt,
2069 char *data, int tdscnt,
2070 int mdrcnt,
2071 int mprcnt,
2072 char **rdata,
2073 char **rparam,
2074 int *rdata_len,
2075 int *rparam_len )
2077 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2078 char *str2 = skip_string(param,tpscnt,str1);
2079 char *p = skip_string(param,tpscnt,str2);
2080 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2081 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
2082 char *p2;
2083 int count = 0;
2084 int total=0,counted=0;
2085 bool missed = False;
2086 int i;
2087 int data_len, fixed_len, string_len;
2088 int f_len = 0, s_len = 0;
2090 if (!str1 || !str2 || !p) {
2091 return False;
2094 if (!prefix_ok(str1,"WrLeh")) {
2095 return False;
2097 if (!check_share_info(uLevel,str2)) {
2098 return False;
2101 /* Ensure all the usershares are loaded. */
2102 become_root();
2103 delete_and_reload_printers(sconn->ev_ctx, sconn->msg_ctx);
2104 load_registry_shares();
2105 count = load_usershare_shares(NULL, connections_snum_used);
2106 unbecome_root();
2108 data_len = fixed_len = string_len = 0;
2109 for (i=0;i<count;i++) {
2110 fstring servicename_dos;
2111 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2112 continue;
2114 push_ascii_fstring(servicename_dos, lp_servicename(talloc_tos(), i));
2115 /* Maximum name length = 13. */
2116 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
2117 total++;
2118 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
2119 if (data_len < buf_len) {
2120 counted++;
2121 fixed_len += f_len;
2122 string_len += s_len;
2123 } else {
2124 missed = True;
2129 *rdata_len = fixed_len + string_len;
2130 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2131 if (!*rdata) {
2132 return False;
2135 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
2136 p = *rdata;
2137 f_len = fixed_len;
2138 s_len = string_len;
2140 for( i = 0; i < count; i++ ) {
2141 fstring servicename_dos;
2142 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2143 continue;
2146 push_ascii_fstring(servicename_dos,
2147 lp_servicename(talloc_tos(), i));
2148 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2149 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2150 break;
2155 *rparam_len = 8;
2156 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2157 if (!*rparam) {
2158 return False;
2160 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2161 SSVAL(*rparam,2,0);
2162 SSVAL(*rparam,4,counted);
2163 SSVAL(*rparam,6,total);
2165 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2166 counted,total,uLevel,
2167 buf_len,*rdata_len,mdrcnt));
2169 return True;
2172 /****************************************************************************
2173 Add a share
2174 ****************************************************************************/
2176 static bool api_RNetShareAdd(struct smbd_server_connection *sconn,
2177 connection_struct *conn,uint64_t vuid,
2178 char *param, int tpscnt,
2179 char *data, int tdscnt,
2180 int mdrcnt,int mprcnt,
2181 char **rdata,char **rparam,
2182 int *rdata_len,int *rparam_len)
2184 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2185 char *str2 = skip_string(param,tpscnt,str1);
2186 char *p = skip_string(param,tpscnt,str2);
2187 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2188 fstring sharename;
2189 fstring comment;
2190 char *pathname = NULL;
2191 unsigned int offset;
2192 int res = ERRunsup;
2193 size_t converted_size;
2195 WERROR werr = WERR_OK;
2196 TALLOC_CTX *mem_ctx = talloc_tos();
2197 NTSTATUS status;
2198 struct rpc_pipe_client *cli = NULL;
2199 union srvsvc_NetShareInfo info;
2200 struct srvsvc_NetShareInfo2 info2;
2201 struct dcerpc_binding_handle *b;
2203 if (!str1 || !str2 || !p) {
2204 return False;
2207 /* check it's a supported varient */
2208 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2209 return False;
2211 if (!check_share_info(uLevel,str2)) {
2212 return False;
2214 if (uLevel != 2) {
2215 return False;
2218 /* Do we have a string ? */
2219 if (skip_string(data,mdrcnt,data) == NULL) {
2220 return False;
2222 pull_ascii_fstring(sharename,data);
2224 if (mdrcnt < 28) {
2225 return False;
2228 /* only support disk share adds */
2229 if (SVAL(data,14)!=STYPE_DISKTREE) {
2230 return False;
2233 offset = IVAL(data, 16);
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;
2243 pull_ascii_fstring(comment, offset? (data+offset) : "");
2245 offset = IVAL(data, 26);
2247 if (offset >= mdrcnt) {
2248 res = ERRinvalidparam;
2249 goto out;
2252 /* Do we have a string ? */
2253 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2254 return False;
2257 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2258 offset ? (data+offset) : "", &converted_size))
2260 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
2261 strerror(errno)));
2264 if (!pathname) {
2265 return false;
2268 status = rpc_pipe_open_interface(mem_ctx, &ndr_table_srvsvc,
2269 conn->session_info,
2270 conn->sconn->remote_address,
2271 conn->sconn->local_address,
2272 conn->sconn->msg_ctx,
2273 &cli);
2274 if (!NT_STATUS_IS_OK(status)) {
2275 DEBUG(0,("api_RNetShareAdd: could not connect to srvsvc: %s\n",
2276 nt_errstr(status)));
2277 res = W_ERROR_V(ntstatus_to_werror(status));
2278 goto out;
2281 b = cli->binding_handle;
2283 info2.name = sharename;
2284 info2.type = STYPE_DISKTREE;
2285 info2.comment = comment;
2286 info2.permissions = 0;
2287 info2.max_users = 0;
2288 info2.current_users = 0;
2289 info2.path = pathname;
2290 info2.password = NULL;
2292 info.info2 = &info2;
2294 status = dcerpc_srvsvc_NetShareAdd(b, mem_ctx,
2295 cli->srv_name_slash,
2297 &info,
2298 NULL,
2299 &werr);
2300 if (!NT_STATUS_IS_OK(status)) {
2301 res = W_ERROR_V(ntstatus_to_werror(status));
2302 goto out;
2304 if (!W_ERROR_IS_OK(werr)) {
2305 res = W_ERROR_V(werr);
2306 goto out;
2309 *rparam_len = 6;
2310 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2311 if (!*rparam) {
2312 return False;
2314 SSVAL(*rparam,0,NERR_Success);
2315 SSVAL(*rparam,2,0); /* converter word */
2316 SSVAL(*rparam,4,*rdata_len);
2317 *rdata_len = 0;
2319 return True;
2321 out:
2323 *rparam_len = 4;
2324 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2325 if (!*rparam) {
2326 return False;
2328 *rdata_len = 0;
2329 SSVAL(*rparam,0,res);
2330 SSVAL(*rparam,2,0);
2331 return True;
2334 /****************************************************************************
2335 view list of groups available
2336 ****************************************************************************/
2338 static bool api_RNetGroupEnum(struct smbd_server_connection *sconn,
2339 connection_struct *conn,uint64_t vuid,
2340 char *param, int tpscnt,
2341 char *data, int tdscnt,
2342 int mdrcnt,int mprcnt,
2343 char **rdata,char **rparam,
2344 int *rdata_len,int *rparam_len)
2346 int i;
2347 int errflags=0;
2348 int resume_context, cli_buf_size;
2349 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2350 char *str2 = skip_string(param,tpscnt,str1);
2351 char *p = skip_string(param,tpscnt,str2);
2353 uint32_t num_groups;
2354 uint32_t resume_handle;
2355 struct rpc_pipe_client *samr_pipe = NULL;
2356 struct policy_handle samr_handle, domain_handle;
2357 NTSTATUS status, result;
2358 struct dcerpc_binding_handle *b;
2360 if (!str1 || !str2 || !p) {
2361 return False;
2364 if (strcmp(str1,"WrLeh") != 0) {
2365 return False;
2368 /* parameters
2369 * W-> resume context (number of users to skip)
2370 * r -> return parameter pointer to receive buffer
2371 * L -> length of receive buffer
2372 * e -> return parameter number of entries
2373 * h -> return parameter total number of users
2376 if (strcmp("B21",str2) != 0) {
2377 return False;
2380 status = rpc_pipe_open_interface(
2381 talloc_tos(), &ndr_table_samr,
2382 conn->session_info, conn->sconn->remote_address,
2383 conn->sconn->local_address, conn->sconn->msg_ctx, &samr_pipe);
2384 if (!NT_STATUS_IS_OK(status)) {
2385 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2386 nt_errstr(status)));
2387 return false;
2390 b = samr_pipe->binding_handle;
2392 status = dcerpc_samr_Connect2(b, talloc_tos(), lp_netbios_name(),
2393 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle,
2394 &result);
2395 if (!NT_STATUS_IS_OK(status)) {
2396 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2397 nt_errstr(status)));
2398 return false;
2400 if (!NT_STATUS_IS_OK(result)) {
2401 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2402 nt_errstr(result)));
2403 return false;
2406 status = dcerpc_samr_OpenDomain(b, talloc_tos(), &samr_handle,
2407 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2408 get_global_sam_sid(), &domain_handle,
2409 &result);
2410 if (!NT_STATUS_IS_OK(status)) {
2411 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2412 nt_errstr(status)));
2413 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2414 return false;
2416 if (!NT_STATUS_IS_OK(result)) {
2417 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2418 nt_errstr(result)));
2419 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2420 return false;
2423 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2424 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2425 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2426 "%d\n", resume_context, cli_buf_size));
2428 *rdata_len = cli_buf_size;
2429 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2430 if (!*rdata) {
2431 return False;
2434 p = *rdata;
2436 errflags = NERR_Success;
2437 num_groups = 0;
2438 resume_handle = 0;
2440 while (true) {
2441 struct samr_SamArray *sam_entries;
2442 uint32_t num_entries;
2444 status = dcerpc_samr_EnumDomainGroups(b, talloc_tos(),
2445 &domain_handle,
2446 &resume_handle,
2447 &sam_entries, 1,
2448 &num_entries,
2449 &result);
2450 if (!NT_STATUS_IS_OK(status)) {
2451 DEBUG(10, ("dcerpc_samr_EnumDomainGroups returned "
2452 "%s\n", nt_errstr(status)));
2453 break;
2455 if (!NT_STATUS_IS_OK(result)) {
2456 status = result;
2457 DEBUG(10, ("dcerpc_samr_EnumDomainGroups returned "
2458 "%s\n", nt_errstr(result)));
2459 break;
2462 if (num_entries == 0) {
2463 DEBUG(10, ("dcerpc_samr_EnumDomainGroups returned "
2464 "no entries -- done\n"));
2465 break;
2468 for(i=0; i<num_entries; i++) {
2469 const char *name;
2471 name = sam_entries->entries[i].name.string;
2473 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2474 /* set overflow error */
2475 DEBUG(3,("overflow on entry %d group %s\n", i,
2476 name));
2477 errflags=234;
2478 break;
2481 /* truncate the name at 21 chars. */
2482 memset(p, 0, 21);
2483 strlcpy(p, name, 21);
2484 DEBUG(10,("adding entry %d group %s\n", i, p));
2485 p += 21;
2486 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2487 * idea why... */
2488 num_groups += 1;
2491 if (errflags != NERR_Success) {
2492 break;
2495 TALLOC_FREE(sam_entries);
2498 dcerpc_samr_Close(b, talloc_tos(), &domain_handle, &result);
2499 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2501 *rdata_len = PTR_DIFF(p,*rdata);
2503 *rparam_len = 8;
2504 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2505 if (!*rparam) {
2506 return False;
2508 SSVAL(*rparam, 0, errflags);
2509 SSVAL(*rparam, 2, 0); /* converter word */
2510 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2511 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2513 return(True);
2516 /*******************************************************************
2517 Get groups that a user is a member of.
2518 ******************************************************************/
2520 static bool api_NetUserGetGroups(struct smbd_server_connection *sconn,
2521 connection_struct *conn,uint64_t vuid,
2522 char *param, int tpscnt,
2523 char *data, int tdscnt,
2524 int mdrcnt,int mprcnt,
2525 char **rdata,char **rparam,
2526 int *rdata_len,int *rparam_len)
2528 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2529 char *str2 = skip_string(param,tpscnt,str1);
2530 char *UserName = skip_string(param,tpscnt,str2);
2531 char *p = skip_string(param,tpscnt,UserName);
2532 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2533 const char *level_string;
2534 int count=0;
2535 bool ret = False;
2536 uint32_t i;
2537 char *endp = NULL;
2539 struct rpc_pipe_client *samr_pipe = NULL;
2540 struct policy_handle samr_handle, domain_handle, user_handle;
2541 struct lsa_String name;
2542 struct lsa_Strings names;
2543 struct samr_Ids type, rid;
2544 struct samr_RidWithAttributeArray *rids;
2545 NTSTATUS status, result;
2546 struct dcerpc_binding_handle *b;
2548 if (!str1 || !str2 || !UserName || !p) {
2549 return False;
2552 *rparam_len = 8;
2553 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2554 if (!*rparam) {
2555 return False;
2558 /* check it's a supported varient */
2560 if ( strcmp(str1,"zWrLeh") != 0 )
2561 return False;
2563 switch( uLevel ) {
2564 case 0:
2565 level_string = "B21";
2566 break;
2567 default:
2568 return False;
2571 if (strcmp(level_string,str2) != 0)
2572 return False;
2574 *rdata_len = mdrcnt + 1024;
2575 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2576 if (!*rdata) {
2577 return False;
2580 SSVAL(*rparam,0,NERR_Success);
2581 SSVAL(*rparam,2,0); /* converter word */
2583 p = *rdata;
2584 endp = *rdata + *rdata_len;
2586 status = rpc_pipe_open_interface(
2587 talloc_tos(), &ndr_table_samr,
2588 conn->session_info, conn->sconn->remote_address,
2589 conn->sconn->local_address, conn->sconn->msg_ctx, &samr_pipe);
2590 if (!NT_STATUS_IS_OK(status)) {
2591 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2592 nt_errstr(status)));
2593 return false;
2596 b = samr_pipe->binding_handle;
2598 status = dcerpc_samr_Connect2(b, talloc_tos(), lp_netbios_name(),
2599 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle,
2600 &result);
2601 if (!NT_STATUS_IS_OK(status)) {
2602 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2603 nt_errstr(status)));
2604 return false;
2606 if (!NT_STATUS_IS_OK(result)) {
2607 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2608 nt_errstr(result)));
2609 return false;
2612 status = dcerpc_samr_OpenDomain(b, talloc_tos(), &samr_handle,
2613 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2614 get_global_sam_sid(), &domain_handle,
2615 &result);
2616 if (!NT_STATUS_IS_OK(status)) {
2617 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2618 nt_errstr(status)));
2619 goto close_sam;
2621 if (!NT_STATUS_IS_OK(result)) {
2622 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2623 nt_errstr(result)));
2624 goto close_sam;
2627 name.string = UserName;
2629 status = dcerpc_samr_LookupNames(b, talloc_tos(),
2630 &domain_handle, 1, &name,
2631 &rid, &type,
2632 &result);
2633 if (!NT_STATUS_IS_OK(status)) {
2634 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2635 nt_errstr(status)));
2636 goto close_domain;
2638 if (!NT_STATUS_IS_OK(result)) {
2639 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2640 nt_errstr(result)));
2641 goto close_domain;
2643 if (rid.count != 1) {
2644 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2645 goto close_domain;
2647 if (type.count != 1) {
2648 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2649 goto close_domain;
2652 if (type.ids[0] != SID_NAME_USER) {
2653 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2654 sid_type_lookup(type.ids[0])));
2655 goto close_domain;
2658 status = dcerpc_samr_OpenUser(b, talloc_tos(),
2659 &domain_handle,
2660 SAMR_USER_ACCESS_GET_GROUPS,
2661 rid.ids[0], &user_handle,
2662 &result);
2663 if (!NT_STATUS_IS_OK(status)) {
2664 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2665 nt_errstr(status)));
2666 goto close_domain;
2668 if (!NT_STATUS_IS_OK(result)) {
2669 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2670 nt_errstr(result)));
2671 goto close_domain;
2674 status = dcerpc_samr_GetGroupsForUser(b, talloc_tos(),
2675 &user_handle, &rids,
2676 &result);
2677 if (!NT_STATUS_IS_OK(status)) {
2678 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2679 nt_errstr(status)));
2680 goto close_user;
2682 if (!NT_STATUS_IS_OK(result)) {
2683 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2684 nt_errstr(result)));
2685 goto close_user;
2688 for (i=0; i<rids->count; i++) {
2690 status = dcerpc_samr_LookupRids(b, talloc_tos(),
2691 &domain_handle,
2692 1, &rids->rids[i].rid,
2693 &names, &type,
2694 &result);
2695 if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result) && (names.count == 1)) {
2696 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2697 p += 21;
2698 count++;
2702 *rdata_len = PTR_DIFF(p,*rdata);
2704 SSVAL(*rparam,4,count); /* is this right?? */
2705 SSVAL(*rparam,6,count); /* is this right?? */
2707 ret = True;
2709 close_user:
2710 dcerpc_samr_Close(b, talloc_tos(), &user_handle, &result);
2711 close_domain:
2712 dcerpc_samr_Close(b, talloc_tos(), &domain_handle, &result);
2713 close_sam:
2714 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2716 return ret;
2719 /*******************************************************************
2720 Get all users.
2721 ******************************************************************/
2723 static bool api_RNetUserEnum(struct smbd_server_connection *sconn,
2724 connection_struct *conn, uint64_t vuid,
2725 char *param, int tpscnt,
2726 char *data, int tdscnt,
2727 int mdrcnt,int mprcnt,
2728 char **rdata,char **rparam,
2729 int *rdata_len,int *rparam_len)
2731 int count_sent=0;
2732 int num_users=0;
2733 int errflags=0;
2734 int i, resume_context, cli_buf_size;
2735 uint32_t resume_handle;
2737 struct rpc_pipe_client *samr_pipe = NULL;
2738 struct policy_handle samr_handle, domain_handle;
2739 NTSTATUS status, result;
2741 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2742 char *str2 = skip_string(param,tpscnt,str1);
2743 char *p = skip_string(param,tpscnt,str2);
2744 char *endp = NULL;
2746 struct dcerpc_binding_handle *b;
2748 if (!str1 || !str2 || !p) {
2749 return False;
2752 if (strcmp(str1,"WrLeh") != 0)
2753 return False;
2754 /* parameters
2755 * W-> resume context (number of users to skip)
2756 * r -> return parameter pointer to receive buffer
2757 * L -> length of receive buffer
2758 * e -> return parameter number of entries
2759 * h -> return parameter total number of users
2762 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2763 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2764 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2765 resume_context, cli_buf_size));
2767 *rparam_len = 8;
2768 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2769 if (!*rparam) {
2770 return False;
2773 /* check it's a supported varient */
2774 if (strcmp("B21",str2) != 0)
2775 return False;
2777 *rdata_len = cli_buf_size;
2778 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2779 if (!*rdata) {
2780 return False;
2783 p = *rdata;
2784 endp = *rdata + *rdata_len;
2786 status = rpc_pipe_open_interface(
2787 talloc_tos(), &ndr_table_samr,
2788 conn->session_info, conn->sconn->remote_address,
2789 conn->sconn->local_address, conn->sconn->msg_ctx, &samr_pipe);
2790 if (!NT_STATUS_IS_OK(status)) {
2791 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2792 nt_errstr(status)));
2793 return false;
2796 b = samr_pipe->binding_handle;
2798 status = dcerpc_samr_Connect2(b, talloc_tos(), lp_netbios_name(),
2799 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle,
2800 &result);
2801 if (!NT_STATUS_IS_OK(status)) {
2802 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2803 nt_errstr(status)));
2804 return false;
2806 if (!NT_STATUS_IS_OK(result)) {
2807 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2808 nt_errstr(result)));
2809 return false;
2812 status = dcerpc_samr_OpenDomain(b, talloc_tos(), &samr_handle,
2813 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2814 get_global_sam_sid(), &domain_handle,
2815 &result);
2816 if (!NT_STATUS_IS_OK(status)) {
2817 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2818 nt_errstr(status)));
2819 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2820 return false;
2822 if (!NT_STATUS_IS_OK(result)) {
2823 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2824 nt_errstr(result)));
2825 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2826 return false;
2829 errflags=NERR_Success;
2831 resume_handle = 0;
2833 while (true) {
2834 struct samr_SamArray *sam_entries;
2835 uint32_t num_entries;
2837 status = dcerpc_samr_EnumDomainUsers(b, talloc_tos(),
2838 &domain_handle,
2839 &resume_handle,
2840 0, &sam_entries, 1,
2841 &num_entries,
2842 &result);
2844 if (!NT_STATUS_IS_OK(status)) {
2845 DEBUG(10, ("dcerpc_samr_EnumDomainUsers returned "
2846 "%s\n", nt_errstr(status)));
2847 break;
2849 if (!NT_STATUS_IS_OK(result)) {
2850 DEBUG(10, ("dcerpc_samr_EnumDomainUsers returned "
2851 "%s\n", nt_errstr(result)));
2852 break;
2855 if (num_entries == 0) {
2856 DEBUG(10, ("dcerpc_samr_EnumDomainUsers returned "
2857 "no entries -- done\n"));
2858 break;
2861 for (i=0; i<num_entries; i++) {
2862 const char *name;
2864 name = sam_entries->entries[i].name.string;
2866 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2867 &&(strlen(name)<=21)) {
2868 strlcpy(p,name,PTR_DIFF(endp,p));
2869 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2870 "username %s\n",count_sent,p));
2871 p += 21;
2872 count_sent++;
2873 } else {
2874 /* set overflow error */
2875 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2876 "username %s\n",count_sent,name));
2877 errflags=234;
2878 break;
2882 if (errflags != NERR_Success) {
2883 break;
2886 TALLOC_FREE(sam_entries);
2889 dcerpc_samr_Close(b, talloc_tos(), &domain_handle, &result);
2890 dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result);
2892 *rdata_len = PTR_DIFF(p,*rdata);
2894 SSVAL(*rparam,0,errflags);
2895 SSVAL(*rparam,2,0); /* converter word */
2896 SSVAL(*rparam,4,count_sent); /* is this right?? */
2897 SSVAL(*rparam,6,num_users); /* is this right?? */
2899 return True;
2902 /****************************************************************************
2903 Get the time of day info.
2904 ****************************************************************************/
2906 static bool api_NetRemoteTOD(struct smbd_server_connection *sconn,
2907 connection_struct *conn,uint64_t vuid,
2908 char *param, int tpscnt,
2909 char *data, int tdscnt,
2910 int mdrcnt,int mprcnt,
2911 char **rdata,char **rparam,
2912 int *rdata_len,int *rparam_len)
2914 struct tm *t;
2915 time_t unixdate = time(NULL);
2916 char *p;
2918 *rparam_len = 4;
2919 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2920 if (!*rparam) {
2921 return False;
2924 *rdata_len = 21;
2925 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2926 if (!*rdata) {
2927 return False;
2930 SSVAL(*rparam,0,NERR_Success);
2931 SSVAL(*rparam,2,0); /* converter word */
2933 p = *rdata;
2935 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2936 by NT in a "net time" operation,
2937 it seems to ignore the one below */
2939 /* the client expects to get localtime, not GMT, in this bit
2940 (I think, this needs testing) */
2941 t = localtime(&unixdate);
2942 if (!t) {
2943 return False;
2946 SIVAL(p,4,0); /* msecs ? */
2947 SCVAL(p,8,t->tm_hour);
2948 SCVAL(p,9,t->tm_min);
2949 SCVAL(p,10,t->tm_sec);
2950 SCVAL(p,11,0); /* hundredths of seconds */
2951 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2952 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2953 SCVAL(p,16,t->tm_mday);
2954 SCVAL(p,17,t->tm_mon + 1);
2955 SSVAL(p,18,1900+t->tm_year);
2956 SCVAL(p,20,t->tm_wday);
2958 return True;
2961 /****************************************************************************
2962 Set the user password (SamOEM version - gets plaintext).
2963 ****************************************************************************/
2965 static bool api_SamOEMChangePassword(struct smbd_server_connection *sconn,
2966 connection_struct *conn,uint64_t vuid,
2967 char *param, int tpscnt,
2968 char *data, int tdscnt,
2969 int mdrcnt,int mprcnt,
2970 char **rdata,char **rparam,
2971 int *rdata_len,int *rparam_len)
2973 fstring user;
2974 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2976 TALLOC_CTX *mem_ctx = talloc_tos();
2977 NTSTATUS status, result;
2978 struct rpc_pipe_client *cli = NULL;
2979 struct lsa_AsciiString server, account;
2980 struct samr_CryptPassword password;
2981 struct samr_Password hash;
2982 int errcode = NERR_badpass;
2983 int bufsize;
2984 struct dcerpc_binding_handle *b;
2986 *rparam_len = 4;
2987 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2988 if (!*rparam) {
2989 return False;
2992 if (!p) {
2993 return False;
2995 *rdata_len = 0;
2997 SSVAL(*rparam,0,NERR_badpass);
3000 * Check the parameter definition is correct.
3003 /* Do we have a string ? */
3004 if (skip_string(param,tpscnt,p) == 0) {
3005 return False;
3007 if(!strequal(p, "zsT")) {
3008 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
3009 return False;
3011 p = skip_string(param, tpscnt, p);
3012 if (!p) {
3013 return False;
3016 /* Do we have a string ? */
3017 if (skip_string(param,tpscnt,p) == 0) {
3018 return False;
3020 if(!strequal(p, "B516B16")) {
3021 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
3022 return False;
3024 p = skip_string(param,tpscnt,p);
3025 if (!p) {
3026 return False;
3028 /* Do we have a string ? */
3029 if (skip_string(param,tpscnt,p) == 0) {
3030 return False;
3032 p += pull_ascii_fstring(user,p);
3034 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
3036 if (tdscnt != 532) {
3037 errcode = W_ERROR_V(WERR_INVALID_PARAMETER);
3038 goto out;
3041 bufsize = get_safe_SVAL(param,tpscnt,p,0,-1);
3042 if (bufsize != 532) {
3043 errcode = W_ERROR_V(WERR_INVALID_PARAMETER);
3044 goto out;
3047 memcpy(password.data, data, 516);
3048 memcpy(hash.hash, data+516, 16);
3050 status = rpc_pipe_open_interface(mem_ctx, &ndr_table_samr,
3051 conn->session_info,
3052 conn->sconn->remote_address,
3053 conn->sconn->local_address,
3054 conn->sconn->msg_ctx,
3055 &cli);
3056 if (!NT_STATUS_IS_OK(status)) {
3057 DEBUG(0,("api_SamOEMChangePassword: could not connect to samr: %s\n",
3058 nt_errstr(status)));
3059 errcode = W_ERROR_V(ntstatus_to_werror(status));
3060 goto out;
3063 b = cli->binding_handle;
3065 init_lsa_AsciiString(&server, lp_netbios_name());
3066 init_lsa_AsciiString(&account, user);
3068 status = dcerpc_samr_OemChangePasswordUser2(b, mem_ctx,
3069 &server,
3070 &account,
3071 &password,
3072 &hash,
3073 &result);
3074 if (!NT_STATUS_IS_OK(status)) {
3075 errcode = W_ERROR_V(ntstatus_to_werror(status));
3076 goto out;
3078 if (!NT_STATUS_IS_OK(result)) {
3079 errcode = W_ERROR_V(ntstatus_to_werror(result));
3080 goto out;
3083 errcode = NERR_Success;
3084 out:
3085 SSVAL(*rparam,0,errcode);
3086 SSVAL(*rparam,2,0); /* converter word */
3088 return(True);
3091 /****************************************************************************
3092 delete a print job
3093 Form: <W> <>
3094 ****************************************************************************/
3096 static bool api_RDosPrintJobDel(struct smbd_server_connection *sconn,
3097 connection_struct *conn,uint64_t vuid,
3098 char *param, int tpscnt,
3099 char *data, int tdscnt,
3100 int mdrcnt,int mprcnt,
3101 char **rdata,char **rparam,
3102 int *rdata_len,int *rparam_len)
3104 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3105 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3106 char *str2 = skip_string(param,tpscnt,str1);
3107 char *p = skip_string(param,tpscnt,str2);
3108 uint32_t jobid;
3109 fstring sharename;
3110 int errcode;
3111 WERROR werr = WERR_OK;
3113 TALLOC_CTX *mem_ctx = talloc_tos();
3114 NTSTATUS status;
3115 struct rpc_pipe_client *cli = NULL;
3116 struct dcerpc_binding_handle *b = NULL;
3117 struct policy_handle handle;
3118 struct spoolss_DevmodeContainer devmode_ctr;
3119 enum spoolss_JobControl command;
3121 if (!str1 || !str2 || !p) {
3122 return False;
3125 * We use 1 here not 2 as we're checking
3126 * the last byte we want to access is safe.
3128 if (!is_offset_safe(param,tpscnt,p,1)) {
3129 return False;
3131 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3132 return False;
3134 /* check it's a supported varient */
3135 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
3136 return(False);
3138 *rparam_len = 4;
3139 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3140 if (!*rparam) {
3141 return False;
3143 *rdata_len = 0;
3145 ZERO_STRUCT(handle);
3147 status = rpc_pipe_open_interface(conn,
3148 &ndr_table_spoolss,
3149 conn->session_info,
3150 conn->sconn->remote_address,
3151 conn->sconn->local_address,
3152 conn->sconn->msg_ctx,
3153 &cli);
3154 if (!NT_STATUS_IS_OK(status)) {
3155 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
3156 nt_errstr(status)));
3157 errcode = W_ERROR_V(ntstatus_to_werror(status));
3158 goto out;
3160 b = cli->binding_handle;
3162 ZERO_STRUCT(devmode_ctr);
3164 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
3165 sharename,
3166 "RAW",
3167 devmode_ctr,
3168 JOB_ACCESS_ADMINISTER,
3169 &handle,
3170 &werr);
3171 if (!NT_STATUS_IS_OK(status)) {
3172 errcode = W_ERROR_V(ntstatus_to_werror(status));
3173 goto out;
3175 if (!W_ERROR_IS_OK(werr)) {
3176 errcode = W_ERROR_V(werr);
3177 goto out;
3180 /* FIXME: formerly NERR_JobNotFound was returned if job did not exist
3181 * and NERR_DestNotFound if share did not exist */
3183 errcode = NERR_Success;
3185 switch (function) {
3186 case 81: /* delete */
3187 command = SPOOLSS_JOB_CONTROL_DELETE;
3188 break;
3189 case 82: /* pause */
3190 command = SPOOLSS_JOB_CONTROL_PAUSE;
3191 break;
3192 case 83: /* resume */
3193 command = SPOOLSS_JOB_CONTROL_RESUME;
3194 break;
3195 default:
3196 errcode = NERR_notsupported;
3197 goto out;
3200 status = dcerpc_spoolss_SetJob(b, mem_ctx,
3201 &handle,
3202 jobid,
3203 NULL, /* unique ptr ctr */
3204 command,
3205 &werr);
3206 if (!NT_STATUS_IS_OK(status)) {
3207 errcode = W_ERROR_V(ntstatus_to_werror(status));
3208 goto out;
3210 if (!W_ERROR_IS_OK(werr)) {
3211 errcode = W_ERROR_V(werr);
3212 goto out;
3215 out:
3216 if (b && is_valid_policy_hnd(&handle)) {
3217 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
3220 SSVAL(*rparam,0,errcode);
3221 SSVAL(*rparam,2,0); /* converter word */
3223 return(True);
3226 /****************************************************************************
3227 Purge a print queue - or pause or resume it.
3228 ****************************************************************************/
3230 static bool api_WPrintQueueCtrl(struct smbd_server_connection *sconn,
3231 connection_struct *conn,uint64_t vuid,
3232 char *param, int tpscnt,
3233 char *data, int tdscnt,
3234 int mdrcnt,int mprcnt,
3235 char **rdata,char **rparam,
3236 int *rdata_len,int *rparam_len)
3238 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3239 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3240 char *str2 = skip_string(param,tpscnt,str1);
3241 char *QueueName = skip_string(param,tpscnt,str2);
3242 int errcode = NERR_notsupported;
3243 WERROR werr = WERR_OK;
3244 NTSTATUS status;
3246 TALLOC_CTX *mem_ctx = talloc_tos();
3247 struct rpc_pipe_client *cli = NULL;
3248 struct dcerpc_binding_handle *b = NULL;
3249 struct policy_handle handle;
3250 struct spoolss_SetPrinterInfoCtr info_ctr;
3251 struct spoolss_DevmodeContainer devmode_ctr;
3252 struct sec_desc_buf secdesc_ctr;
3253 enum spoolss_PrinterControl command;
3255 if (!str1 || !str2 || !QueueName) {
3256 return False;
3259 /* check it's a supported varient */
3260 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3261 return(False);
3263 *rparam_len = 4;
3264 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3265 if (!*rparam) {
3266 return False;
3268 *rdata_len = 0;
3270 if (skip_string(param,tpscnt,QueueName) == NULL) {
3271 return False;
3274 ZERO_STRUCT(handle);
3276 status = rpc_pipe_open_interface(conn,
3277 &ndr_table_spoolss,
3278 conn->session_info,
3279 conn->sconn->remote_address,
3280 conn->sconn->local_address,
3281 conn->sconn->msg_ctx,
3282 &cli);
3283 if (!NT_STATUS_IS_OK(status)) {
3284 DEBUG(0,("api_WPrintQueueCtrl: could not connect to spoolss: %s\n",
3285 nt_errstr(status)));
3286 errcode = W_ERROR_V(ntstatus_to_werror(status));
3287 goto out;
3289 b = cli->binding_handle;
3291 ZERO_STRUCT(devmode_ctr);
3293 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
3294 QueueName,
3295 NULL,
3296 devmode_ctr,
3297 PRINTER_ACCESS_ADMINISTER,
3298 &handle,
3299 &werr);
3300 if (!NT_STATUS_IS_OK(status)) {
3301 errcode = W_ERROR_V(ntstatus_to_werror(status));
3302 goto out;
3304 if (!W_ERROR_IS_OK(werr)) {
3305 errcode = W_ERROR_V(werr);
3306 goto out;
3309 switch (function) {
3310 case 74: /* Pause queue */
3311 command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3312 break;
3313 case 75: /* Resume queue */
3314 command = SPOOLSS_PRINTER_CONTROL_RESUME;
3315 break;
3316 case 103: /* Purge */
3317 command = SPOOLSS_PRINTER_CONTROL_PURGE;
3318 break;
3319 default:
3320 werr = WERR_NOT_SUPPORTED;
3321 break;
3324 if (!W_ERROR_IS_OK(werr)) {
3325 errcode = W_ERROR_V(werr);
3326 goto out;
3329 ZERO_STRUCT(info_ctr);
3330 ZERO_STRUCT(secdesc_ctr);
3332 status = dcerpc_spoolss_SetPrinter(b, mem_ctx,
3333 &handle,
3334 &info_ctr,
3335 &devmode_ctr,
3336 &secdesc_ctr,
3337 command,
3338 &werr);
3339 if (!NT_STATUS_IS_OK(status)) {
3340 errcode = W_ERROR_V(ntstatus_to_werror(status));
3341 goto out;
3343 if (!W_ERROR_IS_OK(werr)) {
3344 errcode = W_ERROR_V(werr);
3345 goto out;
3348 errcode = W_ERROR_V(werr);
3350 out:
3352 if (b && is_valid_policy_hnd(&handle)) {
3353 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
3356 SSVAL(*rparam,0,errcode);
3357 SSVAL(*rparam,2,0); /* converter word */
3359 return(True);
3362 /****************************************************************************
3363 set the property of a print job (undocumented?)
3364 ? function = 0xb -> set name of print job
3365 ? function = 0x6 -> move print job up/down
3366 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3367 or <WWsTP> <WB21BB16B10zWWzDDz>
3368 ****************************************************************************/
3370 static int check_printjob_info(struct pack_desc* desc,
3371 int uLevel, char* id)
3373 desc->subformat = NULL;
3374 switch( uLevel ) {
3375 case 0: desc->format = "W"; break;
3376 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3377 case 2: desc->format = "WWzWWDDzz"; break;
3378 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3379 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3380 default:
3381 DEBUG(0,("check_printjob_info: invalid level %d\n",
3382 uLevel ));
3383 return False;
3385 if (id == NULL || strcmp(desc->format,id) != 0) {
3386 DEBUG(0,("check_printjob_info: invalid format %s\n",
3387 id ? id : "<NULL>" ));
3388 return False;
3390 return True;
3393 static bool api_PrintJobInfo(struct smbd_server_connection *sconn,
3394 connection_struct *conn, uint64_t vuid,
3395 char *param, int tpscnt,
3396 char *data, int tdscnt,
3397 int mdrcnt,int mprcnt,
3398 char **rdata,char **rparam,
3399 int *rdata_len,int *rparam_len)
3401 struct pack_desc desc;
3402 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3403 char *str2 = skip_string(param,tpscnt,str1);
3404 char *p = skip_string(param,tpscnt,str2);
3405 uint32_t jobid;
3406 fstring sharename;
3407 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3408 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3409 int errcode;
3411 TALLOC_CTX *mem_ctx = talloc_tos();
3412 WERROR werr;
3413 NTSTATUS status;
3414 struct rpc_pipe_client *cli = NULL;
3415 struct dcerpc_binding_handle *b = NULL;
3416 struct policy_handle handle;
3417 struct spoolss_DevmodeContainer devmode_ctr;
3418 struct spoolss_JobInfoContainer ctr;
3419 union spoolss_JobInfo info;
3420 struct spoolss_SetJobInfo1 info1;
3422 if (!str1 || !str2 || !p) {
3423 return False;
3426 * We use 1 here not 2 as we're checking
3427 * the last byte we want to access is safe.
3429 if (!is_offset_safe(param,tpscnt,p,1)) {
3430 return False;
3432 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3433 return False;
3434 *rparam_len = 4;
3435 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3436 if (!*rparam) {
3437 return False;
3440 *rdata_len = 0;
3442 /* check it's a supported varient */
3443 if ((strcmp(str1,"WWsTP")) ||
3444 (!check_printjob_info(&desc,uLevel,str2)))
3445 return(False);
3447 errcode = NERR_notsupported;
3449 switch (function) {
3450 case 0xb:
3451 /* change print job name, data gives the name */
3452 break;
3453 default:
3454 goto out;
3457 ZERO_STRUCT(handle);
3459 status = rpc_pipe_open_interface(conn,
3460 &ndr_table_spoolss,
3461 conn->session_info,
3462 conn->sconn->remote_address,
3463 conn->sconn->local_address,
3464 conn->sconn->msg_ctx,
3465 &cli);
3466 if (!NT_STATUS_IS_OK(status)) {
3467 DEBUG(0,("api_PrintJobInfo: could not connect to spoolss: %s\n",
3468 nt_errstr(status)));
3469 errcode = W_ERROR_V(ntstatus_to_werror(status));
3470 goto out;
3472 b = cli->binding_handle;
3474 ZERO_STRUCT(devmode_ctr);
3476 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
3477 sharename,
3478 "RAW",
3479 devmode_ctr,
3480 PRINTER_ACCESS_USE,
3481 &handle,
3482 &werr);
3483 if (!NT_STATUS_IS_OK(status)) {
3484 errcode = W_ERROR_V(ntstatus_to_werror(status));
3485 goto out;
3487 if (!W_ERROR_IS_OK(werr)) {
3488 errcode = W_ERROR_V(werr);
3489 goto out;
3492 werr = rpccli_spoolss_getjob(cli, mem_ctx,
3493 &handle,
3494 jobid,
3495 1, /* level */
3496 0, /* offered */
3497 &info);
3498 if (!W_ERROR_IS_OK(werr)) {
3499 errcode = W_ERROR_V(werr);
3500 goto out;
3503 ZERO_STRUCT(ctr);
3505 info1.job_id = info.info1.job_id;
3506 info1.printer_name = info.info1.printer_name;
3507 info1.user_name = info.info1.user_name;
3508 info1.document_name = data;
3509 info1.data_type = info.info1.data_type;
3510 info1.text_status = info.info1.text_status;
3511 info1.status = info.info1.status;
3512 info1.priority = info.info1.priority;
3513 info1.position = info.info1.position;
3514 info1.total_pages = info.info1.total_pages;
3515 info1.pages_printed = info.info1.pages_printed;
3516 info1.submitted = info.info1.submitted;
3518 ctr.level = 1;
3519 ctr.info.info1 = &info1;
3521 status = dcerpc_spoolss_SetJob(b, mem_ctx,
3522 &handle,
3523 jobid,
3524 &ctr,
3526 &werr);
3527 if (!NT_STATUS_IS_OK(status)) {
3528 errcode = W_ERROR_V(ntstatus_to_werror(status));
3529 goto out;
3531 if (!W_ERROR_IS_OK(werr)) {
3532 errcode = W_ERROR_V(werr);
3533 goto out;
3536 errcode = NERR_Success;
3537 out:
3539 if (b && is_valid_policy_hnd(&handle)) {
3540 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
3543 SSVALS(*rparam,0,errcode);
3544 SSVAL(*rparam,2,0); /* converter word */
3546 return(True);
3550 /****************************************************************************
3551 Get info about the server.
3552 ****************************************************************************/
3554 static bool api_RNetServerGetInfo(struct smbd_server_connection *sconn,
3555 connection_struct *conn,uint64_t vuid,
3556 char *param, int tpscnt,
3557 char *data, int tdscnt,
3558 int mdrcnt,int mprcnt,
3559 char **rdata,char **rparam,
3560 int *rdata_len,int *rparam_len)
3562 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3563 char *str2 = skip_string(param,tpscnt,str1);
3564 char *p = skip_string(param,tpscnt,str2);
3565 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3566 char *p2;
3567 int struct_len;
3569 NTSTATUS status;
3570 WERROR werr;
3571 TALLOC_CTX *mem_ctx = talloc_tos();
3572 struct rpc_pipe_client *cli = NULL;
3573 union srvsvc_NetSrvInfo info;
3574 int errcode;
3575 struct dcerpc_binding_handle *b;
3577 if (!str1 || !str2 || !p) {
3578 return False;
3581 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3583 /* check it's a supported varient */
3584 if (!prefix_ok(str1,"WrLh")) {
3585 return False;
3588 switch( uLevel ) {
3589 case 0:
3590 if (strcmp(str2,"B16") != 0) {
3591 return False;
3593 struct_len = 16;
3594 break;
3595 case 1:
3596 if (strcmp(str2,"B16BBDz") != 0) {
3597 return False;
3599 struct_len = 26;
3600 break;
3601 case 2:
3602 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3603 return False;
3605 struct_len = 134;
3606 break;
3607 case 3:
3608 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3609 return False;
3611 struct_len = 144;
3612 break;
3613 case 20:
3614 if (strcmp(str2,"DN") != 0) {
3615 return False;
3617 struct_len = 6;
3618 break;
3619 case 50:
3620 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3621 return False;
3623 struct_len = 42;
3624 break;
3625 default:
3626 return False;
3629 *rdata_len = mdrcnt;
3630 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3631 if (!*rdata) {
3632 return False;
3635 p = *rdata;
3636 p2 = p + struct_len;
3638 status = rpc_pipe_open_interface(mem_ctx, &ndr_table_srvsvc,
3639 conn->session_info,
3640 conn->sconn->remote_address,
3641 conn->sconn->local_address,
3642 conn->sconn->msg_ctx,
3643 &cli);
3644 if (!NT_STATUS_IS_OK(status)) {
3645 DEBUG(0,("api_RNetServerGetInfo: could not connect to srvsvc: %s\n",
3646 nt_errstr(status)));
3647 errcode = W_ERROR_V(ntstatus_to_werror(status));
3648 goto out;
3651 b = cli->binding_handle;
3653 status = dcerpc_srvsvc_NetSrvGetInfo(b, mem_ctx,
3654 NULL,
3655 101,
3656 &info,
3657 &werr);
3658 if (!NT_STATUS_IS_OK(status)) {
3659 errcode = W_ERROR_V(ntstatus_to_werror(status));
3660 goto out;
3662 if (!W_ERROR_IS_OK(werr)) {
3663 errcode = W_ERROR_V(werr);
3664 goto out;
3667 if (info.info101 == NULL) {
3668 errcode = W_ERROR_V(WERR_INVALID_PARAMETER);
3669 goto out;
3672 if (uLevel != 20) {
3673 size_t len = 0;
3674 status = srvstr_push(NULL, 0, p, info.info101->server_name, 16,
3675 STR_ASCII|STR_UPPER|STR_TERMINATE, &len);
3676 if (!NT_STATUS_IS_OK(status)) {
3677 errcode = W_ERROR_V(ntstatus_to_werror(status));
3678 goto out;
3681 p += 16;
3682 if (uLevel > 0) {
3683 SCVAL(p,0,info.info101->version_major);
3684 SCVAL(p,1,info.info101->version_minor);
3685 SIVAL(p,2,info.info101->server_type);
3687 if (mdrcnt == struct_len) {
3688 SIVAL(p,6,0);
3689 } else {
3690 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3691 if (mdrcnt - struct_len <= 0) {
3692 return false;
3694 push_ascii(p2,
3695 info.info101->comment,
3696 MIN(mdrcnt - struct_len,
3697 MAX_SERVER_STRING_LENGTH),
3698 STR_TERMINATE);
3699 p2 = skip_string(*rdata,*rdata_len,p2);
3700 if (!p2) {
3701 return False;
3706 if (uLevel > 1) {
3707 return False; /* not yet implemented */
3710 errcode = NERR_Success;
3712 out:
3714 *rdata_len = PTR_DIFF(p2,*rdata);
3716 *rparam_len = 6;
3717 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3718 if (!*rparam) {
3719 return False;
3721 SSVAL(*rparam,0,errcode);
3722 SSVAL(*rparam,2,0); /* converter word */
3723 SSVAL(*rparam,4,*rdata_len);
3725 return True;
3728 /****************************************************************************
3729 Get info about the server.
3730 ****************************************************************************/
3732 static bool api_NetWkstaGetInfo(struct smbd_server_connection *sconn,
3733 connection_struct *conn,uint64_t vuid,
3734 char *param, int tpscnt,
3735 char *data, int tdscnt,
3736 int mdrcnt,int mprcnt,
3737 char **rdata,char **rparam,
3738 int *rdata_len,int *rparam_len)
3740 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3741 char *str2 = skip_string(param,tpscnt,str1);
3742 char *p = skip_string(param,tpscnt,str2);
3743 char *p2;
3744 char *endp;
3745 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3747 if (!str1 || !str2 || !p) {
3748 return False;
3751 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3753 *rparam_len = 6;
3754 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3755 if (!*rparam) {
3756 return False;
3759 /* check it's a supported varient */
3760 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3761 return False;
3764 *rdata_len = mdrcnt + 1024;
3765 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3766 if (!*rdata) {
3767 return False;
3770 SSVAL(*rparam,0,NERR_Success);
3771 SSVAL(*rparam,2,0); /* converter word */
3773 p = *rdata;
3774 endp = *rdata + *rdata_len;
3776 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3777 if (!p2) {
3778 return False;
3781 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3782 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3783 if (!strupper_m(p2)) {
3784 return false;
3786 p2 = skip_string(*rdata,*rdata_len,p2);
3787 if (!p2) {
3788 return False;
3790 p += 4;
3792 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3793 strlcpy(p2,conn->session_info->unix_info->sanitized_username,PTR_DIFF(endp,p2));
3794 p2 = skip_string(*rdata,*rdata_len,p2);
3795 if (!p2) {
3796 return False;
3798 p += 4;
3800 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3801 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3802 if (!strupper_m(p2)) {
3803 return false;
3805 p2 = skip_string(*rdata,*rdata_len,p2);
3806 if (!p2) {
3807 return False;
3809 p += 4;
3811 SCVAL(p,0,SAMBA_MAJOR_NBT_ANNOUNCE_VERSION); /* system version - e.g 4 in 4.1 */
3812 SCVAL(p,1,SAMBA_MINOR_NBT_ANNOUNCE_VERSION); /* system version - e.g .1 in 4.1 */
3813 p += 2;
3815 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3816 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3817 p2 = skip_string(*rdata,*rdata_len,p2);
3818 if (!p2) {
3819 return False;
3821 p += 4;
3823 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3824 strlcpy(p2,"",PTR_DIFF(endp,p2));
3825 p2 = skip_string(*rdata,*rdata_len,p2);
3826 if (!p2) {
3827 return False;
3829 p += 4;
3831 *rdata_len = PTR_DIFF(p2,*rdata);
3833 SSVAL(*rparam,4,*rdata_len);
3835 return True;
3838 /****************************************************************************
3839 get info about a user
3841 struct user_info_11 {
3842 char usri11_name[21]; 0-20
3843 char usri11_pad; 21
3844 char *usri11_comment; 22-25
3845 char *usri11_usr_comment; 26-29
3846 unsigned short usri11_priv; 30-31
3847 unsigned long usri11_auth_flags; 32-35
3848 long usri11_password_age; 36-39
3849 char *usri11_homedir; 40-43
3850 char *usri11_parms; 44-47
3851 long usri11_last_logon; 48-51
3852 long usri11_last_logoff; 52-55
3853 unsigned short usri11_bad_pw_count; 56-57
3854 unsigned short usri11_num_logons; 58-59
3855 char *usri11_logon_server; 60-63
3856 unsigned short usri11_country_code; 64-65
3857 char *usri11_workstations; 66-69
3858 unsigned long usri11_max_storage; 70-73
3859 unsigned short usri11_units_per_week; 74-75
3860 unsigned char *usri11_logon_hours; 76-79
3861 unsigned short usri11_code_page; 80-81
3864 where:
3866 usri11_name specifies the user name for which information is retrieved
3868 usri11_pad aligns the next data structure element to a word boundary
3870 usri11_comment is a null terminated ASCII comment
3872 usri11_user_comment is a null terminated ASCII comment about the user
3874 usri11_priv specifies the level of the privilege assigned to the user.
3875 The possible values are:
3877 Name Value Description
3878 USER_PRIV_GUEST 0 Guest privilege
3879 USER_PRIV_USER 1 User privilege
3880 USER_PRV_ADMIN 2 Administrator privilege
3882 usri11_auth_flags specifies the account operator privileges. The
3883 possible values are:
3885 Name Value Description
3886 AF_OP_PRINT 0 Print operator
3889 Leach, Naik [Page 28]
3893 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3896 AF_OP_COMM 1 Communications operator
3897 AF_OP_SERVER 2 Server operator
3898 AF_OP_ACCOUNTS 3 Accounts operator
3901 usri11_password_age specifies how many seconds have elapsed since the
3902 password was last changed.
3904 usri11_home_dir points to a null terminated ASCII string that contains
3905 the path name of the user's home directory.
3907 usri11_parms points to a null terminated ASCII string that is set
3908 aside for use by applications.
3910 usri11_last_logon specifies the time when the user last logged on.
3911 This value is stored as the number of seconds elapsed since
3912 00:00:00, January 1, 1970.
3914 usri11_last_logoff specifies the time when the user last logged off.
3915 This value is stored as the number of seconds elapsed since
3916 00:00:00, January 1, 1970. A value of 0 means the last logoff
3917 time is unknown.
3919 usri11_bad_pw_count specifies the number of incorrect passwords
3920 entered since the last successful logon.
3922 usri11_log1_num_logons specifies the number of times this user has
3923 logged on. A value of -1 means the number of logons is unknown.
3925 usri11_logon_server points to a null terminated ASCII string that
3926 contains the name of the server to which logon requests are sent.
3927 A null string indicates logon requests should be sent to the
3928 domain controller.
3930 usri11_country_code specifies the country code for the user's language
3931 of choice.
3933 usri11_workstations points to a null terminated ASCII string that
3934 contains the names of workstations the user may log on from.
3935 There may be up to 8 workstations, with the names separated by
3936 commas. A null strings indicates there are no restrictions.
3938 usri11_max_storage specifies the maximum amount of disk space the user
3939 can occupy. A value of 0xffffffff indicates there are no
3940 restrictions.
3942 usri11_units_per_week specifies the equal number of time units into
3943 which a week is divided. This value must be equal to 168.
3945 usri11_logon_hours points to a 21 byte (168 bits) string that
3946 specifies the time during which the user can log on. Each bit
3947 represents one unique hour in a week. The first bit (bit 0, word
3948 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3952 Leach, Naik [Page 29]
3956 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3959 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3960 are no restrictions.
3962 usri11_code_page specifies the code page for the user's language of
3963 choice
3965 All of the pointers in this data structure need to be treated
3966 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3967 to be ignored. The converter word returned in the parameters section
3968 needs to be subtracted from the lower 16 bits to calculate an offset
3969 into the return buffer where this ASCII string resides.
3971 There is no auxiliary data in the response.
3973 ****************************************************************************/
3975 #define usri11_name 0
3976 #define usri11_pad 21
3977 #define usri11_comment 22
3978 #define usri11_usr_comment 26
3979 #define usri11_full_name 30
3980 #define usri11_priv 34
3981 #define usri11_auth_flags 36
3982 #define usri11_password_age 40
3983 #define usri11_homedir 44
3984 #define usri11_parms 48
3985 #define usri11_last_logon 52
3986 #define usri11_last_logoff 56
3987 #define usri11_bad_pw_count 60
3988 #define usri11_num_logons 62
3989 #define usri11_logon_server 64
3990 #define usri11_country_code 68
3991 #define usri11_workstations 70
3992 #define usri11_max_storage 74
3993 #define usri11_units_per_week 78
3994 #define usri11_logon_hours 80
3995 #define usri11_code_page 84
3996 #define usri11_end 86
3998 static bool api_RNetUserGetInfo(struct smbd_server_connection *sconn,
3999 connection_struct *conn, uint64_t vuid,
4000 char *param, int tpscnt,
4001 char *data, int tdscnt,
4002 int mdrcnt,int mprcnt,
4003 char **rdata,char **rparam,
4004 int *rdata_len,int *rparam_len)
4006 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4007 char *str2 = skip_string(param,tpscnt,str1);
4008 char *UserName = skip_string(param,tpscnt,str2);
4009 char *p = skip_string(param,tpscnt,UserName);
4010 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4011 char *p2;
4012 char *endp;
4013 const char *level_string;
4015 TALLOC_CTX *mem_ctx = talloc_tos();
4016 NTSTATUS status, result;
4017 struct rpc_pipe_client *cli = NULL;
4018 struct policy_handle connect_handle, domain_handle, user_handle;
4019 struct lsa_String domain_name;
4020 struct dom_sid2 *domain_sid;
4021 struct lsa_String names;
4022 struct samr_Ids rids;
4023 struct samr_Ids types;
4024 int errcode = W_ERROR_V(WERR_NERR_USERNOTFOUND);
4025 uint32_t rid;
4026 union samr_UserInfo *info;
4027 struct dcerpc_binding_handle *b = NULL;
4029 if (!str1 || !str2 || !UserName || !p) {
4030 return False;
4033 *rparam_len = 6;
4034 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4035 if (!*rparam) {
4036 return False;
4039 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
4041 /* check it's a supported variant */
4042 if (strcmp(str1,"zWrLh") != 0) {
4043 return False;
4045 switch( uLevel ) {
4046 case 0: level_string = "B21"; break;
4047 case 1: level_string = "B21BB16DWzzWz"; break;
4048 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
4049 case 10: level_string = "B21Bzzz"; break;
4050 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
4051 default: return False;
4054 if (strcmp(level_string,str2) != 0) {
4055 return False;
4058 *rdata_len = mdrcnt + 1024;
4059 *rdata = smb_realloc_limit(*rdata,*rdata_len);
4060 if (!*rdata) {
4061 return False;
4064 p = *rdata;
4065 endp = *rdata + *rdata_len;
4066 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
4067 if (!p2) {
4068 return False;
4071 ZERO_STRUCT(connect_handle);
4072 ZERO_STRUCT(domain_handle);
4073 ZERO_STRUCT(user_handle);
4075 status = rpc_pipe_open_interface(mem_ctx, &ndr_table_samr,
4076 conn->session_info,
4077 conn->sconn->remote_address,
4078 conn->sconn->local_address,
4079 conn->sconn->msg_ctx,
4080 &cli);
4081 if (!NT_STATUS_IS_OK(status)) {
4082 DEBUG(0,("api_RNetUserGetInfo: could not connect to samr: %s\n",
4083 nt_errstr(status)));
4084 errcode = W_ERROR_V(ntstatus_to_werror(status));
4085 goto out;
4088 b = cli->binding_handle;
4090 status = dcerpc_samr_Connect2(b, mem_ctx,
4091 lp_netbios_name(),
4092 SAMR_ACCESS_CONNECT_TO_SERVER |
4093 SAMR_ACCESS_ENUM_DOMAINS |
4094 SAMR_ACCESS_LOOKUP_DOMAIN,
4095 &connect_handle,
4096 &result);
4097 if (!NT_STATUS_IS_OK(status)) {
4098 errcode = W_ERROR_V(ntstatus_to_werror(status));
4099 goto out;
4101 if (!NT_STATUS_IS_OK(result)) {
4102 errcode = W_ERROR_V(ntstatus_to_werror(result));
4103 goto out;
4106 init_lsa_String(&domain_name, get_global_sam_name());
4108 status = dcerpc_samr_LookupDomain(b, mem_ctx,
4109 &connect_handle,
4110 &domain_name,
4111 &domain_sid,
4112 &result);
4113 if (!NT_STATUS_IS_OK(status)) {
4114 errcode = W_ERROR_V(ntstatus_to_werror(status));
4115 goto out;
4117 if (!NT_STATUS_IS_OK(result)) {
4118 errcode = W_ERROR_V(ntstatus_to_werror(result));
4119 goto out;
4122 status = dcerpc_samr_OpenDomain(b, mem_ctx,
4123 &connect_handle,
4124 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
4125 domain_sid,
4126 &domain_handle,
4127 &result);
4128 if (!NT_STATUS_IS_OK(status)) {
4129 errcode = W_ERROR_V(ntstatus_to_werror(status));
4130 goto out;
4132 if (!NT_STATUS_IS_OK(result)) {
4133 errcode = W_ERROR_V(ntstatus_to_werror(result));
4134 goto out;
4137 init_lsa_String(&names, UserName);
4139 status = dcerpc_samr_LookupNames(b, mem_ctx,
4140 &domain_handle,
4142 &names,
4143 &rids,
4144 &types,
4145 &result);
4146 if (!NT_STATUS_IS_OK(status)) {
4147 errcode = W_ERROR_V(ntstatus_to_werror(status));
4148 goto out;
4150 if (!NT_STATUS_IS_OK(result)) {
4151 errcode = W_ERROR_V(ntstatus_to_werror(result));
4152 goto out;
4155 if (rids.count != 1) {
4156 errcode = W_ERROR_V(WERR_NO_SUCH_USER);
4157 goto out;
4159 if (rids.count != types.count) {
4160 errcode = W_ERROR_V(WERR_INVALID_PARAMETER);
4161 goto out;
4163 if (types.ids[0] != SID_NAME_USER) {
4164 errcode = W_ERROR_V(WERR_INVALID_PARAMETER);
4165 goto out;
4168 rid = rids.ids[0];
4170 status = dcerpc_samr_OpenUser(b, mem_ctx,
4171 &domain_handle,
4172 SAMR_USER_ACCESS_GET_LOCALE |
4173 SAMR_USER_ACCESS_GET_LOGONINFO |
4174 SAMR_USER_ACCESS_GET_ATTRIBUTES |
4175 SAMR_USER_ACCESS_GET_GROUPS |
4176 SAMR_USER_ACCESS_GET_GROUP_MEMBERSHIP |
4177 SEC_STD_READ_CONTROL,
4178 rid,
4179 &user_handle,
4180 &result);
4181 if (!NT_STATUS_IS_OK(status)) {
4182 errcode = W_ERROR_V(ntstatus_to_werror(status));
4183 goto out;
4185 if (!NT_STATUS_IS_OK(result)) {
4186 errcode = W_ERROR_V(ntstatus_to_werror(result));
4187 goto out;
4190 status = dcerpc_samr_QueryUserInfo2(b, mem_ctx,
4191 &user_handle,
4192 UserAllInformation,
4193 &info,
4194 &result);
4195 if (!NT_STATUS_IS_OK(status)) {
4196 errcode = W_ERROR_V(ntstatus_to_werror(status));
4197 goto out;
4199 if (!NT_STATUS_IS_OK(result)) {
4200 errcode = W_ERROR_V(ntstatus_to_werror(result));
4201 goto out;
4204 memset(p,0,21);
4205 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
4207 if (uLevel > 0) {
4208 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
4209 *p2 = 0;
4212 if (uLevel >= 10) {
4213 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
4214 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
4215 p2 = skip_string(*rdata,*rdata_len,p2);
4216 if (!p2) {
4217 return False;
4220 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
4221 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
4222 p2 = skip_string(*rdata,*rdata_len,p2);
4223 if (!p2) {
4224 return False;
4227 /* EEK! the cifsrap.txt doesn't have this in!!!! */
4228 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
4229 strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4230 p2 = skip_string(*rdata,*rdata_len,p2);
4231 if (!p2) {
4232 return False;
4236 if (uLevel == 11) {
4237 const char *homedir = info->info21.home_directory.string;
4238 /* modelled after NTAS 3.51 reply */
4239 SSVAL(p,usri11_priv,
4240 (get_current_uid(conn) == sec_initial_uid())?
4241 USER_PRIV_ADMIN:USER_PRIV_USER);
4242 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
4243 SIVALS(p,usri11_password_age,-1); /* password age */
4244 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
4245 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
4246 p2 = skip_string(*rdata,*rdata_len,p2);
4247 if (!p2) {
4248 return False;
4250 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
4251 strlcpy(p2,"",PTR_DIFF(endp,p2));
4252 p2 = skip_string(*rdata,*rdata_len,p2);
4253 if (!p2) {
4254 return False;
4256 SIVAL(p,usri11_last_logon,0); /* last logon */
4257 SIVAL(p,usri11_last_logoff,0); /* last logoff */
4258 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
4259 SSVALS(p,usri11_num_logons,-1); /* num logons */
4260 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
4261 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
4262 p2 = skip_string(*rdata,*rdata_len,p2);
4263 if (!p2) {
4264 return False;
4266 SSVAL(p,usri11_country_code,0); /* country code */
4268 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
4269 strlcpy(p2,"",PTR_DIFF(endp,p2));
4270 p2 = skip_string(*rdata,*rdata_len,p2);
4271 if (!p2) {
4272 return False;
4275 SIVALS(p,usri11_max_storage,-1); /* max storage */
4276 SSVAL(p,usri11_units_per_week,168); /* units per week */
4277 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
4279 /* a simple way to get logon hours at all times. */
4280 memset(p2,0xff,21);
4281 SCVAL(p2,21,0); /* fix zero termination */
4282 p2 = skip_string(*rdata,*rdata_len,p2);
4283 if (!p2) {
4284 return False;
4287 SSVAL(p,usri11_code_page,0); /* code page */
4290 if (uLevel == 1 || uLevel == 2) {
4291 memset(p+22,' ',16); /* password */
4292 SIVALS(p,38,-1); /* password age */
4293 SSVAL(p,42,
4294 (get_current_uid(conn) == sec_initial_uid())?
4295 USER_PRIV_ADMIN:USER_PRIV_USER);
4296 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
4297 strlcpy(p2, info->info21.home_directory.string,
4298 PTR_DIFF(endp,p2));
4299 p2 = skip_string(*rdata,*rdata_len,p2);
4300 if (!p2) {
4301 return False;
4303 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
4304 *p2++ = 0;
4305 SSVAL(p,52,0); /* flags */
4306 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
4307 strlcpy(p2, info->info21.logon_script.string,
4308 PTR_DIFF(endp,p2));
4309 p2 = skip_string(*rdata,*rdata_len,p2);
4310 if (!p2) {
4311 return False;
4313 if (uLevel == 2) {
4314 SIVAL(p,58,0); /* auth_flags */
4315 SIVAL(p,62,PTR_DIFF(p2,*rdata)); /* full_name */
4316 strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4317 p2 = skip_string(*rdata,*rdata_len,p2);
4318 if (!p2) {
4319 return False;
4321 SIVAL(p,66,0); /* urs_comment */
4322 SIVAL(p,70,PTR_DIFF(p2,*rdata)); /* parms */
4323 strlcpy(p2,"",PTR_DIFF(endp,p2));
4324 p2 = skip_string(*rdata,*rdata_len,p2);
4325 if (!p2) {
4326 return False;
4328 SIVAL(p,74,0); /* workstations */
4329 SIVAL(p,78,0); /* last_logon */
4330 SIVAL(p,82,0); /* last_logoff */
4331 SIVALS(p,86,-1); /* acct_expires */
4332 SIVALS(p,90,-1); /* max_storage */
4333 SSVAL(p,94,168); /* units_per_week */
4334 SIVAL(p,96,PTR_DIFF(p2,*rdata)); /* logon_hours */
4335 memset(p2,-1,21);
4336 p2 += 21;
4337 SSVALS(p,100,-1); /* bad_pw_count */
4338 SSVALS(p,102,-1); /* num_logons */
4339 SIVAL(p,104,PTR_DIFF(p2,*rdata)); /* logon_server */
4341 TALLOC_CTX *ctx = talloc_tos();
4342 int space_rem = *rdata_len - (p2 - *rdata);
4343 char *tmp;
4345 if (space_rem <= 0) {
4346 return false;
4348 tmp = talloc_strdup(ctx, "\\\\%L");
4349 if (!tmp) {
4350 return false;
4352 tmp = talloc_sub_basic(ctx,
4355 tmp);
4356 if (!tmp) {
4357 return false;
4360 push_ascii(p2,
4361 tmp,
4362 space_rem,
4363 STR_TERMINATE);
4365 p2 = skip_string(*rdata,*rdata_len,p2);
4366 if (!p2) {
4367 return False;
4369 SSVAL(p,108,49); /* country_code */
4370 SSVAL(p,110,860); /* code page */
4374 errcode = NERR_Success;
4376 out:
4377 *rdata_len = PTR_DIFF(p2,*rdata);
4379 if (b && is_valid_policy_hnd(&user_handle)) {
4380 dcerpc_samr_Close(b, mem_ctx, &user_handle, &result);
4382 if (b && is_valid_policy_hnd(&domain_handle)) {
4383 dcerpc_samr_Close(b, mem_ctx, &domain_handle, &result);
4385 if (b && is_valid_policy_hnd(&connect_handle)) {
4386 dcerpc_samr_Close(b, mem_ctx, &connect_handle, &result);
4389 SSVAL(*rparam,0,errcode);
4390 SSVAL(*rparam,2,0); /* converter word */
4391 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
4393 return(True);
4396 static bool api_WWkstaUserLogon(struct smbd_server_connection *sconn,
4397 connection_struct *conn,uint64_t vuid,
4398 char *param, int tpscnt,
4399 char *data, int tdscnt,
4400 int mdrcnt,int mprcnt,
4401 char **rdata,char **rparam,
4402 int *rdata_len,int *rparam_len)
4404 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4405 char *str2 = skip_string(param,tpscnt,str1);
4406 char *p = skip_string(param,tpscnt,str2);
4407 int uLevel;
4408 struct pack_desc desc;
4409 char* name;
4410 /* With share level security vuid will always be zero.
4411 Don't depend on vuser being non-null !!. JRA */
4412 struct user_struct *vuser = get_valid_user_struct(sconn, vuid);
4414 if (!str1 || !str2 || !p) {
4415 return False;
4418 if(vuser != NULL) {
4419 DEBUG(3,(" Username of UID %d is %s\n",
4420 (int)vuser->session_info->unix_token->uid,
4421 vuser->session_info->unix_info->unix_name));
4424 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4425 name = get_safe_str_ptr(param,tpscnt,p,2);
4426 if (!name) {
4427 return False;
4430 memset((char *)&desc,'\0',sizeof(desc));
4432 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
4434 /* check it's a supported varient */
4435 if (strcmp(str1,"OOWb54WrLh") != 0) {
4436 return False;
4438 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
4439 return False;
4441 if (mdrcnt > 0) {
4442 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4443 if (!*rdata) {
4444 return False;
4448 desc.base = *rdata;
4449 desc.buflen = mdrcnt;
4450 desc.subformat = NULL;
4451 desc.format = str2;
4453 if (init_package(&desc,1,0)) {
4454 PACKI(&desc,"W",0); /* code */
4455 PACKS(&desc,"B21",name); /* eff. name */
4456 PACKS(&desc,"B",""); /* pad */
4457 PACKI(&desc,"W",
4458 (get_current_uid(conn) == sec_initial_uid())?
4459 USER_PRIV_ADMIN:USER_PRIV_USER);
4460 PACKI(&desc,"D",0); /* auth flags XXX */
4461 PACKI(&desc,"W",0); /* num logons */
4462 PACKI(&desc,"W",0); /* bad pw count */
4463 PACKI(&desc,"D",0); /* last logon */
4464 PACKI(&desc,"D",-1); /* last logoff */
4465 PACKI(&desc,"D",-1); /* logoff time */
4466 PACKI(&desc,"D",-1); /* kickoff time */
4467 PACKI(&desc,"D",0); /* password age */
4468 PACKI(&desc,"D",0); /* password can change */
4469 PACKI(&desc,"D",-1); /* password must change */
4472 fstring mypath;
4473 fstrcpy(mypath,"\\\\");
4474 fstrcat(mypath,get_local_machine_name());
4475 if (!strupper_m(mypath)) {
4476 return false;
4478 PACKS(&desc,"z",mypath); /* computer */
4481 PACKS(&desc,"z",lp_workgroup());/* domain */
4482 PACKS(&desc,"z", vuser ?
4483 vuser->session_info->info->logon_script
4484 : ""); /* script path */
4485 PACKI(&desc,"D",0x00000000); /* reserved */
4488 *rdata_len = desc.usedlen;
4489 *rparam_len = 6;
4490 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4491 if (!*rparam) {
4492 return False;
4494 SSVALS(*rparam,0,desc.errcode);
4495 SSVAL(*rparam,2,0);
4496 SSVAL(*rparam,4,desc.neededlen);
4498 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4500 return True;
4503 /****************************************************************************
4504 api_WAccessGetUserPerms
4505 ****************************************************************************/
4507 static bool api_WAccessGetUserPerms(struct smbd_server_connection *sconn,
4508 connection_struct *conn,uint64_t vuid,
4509 char *param, int tpscnt,
4510 char *data, int tdscnt,
4511 int mdrcnt,int mprcnt,
4512 char **rdata,char **rparam,
4513 int *rdata_len,int *rparam_len)
4515 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4516 char *str2 = skip_string(param,tpscnt,str1);
4517 char *user = skip_string(param,tpscnt,str2);
4518 char *resource = skip_string(param,tpscnt,user);
4520 if (!str1 || !str2 || !user || !resource) {
4521 return False;
4524 if (skip_string(param,tpscnt,resource) == NULL) {
4525 return False;
4527 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4529 /* check it's a supported varient */
4530 if (strcmp(str1,"zzh") != 0) {
4531 return False;
4533 if (strcmp(str2,"") != 0) {
4534 return False;
4537 *rparam_len = 6;
4538 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4539 if (!*rparam) {
4540 return False;
4542 SSVALS(*rparam,0,0); /* errorcode */
4543 SSVAL(*rparam,2,0); /* converter word */
4544 SSVAL(*rparam,4,0x7f); /* permission flags */
4546 return True;
4549 /****************************************************************************
4550 api_WPrintJobEnumerate
4551 ****************************************************************************/
4553 static bool api_WPrintJobGetInfo(struct smbd_server_connection *sconn,
4554 connection_struct *conn, uint64_t vuid,
4555 char *param, int tpscnt,
4556 char *data, int tdscnt,
4557 int mdrcnt,int mprcnt,
4558 char **rdata,char **rparam,
4559 int *rdata_len,int *rparam_len)
4561 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4562 char *str2 = skip_string(param,tpscnt,str1);
4563 char *p = skip_string(param,tpscnt,str2);
4564 int uLevel;
4565 fstring sharename;
4566 uint32_t jobid;
4567 struct pack_desc desc;
4568 char *tmpdata=NULL;
4570 TALLOC_CTX *mem_ctx = talloc_tos();
4571 WERROR werr;
4572 NTSTATUS status;
4573 struct rpc_pipe_client *cli = NULL;
4574 struct dcerpc_binding_handle *b = NULL;
4575 struct policy_handle handle;
4576 struct spoolss_DevmodeContainer devmode_ctr;
4577 union spoolss_JobInfo info;
4579 if (!str1 || !str2 || !p) {
4580 return False;
4583 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4585 memset((char *)&desc,'\0',sizeof(desc));
4586 memset((char *)&status,'\0',sizeof(status));
4588 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4590 /* check it's a supported varient */
4591 if (strcmp(str1,"WWrLh") != 0) {
4592 return False;
4594 if (!check_printjob_info(&desc,uLevel,str2)) {
4595 return False;
4598 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4599 return False;
4602 ZERO_STRUCT(handle);
4604 status = rpc_pipe_open_interface(conn,
4605 &ndr_table_spoolss,
4606 conn->session_info,
4607 conn->sconn->remote_address,
4608 conn->sconn->local_address,
4609 conn->sconn->msg_ctx,
4610 &cli);
4611 if (!NT_STATUS_IS_OK(status)) {
4612 DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n",
4613 nt_errstr(status)));
4614 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4615 goto out;
4617 b = cli->binding_handle;
4619 ZERO_STRUCT(devmode_ctr);
4621 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
4622 sharename,
4623 "RAW",
4624 devmode_ctr,
4625 PRINTER_ACCESS_USE,
4626 &handle,
4627 &werr);
4628 if (!NT_STATUS_IS_OK(status)) {
4629 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4630 goto out;
4632 if (!W_ERROR_IS_OK(werr)) {
4633 desc.errcode = W_ERROR_V(werr);
4634 goto out;
4637 werr = rpccli_spoolss_getjob(cli, mem_ctx,
4638 &handle,
4639 jobid,
4640 2, /* level */
4641 0, /* offered */
4642 &info);
4643 if (!W_ERROR_IS_OK(werr)) {
4644 desc.errcode = W_ERROR_V(werr);
4645 goto out;
4648 if (mdrcnt > 0) {
4649 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4650 if (!*rdata) {
4651 return False;
4653 desc.base = *rdata;
4654 desc.buflen = mdrcnt;
4655 } else {
4657 * Don't return data but need to get correct length
4658 * init_package will return wrong size if buflen=0
4660 desc.buflen = getlen(desc.format);
4661 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4664 if (init_package(&desc,1,0)) {
4665 fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position);
4666 *rdata_len = desc.usedlen;
4667 } else {
4668 desc.errcode = NERR_JobNotFound;
4669 *rdata_len = 0;
4671 out:
4672 if (b && is_valid_policy_hnd(&handle)) {
4673 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
4676 *rparam_len = 6;
4677 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4678 if (!*rparam) {
4679 return False;
4681 SSVALS(*rparam,0,desc.errcode);
4682 SSVAL(*rparam,2,0);
4683 SSVAL(*rparam,4,desc.neededlen);
4685 SAFE_FREE(tmpdata);
4687 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4689 return True;
4692 static bool api_WPrintJobEnumerate(struct smbd_server_connection *sconn,
4693 connection_struct *conn, uint64_t vuid,
4694 char *param, int tpscnt,
4695 char *data, int tdscnt,
4696 int mdrcnt,int mprcnt,
4697 char **rdata,char **rparam,
4698 int *rdata_len,int *rparam_len)
4700 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4701 char *str2 = skip_string(param,tpscnt,str1);
4702 char *p = skip_string(param,tpscnt,str2);
4703 char *name = p;
4704 int uLevel;
4705 int i, succnt=0;
4706 struct pack_desc desc;
4708 TALLOC_CTX *mem_ctx = talloc_tos();
4709 WERROR werr;
4710 NTSTATUS status;
4711 struct rpc_pipe_client *cli = NULL;
4712 struct dcerpc_binding_handle *b = NULL;
4713 struct policy_handle handle;
4714 struct spoolss_DevmodeContainer devmode_ctr;
4715 uint32_t count = 0;
4716 union spoolss_JobInfo *info;
4718 if (!str1 || !str2 || !p) {
4719 return False;
4722 memset((char *)&desc,'\0',sizeof(desc));
4724 p = skip_string(param,tpscnt,p);
4725 if (!p) {
4726 return False;
4728 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4730 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4732 /* check it's a supported variant */
4733 if (strcmp(str1,"zWrLeh") != 0) {
4734 return False;
4737 if (uLevel > 2) {
4738 return False; /* defined only for uLevel 0,1,2 */
4741 if (!check_printjob_info(&desc,uLevel,str2)) {
4742 return False;
4745 ZERO_STRUCT(handle);
4747 status = rpc_pipe_open_interface(conn,
4748 &ndr_table_spoolss,
4749 conn->session_info,
4750 conn->sconn->remote_address,
4751 conn->sconn->local_address,
4752 conn->sconn->msg_ctx,
4753 &cli);
4754 if (!NT_STATUS_IS_OK(status)) {
4755 DEBUG(0,("api_WPrintJobEnumerate: could not connect to spoolss: %s\n",
4756 nt_errstr(status)));
4757 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4758 goto out;
4760 b = cli->binding_handle;
4762 ZERO_STRUCT(devmode_ctr);
4764 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
4765 name,
4766 NULL,
4767 devmode_ctr,
4768 PRINTER_ACCESS_USE,
4769 &handle,
4770 &werr);
4771 if (!NT_STATUS_IS_OK(status)) {
4772 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4773 goto out;
4775 if (!W_ERROR_IS_OK(werr)) {
4776 desc.errcode = W_ERROR_V(werr);
4777 goto out;
4780 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
4781 &handle,
4782 0, /* firstjob */
4783 0xff, /* numjobs */
4784 2, /* level */
4785 0, /* offered */
4786 &count,
4787 &info);
4788 if (!W_ERROR_IS_OK(werr)) {
4789 desc.errcode = W_ERROR_V(werr);
4790 goto out;
4793 if (mdrcnt > 0) {
4794 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4795 if (!*rdata) {
4796 return False;
4799 desc.base = *rdata;
4800 desc.buflen = mdrcnt;
4802 if (init_package(&desc,count,0)) {
4803 succnt = 0;
4804 for (i = 0; i < count; i++) {
4805 fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i);
4806 if (desc.errcode == NERR_Success) {
4807 succnt = i+1;
4811 out:
4812 if (b && is_valid_policy_hnd(&handle)) {
4813 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
4816 *rdata_len = desc.usedlen;
4818 *rparam_len = 8;
4819 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4820 if (!*rparam) {
4821 return False;
4823 SSVALS(*rparam,0,desc.errcode);
4824 SSVAL(*rparam,2,0);
4825 SSVAL(*rparam,4,succnt);
4826 SSVAL(*rparam,6,count);
4828 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4830 return True;
4833 static int check_printdest_info(struct pack_desc* desc,
4834 int uLevel, char* id)
4836 desc->subformat = NULL;
4837 switch( uLevel ) {
4838 case 0:
4839 desc->format = "B9";
4840 break;
4841 case 1:
4842 desc->format = "B9B21WWzW";
4843 break;
4844 case 2:
4845 desc->format = "z";
4846 break;
4847 case 3:
4848 desc->format = "zzzWWzzzWW";
4849 break;
4850 default:
4851 DEBUG(0,("check_printdest_info: invalid level %d\n",
4852 uLevel));
4853 return False;
4855 if (id == NULL || strcmp(desc->format,id) != 0) {
4856 DEBUG(0,("check_printdest_info: invalid string %s\n",
4857 id ? id : "<NULL>" ));
4858 return False;
4860 return True;
4863 static void fill_printdest_info(struct spoolss_PrinterInfo2 *info2, int uLevel,
4864 struct pack_desc* desc)
4866 char buf[100];
4868 strncpy(buf, info2->printername, sizeof(buf)-1);
4869 buf[sizeof(buf)-1] = 0;
4870 (void)strupper_m(buf);
4872 if (uLevel <= 1) {
4873 PACKS(desc,"B9",buf); /* szName */
4874 if (uLevel == 1) {
4875 PACKS(desc,"B21",""); /* szUserName */
4876 PACKI(desc,"W",0); /* uJobId */
4877 PACKI(desc,"W",0); /* fsStatus */
4878 PACKS(desc,"z",""); /* pszStatus */
4879 PACKI(desc,"W",0); /* time */
4883 if (uLevel == 2 || uLevel == 3) {
4884 PACKS(desc,"z",buf); /* pszPrinterName */
4885 if (uLevel == 3) {
4886 PACKS(desc,"z",""); /* pszUserName */
4887 PACKS(desc,"z",""); /* pszLogAddr */
4888 PACKI(desc,"W",0); /* uJobId */
4889 PACKI(desc,"W",0); /* fsStatus */
4890 PACKS(desc,"z",""); /* pszStatus */
4891 PACKS(desc,"z",""); /* pszComment */
4892 PACKS(desc,"z","NULL"); /* pszDrivers */
4893 PACKI(desc,"W",0); /* time */
4894 PACKI(desc,"W",0); /* pad1 */
4899 static bool api_WPrintDestGetInfo(struct smbd_server_connection *sconn,
4900 connection_struct *conn, uint64_t vuid,
4901 char *param, int tpscnt,
4902 char *data, int tdscnt,
4903 int mdrcnt,int mprcnt,
4904 char **rdata,char **rparam,
4905 int *rdata_len,int *rparam_len)
4907 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4908 char *str2 = skip_string(param,tpscnt,str1);
4909 char *p = skip_string(param,tpscnt,str2);
4910 char* PrinterName = p;
4911 int uLevel;
4912 struct pack_desc desc;
4913 char *tmpdata=NULL;
4915 TALLOC_CTX *mem_ctx = talloc_tos();
4916 WERROR werr;
4917 NTSTATUS status;
4918 struct rpc_pipe_client *cli = NULL;
4919 struct dcerpc_binding_handle *b = NULL;
4920 struct policy_handle handle;
4921 struct spoolss_DevmodeContainer devmode_ctr;
4922 union spoolss_PrinterInfo info;
4924 if (!str1 || !str2 || !p) {
4925 return False;
4928 memset((char *)&desc,'\0',sizeof(desc));
4930 p = skip_string(param,tpscnt,p);
4931 if (!p) {
4932 return False;
4934 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4936 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4938 /* check it's a supported varient */
4939 if (strcmp(str1,"zWrLh") != 0) {
4940 return False;
4942 if (!check_printdest_info(&desc,uLevel,str2)) {
4943 return False;
4946 ZERO_STRUCT(handle);
4948 status = rpc_pipe_open_interface(conn,
4949 &ndr_table_spoolss,
4950 conn->session_info,
4951 conn->sconn->remote_address,
4952 conn->sconn->local_address,
4953 conn->sconn->msg_ctx,
4954 &cli);
4955 if (!NT_STATUS_IS_OK(status)) {
4956 DEBUG(0,("api_WPrintDestGetInfo: could not connect to spoolss: %s\n",
4957 nt_errstr(status)));
4958 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4959 goto out;
4961 b = cli->binding_handle;
4963 ZERO_STRUCT(devmode_ctr);
4965 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
4966 PrinterName,
4967 NULL,
4968 devmode_ctr,
4969 PRINTER_ACCESS_USE,
4970 &handle,
4971 &werr);
4972 if (!NT_STATUS_IS_OK(status)) {
4973 *rdata_len = 0;
4974 desc.errcode = NERR_DestNotFound;
4975 desc.neededlen = 0;
4976 goto out;
4978 if (!W_ERROR_IS_OK(werr)) {
4979 *rdata_len = 0;
4980 desc.errcode = NERR_DestNotFound;
4981 desc.neededlen = 0;
4982 goto out;
4985 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
4986 &handle,
4989 &info);
4990 if (!W_ERROR_IS_OK(werr)) {
4991 *rdata_len = 0;
4992 desc.errcode = NERR_DestNotFound;
4993 desc.neededlen = 0;
4994 goto out;
4997 if (mdrcnt > 0) {
4998 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4999 if (!*rdata) {
5000 return False;
5002 desc.base = *rdata;
5003 desc.buflen = mdrcnt;
5004 } else {
5006 * Don't return data but need to get correct length
5007 * init_package will return wrong size if buflen=0
5009 desc.buflen = getlen(desc.format);
5010 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
5012 if (init_package(&desc,1,0)) {
5013 fill_printdest_info(&info.info2, uLevel,&desc);
5016 out:
5017 if (b && is_valid_policy_hnd(&handle)) {
5018 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr);
5021 *rdata_len = desc.usedlen;
5023 *rparam_len = 6;
5024 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5025 if (!*rparam) {
5026 return False;
5028 SSVALS(*rparam,0,desc.errcode);
5029 SSVAL(*rparam,2,0);
5030 SSVAL(*rparam,4,desc.neededlen);
5032 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
5033 SAFE_FREE(tmpdata);
5035 return True;
5038 static bool api_WPrintDestEnum(struct smbd_server_connection *sconn,
5039 connection_struct *conn, uint64_t vuid,
5040 char *param, int tpscnt,
5041 char *data, int tdscnt,
5042 int mdrcnt,int mprcnt,
5043 char **rdata,char **rparam,
5044 int *rdata_len,int *rparam_len)
5046 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5047 char *str2 = skip_string(param,tpscnt,str1);
5048 char *p = skip_string(param,tpscnt,str2);
5049 int uLevel;
5050 int queuecnt;
5051 int i, n, succnt=0;
5052 struct pack_desc desc;
5054 TALLOC_CTX *mem_ctx = talloc_tos();
5055 WERROR werr;
5056 NTSTATUS status;
5057 struct rpc_pipe_client *cli = NULL;
5058 union spoolss_PrinterInfo *info;
5059 uint32_t count;
5061 if (!str1 || !str2 || !p) {
5062 return False;
5065 memset((char *)&desc,'\0',sizeof(desc));
5067 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5069 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
5071 /* check it's a supported varient */
5072 if (strcmp(str1,"WrLeh") != 0) {
5073 return False;
5075 if (!check_printdest_info(&desc,uLevel,str2)) {
5076 return False;
5079 queuecnt = 0;
5081 status = rpc_pipe_open_interface(conn,
5082 &ndr_table_spoolss,
5083 conn->session_info,
5084 conn->sconn->remote_address,
5085 conn->sconn->local_address,
5086 conn->sconn->msg_ctx,
5087 &cli);
5088 if (!NT_STATUS_IS_OK(status)) {
5089 DEBUG(0,("api_WPrintDestEnum: could not connect to spoolss: %s\n",
5090 nt_errstr(status)));
5091 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5092 goto out;
5095 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
5096 PRINTER_ENUM_LOCAL,
5097 cli->srv_name_slash,
5100 &count,
5101 &info);
5102 if (!W_ERROR_IS_OK(werr)) {
5103 desc.errcode = W_ERROR_V(werr);
5104 *rdata_len = 0;
5105 desc.errcode = NERR_DestNotFound;
5106 desc.neededlen = 0;
5107 goto out;
5110 queuecnt = count;
5112 if (mdrcnt > 0) {
5113 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5114 if (!*rdata) {
5115 return False;
5119 desc.base = *rdata;
5120 desc.buflen = mdrcnt;
5121 if (init_package(&desc,queuecnt,0)) {
5122 succnt = 0;
5123 n = 0;
5124 for (i = 0; i < count; i++) {
5125 fill_printdest_info(&info[i].info2, uLevel,&desc);
5126 n++;
5127 if (desc.errcode == NERR_Success) {
5128 succnt = n;
5132 out:
5133 *rdata_len = desc.usedlen;
5135 *rparam_len = 8;
5136 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5137 if (!*rparam) {
5138 return False;
5140 SSVALS(*rparam,0,desc.errcode);
5141 SSVAL(*rparam,2,0);
5142 SSVAL(*rparam,4,succnt);
5143 SSVAL(*rparam,6,queuecnt);
5145 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
5147 return True;
5150 static bool api_WPrintDriverEnum(struct smbd_server_connection *sconn,
5151 connection_struct *conn, uint64_t vuid,
5152 char *param, int tpscnt,
5153 char *data, int tdscnt,
5154 int mdrcnt,int mprcnt,
5155 char **rdata,char **rparam,
5156 int *rdata_len,int *rparam_len)
5158 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5159 char *str2 = skip_string(param,tpscnt,str1);
5160 char *p = skip_string(param,tpscnt,str2);
5161 int uLevel;
5162 int succnt;
5163 struct pack_desc desc;
5165 if (!str1 || !str2 || !p) {
5166 return False;
5169 memset((char *)&desc,'\0',sizeof(desc));
5171 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5173 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
5175 /* check it's a supported varient */
5176 if (strcmp(str1,"WrLeh") != 0) {
5177 return False;
5179 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
5180 return False;
5183 if (mdrcnt > 0) {
5184 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5185 if (!*rdata) {
5186 return False;
5189 desc.base = *rdata;
5190 desc.buflen = mdrcnt;
5191 if (init_package(&desc,1,0)) {
5192 PACKS(&desc,"B41","NULL");
5195 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5197 *rdata_len = desc.usedlen;
5199 *rparam_len = 8;
5200 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5201 if (!*rparam) {
5202 return False;
5204 SSVALS(*rparam,0,desc.errcode);
5205 SSVAL(*rparam,2,0);
5206 SSVAL(*rparam,4,succnt);
5207 SSVAL(*rparam,6,1);
5209 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
5211 return True;
5214 static bool api_WPrintQProcEnum(struct smbd_server_connection *sconn,
5215 connection_struct *conn, uint64_t vuid,
5216 char *param, int tpscnt,
5217 char *data, int tdscnt,
5218 int mdrcnt,int mprcnt,
5219 char **rdata,char **rparam,
5220 int *rdata_len,int *rparam_len)
5222 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5223 char *str2 = skip_string(param,tpscnt,str1);
5224 char *p = skip_string(param,tpscnt,str2);
5225 int uLevel;
5226 int succnt;
5227 struct pack_desc desc;
5229 if (!str1 || !str2 || !p) {
5230 return False;
5232 memset((char *)&desc,'\0',sizeof(desc));
5234 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5236 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
5238 /* check it's a supported varient */
5239 if (strcmp(str1,"WrLeh") != 0) {
5240 return False;
5242 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
5243 return False;
5246 if (mdrcnt > 0) {
5247 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5248 if (!*rdata) {
5249 return False;
5252 desc.base = *rdata;
5253 desc.buflen = mdrcnt;
5254 desc.format = str2;
5255 if (init_package(&desc,1,0)) {
5256 PACKS(&desc,"B13","lpd");
5259 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5261 *rdata_len = desc.usedlen;
5263 *rparam_len = 8;
5264 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5265 if (!*rparam) {
5266 return False;
5268 SSVALS(*rparam,0,desc.errcode);
5269 SSVAL(*rparam,2,0);
5270 SSVAL(*rparam,4,succnt);
5271 SSVAL(*rparam,6,1);
5273 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
5275 return True;
5278 static bool api_WPrintPortEnum(struct smbd_server_connection *sconn,
5279 connection_struct *conn, uint64_t vuid,
5280 char *param, int tpscnt,
5281 char *data, int tdscnt,
5282 int mdrcnt,int mprcnt,
5283 char **rdata,char **rparam,
5284 int *rdata_len,int *rparam_len)
5286 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5287 char *str2 = skip_string(param,tpscnt,str1);
5288 char *p = skip_string(param,tpscnt,str2);
5289 int uLevel;
5290 int succnt;
5291 struct pack_desc desc;
5293 if (!str1 || !str2 || !p) {
5294 return False;
5297 memset((char *)&desc,'\0',sizeof(desc));
5299 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5301 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
5303 /* check it's a supported varient */
5304 if (strcmp(str1,"WrLeh") != 0) {
5305 return False;
5307 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
5308 return False;
5311 if (mdrcnt > 0) {
5312 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5313 if (!*rdata) {
5314 return False;
5317 memset((char *)&desc,'\0',sizeof(desc));
5318 desc.base = *rdata;
5319 desc.buflen = mdrcnt;
5320 desc.format = str2;
5321 if (init_package(&desc,1,0)) {
5322 PACKS(&desc,"B13","lp0");
5325 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5327 *rdata_len = desc.usedlen;
5329 *rparam_len = 8;
5330 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5331 if (!*rparam) {
5332 return False;
5334 SSVALS(*rparam,0,desc.errcode);
5335 SSVAL(*rparam,2,0);
5336 SSVAL(*rparam,4,succnt);
5337 SSVAL(*rparam,6,1);
5339 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
5341 return True;
5344 /****************************************************************************
5345 List open sessions
5346 ****************************************************************************/
5348 static bool api_RNetSessionEnum(struct smbd_server_connection *sconn,
5349 connection_struct *conn, uint64_t vuid,
5350 char *param, int tpscnt,
5351 char *data, int tdscnt,
5352 int mdrcnt,int mprcnt,
5353 char **rdata,char **rparam,
5354 int *rdata_len,int *rparam_len)
5357 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5358 char *str2 = skip_string(param,tpscnt,str1);
5359 char *p = skip_string(param,tpscnt,str2);
5360 int uLevel;
5361 struct pack_desc desc;
5362 int i;
5364 TALLOC_CTX *mem_ctx = talloc_tos();
5365 WERROR werr;
5366 NTSTATUS status;
5367 struct rpc_pipe_client *cli = NULL;
5368 struct dcerpc_binding_handle *b = NULL;
5369 struct srvsvc_NetSessInfoCtr info_ctr;
5370 uint32_t totalentries, resume_handle = 0;
5371 uint32_t count = 0;
5373 if (!str1 || !str2 || !p) {
5374 return False;
5377 ZERO_STRUCT(desc);
5379 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5381 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
5382 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
5383 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
5385 /* check it's a supported varient */
5386 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
5387 return False;
5389 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
5390 return False;
5393 status = rpc_pipe_open_interface(conn,
5394 &ndr_table_srvsvc,
5395 conn->session_info,
5396 conn->sconn->remote_address,
5397 conn->sconn->local_address,
5398 conn->sconn->msg_ctx,
5399 &cli);
5400 if (!NT_STATUS_IS_OK(status)) {
5401 DEBUG(0,("RNetSessionEnum: could not connect to srvsvc: %s\n",
5402 nt_errstr(status)));
5403 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5404 goto out;
5406 b = cli->binding_handle;
5408 info_ctr.level = 1;
5409 info_ctr.ctr.ctr1 = talloc_zero(talloc_tos(), struct srvsvc_NetSessCtr1);
5410 if (info_ctr.ctr.ctr1 == NULL) {
5411 desc.errcode = W_ERROR_V(WERR_NOT_ENOUGH_MEMORY);
5412 goto out;
5415 status = dcerpc_srvsvc_NetSessEnum(b, mem_ctx,
5416 cli->srv_name_slash,
5417 NULL, /* client */
5418 NULL, /* user */
5419 &info_ctr,
5420 (uint32_t)-1, /* max_buffer */
5421 &totalentries,
5422 &resume_handle,
5423 &werr);
5424 if (!NT_STATUS_IS_OK(status)) {
5425 DEBUG(0,("RNetSessionEnum: dcerpc_srvsvc_NetSessEnum failed: %s\n",
5426 nt_errstr(status)));
5427 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5428 goto out;
5431 if (!W_ERROR_IS_OK(werr)) {
5432 DEBUG(0,("RNetSessionEnum: dcerpc_srvsvc_NetSessEnum failed: %s\n",
5433 win_errstr(werr)));
5434 desc.errcode = W_ERROR_V(werr);
5435 goto out;
5438 count = info_ctr.ctr.ctr1->count;
5440 out:
5441 if (mdrcnt > 0) {
5442 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5443 if (!*rdata) {
5444 return False;
5448 desc.base = *rdata;
5449 desc.buflen = mdrcnt;
5450 desc.format = str2;
5451 if (!init_package(&desc, count,0)) {
5452 return False;
5455 for(i=0; i < count; i++) {
5456 PACKS(&desc, "z", info_ctr.ctr.ctr1->array[i].client);
5457 PACKS(&desc, "z", info_ctr.ctr.ctr1->array[i].user);
5458 PACKI(&desc, "W", 1); /* num conns */
5459 PACKI(&desc, "W", info_ctr.ctr.ctr1->array[i].num_open);
5460 PACKI(&desc, "W", 1); /* num users */
5461 PACKI(&desc, "D", 0); /* session time */
5462 PACKI(&desc, "D", 0); /* idle time */
5463 PACKI(&desc, "D", 0); /* flags */
5464 PACKS(&desc, "z", "Unknown Client"); /* client type string */
5467 *rdata_len = desc.usedlen;
5469 *rparam_len = 8;
5470 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5471 if (!*rparam) {
5472 return False;
5474 SSVALS(*rparam,0,desc.errcode);
5475 SSVAL(*rparam,2,0); /* converter */
5476 SSVAL(*rparam,4, count); /* count */
5478 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
5480 return True;
5484 /****************************************************************************
5485 The buffer was too small.
5486 ****************************************************************************/
5488 static bool api_TooSmall(struct smbd_server_connection *sconn,
5489 connection_struct *conn,uint64_t vuid, char *param, char *data,
5490 int mdrcnt, int mprcnt,
5491 char **rdata, char **rparam,
5492 int *rdata_len, int *rparam_len)
5494 *rparam_len = MIN(*rparam_len,mprcnt);
5495 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5496 if (!*rparam) {
5497 return False;
5500 *rdata_len = 0;
5502 SSVAL(*rparam,0,NERR_BufTooSmall);
5504 DEBUG(3,("Supplied buffer too small in API command\n"));
5506 return True;
5509 /****************************************************************************
5510 The request is not supported.
5511 ****************************************************************************/
5513 static bool api_Unsupported(struct smbd_server_connection *sconn,
5514 connection_struct *conn, uint64_t vuid,
5515 char *param, int tpscnt,
5516 char *data, int tdscnt,
5517 int mdrcnt, int mprcnt,
5518 char **rdata, char **rparam,
5519 int *rdata_len, int *rparam_len)
5521 *rparam_len = 4;
5522 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5523 if (!*rparam) {
5524 return False;
5527 *rdata_len = 0;
5529 SSVAL(*rparam,0,NERR_notsupported);
5530 SSVAL(*rparam,2,0); /* converter word */
5532 DEBUG(3,("Unsupported API command\n"));
5534 return True;
5537 static const struct {
5538 const char *name;
5539 int id;
5540 bool (*fn)(struct smbd_server_connection *sconn,
5541 connection_struct *, uint64_t,
5542 char *, int,
5543 char *, int,
5544 int,int,char **,char **,int *,int *);
5545 bool auth_user; /* Deny anonymous access? */
5546 } api_commands[] = {
5547 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
5548 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
5549 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
5550 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
5551 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
5552 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
5553 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
5554 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
5555 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
5556 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
5557 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
5558 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
5559 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
5560 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
5561 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
5562 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
5563 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
5564 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
5565 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
5566 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
5567 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
5568 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
5569 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
5570 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
5571 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
5572 {"NetServerEnum3", RAP_NetServerEnum3, api_RNetServerEnum3}, /* anon OK */
5573 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
5574 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
5575 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
5576 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
5577 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
5578 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
5579 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
5580 {NULL, -1, api_Unsupported}
5581 /* The following RAP calls are not implemented by Samba:
5583 RAP_WFileEnum2 - anon not OK
5588 /****************************************************************************
5589 Handle remote api calls.
5590 ****************************************************************************/
5592 void api_reply(connection_struct *conn, uint64_t vuid,
5593 struct smb_request *req,
5594 char *data, char *params,
5595 int tdscnt, int tpscnt,
5596 int mdrcnt, int mprcnt)
5598 int api_command;
5599 char *rdata = NULL;
5600 char *rparam = NULL;
5601 const char *name1 = NULL;
5602 const char *name2 = NULL;
5603 int rdata_len = 0;
5604 int rparam_len = 0;
5605 bool reply=False;
5606 int i;
5608 if (!params) {
5609 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
5610 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5611 return;
5614 if (tpscnt < 2) {
5615 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5616 return;
5618 api_command = SVAL(params,0);
5619 /* Is there a string at position params+2 ? */
5620 if (skip_string(params,tpscnt,params+2)) {
5621 name1 = params + 2;
5622 } else {
5623 name1 = "";
5625 name2 = skip_string(params,tpscnt,params+2);
5626 if (!name2) {
5627 name2 = "";
5630 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
5631 api_command,
5632 name1,
5633 name2,
5634 tdscnt,tpscnt,mdrcnt,mprcnt));
5636 for (i=0;api_commands[i].name;i++) {
5637 if (api_commands[i].id == api_command && api_commands[i].fn) {
5638 DEBUG(3,("Doing %s\n",api_commands[i].name));
5639 break;
5643 /* Check whether this api call can be done anonymously */
5645 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
5646 struct user_struct *user = get_valid_user_struct(req->sconn, vuid);
5648 if (!user || security_session_user_level(user->session_info, NULL) < SECURITY_USER) {
5649 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5650 return;
5654 rdata = (char *)SMB_MALLOC(1024);
5655 if (rdata) {
5656 memset(rdata,'\0',1024);
5659 rparam = (char *)SMB_MALLOC(1024);
5660 if (rparam) {
5661 memset(rparam,'\0',1024);
5664 if(!rdata || !rparam) {
5665 DEBUG(0,("api_reply: malloc fail !\n"));
5666 SAFE_FREE(rdata);
5667 SAFE_FREE(rparam);
5668 reply_nterror(req, NT_STATUS_NO_MEMORY);
5669 return;
5672 reply = api_commands[i].fn(req->sconn, conn,
5673 vuid,
5674 params,tpscnt, /* params + length */
5675 data,tdscnt, /* data + length */
5676 mdrcnt,mprcnt,
5677 &rdata,&rparam,&rdata_len,&rparam_len);
5680 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
5681 reply = api_TooSmall(req->sconn,conn,vuid,params,data,
5682 mdrcnt,mprcnt,
5683 &rdata,&rparam,&rdata_len,&rparam_len);
5686 /* if we get False back then it's actually unsupported */
5687 if (!reply) {
5688 reply = api_Unsupported(req->sconn,conn,vuid,params,tpscnt,
5689 data,
5690 tdscnt,mdrcnt,mprcnt,
5691 &rdata,&rparam,&rdata_len,&rparam_len);
5694 /* If api_Unsupported returns false we can't return anything. */
5695 if (reply) {
5696 send_trans_reply(conn, req, rparam, rparam_len,
5697 rdata, rdata_len, False);
5700 SAFE_FREE(rdata);
5701 SAFE_FREE(rparam);
5702 return;