s3/doc: add missing documentation for vfs_time_audit
[Samba/gbeck.git] / source3 / smbd / lanman.c
blobfd8b0c7928ea692e6422fd2f2a67306db6ff3b6e
1 /*
2 Unix SMB/CIFS implementation.
3 Inter-process communication and named pipe handling
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Jeremy Allison 2007.
7 SMB Version handling
8 Copyright (C) John H Terpstra 1995-1998
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 This file handles the named pipe and mailslot calls
25 in the SMBtrans protocol
28 #include "includes.h"
29 #include "smbd/globals.h"
30 #include "../librpc/gen_ndr/cli_samr.h"
31 #include "../librpc/gen_ndr/cli_spoolss.h"
32 #include "rpc_client/cli_spoolss.h"
33 #include "rpc_client/init_spoolss.h"
34 #include "../librpc/gen_ndr/cli_srvsvc.h"
35 #include "../librpc/gen_ndr/srv_samr.h"
36 #include "../librpc/gen_ndr/srv_srvsvc.h"
37 #include "../librpc/gen_ndr/rap.h"
38 #include "../lib/util/binsearch.h"
39 #include "../libcli/auth/libcli_auth.h"
40 #include "rpc_client/init_lsa.h"
41 #include "rpc_server/rpc_ncacn_np.h"
42 #include "../libcli/security/security.h"
44 #ifdef CHECK_TYPES
45 #undef CHECK_TYPES
46 #endif
47 #define CHECK_TYPES 0
49 #define NERR_Success 0
50 #define NERR_badpass 86
51 #define NERR_notsupported 50
53 #define NERR_BASE (2100)
54 #define NERR_BufTooSmall (NERR_BASE+23)
55 #define NERR_JobNotFound (NERR_BASE+51)
56 #define NERR_DestNotFound (NERR_BASE+52)
58 #define ACCESS_READ 0x01
59 #define ACCESS_WRITE 0x02
60 #define ACCESS_CREATE 0x04
62 #define SHPWLEN 8 /* share password length */
64 /* Limit size of ipc replies */
66 static char *smb_realloc_limit(void *ptr, size_t size)
68 char *val;
70 size = MAX((size),4*1024);
71 val = (char *)SMB_REALLOC(ptr,size);
72 if (val) {
73 memset(val,'\0',size);
75 return val;
78 static bool api_Unsupported(struct smbd_server_connection *sconn,
79 connection_struct *conn, uint16 vuid,
80 char *param, int tpscnt,
81 char *data, int tdscnt,
82 int mdrcnt, int mprcnt,
83 char **rdata, char **rparam,
84 int *rdata_len, int *rparam_len);
86 static bool api_TooSmall(struct smbd_server_connection *sconn,
87 connection_struct *conn, uint16 vuid, char *param, char *data,
88 int mdrcnt, int mprcnt,
89 char **rdata, char **rparam,
90 int *rdata_len, int *rparam_len);
93 static int CopyExpanded(connection_struct *conn,
94 int snum, char **dst, char *src, int *p_space_remaining)
96 TALLOC_CTX *ctx = talloc_tos();
97 char *buf = NULL;
98 int l;
100 if (!src || !dst || !p_space_remaining || !(*dst) ||
101 *p_space_remaining <= 0) {
102 return 0;
105 buf = talloc_strdup(ctx, src);
106 if (!buf) {
107 *p_space_remaining = 0;
108 return 0;
110 buf = talloc_string_sub(ctx, buf,"%S",lp_servicename(snum));
111 if (!buf) {
112 *p_space_remaining = 0;
113 return 0;
115 buf = talloc_sub_advanced(ctx,
116 lp_servicename(SNUM(conn)),
117 conn->server_info->unix_name,
118 conn->connectpath,
119 conn->server_info->utok.gid,
120 conn->server_info->sanitized_username,
121 conn->server_info->info3->base.domain.string,
122 buf);
123 if (!buf) {
124 *p_space_remaining = 0;
125 return 0;
127 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
128 if (l == -1) {
129 return 0;
131 (*dst) += l;
132 (*p_space_remaining) -= l;
133 return l;
136 static int CopyAndAdvance(char **dst, char *src, int *n)
138 int l;
139 if (!src || !dst || !n || !(*dst)) {
140 return 0;
142 l = push_ascii(*dst,src,*n, STR_TERMINATE);
143 if (l == -1) {
144 return 0;
146 (*dst) += l;
147 (*n) -= l;
148 return l;
151 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
153 TALLOC_CTX *ctx = talloc_tos();
154 char *buf = NULL;
155 if (!s) {
156 return 0;
158 buf = talloc_strdup(ctx,s);
159 if (!buf) {
160 return 0;
162 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
163 if (!buf) {
164 return 0;
166 buf = talloc_sub_advanced(ctx,
167 lp_servicename(SNUM(conn)),
168 conn->server_info->unix_name,
169 conn->connectpath,
170 conn->server_info->utok.gid,
171 conn->server_info->sanitized_username,
172 conn->server_info->info3->base.domain.string,
173 buf);
174 if (!buf) {
175 return 0;
177 return strlen(buf) + 1;
180 /*******************************************************************
181 Check a API string for validity when we only need to check the prefix.
182 ******************************************************************/
184 static bool prefix_ok(const char *str, const char *prefix)
186 return(strncmp(str,prefix,strlen(prefix)) == 0);
189 struct pack_desc {
190 const char *format; /* formatstring for structure */
191 const char *subformat; /* subformat for structure */
192 char *base; /* baseaddress of buffer */
193 int buflen; /* remaining size for fixed part; on init: length of base */
194 int subcount; /* count of substructures */
195 char *structbuf; /* pointer into buffer for remaining fixed part */
196 int stringlen; /* remaining size for variable part */
197 char *stringbuf; /* pointer into buffer for remaining variable part */
198 int neededlen; /* total needed size */
199 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
200 const char *curpos; /* current position; pointer into format or subformat */
201 int errcode;
204 static int get_counter(const char **p)
206 int i, n;
207 if (!p || !(*p)) {
208 return 1;
210 if (!isdigit((int)**p)) {
211 return 1;
213 for (n = 0;;) {
214 i = **p;
215 if (isdigit(i)) {
216 n = 10 * n + (i - '0');
217 } else {
218 return n;
220 (*p)++;
224 static int getlen(const char *p)
226 int n = 0;
227 if (!p) {
228 return 0;
231 while (*p) {
232 switch( *p++ ) {
233 case 'W': /* word (2 byte) */
234 n += 2;
235 break;
236 case 'K': /* status word? (2 byte) */
237 n += 2;
238 break;
239 case 'N': /* count of substructures (word) at end */
240 n += 2;
241 break;
242 case 'D': /* double word (4 byte) */
243 case 'z': /* offset to zero terminated string (4 byte) */
244 case 'l': /* offset to user data (4 byte) */
245 n += 4;
246 break;
247 case 'b': /* offset to data (with counter) (4 byte) */
248 n += 4;
249 get_counter(&p);
250 break;
251 case 'B': /* byte (with optional counter) */
252 n += get_counter(&p);
253 break;
256 return n;
259 static bool init_package(struct pack_desc *p, int count, int subcount)
261 int n = p->buflen;
262 int i;
264 if (!p->format || !p->base) {
265 return False;
268 i = count * getlen(p->format);
269 if (p->subformat) {
270 i += subcount * getlen(p->subformat);
272 p->structbuf = p->base;
273 p->neededlen = 0;
274 p->usedlen = 0;
275 p->subcount = 0;
276 p->curpos = p->format;
277 if (i > n) {
278 p->neededlen = i;
279 i = n = 0;
280 #if 0
282 * This is the old error code we used. Aparently
283 * WinNT/2k systems return ERRbuftoosmall (2123) and
284 * OS/2 needs this. I'm leaving this here so we can revert
285 * if needed. JRA.
287 p->errcode = ERRmoredata;
288 #else
289 p->errcode = ERRbuftoosmall;
290 #endif
291 } else {
292 p->errcode = NERR_Success;
294 p->buflen = i;
295 n -= i;
296 p->stringbuf = p->base + i;
297 p->stringlen = n;
298 return (p->errcode == NERR_Success);
301 static int package(struct pack_desc *p, ...)
303 va_list args;
304 int needed=0, stringneeded;
305 const char *str=NULL;
306 int is_string=0, stringused;
307 int32 temp;
309 va_start(args,p);
311 if (!*p->curpos) {
312 if (!p->subcount) {
313 p->curpos = p->format;
314 } else {
315 p->curpos = p->subformat;
316 p->subcount--;
319 #if CHECK_TYPES
320 str = va_arg(args,char*);
321 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
322 #endif
323 stringneeded = -1;
325 if (!p->curpos) {
326 va_end(args);
327 return 0;
330 switch( *p->curpos++ ) {
331 case 'W': /* word (2 byte) */
332 needed = 2;
333 temp = va_arg(args,int);
334 if (p->buflen >= needed) {
335 SSVAL(p->structbuf,0,temp);
337 break;
338 case 'K': /* status word? (2 byte) */
339 needed = 2;
340 temp = va_arg(args,int);
341 if (p->buflen >= needed) {
342 SSVAL(p->structbuf,0,temp);
344 break;
345 case 'N': /* count of substructures (word) at end */
346 needed = 2;
347 p->subcount = va_arg(args,int);
348 if (p->buflen >= needed) {
349 SSVAL(p->structbuf,0,p->subcount);
351 break;
352 case 'D': /* double word (4 byte) */
353 needed = 4;
354 temp = va_arg(args,int);
355 if (p->buflen >= needed) {
356 SIVAL(p->structbuf,0,temp);
358 break;
359 case 'B': /* byte (with optional counter) */
360 needed = get_counter(&p->curpos);
362 char *s = va_arg(args,char*);
363 if (p->buflen >= needed) {
364 StrnCpy(p->structbuf,s?s:"",needed-1);
367 break;
368 case 'z': /* offset to zero terminated string (4 byte) */
369 str = va_arg(args,char*);
370 stringneeded = (str ? strlen(str)+1 : 0);
371 is_string = 1;
372 break;
373 case 'l': /* offset to user data (4 byte) */
374 str = va_arg(args,char*);
375 stringneeded = va_arg(args,int);
376 is_string = 0;
377 break;
378 case 'b': /* offset to data (with counter) (4 byte) */
379 str = va_arg(args,char*);
380 stringneeded = get_counter(&p->curpos);
381 is_string = 0;
382 break;
385 va_end(args);
386 if (stringneeded >= 0) {
387 needed = 4;
388 if (p->buflen >= needed) {
389 stringused = stringneeded;
390 if (stringused > p->stringlen) {
391 stringused = (is_string ? p->stringlen : 0);
392 if (p->errcode == NERR_Success) {
393 p->errcode = ERRmoredata;
396 if (!stringused) {
397 SIVAL(p->structbuf,0,0);
398 } else {
399 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
400 memcpy(p->stringbuf,str?str:"",stringused);
401 if (is_string) {
402 p->stringbuf[stringused-1] = '\0';
404 p->stringbuf += stringused;
405 p->stringlen -= stringused;
406 p->usedlen += stringused;
409 p->neededlen += stringneeded;
412 p->neededlen += needed;
413 if (p->buflen >= needed) {
414 p->structbuf += needed;
415 p->buflen -= needed;
416 p->usedlen += needed;
417 } else {
418 if (p->errcode == NERR_Success) {
419 p->errcode = ERRmoredata;
422 return 1;
425 #if CHECK_TYPES
426 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
427 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
428 #else
429 #define PACK(desc,t,v) package(desc,v)
430 #define PACKl(desc,t,v,l) package(desc,v,l)
431 #endif
433 static void PACKI(struct pack_desc* desc, const char *t,int v)
435 PACK(desc,t,v);
438 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
440 PACK(desc,t,v);
443 /****************************************************************************
444 Get a print queue.
445 ****************************************************************************/
447 static void PackDriverData(struct pack_desc* desc)
449 char drivdata[4+4+32];
450 SIVAL(drivdata,0,sizeof drivdata); /* cb */
451 SIVAL(drivdata,4,1000); /* lVersion */
452 memset(drivdata+8,0,32); /* szDeviceName */
453 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
454 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
457 static int check_printq_info(struct pack_desc* desc,
458 unsigned int uLevel, char *id1, char *id2)
460 desc->subformat = NULL;
461 switch( uLevel ) {
462 case 0:
463 desc->format = "B13";
464 break;
465 case 1:
466 desc->format = "B13BWWWzzzzzWW";
467 break;
468 case 2:
469 desc->format = "B13BWWWzzzzzWN";
470 desc->subformat = "WB21BB16B10zWWzDDz";
471 break;
472 case 3:
473 desc->format = "zWWWWzzzzWWzzl";
474 break;
475 case 4:
476 desc->format = "zWWWWzzzzWNzzl";
477 desc->subformat = "WWzWWDDzz";
478 break;
479 case 5:
480 desc->format = "z";
481 break;
482 case 51:
483 desc->format = "K";
484 break;
485 case 52:
486 desc->format = "WzzzzzzzzN";
487 desc->subformat = "z";
488 break;
489 default:
490 DEBUG(0,("check_printq_info: invalid level %d\n",
491 uLevel ));
492 return False;
494 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
495 DEBUG(0,("check_printq_info: invalid format %s\n",
496 id1 ? id1 : "<NULL>" ));
497 return False;
499 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
500 DEBUG(0,("check_printq_info: invalid subformat %s\n",
501 id2 ? id2 : "<NULL>" ));
502 return False;
504 return True;
508 #define RAP_JOB_STATUS_QUEUED 0
509 #define RAP_JOB_STATUS_PAUSED 1
510 #define RAP_JOB_STATUS_SPOOLING 2
511 #define RAP_JOB_STATUS_PRINTING 3
512 #define RAP_JOB_STATUS_PRINTED 4
514 #define RAP_QUEUE_STATUS_PAUSED 1
515 #define RAP_QUEUE_STATUS_ERROR 2
517 /* turn a print job status into a on the wire status
519 static int printj_spoolss_status(int v)
521 if (v == JOB_STATUS_QUEUED)
522 return RAP_JOB_STATUS_QUEUED;
523 if (v & JOB_STATUS_PAUSED)
524 return RAP_JOB_STATUS_PAUSED;
525 if (v & JOB_STATUS_SPOOLING)
526 return RAP_JOB_STATUS_SPOOLING;
527 if (v & JOB_STATUS_PRINTING)
528 return RAP_JOB_STATUS_PRINTING;
529 return 0;
532 /* turn a print queue status into a on the wire status
534 static int printq_spoolss_status(int v)
536 if (v == PRINTER_STATUS_OK)
537 return 0;
538 if (v & PRINTER_STATUS_PAUSED)
539 return RAP_QUEUE_STATUS_PAUSED;
540 return RAP_QUEUE_STATUS_ERROR;
543 static void fill_spoolss_printjob_info(int uLevel,
544 struct pack_desc *desc,
545 struct spoolss_JobInfo2 *info2,
546 int n)
548 time_t t = spoolss_Time_to_time_t(&info2->submitted);
550 /* the client expects localtime */
551 t -= get_time_zone(t);
553 PACKI(desc,"W",pjobid_to_rap(info2->printer_name, info2->job_id)); /* uJobId */
554 if (uLevel == 1) {
555 PACKS(desc,"B21", info2->user_name); /* szUserName */
556 PACKS(desc,"B",""); /* pad */
557 PACKS(desc,"B16",""); /* szNotifyName */
558 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
559 PACKS(desc,"z",""); /* pszParms */
560 PACKI(desc,"W",n+1); /* uPosition */
561 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
562 PACKS(desc,"z",""); /* pszStatus */
563 PACKI(desc,"D", t); /* ulSubmitted */
564 PACKI(desc,"D", info2->size); /* ulSize */
565 PACKS(desc,"z", info2->document_name); /* pszComment */
567 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
568 PACKI(desc,"W", info2->priority); /* uPriority */
569 PACKS(desc,"z", info2->user_name); /* pszUserName */
570 PACKI(desc,"W",n+1); /* uPosition */
571 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
572 PACKI(desc,"D",t); /* ulSubmitted */
573 PACKI(desc,"D", info2->size); /* ulSize */
574 PACKS(desc,"z","Samba"); /* pszComment */
575 PACKS(desc,"z", info2->document_name); /* pszDocument */
576 if (uLevel == 3) {
577 PACKS(desc,"z",""); /* pszNotifyName */
578 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
579 PACKS(desc,"z",""); /* pszParms */
580 PACKS(desc,"z",""); /* pszStatus */
581 PACKS(desc,"z", info2->printer_name); /* pszQueue */
582 PACKS(desc,"z","lpd"); /* pszQProcName */
583 PACKS(desc,"z",""); /* pszQProcParms */
584 PACKS(desc,"z","NULL"); /* pszDriverName */
585 PackDriverData(desc); /* pDriverData */
586 PACKS(desc,"z",""); /* pszPrinterName */
587 } else if (uLevel == 4) { /* OS2 */
588 PACKS(desc,"z",""); /* pszSpoolFileName */
589 PACKS(desc,"z",""); /* pszPortName */
590 PACKS(desc,"z",""); /* pszStatus */
591 PACKI(desc,"D",0); /* ulPagesSpooled */
592 PACKI(desc,"D",0); /* ulPagesSent */
593 PACKI(desc,"D",0); /* ulPagesPrinted */
594 PACKI(desc,"D",0); /* ulTimePrinted */
595 PACKI(desc,"D",0); /* ulExtendJobStatus */
596 PACKI(desc,"D",0); /* ulStartPage */
597 PACKI(desc,"D",0); /* ulEndPage */
602 /********************************************************************
603 Respond to the DosPrintQInfo command with a level of 52
604 This is used to get printer driver information for Win9x clients
605 ********************************************************************/
606 static void fill_printq_info_52(struct spoolss_DriverInfo3 *driver,
607 struct pack_desc* desc, int count,
608 const char *printer_name)
610 int i;
611 fstring location;
612 trim_string((char *)driver->driver_path, "\\print$\\WIN40\\0\\", 0);
613 trim_string((char *)driver->data_file, "\\print$\\WIN40\\0\\", 0);
614 trim_string((char *)driver->help_file, "\\print$\\WIN40\\0\\", 0);
616 PACKI(desc, "W", 0x0400); /* don't know */
617 PACKS(desc, "z", driver->driver_name); /* long printer name */
618 PACKS(desc, "z", driver->driver_path); /* Driverfile Name */
619 PACKS(desc, "z", driver->data_file); /* Datafile name */
620 PACKS(desc, "z", driver->monitor_name); /* language monitor */
622 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
623 standard_sub_basic( "", "", location, sizeof(location)-1 );
624 PACKS(desc,"z", location); /* share to retrieve files */
626 PACKS(desc,"z", driver->default_datatype); /* default data type */
627 PACKS(desc,"z", driver->help_file); /* helpfile name */
628 PACKS(desc,"z", driver->driver_path); /* driver name */
630 DEBUG(3,("Printer Driver Name: %s:\n",driver->driver_name));
631 DEBUG(3,("Driver: %s:\n",driver->driver_path));
632 DEBUG(3,("Data File: %s:\n",driver->data_file));
633 DEBUG(3,("Language Monitor: %s:\n",driver->monitor_name));
634 DEBUG(3,("Driver Location: %s:\n",location));
635 DEBUG(3,("Data Type: %s:\n",driver->default_datatype));
636 DEBUG(3,("Help File: %s:\n",driver->help_file));
637 PACKI(desc,"N",count); /* number of files to copy */
639 for ( i=0; i<count && driver->dependent_files && *driver->dependent_files[i]; i++)
641 trim_string((char *)driver->dependent_files[i], "\\print$\\WIN40\\0\\", 0);
642 PACKS(desc,"z",driver->dependent_files[i]); /* driver files to copy */
643 DEBUG(3,("Dependent File: %s:\n", driver->dependent_files[i]));
646 /* sanity check */
647 if ( i != count )
648 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
649 count, i));
651 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", printer_name, i));
653 desc->errcode=NERR_Success;
657 static const char *strip_unc(const char *unc)
659 char *p;
661 if (unc == NULL) {
662 return NULL;
665 if ((p = strrchr(unc, '\\')) != NULL) {
666 return p+1;
669 return unc;
672 static void fill_printq_info(int uLevel,
673 struct pack_desc* desc,
674 int count,
675 union spoolss_JobInfo *job_info,
676 struct spoolss_DriverInfo3 *driver_info,
677 struct spoolss_PrinterInfo2 *printer_info)
679 switch (uLevel) {
680 case 0:
681 case 1:
682 case 2:
683 PACKS(desc,"B13", strip_unc(printer_info->printername));
684 break;
685 case 3:
686 case 4:
687 case 5:
688 PACKS(desc,"z", strip_unc(printer_info->printername));
689 break;
690 case 51:
691 PACKI(desc,"K", printq_spoolss_status(printer_info->status));
692 break;
695 if (uLevel == 1 || uLevel == 2) {
696 PACKS(desc,"B",""); /* alignment */
697 PACKI(desc,"W",5); /* priority */
698 PACKI(desc,"W",0); /* start time */
699 PACKI(desc,"W",0); /* until time */
700 PACKS(desc,"z",""); /* pSepFile */
701 PACKS(desc,"z","lpd"); /* pPrProc */
702 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pDestinations */
703 PACKS(desc,"z",""); /* pParms */
704 if (printer_info->printername == NULL) {
705 PACKS(desc,"z","UNKNOWN PRINTER");
706 PACKI(desc,"W",LPSTAT_ERROR);
707 } else {
708 PACKS(desc,"z", printer_info->comment);
709 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* status */
711 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
714 if (uLevel == 3 || uLevel == 4) {
715 PACKI(desc,"W",5); /* uPriority */
716 PACKI(desc,"W",0); /* uStarttime */
717 PACKI(desc,"W",0); /* uUntiltime */
718 PACKI(desc,"W",5); /* pad1 */
719 PACKS(desc,"z",""); /* pszSepFile */
720 PACKS(desc,"z","WinPrint"); /* pszPrProc */
721 PACKS(desc,"z",NULL); /* pszParms */
722 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
723 /* "don't ask" that it's done this way to fix corrupted
724 Win9X/ME printer comments. */
725 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* fsStatus */
726 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
727 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pszPrinters */
728 PACKS(desc,"z", printer_info->drivername); /* pszDriverName */
729 PackDriverData(desc); /* pDriverData */
732 if (uLevel == 2 || uLevel == 4) {
733 int i;
734 for (i = 0; i < count; i++) {
735 fill_spoolss_printjob_info(uLevel == 2 ? 1 : 2, desc, &job_info[i].info2, i);
739 if (uLevel==52)
740 fill_printq_info_52(driver_info, desc, count, printer_info->printername);
743 /* This function returns the number of files for a given driver */
744 static int get_printerdrivernumber(const struct spoolss_DriverInfo3 *driver)
746 int result = 0;
748 /* count the number of files */
749 while (driver->dependent_files && *driver->dependent_files[result])
750 result++;
752 return result;
755 static bool api_DosPrintQGetInfo(struct smbd_server_connection *sconn,
756 connection_struct *conn, uint16 vuid,
757 char *param, int tpscnt,
758 char *data, int tdscnt,
759 int mdrcnt,int mprcnt,
760 char **rdata,char **rparam,
761 int *rdata_len,int *rparam_len)
763 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
764 char *str2 = skip_string(param,tpscnt,str1);
765 char *p = skip_string(param,tpscnt,str2);
766 char *QueueName = p;
767 unsigned int uLevel;
768 uint32_t count = 0;
769 char *str3;
770 struct pack_desc desc;
771 char* tmpdata=NULL;
773 WERROR werr = WERR_OK;
774 TALLOC_CTX *mem_ctx = talloc_tos();
775 NTSTATUS status;
776 struct rpc_pipe_client *cli = NULL;
777 struct policy_handle handle;
778 struct spoolss_DevmodeContainer devmode_ctr;
779 union spoolss_DriverInfo driver_info;
780 union spoolss_JobInfo *job_info = NULL;
781 union spoolss_PrinterInfo printer_info;
783 if (!str1 || !str2 || !p) {
784 return False;
786 memset((char *)&desc,'\0',sizeof(desc));
788 p = skip_string(param,tpscnt,p);
789 if (!p) {
790 return False;
792 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
793 str3 = get_safe_str_ptr(param,tpscnt,p,4);
794 /* str3 may be null here and is checked in check_printq_info(). */
796 /* remove any trailing username */
797 if ((p = strchr_m(QueueName,'%')))
798 *p = 0;
800 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
802 /* check it's a supported varient */
803 if (!prefix_ok(str1,"zWrLh"))
804 return False;
805 if (!check_printq_info(&desc,uLevel,str2,str3)) {
807 * Patch from Scott Moomaw <scott@bridgewater.edu>
808 * to return the 'invalid info level' error if an
809 * unknown level was requested.
811 *rdata_len = 0;
812 *rparam_len = 6;
813 *rparam = smb_realloc_limit(*rparam,*rparam_len);
814 if (!*rparam) {
815 return False;
817 SSVALS(*rparam,0,ERRunknownlevel);
818 SSVAL(*rparam,2,0);
819 SSVAL(*rparam,4,0);
820 return(True);
823 ZERO_STRUCT(handle);
825 if (QueueName == NULL || (strlen(QueueName) < 1)) {
826 desc.errcode = W_ERROR_V(WERR_INVALID_PARAM);
827 goto out;
830 status = rpc_pipe_open_interface(conn,
831 &ndr_table_spoolss.syntax_id,
832 conn->server_info,
833 &conn->sconn->client_id,
834 conn->sconn->msg_ctx,
835 &cli);
836 if (!NT_STATUS_IS_OK(status)) {
837 DEBUG(0,("api_DosPrintQGetInfo: could not connect to spoolss: %s\n",
838 nt_errstr(status)));
839 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
840 goto out;
843 ZERO_STRUCT(devmode_ctr);
845 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
846 QueueName,
847 "RAW",
848 devmode_ctr,
849 PRINTER_ACCESS_USE,
850 &handle,
851 &werr);
852 if (!NT_STATUS_IS_OK(status)) {
853 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
854 goto out;
856 if (!W_ERROR_IS_OK(werr)) {
857 desc.errcode = W_ERROR_V(werr);
858 goto out;
861 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
862 &handle,
865 &printer_info);
866 if (!W_ERROR_IS_OK(werr)) {
867 desc.errcode = W_ERROR_V(werr);
868 goto out;
871 if (uLevel==52) {
872 uint32_t server_major_version;
873 uint32_t server_minor_version;
875 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
876 &handle,
877 "Windows 4.0",
878 3, /* level */
880 0, /* version */
882 &driver_info,
883 &server_major_version,
884 &server_minor_version);
885 if (!W_ERROR_IS_OK(werr)) {
886 desc.errcode = W_ERROR_V(werr);
887 goto out;
890 count = get_printerdrivernumber(&driver_info.info3);
891 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
892 } else {
893 uint32_t num_jobs;
894 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
895 &handle,
896 0, /* firstjob */
897 0xff, /* numjobs */
898 2, /* level */
899 0, /* offered */
900 &num_jobs,
901 &job_info);
902 if (!W_ERROR_IS_OK(werr)) {
903 desc.errcode = W_ERROR_V(werr);
904 goto out;
907 count = num_jobs;
910 if (mdrcnt > 0) {
911 *rdata = smb_realloc_limit(*rdata,mdrcnt);
912 if (!*rdata) {
913 return False;
915 desc.base = *rdata;
916 desc.buflen = mdrcnt;
917 } else {
919 * Don't return data but need to get correct length
920 * init_package will return wrong size if buflen=0
922 desc.buflen = getlen(desc.format);
923 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
926 if (init_package(&desc,1,count)) {
927 desc.subcount = count;
928 fill_printq_info(uLevel,&desc,count, job_info, &driver_info.info3, &printer_info.info2);
931 *rdata_len = desc.usedlen;
934 * We must set the return code to ERRbuftoosmall
935 * in order to support lanman style printing with Win NT/2k
936 * clients --jerry
938 if (!mdrcnt && lp_disable_spoolss())
939 desc.errcode = ERRbuftoosmall;
941 out:
942 if (cli && is_valid_policy_hnd(&handle)) {
943 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
946 *rdata_len = desc.usedlen;
947 *rparam_len = 6;
948 *rparam = smb_realloc_limit(*rparam,*rparam_len);
949 if (!*rparam) {
950 SAFE_FREE(tmpdata);
951 return False;
953 SSVALS(*rparam,0,desc.errcode);
954 SSVAL(*rparam,2,0);
955 SSVAL(*rparam,4,desc.neededlen);
957 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
959 SAFE_FREE(tmpdata);
961 return(True);
964 /****************************************************************************
965 View list of all print jobs on all queues.
966 ****************************************************************************/
968 static bool api_DosPrintQEnum(struct smbd_server_connection *sconn,
969 connection_struct *conn, uint16 vuid,
970 char *param, int tpscnt,
971 char *data, int tdscnt,
972 int mdrcnt, int mprcnt,
973 char **rdata, char** rparam,
974 int *rdata_len, int *rparam_len)
976 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
977 char *output_format1 = skip_string(param,tpscnt,param_format);
978 char *p = skip_string(param,tpscnt,output_format1);
979 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
980 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
981 int i;
982 struct pack_desc desc;
983 int *subcntarr = NULL;
984 int queuecnt = 0, subcnt = 0, succnt = 0;
986 WERROR werr = WERR_OK;
987 TALLOC_CTX *mem_ctx = talloc_tos();
988 NTSTATUS status;
989 struct rpc_pipe_client *cli = NULL;
990 struct spoolss_DevmodeContainer devmode_ctr;
991 uint32_t num_printers;
992 union spoolss_PrinterInfo *printer_info;
993 union spoolss_DriverInfo *driver_info;
994 union spoolss_JobInfo **job_info;
996 if (!param_format || !output_format1 || !p) {
997 return False;
1000 memset((char *)&desc,'\0',sizeof(desc));
1002 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
1004 if (!prefix_ok(param_format,"WrLeh")) {
1005 return False;
1007 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
1009 * Patch from Scott Moomaw <scott@bridgewater.edu>
1010 * to return the 'invalid info level' error if an
1011 * unknown level was requested.
1013 *rdata_len = 0;
1014 *rparam_len = 6;
1015 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1016 if (!*rparam) {
1017 return False;
1019 SSVALS(*rparam,0,ERRunknownlevel);
1020 SSVAL(*rparam,2,0);
1021 SSVAL(*rparam,4,0);
1022 return(True);
1025 status = rpc_pipe_open_interface(conn,
1026 &ndr_table_spoolss.syntax_id,
1027 conn->server_info,
1028 &conn->sconn->client_id,
1029 conn->sconn->msg_ctx,
1030 &cli);
1031 if (!NT_STATUS_IS_OK(status)) {
1032 DEBUG(0,("api_DosPrintQEnum: could not connect to spoolss: %s\n",
1033 nt_errstr(status)));
1034 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1035 goto out;
1038 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
1039 PRINTER_ENUM_LOCAL,
1040 cli->srv_name_slash,
1043 &num_printers,
1044 &printer_info);
1045 if (!W_ERROR_IS_OK(werr)) {
1046 desc.errcode = W_ERROR_V(werr);
1047 goto out;
1050 queuecnt = num_printers;
1052 job_info = talloc_array(mem_ctx, union spoolss_JobInfo *, num_printers);
1053 if (job_info == NULL) {
1054 goto err;
1057 driver_info = talloc_array(mem_ctx, union spoolss_DriverInfo, num_printers);
1058 if (driver_info == NULL) {
1059 goto err;
1062 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1063 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1064 goto err;
1067 if (mdrcnt > 0) {
1068 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1069 if (!*rdata) {
1070 goto err;
1073 desc.base = *rdata;
1074 desc.buflen = mdrcnt;
1076 subcnt = 0;
1077 for (i = 0; i < num_printers; i++) {
1079 uint32_t num_jobs;
1080 struct policy_handle handle;
1081 const char *printername;
1083 printername = talloc_strdup(mem_ctx, printer_info[i].info2.printername);
1084 if (printername == NULL) {
1085 goto err;
1088 ZERO_STRUCT(handle);
1089 ZERO_STRUCT(devmode_ctr);
1091 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
1092 printername,
1093 "RAW",
1094 devmode_ctr,
1095 PRINTER_ACCESS_USE,
1096 &handle,
1097 &werr);
1098 if (!NT_STATUS_IS_OK(status)) {
1099 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1100 goto out;
1102 if (!W_ERROR_IS_OK(werr)) {
1103 desc.errcode = W_ERROR_V(werr);
1104 goto out;
1107 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
1108 &handle,
1109 0, /* firstjob */
1110 0xff, /* numjobs */
1111 2, /* level */
1112 0, /* offered */
1113 &num_jobs,
1114 &job_info[i]);
1115 if (!W_ERROR_IS_OK(werr)) {
1116 desc.errcode = W_ERROR_V(werr);
1117 goto out;
1120 if (uLevel==52) {
1121 uint32_t server_major_version;
1122 uint32_t server_minor_version;
1124 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1125 &handle,
1126 "Windows 4.0",
1127 3, /* level */
1129 0, /* version */
1131 &driver_info[i],
1132 &server_major_version,
1133 &server_minor_version);
1134 if (!W_ERROR_IS_OK(werr)) {
1135 desc.errcode = W_ERROR_V(werr);
1136 goto out;
1140 subcntarr[i] = num_jobs;
1141 subcnt += subcntarr[i];
1143 if (cli && is_valid_policy_hnd(&handle)) {
1144 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
1148 if (init_package(&desc,queuecnt,subcnt)) {
1149 for (i = 0; i < num_printers; i++) {
1150 fill_printq_info(uLevel,&desc,subcntarr[i], job_info[i], &driver_info[i].info3, &printer_info[i].info2);
1151 if (desc.errcode == NERR_Success) {
1152 succnt = i;
1157 SAFE_FREE(subcntarr);
1158 out:
1159 *rdata_len = desc.usedlen;
1160 *rparam_len = 8;
1161 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1162 if (!*rparam) {
1163 goto err;
1165 SSVALS(*rparam,0,desc.errcode);
1166 SSVAL(*rparam,2,0);
1167 SSVAL(*rparam,4,succnt);
1168 SSVAL(*rparam,6,queuecnt);
1170 return True;
1172 err:
1174 SAFE_FREE(subcntarr);
1176 return False;
1179 /****************************************************************************
1180 Get info level for a server list query.
1181 ****************************************************************************/
1183 static bool check_server_info(int uLevel, char* id)
1185 switch( uLevel ) {
1186 case 0:
1187 if (strcmp(id,"B16") != 0) {
1188 return False;
1190 break;
1191 case 1:
1192 if (strcmp(id,"B16BBDz") != 0) {
1193 return False;
1195 break;
1196 default:
1197 return False;
1199 return True;
1202 struct srv_info_struct {
1203 fstring name;
1204 uint32 type;
1205 fstring comment;
1206 fstring domain;
1207 bool server_added;
1210 /*******************************************************************
1211 Get server info lists from the files saved by nmbd. Return the
1212 number of entries.
1213 ******************************************************************/
1215 static int get_server_info(uint32 servertype,
1216 struct srv_info_struct **servers,
1217 const char *domain)
1219 int count=0;
1220 int alloced=0;
1221 char **lines;
1222 bool local_list_only;
1223 int i;
1225 lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
1226 if (!lines) {
1227 DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
1228 return 0;
1231 /* request for everything is code for request all servers */
1232 if (servertype == SV_TYPE_ALL) {
1233 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1236 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1238 DEBUG(4,("Servertype search: %8x\n",servertype));
1240 for (i=0;lines[i];i++) {
1241 fstring stype;
1242 struct srv_info_struct *s;
1243 const char *ptr = lines[i];
1244 bool ok = True;
1245 TALLOC_CTX *frame = NULL;
1246 char *p;
1248 if (!*ptr) {
1249 continue;
1252 if (count == alloced) {
1253 alloced += 10;
1254 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1255 if (!*servers) {
1256 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1257 TALLOC_FREE(lines);
1258 return 0;
1260 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1262 s = &(*servers)[count];
1264 frame = talloc_stackframe();
1265 s->name[0] = '\0';
1266 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1267 TALLOC_FREE(frame);
1268 continue;
1270 fstrcpy(s->name, p);
1272 stype[0] = '\0';
1273 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1274 TALLOC_FREE(frame);
1275 continue;
1277 fstrcpy(stype, p);
1279 s->comment[0] = '\0';
1280 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1281 TALLOC_FREE(frame);
1282 continue;
1284 fstrcpy(s->comment, p);
1285 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1287 s->domain[0] = '\0';
1288 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1289 /* this allows us to cope with an old nmbd */
1290 fstrcpy(s->domain,lp_workgroup());
1291 } else {
1292 fstrcpy(s->domain, p);
1294 TALLOC_FREE(frame);
1296 if (sscanf(stype,"%X",&s->type) != 1) {
1297 DEBUG(4,("r:host file "));
1298 ok = False;
1301 /* Filter the servers/domains we return based on what was asked for. */
1303 /* Check to see if we are being asked for a local list only. */
1304 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1305 DEBUG(4,("r: local list only"));
1306 ok = False;
1309 /* doesn't match up: don't want it */
1310 if (!(servertype & s->type)) {
1311 DEBUG(4,("r:serv type "));
1312 ok = False;
1315 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1316 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1317 DEBUG(4,("s: dom mismatch "));
1318 ok = False;
1321 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1322 ok = False;
1325 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1326 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1328 if (ok) {
1329 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1330 s->name, s->type, s->comment, s->domain));
1331 s->server_added = True;
1332 count++;
1333 } else {
1334 DEBUG(4,("%20s %8x %25s %15s\n",
1335 s->name, s->type, s->comment, s->domain));
1339 TALLOC_FREE(lines);
1340 return count;
1343 /*******************************************************************
1344 Fill in a server info structure.
1345 ******************************************************************/
1347 static int fill_srv_info(struct srv_info_struct *service,
1348 int uLevel, char **buf, int *buflen,
1349 char **stringbuf, int *stringspace, char *baseaddr)
1351 int struct_len;
1352 char* p;
1353 char* p2;
1354 int l2;
1355 int len;
1357 switch (uLevel) {
1358 case 0:
1359 struct_len = 16;
1360 break;
1361 case 1:
1362 struct_len = 26;
1363 break;
1364 default:
1365 return -1;
1368 if (!buf) {
1369 len = 0;
1370 switch (uLevel) {
1371 case 1:
1372 len = strlen(service->comment)+1;
1373 break;
1376 *buflen = struct_len;
1377 *stringspace = len;
1378 return struct_len + len;
1381 len = struct_len;
1382 p = *buf;
1383 if (*buflen < struct_len) {
1384 return -1;
1386 if (stringbuf) {
1387 p2 = *stringbuf;
1388 l2 = *stringspace;
1389 } else {
1390 p2 = p + struct_len;
1391 l2 = *buflen - struct_len;
1393 if (!baseaddr) {
1394 baseaddr = p;
1397 switch (uLevel) {
1398 case 0:
1399 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1400 break;
1402 case 1:
1403 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1404 SIVAL(p,18,service->type);
1405 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1406 len += CopyAndAdvance(&p2,service->comment,&l2);
1407 break;
1410 if (stringbuf) {
1411 *buf = p + struct_len;
1412 *buflen -= struct_len;
1413 *stringbuf = p2;
1414 *stringspace = l2;
1415 } else {
1416 *buf = p2;
1417 *buflen -= len;
1419 return len;
1423 static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1425 return StrCaseCmp(s1->name,s2->name);
1428 /****************************************************************************
1429 View list of servers available (or possibly domains). The info is
1430 extracted from lists saved by nmbd on the local host.
1431 ****************************************************************************/
1433 static bool api_RNetServerEnum2(struct smbd_server_connection *sconn,
1434 connection_struct *conn, uint16 vuid,
1435 char *param, int tpscnt,
1436 char *data, int tdscnt,
1437 int mdrcnt, int mprcnt, char **rdata,
1438 char **rparam, int *rdata_len, int *rparam_len)
1440 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1441 char *str2 = skip_string(param,tpscnt,str1);
1442 char *p = skip_string(param,tpscnt,str2);
1443 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1444 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1445 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1446 char *p2;
1447 int data_len, fixed_len, string_len;
1448 int f_len = 0, s_len = 0;
1449 struct srv_info_struct *servers=NULL;
1450 int counted=0,total=0;
1451 int i,missed;
1452 fstring domain;
1453 bool domain_request;
1454 bool local_request;
1456 if (!str1 || !str2 || !p) {
1457 return False;
1460 /* If someone sets all the bits they don't really mean to set
1461 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1462 known servers. */
1464 if (servertype == SV_TYPE_ALL) {
1465 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1468 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1469 any other bit (they may just set this bit on its own) they
1470 want all the locally seen servers. However this bit can be
1471 set on its own so set the requested servers to be
1472 ALL - DOMAIN_ENUM. */
1474 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1475 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1478 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1479 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1481 p += 8;
1483 if (!prefix_ok(str1,"WrLehD")) {
1484 return False;
1486 if (!check_server_info(uLevel,str2)) {
1487 return False;
1490 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1491 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1492 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1494 if (strcmp(str1, "WrLehDz") == 0) {
1495 if (skip_string(param,tpscnt,p) == NULL) {
1496 return False;
1498 pull_ascii_fstring(domain, p);
1499 } else {
1500 fstrcpy(domain, lp_workgroup());
1503 DEBUG(4, ("domain [%s]\n", domain));
1505 if (lp_browse_list()) {
1506 total = get_server_info(servertype,&servers,domain);
1509 data_len = fixed_len = string_len = 0;
1510 missed = 0;
1512 TYPESAFE_QSORT(servers, total, srv_comp);
1515 char *lastname=NULL;
1517 for (i=0;i<total;i++) {
1518 struct srv_info_struct *s = &servers[i];
1520 if (lastname && strequal(lastname,s->name)) {
1521 continue;
1523 lastname = s->name;
1524 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1525 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1526 i, s->name, s->type, s->comment, s->domain));
1528 if (data_len < buf_len) {
1529 counted++;
1530 fixed_len += f_len;
1531 string_len += s_len;
1532 } else {
1533 missed++;
1538 *rdata_len = fixed_len + string_len;
1539 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1540 if (!*rdata) {
1541 return False;
1544 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1545 p = *rdata;
1546 f_len = fixed_len;
1547 s_len = string_len;
1550 char *lastname=NULL;
1551 int count2 = counted;
1553 for (i = 0; i < total && count2;i++) {
1554 struct srv_info_struct *s = &servers[i];
1556 if (lastname && strequal(lastname,s->name)) {
1557 continue;
1559 lastname = s->name;
1560 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1561 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1562 i, s->name, s->type, s->comment, s->domain));
1563 count2--;
1567 *rparam_len = 8;
1568 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1569 if (!*rparam) {
1570 return False;
1572 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1573 SSVAL(*rparam,2,0);
1574 SSVAL(*rparam,4,counted);
1575 SSVAL(*rparam,6,counted+missed);
1577 SAFE_FREE(servers);
1579 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1580 domain,uLevel,counted,counted+missed));
1582 return True;
1585 static int srv_name_match(const char *n1, const char *n2)
1588 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1590 * In Windows, FirstNameToReturn need not be an exact match:
1591 * the server will return a list of servers that exist on
1592 * the network greater than or equal to the FirstNameToReturn.
1594 int ret = StrCaseCmp(n1, n2);
1596 if (ret <= 0) {
1597 return 0;
1600 return ret;
1603 static bool api_RNetServerEnum3(struct smbd_server_connection *sconn,
1604 connection_struct *conn, uint16 vuid,
1605 char *param, int tpscnt,
1606 char *data, int tdscnt,
1607 int mdrcnt, int mprcnt, char **rdata,
1608 char **rparam, int *rdata_len, int *rparam_len)
1610 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1611 char *str2 = skip_string(param,tpscnt,str1);
1612 char *p = skip_string(param,tpscnt,str2);
1613 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1614 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1615 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1616 char *p2;
1617 int data_len, fixed_len, string_len;
1618 int f_len = 0, s_len = 0;
1619 struct srv_info_struct *servers=NULL;
1620 int counted=0,first=0,total=0;
1621 int i,missed;
1622 fstring domain;
1623 fstring first_name;
1624 bool domain_request;
1625 bool local_request;
1627 if (!str1 || !str2 || !p) {
1628 return False;
1631 /* If someone sets all the bits they don't really mean to set
1632 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1633 known servers. */
1635 if (servertype == SV_TYPE_ALL) {
1636 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1639 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1640 any other bit (they may just set this bit on its own) they
1641 want all the locally seen servers. However this bit can be
1642 set on its own so set the requested servers to be
1643 ALL - DOMAIN_ENUM. */
1645 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1646 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1649 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1650 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1652 p += 8;
1654 if (strcmp(str1, "WrLehDzz") != 0) {
1655 return false;
1657 if (!check_server_info(uLevel,str2)) {
1658 return False;
1661 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1662 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1663 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1665 if (skip_string(param,tpscnt,p) == NULL) {
1666 return False;
1668 pull_ascii_fstring(domain, p);
1669 if (domain[0] == '\0') {
1670 fstrcpy(domain, lp_workgroup());
1672 p = skip_string(param,tpscnt,p);
1673 if (skip_string(param,tpscnt,p) == NULL) {
1674 return False;
1676 pull_ascii_fstring(first_name, p);
1678 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1679 domain, first_name));
1681 if (lp_browse_list()) {
1682 total = get_server_info(servertype,&servers,domain);
1685 data_len = fixed_len = string_len = 0;
1686 missed = 0;
1688 TYPESAFE_QSORT(servers, total, srv_comp);
1690 if (first_name[0] != '\0') {
1691 struct srv_info_struct *first_server = NULL;
1693 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1694 srv_name_match, first_server);
1695 if (first_server) {
1696 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1698 * The binary search may not find the exact match
1699 * so we need to search backward to find the first match
1701 * This implements the strange matching windows
1702 * implements. (see the comment in srv_name_match().
1704 for (;first > 0;) {
1705 int ret;
1706 ret = StrCaseCmp(first_name,
1707 servers[first-1].name);
1708 if (ret > 0) {
1709 break;
1711 first--;
1713 } else {
1714 /* we should return no entries */
1715 first = total;
1720 char *lastname=NULL;
1722 for (i=first;i<total;i++) {
1723 struct srv_info_struct *s = &servers[i];
1725 if (lastname && strequal(lastname,s->name)) {
1726 continue;
1728 lastname = s->name;
1729 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1730 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1731 i, s->name, s->type, s->comment, s->domain));
1733 if (data_len < buf_len) {
1734 counted++;
1735 fixed_len += f_len;
1736 string_len += s_len;
1737 } else {
1738 missed++;
1743 *rdata_len = fixed_len + string_len;
1744 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1745 if (!*rdata) {
1746 return False;
1749 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1750 p = *rdata;
1751 f_len = fixed_len;
1752 s_len = string_len;
1755 char *lastname=NULL;
1756 int count2 = counted;
1758 for (i = first; i < total && count2;i++) {
1759 struct srv_info_struct *s = &servers[i];
1761 if (lastname && strequal(lastname,s->name)) {
1762 continue;
1764 lastname = s->name;
1765 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1766 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1767 i, s->name, s->type, s->comment, s->domain));
1768 count2--;
1772 *rparam_len = 8;
1773 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1774 if (!*rparam) {
1775 return False;
1777 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1778 SSVAL(*rparam,2,0);
1779 SSVAL(*rparam,4,counted);
1780 SSVAL(*rparam,6,counted+missed);
1782 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1783 domain,uLevel,first,first_name,
1784 first < total ? servers[first].name : "",
1785 counted,counted+missed));
1787 SAFE_FREE(servers);
1789 return True;
1792 /****************************************************************************
1793 command 0x34 - suspected of being a "Lookup Names" stub api
1794 ****************************************************************************/
1796 static bool api_RNetGroupGetUsers(struct smbd_server_connection *sconn,
1797 connection_struct *conn, uint16 vuid,
1798 char *param, int tpscnt,
1799 char *data, int tdscnt,
1800 int mdrcnt, int mprcnt, char **rdata,
1801 char **rparam, int *rdata_len, int *rparam_len)
1803 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1804 char *str2 = skip_string(param,tpscnt,str1);
1805 char *p = skip_string(param,tpscnt,str2);
1806 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1807 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1808 int counted=0;
1809 int missed=0;
1811 if (!str1 || !str2 || !p) {
1812 return False;
1815 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1816 str1, str2, p, uLevel, buf_len));
1818 if (!prefix_ok(str1,"zWrLeh")) {
1819 return False;
1822 *rdata_len = 0;
1824 *rparam_len = 8;
1825 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1826 if (!*rparam) {
1827 return False;
1830 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1831 SSVAL(*rparam,2,0);
1832 SSVAL(*rparam,4,counted);
1833 SSVAL(*rparam,6,counted+missed);
1835 return True;
1838 /****************************************************************************
1839 get info about a share
1840 ****************************************************************************/
1842 static bool check_share_info(int uLevel, char* id)
1844 switch( uLevel ) {
1845 case 0:
1846 if (strcmp(id,"B13") != 0) {
1847 return False;
1849 break;
1850 case 1:
1851 /* Level-2 descriptor is allowed (and ignored) */
1852 if (strcmp(id,"B13BWz") != 0 &&
1853 strcmp(id,"B13BWzWWWzB9B") != 0) {
1854 return False;
1856 break;
1857 case 2:
1858 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1859 return False;
1861 break;
1862 case 91:
1863 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1864 return False;
1866 break;
1867 default:
1868 return False;
1870 return True;
1873 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1874 char** buf, int* buflen,
1875 char** stringbuf, int* stringspace, char* baseaddr)
1877 int struct_len;
1878 char* p;
1879 char* p2;
1880 int l2;
1881 int len;
1883 switch( uLevel ) {
1884 case 0:
1885 struct_len = 13;
1886 break;
1887 case 1:
1888 struct_len = 20;
1889 break;
1890 case 2:
1891 struct_len = 40;
1892 break;
1893 case 91:
1894 struct_len = 68;
1895 break;
1896 default:
1897 return -1;
1900 if (!buf) {
1901 len = 0;
1903 if (uLevel > 0) {
1904 len += StrlenExpanded(conn,snum,lp_comment(snum));
1906 if (uLevel > 1) {
1907 len += strlen(lp_pathname(snum)) + 1;
1909 if (buflen) {
1910 *buflen = struct_len;
1912 if (stringspace) {
1913 *stringspace = len;
1915 return struct_len + len;
1918 len = struct_len;
1919 p = *buf;
1920 if ((*buflen) < struct_len) {
1921 return -1;
1924 if (stringbuf) {
1925 p2 = *stringbuf;
1926 l2 = *stringspace;
1927 } else {
1928 p2 = p + struct_len;
1929 l2 = (*buflen) - struct_len;
1932 if (!baseaddr) {
1933 baseaddr = p;
1936 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1938 if (uLevel > 0) {
1939 int type;
1941 SCVAL(p,13,0);
1942 type = STYPE_DISKTREE;
1943 if (lp_print_ok(snum)) {
1944 type = STYPE_PRINTQ;
1946 if (strequal("IPC",lp_fstype(snum))) {
1947 type = STYPE_IPC;
1949 SSVAL(p,14,type); /* device type */
1950 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1951 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1954 if (uLevel > 1) {
1955 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1956 SSVALS(p,22,-1); /* max uses */
1957 SSVAL(p,24,1); /* current uses */
1958 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1959 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1960 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1963 if (uLevel > 2) {
1964 memset(p+40,0,SHPWLEN+2);
1965 SSVAL(p,50,0);
1966 SIVAL(p,52,0);
1967 SSVAL(p,56,0);
1968 SSVAL(p,58,0);
1969 SIVAL(p,60,0);
1970 SSVAL(p,64,0);
1971 SSVAL(p,66,0);
1974 if (stringbuf) {
1975 (*buf) = p + struct_len;
1976 (*buflen) -= struct_len;
1977 (*stringbuf) = p2;
1978 (*stringspace) = l2;
1979 } else {
1980 (*buf) = p2;
1981 (*buflen) -= len;
1984 return len;
1987 static bool api_RNetShareGetInfo(struct smbd_server_connection *sconn,
1988 connection_struct *conn,uint16 vuid,
1989 char *param, int tpscnt,
1990 char *data, int tdscnt,
1991 int mdrcnt,int mprcnt,
1992 char **rdata,char **rparam,
1993 int *rdata_len,int *rparam_len)
1995 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1996 char *str2 = skip_string(param,tpscnt,str1);
1997 char *netname_in = skip_string(param,tpscnt,str2);
1998 char *netname = NULL;
1999 char *p = skip_string(param,tpscnt,netname);
2000 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2001 int snum;
2003 if (!str1 || !str2 || !netname || !p) {
2004 return False;
2007 snum = find_service(talloc_tos(), netname_in, &netname);
2008 if (snum < 0 || !netname) {
2009 return False;
2012 /* check it's a supported varient */
2013 if (!prefix_ok(str1,"zWrLh")) {
2014 return False;
2016 if (!check_share_info(uLevel,str2)) {
2017 return False;
2020 *rdata = smb_realloc_limit(*rdata,mdrcnt);
2021 if (!*rdata) {
2022 return False;
2024 p = *rdata;
2025 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
2026 if (*rdata_len < 0) {
2027 return False;
2030 *rparam_len = 6;
2031 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2032 if (!*rparam) {
2033 return False;
2035 SSVAL(*rparam,0,NERR_Success);
2036 SSVAL(*rparam,2,0); /* converter word */
2037 SSVAL(*rparam,4,*rdata_len);
2039 return True;
2042 /****************************************************************************
2043 View the list of available shares.
2045 This function is the server side of the NetShareEnum() RAP call.
2046 It fills the return buffer with share names and share comments.
2047 Note that the return buffer normally (in all known cases) allows only
2048 twelve byte strings for share names (plus one for a nul terminator).
2049 Share names longer than 12 bytes must be skipped.
2050 ****************************************************************************/
2052 static bool api_RNetShareEnum(struct smbd_server_connection *sconn,
2053 connection_struct *conn, uint16 vuid,
2054 char *param, int tpscnt,
2055 char *data, int tdscnt,
2056 int mdrcnt,
2057 int mprcnt,
2058 char **rdata,
2059 char **rparam,
2060 int *rdata_len,
2061 int *rparam_len )
2063 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2064 char *str2 = skip_string(param,tpscnt,str1);
2065 char *p = skip_string(param,tpscnt,str2);
2066 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2067 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
2068 char *p2;
2069 int count = 0;
2070 int total=0,counted=0;
2071 bool missed = False;
2072 int i;
2073 int data_len, fixed_len, string_len;
2074 int f_len = 0, s_len = 0;
2076 if (!str1 || !str2 || !p) {
2077 return False;
2080 if (!prefix_ok(str1,"WrLeh")) {
2081 return False;
2083 if (!check_share_info(uLevel,str2)) {
2084 return False;
2087 /* Ensure all the usershares are loaded. */
2088 become_root();
2089 load_registry_shares();
2090 count = load_usershare_shares();
2091 unbecome_root();
2093 data_len = fixed_len = string_len = 0;
2094 for (i=0;i<count;i++) {
2095 fstring servicename_dos;
2096 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2097 continue;
2099 push_ascii_fstring(servicename_dos, lp_servicename(i));
2100 /* Maximum name length = 13. */
2101 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
2102 total++;
2103 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
2104 if (data_len < buf_len) {
2105 counted++;
2106 fixed_len += f_len;
2107 string_len += s_len;
2108 } else {
2109 missed = True;
2114 *rdata_len = fixed_len + string_len;
2115 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2116 if (!*rdata) {
2117 return False;
2120 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
2121 p = *rdata;
2122 f_len = fixed_len;
2123 s_len = string_len;
2125 for( i = 0; i < count; i++ ) {
2126 fstring servicename_dos;
2127 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2128 continue;
2131 push_ascii_fstring(servicename_dos, lp_servicename(i));
2132 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2133 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2134 break;
2139 *rparam_len = 8;
2140 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2141 if (!*rparam) {
2142 return False;
2144 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2145 SSVAL(*rparam,2,0);
2146 SSVAL(*rparam,4,counted);
2147 SSVAL(*rparam,6,total);
2149 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2150 counted,total,uLevel,
2151 buf_len,*rdata_len,mdrcnt));
2153 return True;
2156 /****************************************************************************
2157 Add a share
2158 ****************************************************************************/
2160 static bool api_RNetShareAdd(struct smbd_server_connection *sconn,
2161 connection_struct *conn,uint16 vuid,
2162 char *param, int tpscnt,
2163 char *data, int tdscnt,
2164 int mdrcnt,int mprcnt,
2165 char **rdata,char **rparam,
2166 int *rdata_len,int *rparam_len)
2168 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2169 char *str2 = skip_string(param,tpscnt,str1);
2170 char *p = skip_string(param,tpscnt,str2);
2171 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2172 fstring sharename;
2173 fstring comment;
2174 char *pathname = NULL;
2175 unsigned int offset;
2176 int res = ERRunsup;
2177 size_t converted_size;
2179 WERROR werr = WERR_OK;
2180 TALLOC_CTX *mem_ctx = talloc_tos();
2181 NTSTATUS status;
2182 struct rpc_pipe_client *cli = NULL;
2183 union srvsvc_NetShareInfo info;
2184 struct srvsvc_NetShareInfo2 info2;
2186 if (!str1 || !str2 || !p) {
2187 return False;
2190 /* check it's a supported varient */
2191 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2192 return False;
2194 if (!check_share_info(uLevel,str2)) {
2195 return False;
2197 if (uLevel != 2) {
2198 return False;
2201 /* Do we have a string ? */
2202 if (skip_string(data,mdrcnt,data) == NULL) {
2203 return False;
2205 pull_ascii_fstring(sharename,data);
2207 if (mdrcnt < 28) {
2208 return False;
2211 /* only support disk share adds */
2212 if (SVAL(data,14)!=STYPE_DISKTREE) {
2213 return False;
2216 offset = IVAL(data, 16);
2217 if (offset >= mdrcnt) {
2218 res = ERRinvalidparam;
2219 goto out;
2222 /* Do we have a string ? */
2223 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2224 return False;
2226 pull_ascii_fstring(comment, offset? (data+offset) : "");
2228 offset = IVAL(data, 26);
2230 if (offset >= mdrcnt) {
2231 res = ERRinvalidparam;
2232 goto out;
2235 /* Do we have a string ? */
2236 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2237 return False;
2240 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2241 offset ? (data+offset) : "", &converted_size))
2243 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
2244 strerror(errno)));
2247 if (!pathname) {
2248 return false;
2251 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_srvsvc.syntax_id,
2252 conn->server_info,
2253 &conn->sconn->client_id,
2254 conn->sconn->msg_ctx,
2255 &cli);
2256 if (!NT_STATUS_IS_OK(status)) {
2257 DEBUG(0,("api_RNetShareAdd: could not connect to srvsvc: %s\n",
2258 nt_errstr(status)));
2259 res = W_ERROR_V(ntstatus_to_werror(status));
2260 goto out;
2263 info2.name = sharename;
2264 info2.type = STYPE_DISKTREE;
2265 info2.comment = comment;
2266 info2.permissions = 0;
2267 info2.max_users = 0;
2268 info2.current_users = 0;
2269 info2.path = pathname;
2270 info2.password = NULL;
2272 info.info2 = &info2;
2274 status = rpccli_srvsvc_NetShareAdd(cli, mem_ctx,
2275 cli->srv_name_slash,
2277 &info,
2278 NULL,
2279 &werr);
2280 if (!NT_STATUS_IS_OK(status)) {
2281 res = W_ERROR_V(ntstatus_to_werror(status));
2282 goto out;
2284 if (!W_ERROR_IS_OK(werr)) {
2285 res = W_ERROR_V(werr);
2286 goto out;
2289 *rparam_len = 6;
2290 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2291 if (!*rparam) {
2292 return False;
2294 SSVAL(*rparam,0,NERR_Success);
2295 SSVAL(*rparam,2,0); /* converter word */
2296 SSVAL(*rparam,4,*rdata_len);
2297 *rdata_len = 0;
2299 return True;
2301 out:
2303 *rparam_len = 4;
2304 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2305 if (!*rparam) {
2306 return False;
2308 *rdata_len = 0;
2309 SSVAL(*rparam,0,res);
2310 SSVAL(*rparam,2,0);
2311 return True;
2314 /****************************************************************************
2315 view list of groups available
2316 ****************************************************************************/
2318 static bool api_RNetGroupEnum(struct smbd_server_connection *sconn,
2319 connection_struct *conn,uint16 vuid,
2320 char *param, int tpscnt,
2321 char *data, int tdscnt,
2322 int mdrcnt,int mprcnt,
2323 char **rdata,char **rparam,
2324 int *rdata_len,int *rparam_len)
2326 int i;
2327 int errflags=0;
2328 int resume_context, cli_buf_size;
2329 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2330 char *str2 = skip_string(param,tpscnt,str1);
2331 char *p = skip_string(param,tpscnt,str2);
2333 uint32_t num_groups;
2334 uint32_t resume_handle;
2335 struct rpc_pipe_client *samr_pipe;
2336 struct policy_handle samr_handle, domain_handle;
2337 NTSTATUS status;
2339 if (!str1 || !str2 || !p) {
2340 return False;
2343 if (strcmp(str1,"WrLeh") != 0) {
2344 return False;
2347 /* parameters
2348 * W-> resume context (number of users to skip)
2349 * r -> return parameter pointer to receive buffer
2350 * L -> length of receive buffer
2351 * e -> return parameter number of entries
2352 * h -> return parameter total number of users
2355 if (strcmp("B21",str2) != 0) {
2356 return False;
2359 status = rpc_pipe_open_internal(
2360 talloc_tos(), &ndr_table_samr.syntax_id,
2361 conn->server_info, &conn->sconn->client_id,
2362 conn->sconn->msg_ctx, &samr_pipe);
2363 if (!NT_STATUS_IS_OK(status)) {
2364 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2365 nt_errstr(status)));
2366 return false;
2369 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2370 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2371 if (!NT_STATUS_IS_OK(status)) {
2372 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2373 nt_errstr(status)));
2374 return false;
2377 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2378 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2379 get_global_sam_sid(), &domain_handle);
2380 if (!NT_STATUS_IS_OK(status)) {
2381 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2382 nt_errstr(status)));
2383 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2384 return false;
2387 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2388 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2389 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2390 "%d\n", resume_context, cli_buf_size));
2392 *rdata_len = cli_buf_size;
2393 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2394 if (!*rdata) {
2395 return False;
2398 p = *rdata;
2400 errflags = NERR_Success;
2401 num_groups = 0;
2402 resume_handle = 0;
2404 while (true) {
2405 struct samr_SamArray *sam_entries;
2406 uint32_t num_entries;
2408 status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
2409 &domain_handle,
2410 &resume_handle,
2411 &sam_entries, 1,
2412 &num_entries);
2413 if (!NT_STATUS_IS_OK(status)) {
2414 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2415 "%s\n", nt_errstr(status)));
2416 break;
2419 if (num_entries == 0) {
2420 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2421 "no entries -- done\n"));
2422 break;
2425 for(i=0; i<num_entries; i++) {
2426 const char *name;
2428 name = sam_entries->entries[i].name.string;
2430 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2431 /* set overflow error */
2432 DEBUG(3,("overflow on entry %d group %s\n", i,
2433 name));
2434 errflags=234;
2435 break;
2438 /* truncate the name at 21 chars. */
2439 memset(p, 0, 21);
2440 strlcpy(p, name, 21);
2441 DEBUG(10,("adding entry %d group %s\n", i, p));
2442 p += 21;
2443 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2444 * idea why... */
2445 num_groups += 1;
2448 if (errflags != NERR_Success) {
2449 break;
2452 TALLOC_FREE(sam_entries);
2455 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2456 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2458 *rdata_len = PTR_DIFF(p,*rdata);
2460 *rparam_len = 8;
2461 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2462 if (!*rparam) {
2463 return False;
2465 SSVAL(*rparam, 0, errflags);
2466 SSVAL(*rparam, 2, 0); /* converter word */
2467 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2468 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2470 return(True);
2473 /*******************************************************************
2474 Get groups that a user is a member of.
2475 ******************************************************************/
2477 static bool api_NetUserGetGroups(struct smbd_server_connection *sconn,
2478 connection_struct *conn,uint16 vuid,
2479 char *param, int tpscnt,
2480 char *data, int tdscnt,
2481 int mdrcnt,int mprcnt,
2482 char **rdata,char **rparam,
2483 int *rdata_len,int *rparam_len)
2485 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2486 char *str2 = skip_string(param,tpscnt,str1);
2487 char *UserName = skip_string(param,tpscnt,str2);
2488 char *p = skip_string(param,tpscnt,UserName);
2489 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2490 const char *level_string;
2491 int count=0;
2492 bool ret = False;
2493 uint32_t i;
2494 char *endp = NULL;
2496 struct rpc_pipe_client *samr_pipe;
2497 struct policy_handle samr_handle, domain_handle, user_handle;
2498 struct lsa_String name;
2499 struct lsa_Strings names;
2500 struct samr_Ids type, rid;
2501 struct samr_RidWithAttributeArray *rids;
2502 NTSTATUS status;
2504 if (!str1 || !str2 || !UserName || !p) {
2505 return False;
2508 *rparam_len = 8;
2509 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2510 if (!*rparam) {
2511 return False;
2514 /* check it's a supported varient */
2516 if ( strcmp(str1,"zWrLeh") != 0 )
2517 return False;
2519 switch( uLevel ) {
2520 case 0:
2521 level_string = "B21";
2522 break;
2523 default:
2524 return False;
2527 if (strcmp(level_string,str2) != 0)
2528 return False;
2530 *rdata_len = mdrcnt + 1024;
2531 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2532 if (!*rdata) {
2533 return False;
2536 SSVAL(*rparam,0,NERR_Success);
2537 SSVAL(*rparam,2,0); /* converter word */
2539 p = *rdata;
2540 endp = *rdata + *rdata_len;
2542 status = rpc_pipe_open_internal(
2543 talloc_tos(), &ndr_table_samr.syntax_id,
2544 conn->server_info, &conn->sconn->client_id,
2545 conn->sconn->msg_ctx, &samr_pipe);
2546 if (!NT_STATUS_IS_OK(status)) {
2547 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2548 nt_errstr(status)));
2549 return false;
2552 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2553 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2554 if (!NT_STATUS_IS_OK(status)) {
2555 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2556 nt_errstr(status)));
2557 return false;
2560 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2561 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2562 get_global_sam_sid(), &domain_handle);
2563 if (!NT_STATUS_IS_OK(status)) {
2564 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2565 nt_errstr(status)));
2566 goto close_sam;
2569 name.string = UserName;
2571 status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
2572 &domain_handle, 1, &name,
2573 &rid, &type);
2574 if (!NT_STATUS_IS_OK(status)) {
2575 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2576 nt_errstr(status)));
2577 goto close_domain;
2580 if (type.ids[0] != SID_NAME_USER) {
2581 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2582 sid_type_lookup(type.ids[0])));
2583 goto close_domain;
2586 status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
2587 &domain_handle,
2588 SAMR_USER_ACCESS_GET_GROUPS,
2589 rid.ids[0], &user_handle);
2590 if (!NT_STATUS_IS_OK(status)) {
2591 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2592 nt_errstr(status)));
2593 goto close_domain;
2596 status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
2597 &user_handle, &rids);
2598 if (!NT_STATUS_IS_OK(status)) {
2599 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2600 nt_errstr(status)));
2601 goto close_user;
2604 for (i=0; i<rids->count; i++) {
2606 status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
2607 &domain_handle,
2608 1, &rids->rids[i].rid,
2609 &names, &type);
2610 if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
2611 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2612 p += 21;
2613 count++;
2617 *rdata_len = PTR_DIFF(p,*rdata);
2619 SSVAL(*rparam,4,count); /* is this right?? */
2620 SSVAL(*rparam,6,count); /* is this right?? */
2622 ret = True;
2624 close_user:
2625 rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
2626 close_domain:
2627 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2628 close_sam:
2629 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2631 return ret;
2634 /*******************************************************************
2635 Get all users.
2636 ******************************************************************/
2638 static bool api_RNetUserEnum(struct smbd_server_connection *sconn,
2639 connection_struct *conn, uint16 vuid,
2640 char *param, int tpscnt,
2641 char *data, int tdscnt,
2642 int mdrcnt,int mprcnt,
2643 char **rdata,char **rparam,
2644 int *rdata_len,int *rparam_len)
2646 int count_sent=0;
2647 int num_users=0;
2648 int errflags=0;
2649 int i, resume_context, cli_buf_size;
2650 uint32_t resume_handle;
2652 struct rpc_pipe_client *samr_pipe;
2653 struct policy_handle samr_handle, domain_handle;
2654 NTSTATUS status;
2656 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2657 char *str2 = skip_string(param,tpscnt,str1);
2658 char *p = skip_string(param,tpscnt,str2);
2659 char *endp = NULL;
2661 if (!str1 || !str2 || !p) {
2662 return False;
2665 if (strcmp(str1,"WrLeh") != 0)
2666 return False;
2667 /* parameters
2668 * W-> resume context (number of users to skip)
2669 * r -> return parameter pointer to receive buffer
2670 * L -> length of receive buffer
2671 * e -> return parameter number of entries
2672 * h -> return parameter total number of users
2675 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2676 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2677 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2678 resume_context, cli_buf_size));
2680 *rparam_len = 8;
2681 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2682 if (!*rparam) {
2683 return False;
2686 /* check it's a supported varient */
2687 if (strcmp("B21",str2) != 0)
2688 return False;
2690 *rdata_len = cli_buf_size;
2691 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2692 if (!*rdata) {
2693 return False;
2696 p = *rdata;
2697 endp = *rdata + *rdata_len;
2699 status = rpc_pipe_open_internal(
2700 talloc_tos(), &ndr_table_samr.syntax_id,
2701 conn->server_info, &conn->sconn->client_id,
2702 conn->sconn->msg_ctx, &samr_pipe);
2703 if (!NT_STATUS_IS_OK(status)) {
2704 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2705 nt_errstr(status)));
2706 return false;
2709 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2710 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2711 if (!NT_STATUS_IS_OK(status)) {
2712 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2713 nt_errstr(status)));
2714 return false;
2717 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2718 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2719 get_global_sam_sid(), &domain_handle);
2720 if (!NT_STATUS_IS_OK(status)) {
2721 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2722 nt_errstr(status)));
2723 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2724 return false;
2727 errflags=NERR_Success;
2729 resume_handle = 0;
2731 while (true) {
2732 struct samr_SamArray *sam_entries;
2733 uint32_t num_entries;
2735 status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
2736 &domain_handle,
2737 &resume_handle,
2738 0, &sam_entries, 1,
2739 &num_entries);
2741 if (!NT_STATUS_IS_OK(status)) {
2742 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2743 "%s\n", nt_errstr(status)));
2744 break;
2747 if (num_entries == 0) {
2748 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2749 "no entries -- done\n"));
2750 break;
2753 for (i=0; i<num_entries; i++) {
2754 const char *name;
2756 name = sam_entries->entries[i].name.string;
2758 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2759 &&(strlen(name)<=21)) {
2760 strlcpy(p,name,PTR_DIFF(endp,p));
2761 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2762 "username %s\n",count_sent,p));
2763 p += 21;
2764 count_sent++;
2765 } else {
2766 /* set overflow error */
2767 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2768 "username %s\n",count_sent,name));
2769 errflags=234;
2770 break;
2774 if (errflags != NERR_Success) {
2775 break;
2778 TALLOC_FREE(sam_entries);
2781 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2782 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2784 *rdata_len = PTR_DIFF(p,*rdata);
2786 SSVAL(*rparam,0,errflags);
2787 SSVAL(*rparam,2,0); /* converter word */
2788 SSVAL(*rparam,4,count_sent); /* is this right?? */
2789 SSVAL(*rparam,6,num_users); /* is this right?? */
2791 return True;
2794 /****************************************************************************
2795 Get the time of day info.
2796 ****************************************************************************/
2798 static bool api_NetRemoteTOD(struct smbd_server_connection *sconn,
2799 connection_struct *conn,uint16 vuid,
2800 char *param, int tpscnt,
2801 char *data, int tdscnt,
2802 int mdrcnt,int mprcnt,
2803 char **rdata,char **rparam,
2804 int *rdata_len,int *rparam_len)
2806 struct tm *t;
2807 time_t unixdate = time(NULL);
2808 char *p;
2810 *rparam_len = 4;
2811 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2812 if (!*rparam) {
2813 return False;
2816 *rdata_len = 21;
2817 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2818 if (!*rdata) {
2819 return False;
2822 SSVAL(*rparam,0,NERR_Success);
2823 SSVAL(*rparam,2,0); /* converter word */
2825 p = *rdata;
2827 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2828 by NT in a "net time" operation,
2829 it seems to ignore the one below */
2831 /* the client expects to get localtime, not GMT, in this bit
2832 (I think, this needs testing) */
2833 t = localtime(&unixdate);
2834 if (!t) {
2835 return False;
2838 SIVAL(p,4,0); /* msecs ? */
2839 SCVAL(p,8,t->tm_hour);
2840 SCVAL(p,9,t->tm_min);
2841 SCVAL(p,10,t->tm_sec);
2842 SCVAL(p,11,0); /* hundredths of seconds */
2843 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2844 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2845 SCVAL(p,16,t->tm_mday);
2846 SCVAL(p,17,t->tm_mon + 1);
2847 SSVAL(p,18,1900+t->tm_year);
2848 SCVAL(p,20,t->tm_wday);
2850 return True;
2853 /****************************************************************************
2854 Set the user password.
2855 *****************************************************************************/
2857 static bool api_SetUserPassword(struct smbd_server_connection *sconn,
2858 connection_struct *conn,uint16 vuid,
2859 char *param, int tpscnt,
2860 char *data, int tdscnt,
2861 int mdrcnt,int mprcnt,
2862 char **rdata,char **rparam,
2863 int *rdata_len,int *rparam_len)
2865 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2866 char *p = NULL;
2867 fstring user;
2868 fstring pass1,pass2;
2869 TALLOC_CTX *mem_ctx = talloc_tos();
2870 NTSTATUS status;
2871 struct rpc_pipe_client *cli = NULL;
2872 struct policy_handle connect_handle, domain_handle, user_handle;
2873 struct lsa_String domain_name;
2874 struct dom_sid2 *domain_sid;
2875 struct lsa_String names;
2876 struct samr_Ids rids;
2877 struct samr_Ids types;
2878 struct samr_Password old_lm_hash;
2879 struct samr_Password new_lm_hash;
2880 int errcode = NERR_badpass;
2881 uint32_t rid;
2882 int encrypted;
2883 int min_pwd_length;
2885 /* Skip 2 strings. */
2886 p = skip_string(param,tpscnt,np);
2887 p = skip_string(param,tpscnt,p);
2889 if (!np || !p) {
2890 return False;
2893 /* Do we have a string ? */
2894 if (skip_string(param,tpscnt,p) == NULL) {
2895 return False;
2897 pull_ascii_fstring(user,p);
2899 p = skip_string(param,tpscnt,p);
2900 if (!p) {
2901 return False;
2904 memset(pass1,'\0',sizeof(pass1));
2905 memset(pass2,'\0',sizeof(pass2));
2907 * We use 31 here not 32 as we're checking
2908 * the last byte we want to access is safe.
2910 if (!is_offset_safe(param,tpscnt,p,31)) {
2911 return False;
2913 memcpy(pass1,p,16);
2914 memcpy(pass2,p+16,16);
2916 encrypted = get_safe_SVAL(param,tpscnt,p+32,0,-1);
2917 if (encrypted == -1) {
2918 errcode = W_ERROR_V(WERR_INVALID_PARAM);
2919 goto out;
2922 min_pwd_length = get_safe_SVAL(param,tpscnt,p+34,0,-1);
2923 if (min_pwd_length == -1) {
2924 errcode = W_ERROR_V(WERR_INVALID_PARAM);
2925 goto out;
2928 *rparam_len = 4;
2929 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2930 if (!*rparam) {
2931 return False;
2934 *rdata_len = 0;
2936 DEBUG(3,("Set password for <%s> (encrypted: %d, min_pwd_length: %d)\n",
2937 user, encrypted, min_pwd_length));
2939 ZERO_STRUCT(connect_handle);
2940 ZERO_STRUCT(domain_handle);
2941 ZERO_STRUCT(user_handle);
2943 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_samr.syntax_id,
2944 conn->server_info,
2945 &conn->sconn->client_id,
2946 conn->sconn->msg_ctx,
2947 &cli);
2948 if (!NT_STATUS_IS_OK(status)) {
2949 DEBUG(0,("api_SetUserPassword: could not connect to samr: %s\n",
2950 nt_errstr(status)));
2951 errcode = W_ERROR_V(ntstatus_to_werror(status));
2952 goto out;
2955 status = rpccli_samr_Connect2(cli, mem_ctx,
2956 global_myname(),
2957 SAMR_ACCESS_CONNECT_TO_SERVER |
2958 SAMR_ACCESS_ENUM_DOMAINS |
2959 SAMR_ACCESS_LOOKUP_DOMAIN,
2960 &connect_handle);
2961 if (!NT_STATUS_IS_OK(status)) {
2962 errcode = W_ERROR_V(ntstatus_to_werror(status));
2963 goto out;
2966 init_lsa_String(&domain_name, get_global_sam_name());
2968 status = rpccli_samr_LookupDomain(cli, mem_ctx,
2969 &connect_handle,
2970 &domain_name,
2971 &domain_sid);
2972 if (!NT_STATUS_IS_OK(status)) {
2973 errcode = W_ERROR_V(ntstatus_to_werror(status));
2974 goto out;
2977 status = rpccli_samr_OpenDomain(cli, mem_ctx,
2978 &connect_handle,
2979 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2980 domain_sid,
2981 &domain_handle);
2982 if (!NT_STATUS_IS_OK(status)) {
2983 errcode = W_ERROR_V(ntstatus_to_werror(status));
2984 goto out;
2987 init_lsa_String(&names, user);
2989 status = rpccli_samr_LookupNames(cli, mem_ctx,
2990 &domain_handle,
2992 &names,
2993 &rids,
2994 &types);
2995 if (!NT_STATUS_IS_OK(status)) {
2996 errcode = W_ERROR_V(ntstatus_to_werror(status));
2997 goto out;
3000 if (rids.count != 1) {
3001 errcode = W_ERROR_V(WERR_NO_SUCH_USER);
3002 goto out;
3004 if (rids.count != types.count) {
3005 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3006 goto out;
3008 if (types.ids[0] != SID_NAME_USER) {
3009 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3010 goto out;
3013 rid = rids.ids[0];
3015 status = rpccli_samr_OpenUser(cli, mem_ctx,
3016 &domain_handle,
3017 SAMR_USER_ACCESS_CHANGE_PASSWORD,
3018 rid,
3019 &user_handle);
3020 if (!NT_STATUS_IS_OK(status)) {
3021 errcode = W_ERROR_V(ntstatus_to_werror(status));
3022 goto out;
3025 if (encrypted == 0) {
3026 E_deshash(pass1, old_lm_hash.hash);
3027 E_deshash(pass2, new_lm_hash.hash);
3028 } else {
3029 ZERO_STRUCT(old_lm_hash);
3030 ZERO_STRUCT(new_lm_hash);
3031 memcpy(old_lm_hash.hash, pass1, MIN(strlen(pass1), 16));
3032 memcpy(new_lm_hash.hash, pass1, MIN(strlen(pass2), 16));
3035 status = rpccli_samr_ChangePasswordUser(cli, mem_ctx,
3036 &user_handle,
3037 true, /* lm_present */
3038 &old_lm_hash,
3039 &new_lm_hash,
3040 false, /* nt_present */
3041 NULL, /* old_nt_crypted */
3042 NULL, /* new_nt_crypted */
3043 false, /* cross1_present */
3044 NULL, /* nt_cross */
3045 false, /* cross2_present */
3046 NULL); /* lm_cross */
3047 if (!NT_STATUS_IS_OK(status)) {
3048 errcode = W_ERROR_V(ntstatus_to_werror(status));
3049 goto out;
3052 errcode = NERR_Success;
3053 out:
3055 if (cli && is_valid_policy_hnd(&user_handle)) {
3056 rpccli_samr_Close(cli, mem_ctx, &user_handle);
3058 if (cli && is_valid_policy_hnd(&domain_handle)) {
3059 rpccli_samr_Close(cli, mem_ctx, &domain_handle);
3061 if (cli && is_valid_policy_hnd(&connect_handle)) {
3062 rpccli_samr_Close(cli, mem_ctx, &connect_handle);
3065 memset((char *)pass1,'\0',sizeof(fstring));
3066 memset((char *)pass2,'\0',sizeof(fstring));
3068 SSVAL(*rparam,0,errcode);
3069 SSVAL(*rparam,2,0); /* converter word */
3070 return(True);
3073 /****************************************************************************
3074 Set the user password (SamOEM version - gets plaintext).
3075 ****************************************************************************/
3077 static bool api_SamOEMChangePassword(struct smbd_server_connection *sconn,
3078 connection_struct *conn,uint16 vuid,
3079 char *param, int tpscnt,
3080 char *data, int tdscnt,
3081 int mdrcnt,int mprcnt,
3082 char **rdata,char **rparam,
3083 int *rdata_len,int *rparam_len)
3085 fstring user;
3086 char *p = get_safe_str_ptr(param,tpscnt,param,2);
3088 TALLOC_CTX *mem_ctx = talloc_tos();
3089 NTSTATUS status;
3090 struct rpc_pipe_client *cli = NULL;
3091 struct lsa_AsciiString server, account;
3092 struct samr_CryptPassword password;
3093 struct samr_Password hash;
3094 int errcode = NERR_badpass;
3095 int bufsize;
3097 *rparam_len = 4;
3098 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3099 if (!*rparam) {
3100 return False;
3103 if (!p) {
3104 return False;
3106 *rdata_len = 0;
3108 SSVAL(*rparam,0,NERR_badpass);
3111 * Check the parameter definition is correct.
3114 /* Do we have a string ? */
3115 if (skip_string(param,tpscnt,p) == 0) {
3116 return False;
3118 if(!strequal(p, "zsT")) {
3119 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
3120 return False;
3122 p = skip_string(param, tpscnt, p);
3123 if (!p) {
3124 return False;
3127 /* Do we have a string ? */
3128 if (skip_string(param,tpscnt,p) == 0) {
3129 return False;
3131 if(!strequal(p, "B516B16")) {
3132 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
3133 return False;
3135 p = skip_string(param,tpscnt,p);
3136 if (!p) {
3137 return False;
3139 /* Do we have a string ? */
3140 if (skip_string(param,tpscnt,p) == 0) {
3141 return False;
3143 p += pull_ascii_fstring(user,p);
3145 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
3147 if (tdscnt != 532) {
3148 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3149 goto out;
3152 bufsize = get_safe_SVAL(param,tpscnt,p,0,-1);
3153 if (bufsize != 532) {
3154 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3155 goto out;
3158 memcpy(password.data, data, 516);
3159 memcpy(hash.hash, data+516, 16);
3161 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_samr.syntax_id,
3162 conn->server_info,
3163 &conn->sconn->client_id,
3164 conn->sconn->msg_ctx,
3165 &cli);
3166 if (!NT_STATUS_IS_OK(status)) {
3167 DEBUG(0,("api_SamOEMChangePassword: could not connect to samr: %s\n",
3168 nt_errstr(status)));
3169 errcode = W_ERROR_V(ntstatus_to_werror(status));
3170 goto out;
3173 init_lsa_AsciiString(&server, global_myname());
3174 init_lsa_AsciiString(&account, user);
3176 status = rpccli_samr_OemChangePasswordUser2(cli, mem_ctx,
3177 &server,
3178 &account,
3179 &password,
3180 &hash);
3181 if (!NT_STATUS_IS_OK(status)) {
3182 errcode = W_ERROR_V(ntstatus_to_werror(status));
3183 goto out;
3186 errcode = NERR_Success;
3187 out:
3188 SSVAL(*rparam,0,errcode);
3189 SSVAL(*rparam,2,0); /* converter word */
3191 return(True);
3194 /****************************************************************************
3195 delete a print job
3196 Form: <W> <>
3197 ****************************************************************************/
3199 static bool api_RDosPrintJobDel(struct smbd_server_connection *sconn,
3200 connection_struct *conn,uint16 vuid,
3201 char *param, int tpscnt,
3202 char *data, int tdscnt,
3203 int mdrcnt,int mprcnt,
3204 char **rdata,char **rparam,
3205 int *rdata_len,int *rparam_len)
3207 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3208 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3209 char *str2 = skip_string(param,tpscnt,str1);
3210 char *p = skip_string(param,tpscnt,str2);
3211 uint32 jobid;
3212 fstring sharename;
3213 int errcode;
3214 WERROR werr = WERR_OK;
3216 TALLOC_CTX *mem_ctx = talloc_tos();
3217 NTSTATUS status;
3218 struct rpc_pipe_client *cli = NULL;
3219 struct policy_handle handle;
3220 struct spoolss_DevmodeContainer devmode_ctr;
3221 enum spoolss_JobControl command;
3223 if (!str1 || !str2 || !p) {
3224 return False;
3227 * We use 1 here not 2 as we're checking
3228 * the last byte we want to access is safe.
3230 if (!is_offset_safe(param,tpscnt,p,1)) {
3231 return False;
3233 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3234 return False;
3236 /* check it's a supported varient */
3237 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
3238 return(False);
3240 *rparam_len = 4;
3241 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3242 if (!*rparam) {
3243 return False;
3245 *rdata_len = 0;
3247 ZERO_STRUCT(handle);
3249 status = rpc_pipe_open_interface(conn,
3250 &ndr_table_spoolss.syntax_id,
3251 conn->server_info,
3252 &conn->sconn->client_id,
3253 conn->sconn->msg_ctx,
3254 &cli);
3255 if (!NT_STATUS_IS_OK(status)) {
3256 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
3257 nt_errstr(status)));
3258 errcode = W_ERROR_V(ntstatus_to_werror(status));
3259 goto out;
3262 ZERO_STRUCT(devmode_ctr);
3264 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3265 sharename,
3266 "RAW",
3267 devmode_ctr,
3268 JOB_ACCESS_ADMINISTER,
3269 &handle,
3270 &werr);
3271 if (!NT_STATUS_IS_OK(status)) {
3272 errcode = W_ERROR_V(ntstatus_to_werror(status));
3273 goto out;
3275 if (!W_ERROR_IS_OK(werr)) {
3276 errcode = W_ERROR_V(werr);
3277 goto out;
3280 /* FIXME: formerly NERR_JobNotFound was returned if job did not exist
3281 * and NERR_DestNotFound if share did not exist */
3283 errcode = NERR_Success;
3285 switch (function) {
3286 case 81: /* delete */
3287 command = SPOOLSS_JOB_CONTROL_DELETE;
3288 break;
3289 case 82: /* pause */
3290 command = SPOOLSS_JOB_CONTROL_PAUSE;
3291 break;
3292 case 83: /* resume */
3293 command = SPOOLSS_JOB_CONTROL_RESUME;
3294 break;
3295 default:
3296 errcode = NERR_notsupported;
3297 goto out;
3300 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3301 &handle,
3302 jobid,
3303 NULL, /* unique ptr ctr */
3304 command,
3305 &werr);
3306 if (!NT_STATUS_IS_OK(status)) {
3307 errcode = W_ERROR_V(ntstatus_to_werror(status));
3308 goto out;
3310 if (!W_ERROR_IS_OK(werr)) {
3311 errcode = W_ERROR_V(werr);
3312 goto out;
3315 out:
3316 if (cli && is_valid_policy_hnd(&handle)) {
3317 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3320 SSVAL(*rparam,0,errcode);
3321 SSVAL(*rparam,2,0); /* converter word */
3323 return(True);
3326 /****************************************************************************
3327 Purge a print queue - or pause or resume it.
3328 ****************************************************************************/
3330 static bool api_WPrintQueueCtrl(struct smbd_server_connection *sconn,
3331 connection_struct *conn,uint16 vuid,
3332 char *param, int tpscnt,
3333 char *data, int tdscnt,
3334 int mdrcnt,int mprcnt,
3335 char **rdata,char **rparam,
3336 int *rdata_len,int *rparam_len)
3338 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3339 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3340 char *str2 = skip_string(param,tpscnt,str1);
3341 char *QueueName = skip_string(param,tpscnt,str2);
3342 int errcode = NERR_notsupported;
3343 WERROR werr = WERR_OK;
3344 NTSTATUS status;
3346 TALLOC_CTX *mem_ctx = talloc_tos();
3347 struct rpc_pipe_client *cli = NULL;
3348 struct policy_handle handle;
3349 struct spoolss_SetPrinterInfoCtr info_ctr;
3350 struct spoolss_DevmodeContainer devmode_ctr;
3351 struct sec_desc_buf secdesc_ctr;
3352 enum spoolss_PrinterControl command;
3354 if (!str1 || !str2 || !QueueName) {
3355 return False;
3358 /* check it's a supported varient */
3359 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3360 return(False);
3362 *rparam_len = 4;
3363 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3364 if (!*rparam) {
3365 return False;
3367 *rdata_len = 0;
3369 if (skip_string(param,tpscnt,QueueName) == NULL) {
3370 return False;
3373 ZERO_STRUCT(handle);
3375 status = rpc_pipe_open_interface(conn,
3376 &ndr_table_spoolss.syntax_id,
3377 conn->server_info,
3378 &conn->sconn->client_id,
3379 conn->sconn->msg_ctx,
3380 &cli);
3381 if (!NT_STATUS_IS_OK(status)) {
3382 DEBUG(0,("api_WPrintQueueCtrl: could not connect to spoolss: %s\n",
3383 nt_errstr(status)));
3384 errcode = W_ERROR_V(ntstatus_to_werror(status));
3385 goto out;
3388 ZERO_STRUCT(devmode_ctr);
3390 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3391 QueueName,
3392 NULL,
3393 devmode_ctr,
3394 SEC_FLAG_MAXIMUM_ALLOWED,
3395 &handle,
3396 &werr);
3397 if (!NT_STATUS_IS_OK(status)) {
3398 errcode = W_ERROR_V(ntstatus_to_werror(status));
3399 goto out;
3401 if (!W_ERROR_IS_OK(werr)) {
3402 errcode = W_ERROR_V(werr);
3403 goto out;
3406 switch (function) {
3407 case 74: /* Pause queue */
3408 command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3409 break;
3410 case 75: /* Resume queue */
3411 command = SPOOLSS_PRINTER_CONTROL_RESUME;
3412 break;
3413 case 103: /* Purge */
3414 command = SPOOLSS_PRINTER_CONTROL_PURGE;
3415 break;
3416 default:
3417 werr = WERR_NOT_SUPPORTED;
3418 break;
3421 if (!W_ERROR_IS_OK(werr)) {
3422 errcode = W_ERROR_V(werr);
3423 goto out;
3426 ZERO_STRUCT(info_ctr);
3427 ZERO_STRUCT(secdesc_ctr);
3429 status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
3430 &handle,
3431 &info_ctr,
3432 &devmode_ctr,
3433 &secdesc_ctr,
3434 command,
3435 &werr);
3436 if (!NT_STATUS_IS_OK(status)) {
3437 errcode = W_ERROR_V(ntstatus_to_werror(status));
3438 goto out;
3440 if (!W_ERROR_IS_OK(werr)) {
3441 errcode = W_ERROR_V(werr);
3442 goto out;
3445 errcode = W_ERROR_V(werr);
3447 out:
3449 if (cli && is_valid_policy_hnd(&handle)) {
3450 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3453 SSVAL(*rparam,0,errcode);
3454 SSVAL(*rparam,2,0); /* converter word */
3456 return(True);
3459 /****************************************************************************
3460 set the property of a print job (undocumented?)
3461 ? function = 0xb -> set name of print job
3462 ? function = 0x6 -> move print job up/down
3463 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3464 or <WWsTP> <WB21BB16B10zWWzDDz>
3465 ****************************************************************************/
3467 static int check_printjob_info(struct pack_desc* desc,
3468 int uLevel, char* id)
3470 desc->subformat = NULL;
3471 switch( uLevel ) {
3472 case 0: desc->format = "W"; break;
3473 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3474 case 2: desc->format = "WWzWWDDzz"; break;
3475 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3476 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3477 default:
3478 DEBUG(0,("check_printjob_info: invalid level %d\n",
3479 uLevel ));
3480 return False;
3482 if (id == NULL || strcmp(desc->format,id) != 0) {
3483 DEBUG(0,("check_printjob_info: invalid format %s\n",
3484 id ? id : "<NULL>" ));
3485 return False;
3487 return True;
3490 static bool api_PrintJobInfo(struct smbd_server_connection *sconn,
3491 connection_struct *conn, uint16 vuid,
3492 char *param, int tpscnt,
3493 char *data, int tdscnt,
3494 int mdrcnt,int mprcnt,
3495 char **rdata,char **rparam,
3496 int *rdata_len,int *rparam_len)
3498 struct pack_desc desc;
3499 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3500 char *str2 = skip_string(param,tpscnt,str1);
3501 char *p = skip_string(param,tpscnt,str2);
3502 uint32 jobid;
3503 fstring sharename;
3504 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3505 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3506 int errcode;
3508 TALLOC_CTX *mem_ctx = talloc_tos();
3509 WERROR werr;
3510 NTSTATUS status;
3511 struct rpc_pipe_client *cli = NULL;
3512 struct policy_handle handle;
3513 struct spoolss_DevmodeContainer devmode_ctr;
3514 struct spoolss_JobInfoContainer ctr;
3515 union spoolss_JobInfo info;
3516 struct spoolss_SetJobInfo1 info1;
3518 if (!str1 || !str2 || !p) {
3519 return False;
3522 * We use 1 here not 2 as we're checking
3523 * the last byte we want to access is safe.
3525 if (!is_offset_safe(param,tpscnt,p,1)) {
3526 return False;
3528 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3529 return False;
3530 *rparam_len = 4;
3531 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3532 if (!*rparam) {
3533 return False;
3536 *rdata_len = 0;
3538 /* check it's a supported varient */
3539 if ((strcmp(str1,"WWsTP")) ||
3540 (!check_printjob_info(&desc,uLevel,str2)))
3541 return(False);
3543 errcode = NERR_notsupported;
3545 switch (function) {
3546 case 0xb:
3547 /* change print job name, data gives the name */
3548 break;
3549 default:
3550 goto out;
3553 ZERO_STRUCT(handle);
3555 status = rpc_pipe_open_interface(conn,
3556 &ndr_table_spoolss.syntax_id,
3557 conn->server_info,
3558 &conn->sconn->client_id,
3559 conn->sconn->msg_ctx,
3560 &cli);
3561 if (!NT_STATUS_IS_OK(status)) {
3562 DEBUG(0,("api_PrintJobInfo: could not connect to spoolss: %s\n",
3563 nt_errstr(status)));
3564 errcode = W_ERROR_V(ntstatus_to_werror(status));
3565 goto out;
3568 ZERO_STRUCT(devmode_ctr);
3570 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3571 sharename,
3572 "RAW",
3573 devmode_ctr,
3574 PRINTER_ACCESS_USE,
3575 &handle,
3576 &werr);
3577 if (!NT_STATUS_IS_OK(status)) {
3578 errcode = W_ERROR_V(ntstatus_to_werror(status));
3579 goto out;
3581 if (!W_ERROR_IS_OK(werr)) {
3582 errcode = W_ERROR_V(werr);
3583 goto out;
3586 werr = rpccli_spoolss_getjob(cli, mem_ctx,
3587 &handle,
3588 jobid,
3589 1, /* level */
3590 0, /* offered */
3591 &info);
3592 if (!W_ERROR_IS_OK(werr)) {
3593 errcode = W_ERROR_V(werr);
3594 goto out;
3597 ZERO_STRUCT(ctr);
3599 info1.job_id = info.info1.job_id;
3600 info1.printer_name = info.info1.printer_name;
3601 info1.user_name = info.info1.user_name;
3602 info1.document_name = data;
3603 info1.data_type = info.info1.data_type;
3604 info1.text_status = info.info1.text_status;
3605 info1.status = info.info1.status;
3606 info1.priority = info.info1.priority;
3607 info1.position = info.info1.position;
3608 info1.total_pages = info.info1.total_pages;
3609 info1.pages_printed = info.info1.pages_printed;
3610 info1.submitted = info.info1.submitted;
3612 ctr.level = 1;
3613 ctr.info.info1 = &info1;
3615 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3616 &handle,
3617 jobid,
3618 &ctr,
3620 &werr);
3621 if (!NT_STATUS_IS_OK(status)) {
3622 errcode = W_ERROR_V(ntstatus_to_werror(status));
3623 goto out;
3625 if (!W_ERROR_IS_OK(werr)) {
3626 errcode = W_ERROR_V(werr);
3627 goto out;
3630 errcode = NERR_Success;
3631 out:
3633 if (cli && is_valid_policy_hnd(&handle)) {
3634 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3637 SSVALS(*rparam,0,errcode);
3638 SSVAL(*rparam,2,0); /* converter word */
3640 return(True);
3644 /****************************************************************************
3645 Get info about the server.
3646 ****************************************************************************/
3648 static bool api_RNetServerGetInfo(struct smbd_server_connection *sconn,
3649 connection_struct *conn,uint16 vuid,
3650 char *param, int tpscnt,
3651 char *data, int tdscnt,
3652 int mdrcnt,int mprcnt,
3653 char **rdata,char **rparam,
3654 int *rdata_len,int *rparam_len)
3656 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3657 char *str2 = skip_string(param,tpscnt,str1);
3658 char *p = skip_string(param,tpscnt,str2);
3659 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3660 char *p2;
3661 int struct_len;
3663 NTSTATUS status;
3664 WERROR werr;
3665 TALLOC_CTX *mem_ctx = talloc_tos();
3666 struct rpc_pipe_client *cli = NULL;
3667 union srvsvc_NetSrvInfo info;
3668 int errcode;
3670 if (!str1 || !str2 || !p) {
3671 return False;
3674 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3676 /* check it's a supported varient */
3677 if (!prefix_ok(str1,"WrLh")) {
3678 return False;
3681 switch( uLevel ) {
3682 case 0:
3683 if (strcmp(str2,"B16") != 0) {
3684 return False;
3686 struct_len = 16;
3687 break;
3688 case 1:
3689 if (strcmp(str2,"B16BBDz") != 0) {
3690 return False;
3692 struct_len = 26;
3693 break;
3694 case 2:
3695 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3696 return False;
3698 struct_len = 134;
3699 break;
3700 case 3:
3701 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3702 return False;
3704 struct_len = 144;
3705 break;
3706 case 20:
3707 if (strcmp(str2,"DN") != 0) {
3708 return False;
3710 struct_len = 6;
3711 break;
3712 case 50:
3713 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3714 return False;
3716 struct_len = 42;
3717 break;
3718 default:
3719 return False;
3722 *rdata_len = mdrcnt;
3723 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3724 if (!*rdata) {
3725 return False;
3728 p = *rdata;
3729 p2 = p + struct_len;
3731 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_srvsvc.syntax_id,
3732 conn->server_info,
3733 &conn->sconn->client_id,
3734 conn->sconn->msg_ctx,
3735 &cli);
3736 if (!NT_STATUS_IS_OK(status)) {
3737 DEBUG(0,("api_RNetServerGetInfo: could not connect to srvsvc: %s\n",
3738 nt_errstr(status)));
3739 errcode = W_ERROR_V(ntstatus_to_werror(status));
3740 goto out;
3743 status = rpccli_srvsvc_NetSrvGetInfo(cli, mem_ctx,
3744 NULL,
3745 101,
3746 &info,
3747 &werr);
3748 if (!NT_STATUS_IS_OK(status)) {
3749 errcode = W_ERROR_V(ntstatus_to_werror(status));
3750 goto out;
3752 if (!W_ERROR_IS_OK(werr)) {
3753 errcode = W_ERROR_V(werr);
3754 goto out;
3757 if (info.info101 == NULL) {
3758 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3759 goto out;
3762 if (uLevel != 20) {
3763 srvstr_push(NULL, 0, p, info.info101->server_name, 16,
3764 STR_ASCII|STR_UPPER|STR_TERMINATE);
3766 p += 16;
3767 if (uLevel > 0) {
3768 SCVAL(p,0,info.info101->version_major);
3769 SCVAL(p,1,info.info101->version_minor);
3770 SIVAL(p,2,info.info101->server_type);
3772 if (mdrcnt == struct_len) {
3773 SIVAL(p,6,0);
3774 } else {
3775 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3776 if (mdrcnt - struct_len <= 0) {
3777 return false;
3779 push_ascii(p2,
3780 info.info101->comment,
3781 MIN(mdrcnt - struct_len,
3782 MAX_SERVER_STRING_LENGTH),
3783 STR_TERMINATE);
3784 p2 = skip_string(*rdata,*rdata_len,p2);
3785 if (!p2) {
3786 return False;
3791 if (uLevel > 1) {
3792 return False; /* not yet implemented */
3795 errcode = NERR_Success;
3797 out:
3799 *rdata_len = PTR_DIFF(p2,*rdata);
3801 *rparam_len = 6;
3802 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3803 if (!*rparam) {
3804 return False;
3806 SSVAL(*rparam,0,errcode);
3807 SSVAL(*rparam,2,0); /* converter word */
3808 SSVAL(*rparam,4,*rdata_len);
3810 return True;
3813 /****************************************************************************
3814 Get info about the server.
3815 ****************************************************************************/
3817 static bool api_NetWkstaGetInfo(struct smbd_server_connection *sconn,
3818 connection_struct *conn,uint16 vuid,
3819 char *param, int tpscnt,
3820 char *data, int tdscnt,
3821 int mdrcnt,int mprcnt,
3822 char **rdata,char **rparam,
3823 int *rdata_len,int *rparam_len)
3825 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3826 char *str2 = skip_string(param,tpscnt,str1);
3827 char *p = skip_string(param,tpscnt,str2);
3828 char *p2;
3829 char *endp;
3830 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3832 if (!str1 || !str2 || !p) {
3833 return False;
3836 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3838 *rparam_len = 6;
3839 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3840 if (!*rparam) {
3841 return False;
3844 /* check it's a supported varient */
3845 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3846 return False;
3849 *rdata_len = mdrcnt + 1024;
3850 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3851 if (!*rdata) {
3852 return False;
3855 SSVAL(*rparam,0,NERR_Success);
3856 SSVAL(*rparam,2,0); /* converter word */
3858 p = *rdata;
3859 endp = *rdata + *rdata_len;
3861 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3862 if (!p2) {
3863 return False;
3866 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3867 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3868 strupper_m(p2);
3869 p2 = skip_string(*rdata,*rdata_len,p2);
3870 if (!p2) {
3871 return False;
3873 p += 4;
3875 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3876 strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3877 p2 = skip_string(*rdata,*rdata_len,p2);
3878 if (!p2) {
3879 return False;
3881 p += 4;
3883 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3884 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3885 strupper_m(p2);
3886 p2 = skip_string(*rdata,*rdata_len,p2);
3887 if (!p2) {
3888 return False;
3890 p += 4;
3892 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3893 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3894 p += 2;
3896 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3897 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3898 p2 = skip_string(*rdata,*rdata_len,p2);
3899 if (!p2) {
3900 return False;
3902 p += 4;
3904 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3905 strlcpy(p2,"",PTR_DIFF(endp,p2));
3906 p2 = skip_string(*rdata,*rdata_len,p2);
3907 if (!p2) {
3908 return False;
3910 p += 4;
3912 *rdata_len = PTR_DIFF(p2,*rdata);
3914 SSVAL(*rparam,4,*rdata_len);
3916 return True;
3919 /****************************************************************************
3920 get info about a user
3922 struct user_info_11 {
3923 char usri11_name[21]; 0-20
3924 char usri11_pad; 21
3925 char *usri11_comment; 22-25
3926 char *usri11_usr_comment; 26-29
3927 unsigned short usri11_priv; 30-31
3928 unsigned long usri11_auth_flags; 32-35
3929 long usri11_password_age; 36-39
3930 char *usri11_homedir; 40-43
3931 char *usri11_parms; 44-47
3932 long usri11_last_logon; 48-51
3933 long usri11_last_logoff; 52-55
3934 unsigned short usri11_bad_pw_count; 56-57
3935 unsigned short usri11_num_logons; 58-59
3936 char *usri11_logon_server; 60-63
3937 unsigned short usri11_country_code; 64-65
3938 char *usri11_workstations; 66-69
3939 unsigned long usri11_max_storage; 70-73
3940 unsigned short usri11_units_per_week; 74-75
3941 unsigned char *usri11_logon_hours; 76-79
3942 unsigned short usri11_code_page; 80-81
3945 where:
3947 usri11_name specifies the user name for which information is retrieved
3949 usri11_pad aligns the next data structure element to a word boundary
3951 usri11_comment is a null terminated ASCII comment
3953 usri11_user_comment is a null terminated ASCII comment about the user
3955 usri11_priv specifies the level of the privilege assigned to the user.
3956 The possible values are:
3958 Name Value Description
3959 USER_PRIV_GUEST 0 Guest privilege
3960 USER_PRIV_USER 1 User privilege
3961 USER_PRV_ADMIN 2 Administrator privilege
3963 usri11_auth_flags specifies the account operator privileges. The
3964 possible values are:
3966 Name Value Description
3967 AF_OP_PRINT 0 Print operator
3970 Leach, Naik [Page 28]
3974 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3977 AF_OP_COMM 1 Communications operator
3978 AF_OP_SERVER 2 Server operator
3979 AF_OP_ACCOUNTS 3 Accounts operator
3982 usri11_password_age specifies how many seconds have elapsed since the
3983 password was last changed.
3985 usri11_home_dir points to a null terminated ASCII string that contains
3986 the path name of the user's home directory.
3988 usri11_parms points to a null terminated ASCII string that is set
3989 aside for use by applications.
3991 usri11_last_logon specifies the time when the user last logged on.
3992 This value is stored as the number of seconds elapsed since
3993 00:00:00, January 1, 1970.
3995 usri11_last_logoff specifies the time when the user last logged off.
3996 This value is stored as the number of seconds elapsed since
3997 00:00:00, January 1, 1970. A value of 0 means the last logoff
3998 time is unknown.
4000 usri11_bad_pw_count specifies the number of incorrect passwords
4001 entered since the last successful logon.
4003 usri11_log1_num_logons specifies the number of times this user has
4004 logged on. A value of -1 means the number of logons is unknown.
4006 usri11_logon_server points to a null terminated ASCII string that
4007 contains the name of the server to which logon requests are sent.
4008 A null string indicates logon requests should be sent to the
4009 domain controller.
4011 usri11_country_code specifies the country code for the user's language
4012 of choice.
4014 usri11_workstations points to a null terminated ASCII string that
4015 contains the names of workstations the user may log on from.
4016 There may be up to 8 workstations, with the names separated by
4017 commas. A null strings indicates there are no restrictions.
4019 usri11_max_storage specifies the maximum amount of disk space the user
4020 can occupy. A value of 0xffffffff indicates there are no
4021 restrictions.
4023 usri11_units_per_week specifies the equal number of time units into
4024 which a week is divided. This value must be equal to 168.
4026 usri11_logon_hours points to a 21 byte (168 bits) string that
4027 specifies the time during which the user can log on. Each bit
4028 represents one unique hour in a week. The first bit (bit 0, word
4029 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
4033 Leach, Naik [Page 29]
4037 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
4040 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
4041 are no restrictions.
4043 usri11_code_page specifies the code page for the user's language of
4044 choice
4046 All of the pointers in this data structure need to be treated
4047 specially. The pointer is a 32 bit pointer. The higher 16 bits need
4048 to be ignored. The converter word returned in the parameters section
4049 needs to be subtracted from the lower 16 bits to calculate an offset
4050 into the return buffer where this ASCII string resides.
4052 There is no auxiliary data in the response.
4054 ****************************************************************************/
4056 #define usri11_name 0
4057 #define usri11_pad 21
4058 #define usri11_comment 22
4059 #define usri11_usr_comment 26
4060 #define usri11_full_name 30
4061 #define usri11_priv 34
4062 #define usri11_auth_flags 36
4063 #define usri11_password_age 40
4064 #define usri11_homedir 44
4065 #define usri11_parms 48
4066 #define usri11_last_logon 52
4067 #define usri11_last_logoff 56
4068 #define usri11_bad_pw_count 60
4069 #define usri11_num_logons 62
4070 #define usri11_logon_server 64
4071 #define usri11_country_code 68
4072 #define usri11_workstations 70
4073 #define usri11_max_storage 74
4074 #define usri11_units_per_week 78
4075 #define usri11_logon_hours 80
4076 #define usri11_code_page 84
4077 #define usri11_end 86
4079 static bool api_RNetUserGetInfo(struct smbd_server_connection *sconn,
4080 connection_struct *conn, uint16 vuid,
4081 char *param, int tpscnt,
4082 char *data, int tdscnt,
4083 int mdrcnt,int mprcnt,
4084 char **rdata,char **rparam,
4085 int *rdata_len,int *rparam_len)
4087 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4088 char *str2 = skip_string(param,tpscnt,str1);
4089 char *UserName = skip_string(param,tpscnt,str2);
4090 char *p = skip_string(param,tpscnt,UserName);
4091 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4092 char *p2;
4093 char *endp;
4094 const char *level_string;
4096 TALLOC_CTX *mem_ctx = talloc_tos();
4097 NTSTATUS status;
4098 struct rpc_pipe_client *cli = NULL;
4099 struct policy_handle connect_handle, domain_handle, user_handle;
4100 struct lsa_String domain_name;
4101 struct dom_sid2 *domain_sid;
4102 struct lsa_String names;
4103 struct samr_Ids rids;
4104 struct samr_Ids types;
4105 int errcode = W_ERROR_V(WERR_USER_NOT_FOUND);
4106 uint32_t rid;
4107 union samr_UserInfo *info;
4109 if (!str1 || !str2 || !UserName || !p) {
4110 return False;
4113 *rparam_len = 6;
4114 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4115 if (!*rparam) {
4116 return False;
4119 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
4121 /* check it's a supported variant */
4122 if (strcmp(str1,"zWrLh") != 0) {
4123 return False;
4125 switch( uLevel ) {
4126 case 0: level_string = "B21"; break;
4127 case 1: level_string = "B21BB16DWzzWz"; break;
4128 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
4129 case 10: level_string = "B21Bzzz"; break;
4130 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
4131 default: return False;
4134 if (strcmp(level_string,str2) != 0) {
4135 return False;
4138 *rdata_len = mdrcnt + 1024;
4139 *rdata = smb_realloc_limit(*rdata,*rdata_len);
4140 if (!*rdata) {
4141 return False;
4144 p = *rdata;
4145 endp = *rdata + *rdata_len;
4146 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
4147 if (!p2) {
4148 return False;
4151 ZERO_STRUCT(connect_handle);
4152 ZERO_STRUCT(domain_handle);
4153 ZERO_STRUCT(user_handle);
4155 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_samr.syntax_id,
4156 conn->server_info,
4157 &conn->sconn->client_id,
4158 conn->sconn->msg_ctx,
4159 &cli);
4160 if (!NT_STATUS_IS_OK(status)) {
4161 DEBUG(0,("api_RNetUserGetInfo: could not connect to samr: %s\n",
4162 nt_errstr(status)));
4163 errcode = W_ERROR_V(ntstatus_to_werror(status));
4164 goto out;
4167 status = rpccli_samr_Connect2(cli, mem_ctx,
4168 global_myname(),
4169 SAMR_ACCESS_CONNECT_TO_SERVER |
4170 SAMR_ACCESS_ENUM_DOMAINS |
4171 SAMR_ACCESS_LOOKUP_DOMAIN,
4172 &connect_handle);
4173 if (!NT_STATUS_IS_OK(status)) {
4174 errcode = W_ERROR_V(ntstatus_to_werror(status));
4175 goto out;
4178 init_lsa_String(&domain_name, get_global_sam_name());
4180 status = rpccli_samr_LookupDomain(cli, mem_ctx,
4181 &connect_handle,
4182 &domain_name,
4183 &domain_sid);
4184 if (!NT_STATUS_IS_OK(status)) {
4185 errcode = W_ERROR_V(ntstatus_to_werror(status));
4186 goto out;
4189 status = rpccli_samr_OpenDomain(cli, mem_ctx,
4190 &connect_handle,
4191 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
4192 domain_sid,
4193 &domain_handle);
4194 if (!NT_STATUS_IS_OK(status)) {
4195 errcode = W_ERROR_V(ntstatus_to_werror(status));
4196 goto out;
4199 init_lsa_String(&names, UserName);
4201 status = rpccli_samr_LookupNames(cli, mem_ctx,
4202 &domain_handle,
4204 &names,
4205 &rids,
4206 &types);
4207 if (!NT_STATUS_IS_OK(status)) {
4208 errcode = W_ERROR_V(ntstatus_to_werror(status));
4209 goto out;
4212 if (rids.count != 1) {
4213 errcode = W_ERROR_V(WERR_NO_SUCH_USER);
4214 goto out;
4216 if (rids.count != types.count) {
4217 errcode = W_ERROR_V(WERR_INVALID_PARAM);
4218 goto out;
4220 if (types.ids[0] != SID_NAME_USER) {
4221 errcode = W_ERROR_V(WERR_INVALID_PARAM);
4222 goto out;
4225 rid = rids.ids[0];
4227 status = rpccli_samr_OpenUser(cli, mem_ctx,
4228 &domain_handle,
4229 SAMR_USER_ACCESS_GET_LOCALE |
4230 SAMR_USER_ACCESS_GET_LOGONINFO |
4231 SAMR_USER_ACCESS_GET_ATTRIBUTES |
4232 SAMR_USER_ACCESS_GET_GROUPS |
4233 SAMR_USER_ACCESS_GET_GROUP_MEMBERSHIP |
4234 SEC_STD_READ_CONTROL,
4235 rid,
4236 &user_handle);
4237 if (!NT_STATUS_IS_OK(status)) {
4238 errcode = W_ERROR_V(ntstatus_to_werror(status));
4239 goto out;
4242 status = rpccli_samr_QueryUserInfo2(cli, mem_ctx,
4243 &user_handle,
4244 UserAllInformation,
4245 &info);
4246 if (!NT_STATUS_IS_OK(status)) {
4247 errcode = W_ERROR_V(ntstatus_to_werror(status));
4248 goto out;
4251 memset(p,0,21);
4252 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
4254 if (uLevel > 0) {
4255 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
4256 *p2 = 0;
4259 if (uLevel >= 10) {
4260 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
4261 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
4262 p2 = skip_string(*rdata,*rdata_len,p2);
4263 if (!p2) {
4264 return False;
4267 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
4268 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
4269 p2 = skip_string(*rdata,*rdata_len,p2);
4270 if (!p2) {
4271 return False;
4274 /* EEK! the cifsrap.txt doesn't have this in!!!! */
4275 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
4276 strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4277 p2 = skip_string(*rdata,*rdata_len,p2);
4278 if (!p2) {
4279 return False;
4283 if (uLevel == 11) {
4284 const char *homedir = info->info21.home_directory.string;
4285 /* modelled after NTAS 3.51 reply */
4286 SSVAL(p,usri11_priv,
4287 (get_current_uid(conn) == sec_initial_uid())?
4288 USER_PRIV_ADMIN:USER_PRIV_USER);
4289 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
4290 SIVALS(p,usri11_password_age,-1); /* password age */
4291 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
4292 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
4293 p2 = skip_string(*rdata,*rdata_len,p2);
4294 if (!p2) {
4295 return False;
4297 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
4298 strlcpy(p2,"",PTR_DIFF(endp,p2));
4299 p2 = skip_string(*rdata,*rdata_len,p2);
4300 if (!p2) {
4301 return False;
4303 SIVAL(p,usri11_last_logon,0); /* last logon */
4304 SIVAL(p,usri11_last_logoff,0); /* last logoff */
4305 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
4306 SSVALS(p,usri11_num_logons,-1); /* num logons */
4307 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
4308 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
4309 p2 = skip_string(*rdata,*rdata_len,p2);
4310 if (!p2) {
4311 return False;
4313 SSVAL(p,usri11_country_code,0); /* country code */
4315 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
4316 strlcpy(p2,"",PTR_DIFF(endp,p2));
4317 p2 = skip_string(*rdata,*rdata_len,p2);
4318 if (!p2) {
4319 return False;
4322 SIVALS(p,usri11_max_storage,-1); /* max storage */
4323 SSVAL(p,usri11_units_per_week,168); /* units per week */
4324 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
4326 /* a simple way to get logon hours at all times. */
4327 memset(p2,0xff,21);
4328 SCVAL(p2,21,0); /* fix zero termination */
4329 p2 = skip_string(*rdata,*rdata_len,p2);
4330 if (!p2) {
4331 return False;
4334 SSVAL(p,usri11_code_page,0); /* code page */
4337 if (uLevel == 1 || uLevel == 2) {
4338 memset(p+22,' ',16); /* password */
4339 SIVALS(p,38,-1); /* password age */
4340 SSVAL(p,42,
4341 (get_current_uid(conn) == sec_initial_uid())?
4342 USER_PRIV_ADMIN:USER_PRIV_USER);
4343 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
4344 strlcpy(p2, info->info21.home_directory.string,
4345 PTR_DIFF(endp,p2));
4346 p2 = skip_string(*rdata,*rdata_len,p2);
4347 if (!p2) {
4348 return False;
4350 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
4351 *p2++ = 0;
4352 SSVAL(p,52,0); /* flags */
4353 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
4354 strlcpy(p2, info->info21.logon_script.string,
4355 PTR_DIFF(endp,p2));
4356 p2 = skip_string(*rdata,*rdata_len,p2);
4357 if (!p2) {
4358 return False;
4360 if (uLevel == 2) {
4361 SIVAL(p,58,0); /* auth_flags */
4362 SIVAL(p,62,PTR_DIFF(p2,*rdata)); /* full_name */
4363 strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4364 p2 = skip_string(*rdata,*rdata_len,p2);
4365 if (!p2) {
4366 return False;
4368 SIVAL(p,66,0); /* urs_comment */
4369 SIVAL(p,70,PTR_DIFF(p2,*rdata)); /* parms */
4370 strlcpy(p2,"",PTR_DIFF(endp,p2));
4371 p2 = skip_string(*rdata,*rdata_len,p2);
4372 if (!p2) {
4373 return False;
4375 SIVAL(p,74,0); /* workstations */
4376 SIVAL(p,78,0); /* last_logon */
4377 SIVAL(p,82,0); /* last_logoff */
4378 SIVALS(p,86,-1); /* acct_expires */
4379 SIVALS(p,90,-1); /* max_storage */
4380 SSVAL(p,94,168); /* units_per_week */
4381 SIVAL(p,96,PTR_DIFF(p2,*rdata)); /* logon_hours */
4382 memset(p2,-1,21);
4383 p2 += 21;
4384 SSVALS(p,100,-1); /* bad_pw_count */
4385 SSVALS(p,102,-1); /* num_logons */
4386 SIVAL(p,104,PTR_DIFF(p2,*rdata)); /* logon_server */
4388 TALLOC_CTX *ctx = talloc_tos();
4389 int space_rem = *rdata_len - (p2 - *rdata);
4390 char *tmp;
4392 if (space_rem <= 0) {
4393 return false;
4395 tmp = talloc_strdup(ctx, "\\\\%L");
4396 if (!tmp) {
4397 return false;
4399 tmp = talloc_sub_basic(ctx,
4402 tmp);
4403 if (!tmp) {
4404 return false;
4407 push_ascii(p2,
4408 tmp,
4409 space_rem,
4410 STR_TERMINATE);
4412 p2 = skip_string(*rdata,*rdata_len,p2);
4413 if (!p2) {
4414 return False;
4416 SSVAL(p,108,49); /* country_code */
4417 SSVAL(p,110,860); /* code page */
4421 errcode = NERR_Success;
4423 out:
4424 *rdata_len = PTR_DIFF(p2,*rdata);
4426 if (cli && is_valid_policy_hnd(&user_handle)) {
4427 rpccli_samr_Close(cli, mem_ctx, &user_handle);
4429 if (cli && is_valid_policy_hnd(&domain_handle)) {
4430 rpccli_samr_Close(cli, mem_ctx, &domain_handle);
4432 if (cli && is_valid_policy_hnd(&connect_handle)) {
4433 rpccli_samr_Close(cli, mem_ctx, &connect_handle);
4436 SSVAL(*rparam,0,errcode);
4437 SSVAL(*rparam,2,0); /* converter word */
4438 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
4440 return(True);
4443 static bool api_WWkstaUserLogon(struct smbd_server_connection *sconn,
4444 connection_struct *conn,uint16 vuid,
4445 char *param, int tpscnt,
4446 char *data, int tdscnt,
4447 int mdrcnt,int mprcnt,
4448 char **rdata,char **rparam,
4449 int *rdata_len,int *rparam_len)
4451 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4452 char *str2 = skip_string(param,tpscnt,str1);
4453 char *p = skip_string(param,tpscnt,str2);
4454 int uLevel;
4455 struct pack_desc desc;
4456 char* name;
4457 /* With share level security vuid will always be zero.
4458 Don't depend on vuser being non-null !!. JRA */
4459 user_struct *vuser = get_valid_user_struct(sconn, vuid);
4461 if (!str1 || !str2 || !p) {
4462 return False;
4465 if(vuser != NULL) {
4466 DEBUG(3,(" Username of UID %d is %s\n",
4467 (int)vuser->server_info->utok.uid,
4468 vuser->server_info->unix_name));
4471 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4472 name = get_safe_str_ptr(param,tpscnt,p,2);
4473 if (!name) {
4474 return False;
4477 memset((char *)&desc,'\0',sizeof(desc));
4479 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
4481 /* check it's a supported varient */
4482 if (strcmp(str1,"OOWb54WrLh") != 0) {
4483 return False;
4485 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
4486 return False;
4488 if (mdrcnt > 0) {
4489 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4490 if (!*rdata) {
4491 return False;
4495 desc.base = *rdata;
4496 desc.buflen = mdrcnt;
4497 desc.subformat = NULL;
4498 desc.format = str2;
4500 if (init_package(&desc,1,0)) {
4501 PACKI(&desc,"W",0); /* code */
4502 PACKS(&desc,"B21",name); /* eff. name */
4503 PACKS(&desc,"B",""); /* pad */
4504 PACKI(&desc,"W",
4505 (get_current_uid(conn) == sec_initial_uid())?
4506 USER_PRIV_ADMIN:USER_PRIV_USER);
4507 PACKI(&desc,"D",0); /* auth flags XXX */
4508 PACKI(&desc,"W",0); /* num logons */
4509 PACKI(&desc,"W",0); /* bad pw count */
4510 PACKI(&desc,"D",0); /* last logon */
4511 PACKI(&desc,"D",-1); /* last logoff */
4512 PACKI(&desc,"D",-1); /* logoff time */
4513 PACKI(&desc,"D",-1); /* kickoff time */
4514 PACKI(&desc,"D",0); /* password age */
4515 PACKI(&desc,"D",0); /* password can change */
4516 PACKI(&desc,"D",-1); /* password must change */
4519 fstring mypath;
4520 fstrcpy(mypath,"\\\\");
4521 fstrcat(mypath,get_local_machine_name());
4522 strupper_m(mypath);
4523 PACKS(&desc,"z",mypath); /* computer */
4526 PACKS(&desc,"z",lp_workgroup());/* domain */
4527 PACKS(&desc,"z", vuser ?
4528 vuser->server_info->info3->base.logon_script.string
4529 : ""); /* script path */
4530 PACKI(&desc,"D",0x00000000); /* reserved */
4533 *rdata_len = desc.usedlen;
4534 *rparam_len = 6;
4535 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4536 if (!*rparam) {
4537 return False;
4539 SSVALS(*rparam,0,desc.errcode);
4540 SSVAL(*rparam,2,0);
4541 SSVAL(*rparam,4,desc.neededlen);
4543 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4545 return True;
4548 /****************************************************************************
4549 api_WAccessGetUserPerms
4550 ****************************************************************************/
4552 static bool api_WAccessGetUserPerms(struct smbd_server_connection *sconn,
4553 connection_struct *conn,uint16 vuid,
4554 char *param, int tpscnt,
4555 char *data, int tdscnt,
4556 int mdrcnt,int mprcnt,
4557 char **rdata,char **rparam,
4558 int *rdata_len,int *rparam_len)
4560 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4561 char *str2 = skip_string(param,tpscnt,str1);
4562 char *user = skip_string(param,tpscnt,str2);
4563 char *resource = skip_string(param,tpscnt,user);
4565 if (!str1 || !str2 || !user || !resource) {
4566 return False;
4569 if (skip_string(param,tpscnt,resource) == NULL) {
4570 return False;
4572 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4574 /* check it's a supported varient */
4575 if (strcmp(str1,"zzh") != 0) {
4576 return False;
4578 if (strcmp(str2,"") != 0) {
4579 return False;
4582 *rparam_len = 6;
4583 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4584 if (!*rparam) {
4585 return False;
4587 SSVALS(*rparam,0,0); /* errorcode */
4588 SSVAL(*rparam,2,0); /* converter word */
4589 SSVAL(*rparam,4,0x7f); /* permission flags */
4591 return True;
4594 /****************************************************************************
4595 api_WPrintJobEnumerate
4596 ****************************************************************************/
4598 static bool api_WPrintJobGetInfo(struct smbd_server_connection *sconn,
4599 connection_struct *conn, uint16 vuid,
4600 char *param, int tpscnt,
4601 char *data, int tdscnt,
4602 int mdrcnt,int mprcnt,
4603 char **rdata,char **rparam,
4604 int *rdata_len,int *rparam_len)
4606 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4607 char *str2 = skip_string(param,tpscnt,str1);
4608 char *p = skip_string(param,tpscnt,str2);
4609 int uLevel;
4610 fstring sharename;
4611 uint32 jobid;
4612 struct pack_desc desc;
4613 char *tmpdata=NULL;
4615 TALLOC_CTX *mem_ctx = talloc_tos();
4616 WERROR werr;
4617 NTSTATUS status;
4618 struct rpc_pipe_client *cli = NULL;
4619 struct policy_handle handle;
4620 struct spoolss_DevmodeContainer devmode_ctr;
4621 union spoolss_JobInfo info;
4623 if (!str1 || !str2 || !p) {
4624 return False;
4627 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4629 memset((char *)&desc,'\0',sizeof(desc));
4630 memset((char *)&status,'\0',sizeof(status));
4632 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4634 /* check it's a supported varient */
4635 if (strcmp(str1,"WWrLh") != 0) {
4636 return False;
4638 if (!check_printjob_info(&desc,uLevel,str2)) {
4639 return False;
4642 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4643 return False;
4646 ZERO_STRUCT(handle);
4648 status = rpc_pipe_open_interface(conn,
4649 &ndr_table_spoolss.syntax_id,
4650 conn->server_info,
4651 &conn->sconn->client_id,
4652 conn->sconn->msg_ctx,
4653 &cli);
4654 if (!NT_STATUS_IS_OK(status)) {
4655 DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n",
4656 nt_errstr(status)));
4657 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4658 goto out;
4661 ZERO_STRUCT(devmode_ctr);
4663 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4664 sharename,
4665 "RAW",
4666 devmode_ctr,
4667 PRINTER_ACCESS_USE,
4668 &handle,
4669 &werr);
4670 if (!NT_STATUS_IS_OK(status)) {
4671 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4672 goto out;
4674 if (!W_ERROR_IS_OK(werr)) {
4675 desc.errcode = W_ERROR_V(werr);
4676 goto out;
4679 werr = rpccli_spoolss_getjob(cli, mem_ctx,
4680 &handle,
4681 jobid,
4682 2, /* level */
4683 0, /* offered */
4684 &info);
4685 if (!W_ERROR_IS_OK(werr)) {
4686 desc.errcode = W_ERROR_V(werr);
4687 goto out;
4690 if (mdrcnt > 0) {
4691 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4692 if (!*rdata) {
4693 return False;
4695 desc.base = *rdata;
4696 desc.buflen = mdrcnt;
4697 } else {
4699 * Don't return data but need to get correct length
4700 * init_package will return wrong size if buflen=0
4702 desc.buflen = getlen(desc.format);
4703 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4706 if (init_package(&desc,1,0)) {
4707 fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position);
4708 *rdata_len = desc.usedlen;
4709 } else {
4710 desc.errcode = NERR_JobNotFound;
4711 *rdata_len = 0;
4713 out:
4714 if (cli && is_valid_policy_hnd(&handle)) {
4715 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4718 *rparam_len = 6;
4719 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4720 if (!*rparam) {
4721 return False;
4723 SSVALS(*rparam,0,desc.errcode);
4724 SSVAL(*rparam,2,0);
4725 SSVAL(*rparam,4,desc.neededlen);
4727 SAFE_FREE(tmpdata);
4729 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4731 return True;
4734 static bool api_WPrintJobEnumerate(struct smbd_server_connection *sconn,
4735 connection_struct *conn, uint16 vuid,
4736 char *param, int tpscnt,
4737 char *data, int tdscnt,
4738 int mdrcnt,int mprcnt,
4739 char **rdata,char **rparam,
4740 int *rdata_len,int *rparam_len)
4742 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4743 char *str2 = skip_string(param,tpscnt,str1);
4744 char *p = skip_string(param,tpscnt,str2);
4745 char *name = p;
4746 int uLevel;
4747 int i, succnt=0;
4748 struct pack_desc desc;
4750 TALLOC_CTX *mem_ctx = talloc_tos();
4751 WERROR werr;
4752 NTSTATUS status;
4753 struct rpc_pipe_client *cli = NULL;
4754 struct policy_handle handle;
4755 struct spoolss_DevmodeContainer devmode_ctr;
4756 uint32_t count = 0;
4757 union spoolss_JobInfo *info;
4759 if (!str1 || !str2 || !p) {
4760 return False;
4763 memset((char *)&desc,'\0',sizeof(desc));
4765 p = skip_string(param,tpscnt,p);
4766 if (!p) {
4767 return False;
4769 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4771 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4773 /* check it's a supported variant */
4774 if (strcmp(str1,"zWrLeh") != 0) {
4775 return False;
4778 if (uLevel > 2) {
4779 return False; /* defined only for uLevel 0,1,2 */
4782 if (!check_printjob_info(&desc,uLevel,str2)) {
4783 return False;
4786 ZERO_STRUCT(handle);
4788 status = rpc_pipe_open_interface(conn,
4789 &ndr_table_spoolss.syntax_id,
4790 conn->server_info,
4791 &conn->sconn->client_id,
4792 conn->sconn->msg_ctx,
4793 &cli);
4794 if (!NT_STATUS_IS_OK(status)) {
4795 DEBUG(0,("api_WPrintJobEnumerate: could not connect to spoolss: %s\n",
4796 nt_errstr(status)));
4797 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4798 goto out;
4801 ZERO_STRUCT(devmode_ctr);
4803 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4804 name,
4805 NULL,
4806 devmode_ctr,
4807 SEC_FLAG_MAXIMUM_ALLOWED,
4808 &handle,
4809 &werr);
4810 if (!NT_STATUS_IS_OK(status)) {
4811 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4812 goto out;
4814 if (!W_ERROR_IS_OK(werr)) {
4815 desc.errcode = W_ERROR_V(werr);
4816 goto out;
4819 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
4820 &handle,
4821 0, /* firstjob */
4822 0xff, /* numjobs */
4823 2, /* level */
4824 0, /* offered */
4825 &count,
4826 &info);
4827 if (!W_ERROR_IS_OK(werr)) {
4828 desc.errcode = W_ERROR_V(werr);
4829 goto out;
4832 if (mdrcnt > 0) {
4833 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4834 if (!*rdata) {
4835 return False;
4838 desc.base = *rdata;
4839 desc.buflen = mdrcnt;
4841 if (init_package(&desc,count,0)) {
4842 succnt = 0;
4843 for (i = 0; i < count; i++) {
4844 fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i);
4845 if (desc.errcode == NERR_Success) {
4846 succnt = i+1;
4850 out:
4851 if (cli && is_valid_policy_hnd(&handle)) {
4852 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4855 *rdata_len = desc.usedlen;
4857 *rparam_len = 8;
4858 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4859 if (!*rparam) {
4860 return False;
4862 SSVALS(*rparam,0,desc.errcode);
4863 SSVAL(*rparam,2,0);
4864 SSVAL(*rparam,4,succnt);
4865 SSVAL(*rparam,6,count);
4867 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4869 return True;
4872 static int check_printdest_info(struct pack_desc* desc,
4873 int uLevel, char* id)
4875 desc->subformat = NULL;
4876 switch( uLevel ) {
4877 case 0:
4878 desc->format = "B9";
4879 break;
4880 case 1:
4881 desc->format = "B9B21WWzW";
4882 break;
4883 case 2:
4884 desc->format = "z";
4885 break;
4886 case 3:
4887 desc->format = "zzzWWzzzWW";
4888 break;
4889 default:
4890 DEBUG(0,("check_printdest_info: invalid level %d\n",
4891 uLevel));
4892 return False;
4894 if (id == NULL || strcmp(desc->format,id) != 0) {
4895 DEBUG(0,("check_printdest_info: invalid string %s\n",
4896 id ? id : "<NULL>" ));
4897 return False;
4899 return True;
4902 static void fill_printdest_info(struct spoolss_PrinterInfo2 *info2, int uLevel,
4903 struct pack_desc* desc)
4905 char buf[100];
4907 strncpy(buf, info2->printername, sizeof(buf)-1);
4908 buf[sizeof(buf)-1] = 0;
4909 strupper_m(buf);
4911 if (uLevel <= 1) {
4912 PACKS(desc,"B9",buf); /* szName */
4913 if (uLevel == 1) {
4914 PACKS(desc,"B21",""); /* szUserName */
4915 PACKI(desc,"W",0); /* uJobId */
4916 PACKI(desc,"W",0); /* fsStatus */
4917 PACKS(desc,"z",""); /* pszStatus */
4918 PACKI(desc,"W",0); /* time */
4922 if (uLevel == 2 || uLevel == 3) {
4923 PACKS(desc,"z",buf); /* pszPrinterName */
4924 if (uLevel == 3) {
4925 PACKS(desc,"z",""); /* pszUserName */
4926 PACKS(desc,"z",""); /* pszLogAddr */
4927 PACKI(desc,"W",0); /* uJobId */
4928 PACKI(desc,"W",0); /* fsStatus */
4929 PACKS(desc,"z",""); /* pszStatus */
4930 PACKS(desc,"z",""); /* pszComment */
4931 PACKS(desc,"z","NULL"); /* pszDrivers */
4932 PACKI(desc,"W",0); /* time */
4933 PACKI(desc,"W",0); /* pad1 */
4938 static bool api_WPrintDestGetInfo(struct smbd_server_connection *sconn,
4939 connection_struct *conn, uint16 vuid,
4940 char *param, int tpscnt,
4941 char *data, int tdscnt,
4942 int mdrcnt,int mprcnt,
4943 char **rdata,char **rparam,
4944 int *rdata_len,int *rparam_len)
4946 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4947 char *str2 = skip_string(param,tpscnt,str1);
4948 char *p = skip_string(param,tpscnt,str2);
4949 char* PrinterName = p;
4950 int uLevel;
4951 struct pack_desc desc;
4952 char *tmpdata=NULL;
4954 TALLOC_CTX *mem_ctx = talloc_tos();
4955 WERROR werr;
4956 NTSTATUS status;
4957 struct rpc_pipe_client *cli = NULL;
4958 struct policy_handle handle;
4959 struct spoolss_DevmodeContainer devmode_ctr;
4960 union spoolss_PrinterInfo info;
4962 if (!str1 || !str2 || !p) {
4963 return False;
4966 memset((char *)&desc,'\0',sizeof(desc));
4968 p = skip_string(param,tpscnt,p);
4969 if (!p) {
4970 return False;
4972 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4974 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4976 /* check it's a supported varient */
4977 if (strcmp(str1,"zWrLh") != 0) {
4978 return False;
4980 if (!check_printdest_info(&desc,uLevel,str2)) {
4981 return False;
4984 ZERO_STRUCT(handle);
4986 status = rpc_pipe_open_interface(conn,
4987 &ndr_table_spoolss.syntax_id,
4988 conn->server_info,
4989 &conn->sconn->client_id,
4990 conn->sconn->msg_ctx,
4991 &cli);
4992 if (!NT_STATUS_IS_OK(status)) {
4993 DEBUG(0,("api_WPrintDestGetInfo: could not connect to spoolss: %s\n",
4994 nt_errstr(status)));
4995 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4996 goto out;
4999 ZERO_STRUCT(devmode_ctr);
5001 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
5002 PrinterName,
5003 NULL,
5004 devmode_ctr,
5005 SEC_FLAG_MAXIMUM_ALLOWED,
5006 &handle,
5007 &werr);
5008 if (!NT_STATUS_IS_OK(status)) {
5009 *rdata_len = 0;
5010 desc.errcode = NERR_DestNotFound;
5011 desc.neededlen = 0;
5012 goto out;
5014 if (!W_ERROR_IS_OK(werr)) {
5015 *rdata_len = 0;
5016 desc.errcode = NERR_DestNotFound;
5017 desc.neededlen = 0;
5018 goto out;
5021 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
5022 &handle,
5025 &info);
5026 if (!W_ERROR_IS_OK(werr)) {
5027 *rdata_len = 0;
5028 desc.errcode = NERR_DestNotFound;
5029 desc.neededlen = 0;
5030 goto out;
5033 if (mdrcnt > 0) {
5034 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5035 if (!*rdata) {
5036 return False;
5038 desc.base = *rdata;
5039 desc.buflen = mdrcnt;
5040 } else {
5042 * Don't return data but need to get correct length
5043 * init_package will return wrong size if buflen=0
5045 desc.buflen = getlen(desc.format);
5046 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
5048 if (init_package(&desc,1,0)) {
5049 fill_printdest_info(&info.info2, uLevel,&desc);
5052 out:
5053 if (cli && is_valid_policy_hnd(&handle)) {
5054 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
5057 *rdata_len = desc.usedlen;
5059 *rparam_len = 6;
5060 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5061 if (!*rparam) {
5062 return False;
5064 SSVALS(*rparam,0,desc.errcode);
5065 SSVAL(*rparam,2,0);
5066 SSVAL(*rparam,4,desc.neededlen);
5068 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
5069 SAFE_FREE(tmpdata);
5071 return True;
5074 static bool api_WPrintDestEnum(struct smbd_server_connection *sconn,
5075 connection_struct *conn, uint16 vuid,
5076 char *param, int tpscnt,
5077 char *data, int tdscnt,
5078 int mdrcnt,int mprcnt,
5079 char **rdata,char **rparam,
5080 int *rdata_len,int *rparam_len)
5082 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5083 char *str2 = skip_string(param,tpscnt,str1);
5084 char *p = skip_string(param,tpscnt,str2);
5085 int uLevel;
5086 int queuecnt;
5087 int i, n, succnt=0;
5088 struct pack_desc desc;
5090 TALLOC_CTX *mem_ctx = talloc_tos();
5091 WERROR werr;
5092 NTSTATUS status;
5093 struct rpc_pipe_client *cli = NULL;
5094 union spoolss_PrinterInfo *info;
5095 uint32_t count;
5097 if (!str1 || !str2 || !p) {
5098 return False;
5101 memset((char *)&desc,'\0',sizeof(desc));
5103 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5105 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
5107 /* check it's a supported varient */
5108 if (strcmp(str1,"WrLeh") != 0) {
5109 return False;
5111 if (!check_printdest_info(&desc,uLevel,str2)) {
5112 return False;
5115 queuecnt = 0;
5117 status = rpc_pipe_open_interface(conn,
5118 &ndr_table_spoolss.syntax_id,
5119 conn->server_info,
5120 &conn->sconn->client_id,
5121 conn->sconn->msg_ctx,
5122 &cli);
5123 if (!NT_STATUS_IS_OK(status)) {
5124 DEBUG(0,("api_WPrintDestEnum: could not connect to spoolss: %s\n",
5125 nt_errstr(status)));
5126 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5127 goto out;
5130 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
5131 PRINTER_ENUM_LOCAL,
5132 cli->srv_name_slash,
5135 &count,
5136 &info);
5137 if (!W_ERROR_IS_OK(werr)) {
5138 desc.errcode = W_ERROR_V(werr);
5139 *rdata_len = 0;
5140 desc.errcode = NERR_DestNotFound;
5141 desc.neededlen = 0;
5142 goto out;
5145 queuecnt = count;
5147 if (mdrcnt > 0) {
5148 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5149 if (!*rdata) {
5150 return False;
5154 desc.base = *rdata;
5155 desc.buflen = mdrcnt;
5156 if (init_package(&desc,queuecnt,0)) {
5157 succnt = 0;
5158 n = 0;
5159 for (i = 0; i < count; i++) {
5160 fill_printdest_info(&info[i].info2, uLevel,&desc);
5161 n++;
5162 if (desc.errcode == NERR_Success) {
5163 succnt = n;
5167 out:
5168 *rdata_len = desc.usedlen;
5170 *rparam_len = 8;
5171 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5172 if (!*rparam) {
5173 return False;
5175 SSVALS(*rparam,0,desc.errcode);
5176 SSVAL(*rparam,2,0);
5177 SSVAL(*rparam,4,succnt);
5178 SSVAL(*rparam,6,queuecnt);
5180 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
5182 return True;
5185 static bool api_WPrintDriverEnum(struct smbd_server_connection *sconn,
5186 connection_struct *conn, uint16 vuid,
5187 char *param, int tpscnt,
5188 char *data, int tdscnt,
5189 int mdrcnt,int mprcnt,
5190 char **rdata,char **rparam,
5191 int *rdata_len,int *rparam_len)
5193 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5194 char *str2 = skip_string(param,tpscnt,str1);
5195 char *p = skip_string(param,tpscnt,str2);
5196 int uLevel;
5197 int succnt;
5198 struct pack_desc desc;
5200 if (!str1 || !str2 || !p) {
5201 return False;
5204 memset((char *)&desc,'\0',sizeof(desc));
5206 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5208 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
5210 /* check it's a supported varient */
5211 if (strcmp(str1,"WrLeh") != 0) {
5212 return False;
5214 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
5215 return False;
5218 if (mdrcnt > 0) {
5219 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5220 if (!*rdata) {
5221 return False;
5224 desc.base = *rdata;
5225 desc.buflen = mdrcnt;
5226 if (init_package(&desc,1,0)) {
5227 PACKS(&desc,"B41","NULL");
5230 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5232 *rdata_len = desc.usedlen;
5234 *rparam_len = 8;
5235 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5236 if (!*rparam) {
5237 return False;
5239 SSVALS(*rparam,0,desc.errcode);
5240 SSVAL(*rparam,2,0);
5241 SSVAL(*rparam,4,succnt);
5242 SSVAL(*rparam,6,1);
5244 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
5246 return True;
5249 static bool api_WPrintQProcEnum(struct smbd_server_connection *sconn,
5250 connection_struct *conn, uint16 vuid,
5251 char *param, int tpscnt,
5252 char *data, int tdscnt,
5253 int mdrcnt,int mprcnt,
5254 char **rdata,char **rparam,
5255 int *rdata_len,int *rparam_len)
5257 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5258 char *str2 = skip_string(param,tpscnt,str1);
5259 char *p = skip_string(param,tpscnt,str2);
5260 int uLevel;
5261 int succnt;
5262 struct pack_desc desc;
5264 if (!str1 || !str2 || !p) {
5265 return False;
5267 memset((char *)&desc,'\0',sizeof(desc));
5269 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5271 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
5273 /* check it's a supported varient */
5274 if (strcmp(str1,"WrLeh") != 0) {
5275 return False;
5277 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
5278 return False;
5281 if (mdrcnt > 0) {
5282 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5283 if (!*rdata) {
5284 return False;
5287 desc.base = *rdata;
5288 desc.buflen = mdrcnt;
5289 desc.format = str2;
5290 if (init_package(&desc,1,0)) {
5291 PACKS(&desc,"B13","lpd");
5294 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5296 *rdata_len = desc.usedlen;
5298 *rparam_len = 8;
5299 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5300 if (!*rparam) {
5301 return False;
5303 SSVALS(*rparam,0,desc.errcode);
5304 SSVAL(*rparam,2,0);
5305 SSVAL(*rparam,4,succnt);
5306 SSVAL(*rparam,6,1);
5308 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
5310 return True;
5313 static bool api_WPrintPortEnum(struct smbd_server_connection *sconn,
5314 connection_struct *conn, uint16 vuid,
5315 char *param, int tpscnt,
5316 char *data, int tdscnt,
5317 int mdrcnt,int mprcnt,
5318 char **rdata,char **rparam,
5319 int *rdata_len,int *rparam_len)
5321 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5322 char *str2 = skip_string(param,tpscnt,str1);
5323 char *p = skip_string(param,tpscnt,str2);
5324 int uLevel;
5325 int succnt;
5326 struct pack_desc desc;
5328 if (!str1 || !str2 || !p) {
5329 return False;
5332 memset((char *)&desc,'\0',sizeof(desc));
5334 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5336 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
5338 /* check it's a supported varient */
5339 if (strcmp(str1,"WrLeh") != 0) {
5340 return False;
5342 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
5343 return False;
5346 if (mdrcnt > 0) {
5347 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5348 if (!*rdata) {
5349 return False;
5352 memset((char *)&desc,'\0',sizeof(desc));
5353 desc.base = *rdata;
5354 desc.buflen = mdrcnt;
5355 desc.format = str2;
5356 if (init_package(&desc,1,0)) {
5357 PACKS(&desc,"B13","lp0");
5360 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5362 *rdata_len = desc.usedlen;
5364 *rparam_len = 8;
5365 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5366 if (!*rparam) {
5367 return False;
5369 SSVALS(*rparam,0,desc.errcode);
5370 SSVAL(*rparam,2,0);
5371 SSVAL(*rparam,4,succnt);
5372 SSVAL(*rparam,6,1);
5374 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
5376 return True;
5379 /****************************************************************************
5380 List open sessions
5381 ****************************************************************************/
5383 static bool api_RNetSessionEnum(struct smbd_server_connection *sconn,
5384 connection_struct *conn, uint16 vuid,
5385 char *param, int tpscnt,
5386 char *data, int tdscnt,
5387 int mdrcnt,int mprcnt,
5388 char **rdata,char **rparam,
5389 int *rdata_len,int *rparam_len)
5392 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5393 char *str2 = skip_string(param,tpscnt,str1);
5394 char *p = skip_string(param,tpscnt,str2);
5395 int uLevel;
5396 struct pack_desc desc;
5397 struct sessionid *session_list;
5398 int i, num_sessions;
5400 if (!str1 || !str2 || !p) {
5401 return False;
5404 memset((char *)&desc,'\0',sizeof(desc));
5406 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5408 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
5409 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
5410 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
5412 /* check it's a supported varient */
5413 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
5414 return False;
5416 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
5417 return False;
5420 num_sessions = list_sessions(talloc_tos(), &session_list);
5422 if (mdrcnt > 0) {
5423 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5424 if (!*rdata) {
5425 return False;
5428 memset((char *)&desc,'\0',sizeof(desc));
5429 desc.base = *rdata;
5430 desc.buflen = mdrcnt;
5431 desc.format = str2;
5432 if (!init_package(&desc,num_sessions,0)) {
5433 return False;
5436 for(i=0; i<num_sessions; i++) {
5437 PACKS(&desc, "z", session_list[i].remote_machine);
5438 PACKS(&desc, "z", session_list[i].username);
5439 PACKI(&desc, "W", 1); /* num conns */
5440 PACKI(&desc, "W", 0); /* num opens */
5441 PACKI(&desc, "W", 1); /* num users */
5442 PACKI(&desc, "D", 0); /* session time */
5443 PACKI(&desc, "D", 0); /* idle time */
5444 PACKI(&desc, "D", 0); /* flags */
5445 PACKS(&desc, "z", "Unknown Client"); /* client type string */
5448 *rdata_len = desc.usedlen;
5450 *rparam_len = 8;
5451 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5452 if (!*rparam) {
5453 return False;
5455 SSVALS(*rparam,0,desc.errcode);
5456 SSVAL(*rparam,2,0); /* converter */
5457 SSVAL(*rparam,4,num_sessions); /* count */
5459 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
5461 return True;
5465 /****************************************************************************
5466 The buffer was too small.
5467 ****************************************************************************/
5469 static bool api_TooSmall(struct smbd_server_connection *sconn,
5470 connection_struct *conn,uint16 vuid, char *param, char *data,
5471 int mdrcnt, int mprcnt,
5472 char **rdata, char **rparam,
5473 int *rdata_len, int *rparam_len)
5475 *rparam_len = MIN(*rparam_len,mprcnt);
5476 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5477 if (!*rparam) {
5478 return False;
5481 *rdata_len = 0;
5483 SSVAL(*rparam,0,NERR_BufTooSmall);
5485 DEBUG(3,("Supplied buffer too small in API command\n"));
5487 return True;
5490 /****************************************************************************
5491 The request is not supported.
5492 ****************************************************************************/
5494 static bool api_Unsupported(struct smbd_server_connection *sconn,
5495 connection_struct *conn, uint16 vuid,
5496 char *param, int tpscnt,
5497 char *data, int tdscnt,
5498 int mdrcnt, int mprcnt,
5499 char **rdata, char **rparam,
5500 int *rdata_len, int *rparam_len)
5502 *rparam_len = 4;
5503 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5504 if (!*rparam) {
5505 return False;
5508 *rdata_len = 0;
5510 SSVAL(*rparam,0,NERR_notsupported);
5511 SSVAL(*rparam,2,0); /* converter word */
5513 DEBUG(3,("Unsupported API command\n"));
5515 return True;
5518 static const struct {
5519 const char *name;
5520 int id;
5521 bool (*fn)(struct smbd_server_connection *sconn,
5522 connection_struct *, uint16,
5523 char *, int,
5524 char *, int,
5525 int,int,char **,char **,int *,int *);
5526 bool auth_user; /* Deny anonymous access? */
5527 } api_commands[] = {
5528 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
5529 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
5530 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
5531 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
5532 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
5533 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
5534 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
5535 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
5536 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
5537 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
5538 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
5539 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
5540 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
5541 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
5542 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
5543 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
5544 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
5545 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
5546 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
5547 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
5548 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
5549 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
5550 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
5551 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
5552 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
5553 {"NetServerEnum3", RAP_NetServerEnum3, api_RNetServerEnum3}, /* anon OK */
5554 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
5555 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
5556 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
5557 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
5558 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
5559 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
5560 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
5561 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
5562 {NULL, -1, api_Unsupported}
5563 /* The following RAP calls are not implemented by Samba:
5565 RAP_WFileEnum2 - anon not OK
5570 /****************************************************************************
5571 Handle remote api calls.
5572 ****************************************************************************/
5574 void api_reply(connection_struct *conn, uint16 vuid,
5575 struct smb_request *req,
5576 char *data, char *params,
5577 int tdscnt, int tpscnt,
5578 int mdrcnt, int mprcnt)
5580 int api_command;
5581 char *rdata = NULL;
5582 char *rparam = NULL;
5583 const char *name1 = NULL;
5584 const char *name2 = NULL;
5585 int rdata_len = 0;
5586 int rparam_len = 0;
5587 bool reply=False;
5588 int i;
5590 if (!params) {
5591 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
5592 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5593 return;
5596 if (tpscnt < 2) {
5597 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5598 return;
5600 api_command = SVAL(params,0);
5601 /* Is there a string at position params+2 ? */
5602 if (skip_string(params,tpscnt,params+2)) {
5603 name1 = params + 2;
5604 } else {
5605 name1 = "";
5607 name2 = skip_string(params,tpscnt,params+2);
5608 if (!name2) {
5609 name2 = "";
5612 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
5613 api_command,
5614 name1,
5615 name2,
5616 tdscnt,tpscnt,mdrcnt,mprcnt));
5618 for (i=0;api_commands[i].name;i++) {
5619 if (api_commands[i].id == api_command && api_commands[i].fn) {
5620 DEBUG(3,("Doing %s\n",api_commands[i].name));
5621 break;
5625 /* Check whether this api call can be done anonymously */
5627 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
5628 user_struct *user = get_valid_user_struct(req->sconn, vuid);
5630 if (!user || user->server_info->guest) {
5631 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5632 return;
5636 rdata = (char *)SMB_MALLOC(1024);
5637 if (rdata) {
5638 memset(rdata,'\0',1024);
5641 rparam = (char *)SMB_MALLOC(1024);
5642 if (rparam) {
5643 memset(rparam,'\0',1024);
5646 if(!rdata || !rparam) {
5647 DEBUG(0,("api_reply: malloc fail !\n"));
5648 SAFE_FREE(rdata);
5649 SAFE_FREE(rparam);
5650 reply_nterror(req, NT_STATUS_NO_MEMORY);
5651 return;
5654 reply = api_commands[i].fn(req->sconn, conn,
5655 vuid,
5656 params,tpscnt, /* params + length */
5657 data,tdscnt, /* data + length */
5658 mdrcnt,mprcnt,
5659 &rdata,&rparam,&rdata_len,&rparam_len);
5662 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
5663 reply = api_TooSmall(req->sconn,conn,vuid,params,data,
5664 mdrcnt,mprcnt,
5665 &rdata,&rparam,&rdata_len,&rparam_len);
5668 /* if we get False back then it's actually unsupported */
5669 if (!reply) {
5670 reply = api_Unsupported(req->sconn,conn,vuid,params,tpscnt,
5671 data,
5672 tdscnt,mdrcnt,mprcnt,
5673 &rdata,&rparam,&rdata_len,&rparam_len);
5676 /* If api_Unsupported returns false we can't return anything. */
5677 if (reply) {
5678 send_trans_reply(conn, req, rparam, rparam_len,
5679 rdata, rdata_len, False);
5682 SAFE_FREE(rdata);
5683 SAFE_FREE(rparam);
5684 return;