s3-auth: Move auth_ntlmssp wrappers in their own file
[Samba/vl.git] / source3 / smbd / lanman.c
blobce7ad0e56d27fddff26a6c5859c51964c2f3e083
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"
41 #ifdef CHECK_TYPES
42 #undef CHECK_TYPES
43 #endif
44 #define CHECK_TYPES 0
46 #define NERR_Success 0
47 #define NERR_badpass 86
48 #define NERR_notsupported 50
50 #define NERR_BASE (2100)
51 #define NERR_BufTooSmall (NERR_BASE+23)
52 #define NERR_JobNotFound (NERR_BASE+51)
53 #define NERR_DestNotFound (NERR_BASE+52)
55 #define ACCESS_READ 0x01
56 #define ACCESS_WRITE 0x02
57 #define ACCESS_CREATE 0x04
59 #define SHPWLEN 8 /* share password length */
61 /* Limit size of ipc replies */
63 static char *smb_realloc_limit(void *ptr, size_t size)
65 char *val;
67 size = MAX((size),4*1024);
68 val = (char *)SMB_REALLOC(ptr,size);
69 if (val) {
70 memset(val,'\0',size);
72 return val;
75 static bool api_Unsupported(struct smbd_server_connection *sconn,
76 connection_struct *conn, uint16 vuid,
77 char *param, int tpscnt,
78 char *data, int tdscnt,
79 int mdrcnt, int mprcnt,
80 char **rdata, char **rparam,
81 int *rdata_len, int *rparam_len);
83 static bool api_TooSmall(struct smbd_server_connection *sconn,
84 connection_struct *conn, uint16 vuid, char *param, char *data,
85 int mdrcnt, int mprcnt,
86 char **rdata, char **rparam,
87 int *rdata_len, int *rparam_len);
90 static int CopyExpanded(connection_struct *conn,
91 int snum, char **dst, char *src, int *p_space_remaining)
93 TALLOC_CTX *ctx = talloc_tos();
94 char *buf = NULL;
95 int l;
97 if (!src || !dst || !p_space_remaining || !(*dst) ||
98 *p_space_remaining <= 0) {
99 return 0;
102 buf = talloc_strdup(ctx, src);
103 if (!buf) {
104 *p_space_remaining = 0;
105 return 0;
107 buf = talloc_string_sub(ctx, buf,"%S",lp_servicename(snum));
108 if (!buf) {
109 *p_space_remaining = 0;
110 return 0;
112 buf = talloc_sub_advanced(ctx,
113 lp_servicename(SNUM(conn)),
114 conn->server_info->unix_name,
115 conn->connectpath,
116 conn->server_info->utok.gid,
117 conn->server_info->sanitized_username,
118 conn->server_info->info3->base.domain.string,
119 buf);
120 if (!buf) {
121 *p_space_remaining = 0;
122 return 0;
124 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
125 if (l == -1) {
126 return 0;
128 (*dst) += l;
129 (*p_space_remaining) -= l;
130 return l;
133 static int CopyAndAdvance(char **dst, char *src, int *n)
135 int l;
136 if (!src || !dst || !n || !(*dst)) {
137 return 0;
139 l = push_ascii(*dst,src,*n, STR_TERMINATE);
140 if (l == -1) {
141 return 0;
143 (*dst) += l;
144 (*n) -= l;
145 return l;
148 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
150 TALLOC_CTX *ctx = talloc_tos();
151 char *buf = NULL;
152 if (!s) {
153 return 0;
155 buf = talloc_strdup(ctx,s);
156 if (!buf) {
157 return 0;
159 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
160 if (!buf) {
161 return 0;
163 buf = talloc_sub_advanced(ctx,
164 lp_servicename(SNUM(conn)),
165 conn->server_info->unix_name,
166 conn->connectpath,
167 conn->server_info->utok.gid,
168 conn->server_info->sanitized_username,
169 conn->server_info->info3->base.domain.string,
170 buf);
171 if (!buf) {
172 return 0;
174 return strlen(buf) + 1;
177 /*******************************************************************
178 Check a API string for validity when we only need to check the prefix.
179 ******************************************************************/
181 static bool prefix_ok(const char *str, const char *prefix)
183 return(strncmp(str,prefix,strlen(prefix)) == 0);
186 struct pack_desc {
187 const char *format; /* formatstring for structure */
188 const char *subformat; /* subformat for structure */
189 char *base; /* baseaddress of buffer */
190 int buflen; /* remaining size for fixed part; on init: length of base */
191 int subcount; /* count of substructures */
192 char *structbuf; /* pointer into buffer for remaining fixed part */
193 int stringlen; /* remaining size for variable part */
194 char *stringbuf; /* pointer into buffer for remaining variable part */
195 int neededlen; /* total needed size */
196 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
197 const char *curpos; /* current position; pointer into format or subformat */
198 int errcode;
201 static int get_counter(const char **p)
203 int i, n;
204 if (!p || !(*p)) {
205 return 1;
207 if (!isdigit((int)**p)) {
208 return 1;
210 for (n = 0;;) {
211 i = **p;
212 if (isdigit(i)) {
213 n = 10 * n + (i - '0');
214 } else {
215 return n;
217 (*p)++;
221 static int getlen(const char *p)
223 int n = 0;
224 if (!p) {
225 return 0;
228 while (*p) {
229 switch( *p++ ) {
230 case 'W': /* word (2 byte) */
231 n += 2;
232 break;
233 case 'K': /* status word? (2 byte) */
234 n += 2;
235 break;
236 case 'N': /* count of substructures (word) at end */
237 n += 2;
238 break;
239 case 'D': /* double word (4 byte) */
240 case 'z': /* offset to zero terminated string (4 byte) */
241 case 'l': /* offset to user data (4 byte) */
242 n += 4;
243 break;
244 case 'b': /* offset to data (with counter) (4 byte) */
245 n += 4;
246 get_counter(&p);
247 break;
248 case 'B': /* byte (with optional counter) */
249 n += get_counter(&p);
250 break;
253 return n;
256 static bool init_package(struct pack_desc *p, int count, int subcount)
258 int n = p->buflen;
259 int i;
261 if (!p->format || !p->base) {
262 return False;
265 i = count * getlen(p->format);
266 if (p->subformat) {
267 i += subcount * getlen(p->subformat);
269 p->structbuf = p->base;
270 p->neededlen = 0;
271 p->usedlen = 0;
272 p->subcount = 0;
273 p->curpos = p->format;
274 if (i > n) {
275 p->neededlen = i;
276 i = n = 0;
277 #if 0
279 * This is the old error code we used. Aparently
280 * WinNT/2k systems return ERRbuftoosmall (2123) and
281 * OS/2 needs this. I'm leaving this here so we can revert
282 * if needed. JRA.
284 p->errcode = ERRmoredata;
285 #else
286 p->errcode = ERRbuftoosmall;
287 #endif
288 } else {
289 p->errcode = NERR_Success;
291 p->buflen = i;
292 n -= i;
293 p->stringbuf = p->base + i;
294 p->stringlen = n;
295 return (p->errcode == NERR_Success);
298 static int package(struct pack_desc *p, ...)
300 va_list args;
301 int needed=0, stringneeded;
302 const char *str=NULL;
303 int is_string=0, stringused;
304 int32 temp;
306 va_start(args,p);
308 if (!*p->curpos) {
309 if (!p->subcount) {
310 p->curpos = p->format;
311 } else {
312 p->curpos = p->subformat;
313 p->subcount--;
316 #if CHECK_TYPES
317 str = va_arg(args,char*);
318 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
319 #endif
320 stringneeded = -1;
322 if (!p->curpos) {
323 va_end(args);
324 return 0;
327 switch( *p->curpos++ ) {
328 case 'W': /* word (2 byte) */
329 needed = 2;
330 temp = va_arg(args,int);
331 if (p->buflen >= needed) {
332 SSVAL(p->structbuf,0,temp);
334 break;
335 case 'K': /* status word? (2 byte) */
336 needed = 2;
337 temp = va_arg(args,int);
338 if (p->buflen >= needed) {
339 SSVAL(p->structbuf,0,temp);
341 break;
342 case 'N': /* count of substructures (word) at end */
343 needed = 2;
344 p->subcount = va_arg(args,int);
345 if (p->buflen >= needed) {
346 SSVAL(p->structbuf,0,p->subcount);
348 break;
349 case 'D': /* double word (4 byte) */
350 needed = 4;
351 temp = va_arg(args,int);
352 if (p->buflen >= needed) {
353 SIVAL(p->structbuf,0,temp);
355 break;
356 case 'B': /* byte (with optional counter) */
357 needed = get_counter(&p->curpos);
359 char *s = va_arg(args,char*);
360 if (p->buflen >= needed) {
361 StrnCpy(p->structbuf,s?s:"",needed-1);
364 break;
365 case 'z': /* offset to zero terminated string (4 byte) */
366 str = va_arg(args,char*);
367 stringneeded = (str ? strlen(str)+1 : 0);
368 is_string = 1;
369 break;
370 case 'l': /* offset to user data (4 byte) */
371 str = va_arg(args,char*);
372 stringneeded = va_arg(args,int);
373 is_string = 0;
374 break;
375 case 'b': /* offset to data (with counter) (4 byte) */
376 str = va_arg(args,char*);
377 stringneeded = get_counter(&p->curpos);
378 is_string = 0;
379 break;
382 va_end(args);
383 if (stringneeded >= 0) {
384 needed = 4;
385 if (p->buflen >= needed) {
386 stringused = stringneeded;
387 if (stringused > p->stringlen) {
388 stringused = (is_string ? p->stringlen : 0);
389 if (p->errcode == NERR_Success) {
390 p->errcode = ERRmoredata;
393 if (!stringused) {
394 SIVAL(p->structbuf,0,0);
395 } else {
396 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
397 memcpy(p->stringbuf,str?str:"",stringused);
398 if (is_string) {
399 p->stringbuf[stringused-1] = '\0';
401 p->stringbuf += stringused;
402 p->stringlen -= stringused;
403 p->usedlen += stringused;
406 p->neededlen += stringneeded;
409 p->neededlen += needed;
410 if (p->buflen >= needed) {
411 p->structbuf += needed;
412 p->buflen -= needed;
413 p->usedlen += needed;
414 } else {
415 if (p->errcode == NERR_Success) {
416 p->errcode = ERRmoredata;
419 return 1;
422 #if CHECK_TYPES
423 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
424 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
425 #else
426 #define PACK(desc,t,v) package(desc,v)
427 #define PACKl(desc,t,v,l) package(desc,v,l)
428 #endif
430 static void PACKI(struct pack_desc* desc, const char *t,int v)
432 PACK(desc,t,v);
435 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
437 PACK(desc,t,v);
440 /****************************************************************************
441 Get a print queue.
442 ****************************************************************************/
444 static void PackDriverData(struct pack_desc* desc)
446 char drivdata[4+4+32];
447 SIVAL(drivdata,0,sizeof drivdata); /* cb */
448 SIVAL(drivdata,4,1000); /* lVersion */
449 memset(drivdata+8,0,32); /* szDeviceName */
450 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
451 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
454 static int check_printq_info(struct pack_desc* desc,
455 unsigned int uLevel, char *id1, char *id2)
457 desc->subformat = NULL;
458 switch( uLevel ) {
459 case 0:
460 desc->format = "B13";
461 break;
462 case 1:
463 desc->format = "B13BWWWzzzzzWW";
464 break;
465 case 2:
466 desc->format = "B13BWWWzzzzzWN";
467 desc->subformat = "WB21BB16B10zWWzDDz";
468 break;
469 case 3:
470 desc->format = "zWWWWzzzzWWzzl";
471 break;
472 case 4:
473 desc->format = "zWWWWzzzzWNzzl";
474 desc->subformat = "WWzWWDDzz";
475 break;
476 case 5:
477 desc->format = "z";
478 break;
479 case 51:
480 desc->format = "K";
481 break;
482 case 52:
483 desc->format = "WzzzzzzzzN";
484 desc->subformat = "z";
485 break;
486 default:
487 DEBUG(0,("check_printq_info: invalid level %d\n",
488 uLevel ));
489 return False;
491 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
492 DEBUG(0,("check_printq_info: invalid format %s\n",
493 id1 ? id1 : "<NULL>" ));
494 return False;
496 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
497 DEBUG(0,("check_printq_info: invalid subformat %s\n",
498 id2 ? id2 : "<NULL>" ));
499 return False;
501 return True;
505 #define RAP_JOB_STATUS_QUEUED 0
506 #define RAP_JOB_STATUS_PAUSED 1
507 #define RAP_JOB_STATUS_SPOOLING 2
508 #define RAP_JOB_STATUS_PRINTING 3
509 #define RAP_JOB_STATUS_PRINTED 4
511 #define RAP_QUEUE_STATUS_PAUSED 1
512 #define RAP_QUEUE_STATUS_ERROR 2
514 /* turn a print job status into a on the wire status
516 static int printj_spoolss_status(int v)
518 if (v == JOB_STATUS_QUEUED)
519 return RAP_JOB_STATUS_QUEUED;
520 if (v & JOB_STATUS_PAUSED)
521 return RAP_JOB_STATUS_PAUSED;
522 if (v & JOB_STATUS_SPOOLING)
523 return RAP_JOB_STATUS_SPOOLING;
524 if (v & JOB_STATUS_PRINTING)
525 return RAP_JOB_STATUS_PRINTING;
526 return 0;
529 /* turn a print queue status into a on the wire status
531 static int printq_spoolss_status(int v)
533 if (v == PRINTER_STATUS_OK)
534 return 0;
535 if (v & PRINTER_STATUS_PAUSED)
536 return RAP_QUEUE_STATUS_PAUSED;
537 return RAP_QUEUE_STATUS_ERROR;
540 static void fill_spoolss_printjob_info(int uLevel,
541 struct pack_desc *desc,
542 struct spoolss_JobInfo2 *info2,
543 int n)
545 time_t t = spoolss_Time_to_time_t(&info2->submitted);
547 /* the client expects localtime */
548 t -= get_time_zone(t);
550 PACKI(desc,"W",pjobid_to_rap(info2->printer_name, info2->job_id)); /* uJobId */
551 if (uLevel == 1) {
552 PACKS(desc,"B21", info2->user_name); /* szUserName */
553 PACKS(desc,"B",""); /* pad */
554 PACKS(desc,"B16",""); /* szNotifyName */
555 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
556 PACKS(desc,"z",""); /* pszParms */
557 PACKI(desc,"W",n+1); /* uPosition */
558 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
559 PACKS(desc,"z",""); /* pszStatus */
560 PACKI(desc,"D", t); /* ulSubmitted */
561 PACKI(desc,"D", info2->size); /* ulSize */
562 PACKS(desc,"z", info2->document_name); /* pszComment */
564 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
565 PACKI(desc,"W", info2->priority); /* uPriority */
566 PACKS(desc,"z", info2->user_name); /* pszUserName */
567 PACKI(desc,"W",n+1); /* uPosition */
568 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
569 PACKI(desc,"D",t); /* ulSubmitted */
570 PACKI(desc,"D", info2->size); /* ulSize */
571 PACKS(desc,"z","Samba"); /* pszComment */
572 PACKS(desc,"z", info2->document_name); /* pszDocument */
573 if (uLevel == 3) {
574 PACKS(desc,"z",""); /* pszNotifyName */
575 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
576 PACKS(desc,"z",""); /* pszParms */
577 PACKS(desc,"z",""); /* pszStatus */
578 PACKS(desc,"z", info2->printer_name); /* pszQueue */
579 PACKS(desc,"z","lpd"); /* pszQProcName */
580 PACKS(desc,"z",""); /* pszQProcParms */
581 PACKS(desc,"z","NULL"); /* pszDriverName */
582 PackDriverData(desc); /* pDriverData */
583 PACKS(desc,"z",""); /* pszPrinterName */
584 } else if (uLevel == 4) { /* OS2 */
585 PACKS(desc,"z",""); /* pszSpoolFileName */
586 PACKS(desc,"z",""); /* pszPortName */
587 PACKS(desc,"z",""); /* pszStatus */
588 PACKI(desc,"D",0); /* ulPagesSpooled */
589 PACKI(desc,"D",0); /* ulPagesSent */
590 PACKI(desc,"D",0); /* ulPagesPrinted */
591 PACKI(desc,"D",0); /* ulTimePrinted */
592 PACKI(desc,"D",0); /* ulExtendJobStatus */
593 PACKI(desc,"D",0); /* ulStartPage */
594 PACKI(desc,"D",0); /* ulEndPage */
599 /********************************************************************
600 Respond to the DosPrintQInfo command with a level of 52
601 This is used to get printer driver information for Win9x clients
602 ********************************************************************/
603 static void fill_printq_info_52(struct spoolss_DriverInfo3 *driver,
604 struct pack_desc* desc, int count,
605 const char *printer_name)
607 int i;
608 fstring location;
609 trim_string((char *)driver->driver_path, "\\print$\\WIN40\\0\\", 0);
610 trim_string((char *)driver->data_file, "\\print$\\WIN40\\0\\", 0);
611 trim_string((char *)driver->help_file, "\\print$\\WIN40\\0\\", 0);
613 PACKI(desc, "W", 0x0400); /* don't know */
614 PACKS(desc, "z", driver->driver_name); /* long printer name */
615 PACKS(desc, "z", driver->driver_path); /* Driverfile Name */
616 PACKS(desc, "z", driver->data_file); /* Datafile name */
617 PACKS(desc, "z", driver->monitor_name); /* language monitor */
619 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
620 standard_sub_basic( "", "", location, sizeof(location)-1 );
621 PACKS(desc,"z", location); /* share to retrieve files */
623 PACKS(desc,"z", driver->default_datatype); /* default data type */
624 PACKS(desc,"z", driver->help_file); /* helpfile name */
625 PACKS(desc,"z", driver->driver_path); /* driver name */
627 DEBUG(3,("Printer Driver Name: %s:\n",driver->driver_name));
628 DEBUG(3,("Driver: %s:\n",driver->driver_path));
629 DEBUG(3,("Data File: %s:\n",driver->data_file));
630 DEBUG(3,("Language Monitor: %s:\n",driver->monitor_name));
631 DEBUG(3,("Driver Location: %s:\n",location));
632 DEBUG(3,("Data Type: %s:\n",driver->default_datatype));
633 DEBUG(3,("Help File: %s:\n",driver->help_file));
634 PACKI(desc,"N",count); /* number of files to copy */
636 for ( i=0; i<count && driver->dependent_files && *driver->dependent_files[i]; i++)
638 trim_string((char *)driver->dependent_files[i], "\\print$\\WIN40\\0\\", 0);
639 PACKS(desc,"z",driver->dependent_files[i]); /* driver files to copy */
640 DEBUG(3,("Dependent File: %s:\n", driver->dependent_files[i]));
643 /* sanity check */
644 if ( i != count )
645 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
646 count, i));
648 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", printer_name, i));
650 desc->errcode=NERR_Success;
654 static const char *strip_unc(const char *unc)
656 char *p;
658 if (unc == NULL) {
659 return NULL;
662 if ((p = strrchr(unc, '\\')) != NULL) {
663 return p+1;
666 return unc;
669 static void fill_printq_info(int uLevel,
670 struct pack_desc* desc,
671 int count,
672 union spoolss_JobInfo *job_info,
673 struct spoolss_DriverInfo3 *driver_info,
674 struct spoolss_PrinterInfo2 *printer_info)
676 switch (uLevel) {
677 case 0:
678 case 1:
679 case 2:
680 PACKS(desc,"B13", strip_unc(printer_info->printername));
681 break;
682 case 3:
683 case 4:
684 case 5:
685 PACKS(desc,"z", strip_unc(printer_info->printername));
686 break;
687 case 51:
688 PACKI(desc,"K", printq_spoolss_status(printer_info->status));
689 break;
692 if (uLevel == 1 || uLevel == 2) {
693 PACKS(desc,"B",""); /* alignment */
694 PACKI(desc,"W",5); /* priority */
695 PACKI(desc,"W",0); /* start time */
696 PACKI(desc,"W",0); /* until time */
697 PACKS(desc,"z",""); /* pSepFile */
698 PACKS(desc,"z","lpd"); /* pPrProc */
699 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pDestinations */
700 PACKS(desc,"z",""); /* pParms */
701 if (printer_info->printername == NULL) {
702 PACKS(desc,"z","UNKNOWN PRINTER");
703 PACKI(desc,"W",LPSTAT_ERROR);
704 } else {
705 PACKS(desc,"z", printer_info->comment);
706 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* status */
708 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
711 if (uLevel == 3 || uLevel == 4) {
712 PACKI(desc,"W",5); /* uPriority */
713 PACKI(desc,"W",0); /* uStarttime */
714 PACKI(desc,"W",0); /* uUntiltime */
715 PACKI(desc,"W",5); /* pad1 */
716 PACKS(desc,"z",""); /* pszSepFile */
717 PACKS(desc,"z","WinPrint"); /* pszPrProc */
718 PACKS(desc,"z",NULL); /* pszParms */
719 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
720 /* "don't ask" that it's done this way to fix corrupted
721 Win9X/ME printer comments. */
722 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* fsStatus */
723 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
724 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pszPrinters */
725 PACKS(desc,"z", printer_info->drivername); /* pszDriverName */
726 PackDriverData(desc); /* pDriverData */
729 if (uLevel == 2 || uLevel == 4) {
730 int i;
731 for (i = 0; i < count; i++) {
732 fill_spoolss_printjob_info(uLevel == 2 ? 1 : 2, desc, &job_info[i].info2, i);
736 if (uLevel==52)
737 fill_printq_info_52(driver_info, desc, count, printer_info->printername);
740 /* This function returns the number of files for a given driver */
741 static int get_printerdrivernumber(const struct spoolss_DriverInfo3 *driver)
743 int result = 0;
745 /* count the number of files */
746 while (driver->dependent_files && *driver->dependent_files[result])
747 result++;
749 return result;
752 static bool api_DosPrintQGetInfo(struct smbd_server_connection *sconn,
753 connection_struct *conn, uint16 vuid,
754 char *param, int tpscnt,
755 char *data, int tdscnt,
756 int mdrcnt,int mprcnt,
757 char **rdata,char **rparam,
758 int *rdata_len,int *rparam_len)
760 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
761 char *str2 = skip_string(param,tpscnt,str1);
762 char *p = skip_string(param,tpscnt,str2);
763 char *QueueName = p;
764 unsigned int uLevel;
765 uint32_t count = 0;
766 char *str3;
767 struct pack_desc desc;
768 char* tmpdata=NULL;
770 WERROR werr = WERR_OK;
771 TALLOC_CTX *mem_ctx = talloc_tos();
772 NTSTATUS status;
773 struct rpc_pipe_client *cli = NULL;
774 struct policy_handle handle;
775 struct spoolss_DevmodeContainer devmode_ctr;
776 union spoolss_DriverInfo driver_info;
777 union spoolss_JobInfo *job_info = NULL;
778 union spoolss_PrinterInfo printer_info;
780 if (!str1 || !str2 || !p) {
781 return False;
783 memset((char *)&desc,'\0',sizeof(desc));
785 p = skip_string(param,tpscnt,p);
786 if (!p) {
787 return False;
789 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
790 str3 = get_safe_str_ptr(param,tpscnt,p,4);
791 /* str3 may be null here and is checked in check_printq_info(). */
793 /* remove any trailing username */
794 if ((p = strchr_m(QueueName,'%')))
795 *p = 0;
797 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
799 /* check it's a supported varient */
800 if (!prefix_ok(str1,"zWrLh"))
801 return False;
802 if (!check_printq_info(&desc,uLevel,str2,str3)) {
804 * Patch from Scott Moomaw <scott@bridgewater.edu>
805 * to return the 'invalid info level' error if an
806 * unknown level was requested.
808 *rdata_len = 0;
809 *rparam_len = 6;
810 *rparam = smb_realloc_limit(*rparam,*rparam_len);
811 if (!*rparam) {
812 return False;
814 SSVALS(*rparam,0,ERRunknownlevel);
815 SSVAL(*rparam,2,0);
816 SSVAL(*rparam,4,0);
817 return(True);
820 ZERO_STRUCT(handle);
822 if (QueueName == NULL || (strlen(QueueName) < 1)) {
823 desc.errcode = W_ERROR_V(WERR_INVALID_PARAM);
824 goto out;
827 status = rpc_connect_spoolss_pipe(conn, &cli);
828 if (!NT_STATUS_IS_OK(status)) {
829 DEBUG(0,("api_DosPrintQGetInfo: could not connect to spoolss: %s\n",
830 nt_errstr(status)));
831 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
832 goto out;
835 ZERO_STRUCT(devmode_ctr);
837 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
838 QueueName,
839 "RAW",
840 devmode_ctr,
841 PRINTER_ACCESS_USE,
842 &handle,
843 &werr);
844 if (!NT_STATUS_IS_OK(status)) {
845 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
846 goto out;
848 if (!W_ERROR_IS_OK(werr)) {
849 desc.errcode = W_ERROR_V(werr);
850 goto out;
853 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
854 &handle,
857 &printer_info);
858 if (!W_ERROR_IS_OK(werr)) {
859 desc.errcode = W_ERROR_V(werr);
860 goto out;
863 if (uLevel==52) {
864 uint32_t server_major_version;
865 uint32_t server_minor_version;
867 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
868 &handle,
869 "Windows 4.0",
870 3, /* level */
872 0, /* version */
874 &driver_info,
875 &server_major_version,
876 &server_minor_version);
877 if (!W_ERROR_IS_OK(werr)) {
878 desc.errcode = W_ERROR_V(werr);
879 goto out;
882 count = get_printerdrivernumber(&driver_info.info3);
883 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
884 } else {
885 uint32_t num_jobs;
886 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
887 &handle,
888 0, /* firstjob */
889 0xff, /* numjobs */
890 2, /* level */
891 0, /* offered */
892 &num_jobs,
893 &job_info);
894 if (!W_ERROR_IS_OK(werr)) {
895 desc.errcode = W_ERROR_V(werr);
896 goto out;
899 count = num_jobs;
902 if (mdrcnt > 0) {
903 *rdata = smb_realloc_limit(*rdata,mdrcnt);
904 if (!*rdata) {
905 return False;
907 desc.base = *rdata;
908 desc.buflen = mdrcnt;
909 } else {
911 * Don't return data but need to get correct length
912 * init_package will return wrong size if buflen=0
914 desc.buflen = getlen(desc.format);
915 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
918 if (init_package(&desc,1,count)) {
919 desc.subcount = count;
920 fill_printq_info(uLevel,&desc,count, job_info, &driver_info.info3, &printer_info.info2);
923 *rdata_len = desc.usedlen;
926 * We must set the return code to ERRbuftoosmall
927 * in order to support lanman style printing with Win NT/2k
928 * clients --jerry
930 if (!mdrcnt && lp_disable_spoolss())
931 desc.errcode = ERRbuftoosmall;
933 out:
934 if (cli && is_valid_policy_hnd(&handle)) {
935 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
938 *rdata_len = desc.usedlen;
939 *rparam_len = 6;
940 *rparam = smb_realloc_limit(*rparam,*rparam_len);
941 if (!*rparam) {
942 SAFE_FREE(tmpdata);
943 return False;
945 SSVALS(*rparam,0,desc.errcode);
946 SSVAL(*rparam,2,0);
947 SSVAL(*rparam,4,desc.neededlen);
949 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
951 SAFE_FREE(tmpdata);
953 return(True);
956 /****************************************************************************
957 View list of all print jobs on all queues.
958 ****************************************************************************/
960 static bool api_DosPrintQEnum(struct smbd_server_connection *sconn,
961 connection_struct *conn, uint16 vuid,
962 char *param, int tpscnt,
963 char *data, int tdscnt,
964 int mdrcnt, int mprcnt,
965 char **rdata, char** rparam,
966 int *rdata_len, int *rparam_len)
968 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
969 char *output_format1 = skip_string(param,tpscnt,param_format);
970 char *p = skip_string(param,tpscnt,output_format1);
971 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
972 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
973 int i;
974 struct pack_desc desc;
975 int *subcntarr = NULL;
976 int queuecnt = 0, subcnt = 0, succnt = 0;
978 WERROR werr = WERR_OK;
979 TALLOC_CTX *mem_ctx = talloc_tos();
980 NTSTATUS status;
981 struct rpc_pipe_client *cli = NULL;
982 struct spoolss_DevmodeContainer devmode_ctr;
983 uint32_t num_printers;
984 union spoolss_PrinterInfo *printer_info;
985 union spoolss_DriverInfo *driver_info;
986 union spoolss_JobInfo **job_info;
988 if (!param_format || !output_format1 || !p) {
989 return False;
992 memset((char *)&desc,'\0',sizeof(desc));
994 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
996 if (!prefix_ok(param_format,"WrLeh")) {
997 return False;
999 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
1001 * Patch from Scott Moomaw <scott@bridgewater.edu>
1002 * to return the 'invalid info level' error if an
1003 * unknown level was requested.
1005 *rdata_len = 0;
1006 *rparam_len = 6;
1007 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1008 if (!*rparam) {
1009 return False;
1011 SSVALS(*rparam,0,ERRunknownlevel);
1012 SSVAL(*rparam,2,0);
1013 SSVAL(*rparam,4,0);
1014 return(True);
1017 status = rpc_connect_spoolss_pipe(conn, &cli);
1018 if (!NT_STATUS_IS_OK(status)) {
1019 DEBUG(0,("api_DosPrintQEnum: could not connect to spoolss: %s\n",
1020 nt_errstr(status)));
1021 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1022 goto out;
1025 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
1026 PRINTER_ENUM_LOCAL,
1027 cli->srv_name_slash,
1030 &num_printers,
1031 &printer_info);
1032 if (!W_ERROR_IS_OK(werr)) {
1033 desc.errcode = W_ERROR_V(werr);
1034 goto out;
1037 queuecnt = num_printers;
1039 job_info = talloc_array(mem_ctx, union spoolss_JobInfo *, num_printers);
1040 if (job_info == NULL) {
1041 goto err;
1044 driver_info = talloc_array(mem_ctx, union spoolss_DriverInfo, num_printers);
1045 if (driver_info == NULL) {
1046 goto err;
1049 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1050 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1051 goto err;
1054 if (mdrcnt > 0) {
1055 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1056 if (!*rdata) {
1057 goto err;
1060 desc.base = *rdata;
1061 desc.buflen = mdrcnt;
1063 subcnt = 0;
1064 for (i = 0; i < num_printers; i++) {
1066 uint32_t num_jobs;
1067 struct policy_handle handle;
1068 const char *printername;
1070 printername = talloc_strdup(mem_ctx, printer_info[i].info2.printername);
1071 if (printername == NULL) {
1072 goto err;
1075 ZERO_STRUCT(handle);
1076 ZERO_STRUCT(devmode_ctr);
1078 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
1079 printername,
1080 "RAW",
1081 devmode_ctr,
1082 PRINTER_ACCESS_USE,
1083 &handle,
1084 &werr);
1085 if (!NT_STATUS_IS_OK(status)) {
1086 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1087 goto out;
1089 if (!W_ERROR_IS_OK(werr)) {
1090 desc.errcode = W_ERROR_V(werr);
1091 goto out;
1094 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
1095 &handle,
1096 0, /* firstjob */
1097 0xff, /* numjobs */
1098 2, /* level */
1099 0, /* offered */
1100 &num_jobs,
1101 &job_info[i]);
1102 if (!W_ERROR_IS_OK(werr)) {
1103 desc.errcode = W_ERROR_V(werr);
1104 goto out;
1107 if (uLevel==52) {
1108 uint32_t server_major_version;
1109 uint32_t server_minor_version;
1111 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1112 &handle,
1113 "Windows 4.0",
1114 3, /* level */
1116 0, /* version */
1118 &driver_info[i],
1119 &server_major_version,
1120 &server_minor_version);
1121 if (!W_ERROR_IS_OK(werr)) {
1122 desc.errcode = W_ERROR_V(werr);
1123 goto out;
1127 subcntarr[i] = num_jobs;
1128 subcnt += subcntarr[i];
1130 if (cli && is_valid_policy_hnd(&handle)) {
1131 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
1135 if (init_package(&desc,queuecnt,subcnt)) {
1136 for (i = 0; i < num_printers; i++) {
1137 fill_printq_info(uLevel,&desc,subcntarr[i], job_info[i], &driver_info[i].info3, &printer_info[i].info2);
1138 if (desc.errcode == NERR_Success) {
1139 succnt = i;
1144 SAFE_FREE(subcntarr);
1145 out:
1146 *rdata_len = desc.usedlen;
1147 *rparam_len = 8;
1148 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1149 if (!*rparam) {
1150 goto err;
1152 SSVALS(*rparam,0,desc.errcode);
1153 SSVAL(*rparam,2,0);
1154 SSVAL(*rparam,4,succnt);
1155 SSVAL(*rparam,6,queuecnt);
1157 return True;
1159 err:
1161 SAFE_FREE(subcntarr);
1163 return False;
1166 /****************************************************************************
1167 Get info level for a server list query.
1168 ****************************************************************************/
1170 static bool check_server_info(int uLevel, char* id)
1172 switch( uLevel ) {
1173 case 0:
1174 if (strcmp(id,"B16") != 0) {
1175 return False;
1177 break;
1178 case 1:
1179 if (strcmp(id,"B16BBDz") != 0) {
1180 return False;
1182 break;
1183 default:
1184 return False;
1186 return True;
1189 struct srv_info_struct {
1190 fstring name;
1191 uint32 type;
1192 fstring comment;
1193 fstring domain;
1194 bool server_added;
1197 /*******************************************************************
1198 Get server info lists from the files saved by nmbd. Return the
1199 number of entries.
1200 ******************************************************************/
1202 static int get_server_info(uint32 servertype,
1203 struct srv_info_struct **servers,
1204 const char *domain)
1206 int count=0;
1207 int alloced=0;
1208 char **lines;
1209 bool local_list_only;
1210 int i;
1212 lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
1213 if (!lines) {
1214 DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
1215 return 0;
1218 /* request for everything is code for request all servers */
1219 if (servertype == SV_TYPE_ALL) {
1220 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1223 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1225 DEBUG(4,("Servertype search: %8x\n",servertype));
1227 for (i=0;lines[i];i++) {
1228 fstring stype;
1229 struct srv_info_struct *s;
1230 const char *ptr = lines[i];
1231 bool ok = True;
1232 TALLOC_CTX *frame = NULL;
1233 char *p;
1235 if (!*ptr) {
1236 continue;
1239 if (count == alloced) {
1240 alloced += 10;
1241 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1242 if (!*servers) {
1243 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1244 TALLOC_FREE(lines);
1245 return 0;
1247 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1249 s = &(*servers)[count];
1251 frame = talloc_stackframe();
1252 s->name[0] = '\0';
1253 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1254 TALLOC_FREE(frame);
1255 continue;
1257 fstrcpy(s->name, p);
1259 stype[0] = '\0';
1260 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1261 TALLOC_FREE(frame);
1262 continue;
1264 fstrcpy(stype, p);
1266 s->comment[0] = '\0';
1267 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1268 TALLOC_FREE(frame);
1269 continue;
1271 fstrcpy(s->comment, p);
1272 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1274 s->domain[0] = '\0';
1275 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1276 /* this allows us to cope with an old nmbd */
1277 fstrcpy(s->domain,lp_workgroup());
1278 } else {
1279 fstrcpy(s->domain, p);
1281 TALLOC_FREE(frame);
1283 if (sscanf(stype,"%X",&s->type) != 1) {
1284 DEBUG(4,("r:host file "));
1285 ok = False;
1288 /* Filter the servers/domains we return based on what was asked for. */
1290 /* Check to see if we are being asked for a local list only. */
1291 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1292 DEBUG(4,("r: local list only"));
1293 ok = False;
1296 /* doesn't match up: don't want it */
1297 if (!(servertype & s->type)) {
1298 DEBUG(4,("r:serv type "));
1299 ok = False;
1302 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1303 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1304 DEBUG(4,("s: dom mismatch "));
1305 ok = False;
1308 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1309 ok = False;
1312 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1313 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1315 if (ok) {
1316 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1317 s->name, s->type, s->comment, s->domain));
1318 s->server_added = True;
1319 count++;
1320 } else {
1321 DEBUG(4,("%20s %8x %25s %15s\n",
1322 s->name, s->type, s->comment, s->domain));
1326 TALLOC_FREE(lines);
1327 return count;
1330 /*******************************************************************
1331 Fill in a server info structure.
1332 ******************************************************************/
1334 static int fill_srv_info(struct srv_info_struct *service,
1335 int uLevel, char **buf, int *buflen,
1336 char **stringbuf, int *stringspace, char *baseaddr)
1338 int struct_len;
1339 char* p;
1340 char* p2;
1341 int l2;
1342 int len;
1344 switch (uLevel) {
1345 case 0:
1346 struct_len = 16;
1347 break;
1348 case 1:
1349 struct_len = 26;
1350 break;
1351 default:
1352 return -1;
1355 if (!buf) {
1356 len = 0;
1357 switch (uLevel) {
1358 case 1:
1359 len = strlen(service->comment)+1;
1360 break;
1363 *buflen = struct_len;
1364 *stringspace = len;
1365 return struct_len + len;
1368 len = struct_len;
1369 p = *buf;
1370 if (*buflen < struct_len) {
1371 return -1;
1373 if (stringbuf) {
1374 p2 = *stringbuf;
1375 l2 = *stringspace;
1376 } else {
1377 p2 = p + struct_len;
1378 l2 = *buflen - struct_len;
1380 if (!baseaddr) {
1381 baseaddr = p;
1384 switch (uLevel) {
1385 case 0:
1386 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1387 break;
1389 case 1:
1390 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1391 SIVAL(p,18,service->type);
1392 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1393 len += CopyAndAdvance(&p2,service->comment,&l2);
1394 break;
1397 if (stringbuf) {
1398 *buf = p + struct_len;
1399 *buflen -= struct_len;
1400 *stringbuf = p2;
1401 *stringspace = l2;
1402 } else {
1403 *buf = p2;
1404 *buflen -= len;
1406 return len;
1410 static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1412 return StrCaseCmp(s1->name,s2->name);
1415 /****************************************************************************
1416 View list of servers available (or possibly domains). The info is
1417 extracted from lists saved by nmbd on the local host.
1418 ****************************************************************************/
1420 static bool api_RNetServerEnum2(struct smbd_server_connection *sconn,
1421 connection_struct *conn, uint16 vuid,
1422 char *param, int tpscnt,
1423 char *data, int tdscnt,
1424 int mdrcnt, int mprcnt, char **rdata,
1425 char **rparam, int *rdata_len, int *rparam_len)
1427 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1428 char *str2 = skip_string(param,tpscnt,str1);
1429 char *p = skip_string(param,tpscnt,str2);
1430 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1431 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1432 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1433 char *p2;
1434 int data_len, fixed_len, string_len;
1435 int f_len = 0, s_len = 0;
1436 struct srv_info_struct *servers=NULL;
1437 int counted=0,total=0;
1438 int i,missed;
1439 fstring domain;
1440 bool domain_request;
1441 bool local_request;
1443 if (!str1 || !str2 || !p) {
1444 return False;
1447 /* If someone sets all the bits they don't really mean to set
1448 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1449 known servers. */
1451 if (servertype == SV_TYPE_ALL) {
1452 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1455 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1456 any other bit (they may just set this bit on its own) they
1457 want all the locally seen servers. However this bit can be
1458 set on its own so set the requested servers to be
1459 ALL - DOMAIN_ENUM. */
1461 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1462 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1465 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1466 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1468 p += 8;
1470 if (!prefix_ok(str1,"WrLehD")) {
1471 return False;
1473 if (!check_server_info(uLevel,str2)) {
1474 return False;
1477 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1478 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1479 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1481 if (strcmp(str1, "WrLehDz") == 0) {
1482 if (skip_string(param,tpscnt,p) == NULL) {
1483 return False;
1485 pull_ascii_fstring(domain, p);
1486 } else {
1487 fstrcpy(domain, lp_workgroup());
1490 DEBUG(4, ("domain [%s]\n", domain));
1492 if (lp_browse_list()) {
1493 total = get_server_info(servertype,&servers,domain);
1496 data_len = fixed_len = string_len = 0;
1497 missed = 0;
1499 TYPESAFE_QSORT(servers, total, srv_comp);
1502 char *lastname=NULL;
1504 for (i=0;i<total;i++) {
1505 struct srv_info_struct *s = &servers[i];
1507 if (lastname && strequal(lastname,s->name)) {
1508 continue;
1510 lastname = s->name;
1511 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1512 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1513 i, s->name, s->type, s->comment, s->domain));
1515 if (data_len < buf_len) {
1516 counted++;
1517 fixed_len += f_len;
1518 string_len += s_len;
1519 } else {
1520 missed++;
1525 *rdata_len = fixed_len + string_len;
1526 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1527 if (!*rdata) {
1528 return False;
1531 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1532 p = *rdata;
1533 f_len = fixed_len;
1534 s_len = string_len;
1537 char *lastname=NULL;
1538 int count2 = counted;
1540 for (i = 0; i < total && count2;i++) {
1541 struct srv_info_struct *s = &servers[i];
1543 if (lastname && strequal(lastname,s->name)) {
1544 continue;
1546 lastname = s->name;
1547 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1548 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1549 i, s->name, s->type, s->comment, s->domain));
1550 count2--;
1554 *rparam_len = 8;
1555 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1556 if (!*rparam) {
1557 return False;
1559 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1560 SSVAL(*rparam,2,0);
1561 SSVAL(*rparam,4,counted);
1562 SSVAL(*rparam,6,counted+missed);
1564 SAFE_FREE(servers);
1566 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1567 domain,uLevel,counted,counted+missed));
1569 return True;
1572 static int srv_name_match(const char *n1, const char *n2)
1575 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1577 * In Windows, FirstNameToReturn need not be an exact match:
1578 * the server will return a list of servers that exist on
1579 * the network greater than or equal to the FirstNameToReturn.
1581 int ret = StrCaseCmp(n1, n2);
1583 if (ret <= 0) {
1584 return 0;
1587 return ret;
1590 static bool api_RNetServerEnum3(struct smbd_server_connection *sconn,
1591 connection_struct *conn, uint16 vuid,
1592 char *param, int tpscnt,
1593 char *data, int tdscnt,
1594 int mdrcnt, int mprcnt, char **rdata,
1595 char **rparam, int *rdata_len, int *rparam_len)
1597 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1598 char *str2 = skip_string(param,tpscnt,str1);
1599 char *p = skip_string(param,tpscnt,str2);
1600 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1601 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1602 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1603 char *p2;
1604 int data_len, fixed_len, string_len;
1605 int f_len = 0, s_len = 0;
1606 struct srv_info_struct *servers=NULL;
1607 int counted=0,first=0,total=0;
1608 int i,missed;
1609 fstring domain;
1610 fstring first_name;
1611 bool domain_request;
1612 bool local_request;
1614 if (!str1 || !str2 || !p) {
1615 return False;
1618 /* If someone sets all the bits they don't really mean to set
1619 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1620 known servers. */
1622 if (servertype == SV_TYPE_ALL) {
1623 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1626 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1627 any other bit (they may just set this bit on its own) they
1628 want all the locally seen servers. However this bit can be
1629 set on its own so set the requested servers to be
1630 ALL - DOMAIN_ENUM. */
1632 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1633 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1636 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1637 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1639 p += 8;
1641 if (strcmp(str1, "WrLehDzz") != 0) {
1642 return false;
1644 if (!check_server_info(uLevel,str2)) {
1645 return False;
1648 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1649 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1650 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1652 if (skip_string(param,tpscnt,p) == NULL) {
1653 return False;
1655 pull_ascii_fstring(domain, p);
1656 if (domain[0] == '\0') {
1657 fstrcpy(domain, lp_workgroup());
1659 p = skip_string(param,tpscnt,p);
1660 if (skip_string(param,tpscnt,p) == NULL) {
1661 return False;
1663 pull_ascii_fstring(first_name, p);
1665 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1666 domain, first_name));
1668 if (lp_browse_list()) {
1669 total = get_server_info(servertype,&servers,domain);
1672 data_len = fixed_len = string_len = 0;
1673 missed = 0;
1675 TYPESAFE_QSORT(servers, total, srv_comp);
1677 if (first_name[0] != '\0') {
1678 struct srv_info_struct *first_server = NULL;
1680 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1681 srv_name_match, first_server);
1682 if (first_server) {
1683 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1685 * The binary search may not find the exact match
1686 * so we need to search backward to find the first match
1688 * This implements the strange matching windows
1689 * implements. (see the comment in srv_name_match().
1691 for (;first > 0;) {
1692 int ret;
1693 ret = StrCaseCmp(first_name,
1694 servers[first-1].name);
1695 if (ret > 0) {
1696 break;
1698 first--;
1700 } else {
1701 /* we should return no entries */
1702 first = total;
1707 char *lastname=NULL;
1709 for (i=first;i<total;i++) {
1710 struct srv_info_struct *s = &servers[i];
1712 if (lastname && strequal(lastname,s->name)) {
1713 continue;
1715 lastname = s->name;
1716 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1717 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1718 i, s->name, s->type, s->comment, s->domain));
1720 if (data_len < buf_len) {
1721 counted++;
1722 fixed_len += f_len;
1723 string_len += s_len;
1724 } else {
1725 missed++;
1730 *rdata_len = fixed_len + string_len;
1731 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1732 if (!*rdata) {
1733 return False;
1736 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1737 p = *rdata;
1738 f_len = fixed_len;
1739 s_len = string_len;
1742 char *lastname=NULL;
1743 int count2 = counted;
1745 for (i = first; i < total && count2;i++) {
1746 struct srv_info_struct *s = &servers[i];
1748 if (lastname && strequal(lastname,s->name)) {
1749 continue;
1751 lastname = s->name;
1752 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1753 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1754 i, s->name, s->type, s->comment, s->domain));
1755 count2--;
1759 *rparam_len = 8;
1760 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1761 if (!*rparam) {
1762 return False;
1764 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1765 SSVAL(*rparam,2,0);
1766 SSVAL(*rparam,4,counted);
1767 SSVAL(*rparam,6,counted+missed);
1769 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1770 domain,uLevel,first,first_name,
1771 first < total ? servers[first].name : "",
1772 counted,counted+missed));
1774 SAFE_FREE(servers);
1776 return True;
1779 /****************************************************************************
1780 command 0x34 - suspected of being a "Lookup Names" stub api
1781 ****************************************************************************/
1783 static bool api_RNetGroupGetUsers(struct smbd_server_connection *sconn,
1784 connection_struct *conn, uint16 vuid,
1785 char *param, int tpscnt,
1786 char *data, int tdscnt,
1787 int mdrcnt, int mprcnt, char **rdata,
1788 char **rparam, int *rdata_len, int *rparam_len)
1790 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1791 char *str2 = skip_string(param,tpscnt,str1);
1792 char *p = skip_string(param,tpscnt,str2);
1793 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1794 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1795 int counted=0;
1796 int missed=0;
1798 if (!str1 || !str2 || !p) {
1799 return False;
1802 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1803 str1, str2, p, uLevel, buf_len));
1805 if (!prefix_ok(str1,"zWrLeh")) {
1806 return False;
1809 *rdata_len = 0;
1811 *rparam_len = 8;
1812 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1813 if (!*rparam) {
1814 return False;
1817 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1818 SSVAL(*rparam,2,0);
1819 SSVAL(*rparam,4,counted);
1820 SSVAL(*rparam,6,counted+missed);
1822 return True;
1825 /****************************************************************************
1826 get info about a share
1827 ****************************************************************************/
1829 static bool check_share_info(int uLevel, char* id)
1831 switch( uLevel ) {
1832 case 0:
1833 if (strcmp(id,"B13") != 0) {
1834 return False;
1836 break;
1837 case 1:
1838 /* Level-2 descriptor is allowed (and ignored) */
1839 if (strcmp(id,"B13BWz") != 0 &&
1840 strcmp(id,"B13BWzWWWzB9B") != 0) {
1841 return False;
1843 break;
1844 case 2:
1845 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1846 return False;
1848 break;
1849 case 91:
1850 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1851 return False;
1853 break;
1854 default:
1855 return False;
1857 return True;
1860 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1861 char** buf, int* buflen,
1862 char** stringbuf, int* stringspace, char* baseaddr)
1864 int struct_len;
1865 char* p;
1866 char* p2;
1867 int l2;
1868 int len;
1870 switch( uLevel ) {
1871 case 0:
1872 struct_len = 13;
1873 break;
1874 case 1:
1875 struct_len = 20;
1876 break;
1877 case 2:
1878 struct_len = 40;
1879 break;
1880 case 91:
1881 struct_len = 68;
1882 break;
1883 default:
1884 return -1;
1887 if (!buf) {
1888 len = 0;
1890 if (uLevel > 0) {
1891 len += StrlenExpanded(conn,snum,lp_comment(snum));
1893 if (uLevel > 1) {
1894 len += strlen(lp_pathname(snum)) + 1;
1896 if (buflen) {
1897 *buflen = struct_len;
1899 if (stringspace) {
1900 *stringspace = len;
1902 return struct_len + len;
1905 len = struct_len;
1906 p = *buf;
1907 if ((*buflen) < struct_len) {
1908 return -1;
1911 if (stringbuf) {
1912 p2 = *stringbuf;
1913 l2 = *stringspace;
1914 } else {
1915 p2 = p + struct_len;
1916 l2 = (*buflen) - struct_len;
1919 if (!baseaddr) {
1920 baseaddr = p;
1923 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1925 if (uLevel > 0) {
1926 int type;
1928 SCVAL(p,13,0);
1929 type = STYPE_DISKTREE;
1930 if (lp_print_ok(snum)) {
1931 type = STYPE_PRINTQ;
1933 if (strequal("IPC",lp_fstype(snum))) {
1934 type = STYPE_IPC;
1936 SSVAL(p,14,type); /* device type */
1937 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1938 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1941 if (uLevel > 1) {
1942 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1943 SSVALS(p,22,-1); /* max uses */
1944 SSVAL(p,24,1); /* current uses */
1945 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1946 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1947 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1950 if (uLevel > 2) {
1951 memset(p+40,0,SHPWLEN+2);
1952 SSVAL(p,50,0);
1953 SIVAL(p,52,0);
1954 SSVAL(p,56,0);
1955 SSVAL(p,58,0);
1956 SIVAL(p,60,0);
1957 SSVAL(p,64,0);
1958 SSVAL(p,66,0);
1961 if (stringbuf) {
1962 (*buf) = p + struct_len;
1963 (*buflen) -= struct_len;
1964 (*stringbuf) = p2;
1965 (*stringspace) = l2;
1966 } else {
1967 (*buf) = p2;
1968 (*buflen) -= len;
1971 return len;
1974 static bool api_RNetShareGetInfo(struct smbd_server_connection *sconn,
1975 connection_struct *conn,uint16 vuid,
1976 char *param, int tpscnt,
1977 char *data, int tdscnt,
1978 int mdrcnt,int mprcnt,
1979 char **rdata,char **rparam,
1980 int *rdata_len,int *rparam_len)
1982 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1983 char *str2 = skip_string(param,tpscnt,str1);
1984 char *netname = skip_string(param,tpscnt,str2);
1985 char *p = skip_string(param,tpscnt,netname);
1986 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1987 int snum;
1989 if (!str1 || !str2 || !netname || !p) {
1990 return False;
1993 snum = find_service(netname);
1994 if (snum < 0) {
1995 return False;
1998 /* check it's a supported varient */
1999 if (!prefix_ok(str1,"zWrLh")) {
2000 return False;
2002 if (!check_share_info(uLevel,str2)) {
2003 return False;
2006 *rdata = smb_realloc_limit(*rdata,mdrcnt);
2007 if (!*rdata) {
2008 return False;
2010 p = *rdata;
2011 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
2012 if (*rdata_len < 0) {
2013 return False;
2016 *rparam_len = 6;
2017 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2018 if (!*rparam) {
2019 return False;
2021 SSVAL(*rparam,0,NERR_Success);
2022 SSVAL(*rparam,2,0); /* converter word */
2023 SSVAL(*rparam,4,*rdata_len);
2025 return True;
2028 /****************************************************************************
2029 View the list of available shares.
2031 This function is the server side of the NetShareEnum() RAP call.
2032 It fills the return buffer with share names and share comments.
2033 Note that the return buffer normally (in all known cases) allows only
2034 twelve byte strings for share names (plus one for a nul terminator).
2035 Share names longer than 12 bytes must be skipped.
2036 ****************************************************************************/
2038 static bool api_RNetShareEnum(struct smbd_server_connection *sconn,
2039 connection_struct *conn, uint16 vuid,
2040 char *param, int tpscnt,
2041 char *data, int tdscnt,
2042 int mdrcnt,
2043 int mprcnt,
2044 char **rdata,
2045 char **rparam,
2046 int *rdata_len,
2047 int *rparam_len )
2049 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2050 char *str2 = skip_string(param,tpscnt,str1);
2051 char *p = skip_string(param,tpscnt,str2);
2052 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2053 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
2054 char *p2;
2055 int count = 0;
2056 int total=0,counted=0;
2057 bool missed = False;
2058 int i;
2059 int data_len, fixed_len, string_len;
2060 int f_len = 0, s_len = 0;
2062 if (!str1 || !str2 || !p) {
2063 return False;
2066 if (!prefix_ok(str1,"WrLeh")) {
2067 return False;
2069 if (!check_share_info(uLevel,str2)) {
2070 return False;
2073 /* Ensure all the usershares are loaded. */
2074 become_root();
2075 load_registry_shares();
2076 count = load_usershare_shares();
2077 unbecome_root();
2079 data_len = fixed_len = string_len = 0;
2080 for (i=0;i<count;i++) {
2081 fstring servicename_dos;
2082 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2083 continue;
2085 push_ascii_fstring(servicename_dos, lp_servicename(i));
2086 /* Maximum name length = 13. */
2087 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
2088 total++;
2089 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
2090 if (data_len < buf_len) {
2091 counted++;
2092 fixed_len += f_len;
2093 string_len += s_len;
2094 } else {
2095 missed = True;
2100 *rdata_len = fixed_len + string_len;
2101 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2102 if (!*rdata) {
2103 return False;
2106 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
2107 p = *rdata;
2108 f_len = fixed_len;
2109 s_len = string_len;
2111 for( i = 0; i < count; i++ ) {
2112 fstring servicename_dos;
2113 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2114 continue;
2117 push_ascii_fstring(servicename_dos, lp_servicename(i));
2118 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2119 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2120 break;
2125 *rparam_len = 8;
2126 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2127 if (!*rparam) {
2128 return False;
2130 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2131 SSVAL(*rparam,2,0);
2132 SSVAL(*rparam,4,counted);
2133 SSVAL(*rparam,6,total);
2135 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2136 counted,total,uLevel,
2137 buf_len,*rdata_len,mdrcnt));
2139 return True;
2142 /****************************************************************************
2143 Add a share
2144 ****************************************************************************/
2146 static bool api_RNetShareAdd(struct smbd_server_connection *sconn,
2147 connection_struct *conn,uint16 vuid,
2148 char *param, int tpscnt,
2149 char *data, int tdscnt,
2150 int mdrcnt,int mprcnt,
2151 char **rdata,char **rparam,
2152 int *rdata_len,int *rparam_len)
2154 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2155 char *str2 = skip_string(param,tpscnt,str1);
2156 char *p = skip_string(param,tpscnt,str2);
2157 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2158 fstring sharename;
2159 fstring comment;
2160 char *pathname = NULL;
2161 unsigned int offset;
2162 int res = ERRunsup;
2163 size_t converted_size;
2165 WERROR werr = WERR_OK;
2166 TALLOC_CTX *mem_ctx = talloc_tos();
2167 NTSTATUS status;
2168 struct rpc_pipe_client *cli = NULL;
2169 union srvsvc_NetShareInfo info;
2170 struct srvsvc_NetShareInfo2 info2;
2172 if (!str1 || !str2 || !p) {
2173 return False;
2176 /* check it's a supported varient */
2177 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2178 return False;
2180 if (!check_share_info(uLevel,str2)) {
2181 return False;
2183 if (uLevel != 2) {
2184 return False;
2187 /* Do we have a string ? */
2188 if (skip_string(data,mdrcnt,data) == NULL) {
2189 return False;
2191 pull_ascii_fstring(sharename,data);
2193 if (mdrcnt < 28) {
2194 return False;
2197 /* only support disk share adds */
2198 if (SVAL(data,14)!=STYPE_DISKTREE) {
2199 return False;
2202 offset = IVAL(data, 16);
2203 if (offset >= mdrcnt) {
2204 res = ERRinvalidparam;
2205 goto out;
2208 /* Do we have a string ? */
2209 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2210 return False;
2212 pull_ascii_fstring(comment, offset? (data+offset) : "");
2214 offset = IVAL(data, 26);
2216 if (offset >= mdrcnt) {
2217 res = ERRinvalidparam;
2218 goto out;
2221 /* Do we have a string ? */
2222 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2223 return False;
2226 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2227 offset ? (data+offset) : "", &converted_size))
2229 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
2230 strerror(errno)));
2233 if (!pathname) {
2234 return false;
2237 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_srvsvc.syntax_id,
2238 conn->server_info,
2239 &cli);
2240 if (!NT_STATUS_IS_OK(status)) {
2241 DEBUG(0,("api_RNetShareAdd: could not connect to srvsvc: %s\n",
2242 nt_errstr(status)));
2243 res = W_ERROR_V(ntstatus_to_werror(status));
2244 goto out;
2247 info2.name = sharename;
2248 info2.type = STYPE_DISKTREE;
2249 info2.comment = comment;
2250 info2.permissions = 0;
2251 info2.max_users = 0;
2252 info2.current_users = 0;
2253 info2.path = pathname;
2254 info2.password = NULL;
2256 info.info2 = &info2;
2258 status = rpccli_srvsvc_NetShareAdd(cli, mem_ctx,
2259 cli->srv_name_slash,
2261 &info,
2262 NULL,
2263 &werr);
2264 if (!NT_STATUS_IS_OK(status)) {
2265 res = W_ERROR_V(ntstatus_to_werror(status));
2266 goto out;
2268 if (!W_ERROR_IS_OK(werr)) {
2269 res = W_ERROR_V(werr);
2270 goto out;
2273 *rparam_len = 6;
2274 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2275 if (!*rparam) {
2276 return False;
2278 SSVAL(*rparam,0,NERR_Success);
2279 SSVAL(*rparam,2,0); /* converter word */
2280 SSVAL(*rparam,4,*rdata_len);
2281 *rdata_len = 0;
2283 return True;
2285 out:
2287 *rparam_len = 4;
2288 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2289 if (!*rparam) {
2290 return False;
2292 *rdata_len = 0;
2293 SSVAL(*rparam,0,res);
2294 SSVAL(*rparam,2,0);
2295 return True;
2298 /****************************************************************************
2299 view list of groups available
2300 ****************************************************************************/
2302 static bool api_RNetGroupEnum(struct smbd_server_connection *sconn,
2303 connection_struct *conn,uint16 vuid,
2304 char *param, int tpscnt,
2305 char *data, int tdscnt,
2306 int mdrcnt,int mprcnt,
2307 char **rdata,char **rparam,
2308 int *rdata_len,int *rparam_len)
2310 int i;
2311 int errflags=0;
2312 int resume_context, cli_buf_size;
2313 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2314 char *str2 = skip_string(param,tpscnt,str1);
2315 char *p = skip_string(param,tpscnt,str2);
2317 uint32_t num_groups;
2318 uint32_t resume_handle;
2319 struct rpc_pipe_client *samr_pipe;
2320 struct policy_handle samr_handle, domain_handle;
2321 NTSTATUS status;
2323 if (!str1 || !str2 || !p) {
2324 return False;
2327 if (strcmp(str1,"WrLeh") != 0) {
2328 return False;
2331 /* parameters
2332 * W-> resume context (number of users to skip)
2333 * r -> return parameter pointer to receive buffer
2334 * L -> length of receive buffer
2335 * e -> return parameter number of entries
2336 * h -> return parameter total number of users
2339 if (strcmp("B21",str2) != 0) {
2340 return False;
2343 status = rpc_pipe_open_internal(
2344 talloc_tos(), &ndr_table_samr.syntax_id,
2345 conn->server_info, &samr_pipe);
2346 if (!NT_STATUS_IS_OK(status)) {
2347 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2348 nt_errstr(status)));
2349 return false;
2352 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2353 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2354 if (!NT_STATUS_IS_OK(status)) {
2355 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2356 nt_errstr(status)));
2357 return false;
2360 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2361 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2362 get_global_sam_sid(), &domain_handle);
2363 if (!NT_STATUS_IS_OK(status)) {
2364 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2365 nt_errstr(status)));
2366 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2367 return false;
2370 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2371 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2372 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2373 "%d\n", resume_context, cli_buf_size));
2375 *rdata_len = cli_buf_size;
2376 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2377 if (!*rdata) {
2378 return False;
2381 p = *rdata;
2383 errflags = NERR_Success;
2384 num_groups = 0;
2385 resume_handle = 0;
2387 while (true) {
2388 struct samr_SamArray *sam_entries;
2389 uint32_t num_entries;
2391 status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
2392 &domain_handle,
2393 &resume_handle,
2394 &sam_entries, 1,
2395 &num_entries);
2396 if (!NT_STATUS_IS_OK(status)) {
2397 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2398 "%s\n", nt_errstr(status)));
2399 break;
2402 if (num_entries == 0) {
2403 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2404 "no entries -- done\n"));
2405 break;
2408 for(i=0; i<num_entries; i++) {
2409 const char *name;
2411 name = sam_entries->entries[i].name.string;
2413 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2414 /* set overflow error */
2415 DEBUG(3,("overflow on entry %d group %s\n", i,
2416 name));
2417 errflags=234;
2418 break;
2421 /* truncate the name at 21 chars. */
2422 memset(p, 0, 21);
2423 strlcpy(p, name, 21);
2424 DEBUG(10,("adding entry %d group %s\n", i, p));
2425 p += 21;
2426 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2427 * idea why... */
2428 num_groups += 1;
2431 if (errflags != NERR_Success) {
2432 break;
2435 TALLOC_FREE(sam_entries);
2438 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2439 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2441 *rdata_len = PTR_DIFF(p,*rdata);
2443 *rparam_len = 8;
2444 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2445 if (!*rparam) {
2446 return False;
2448 SSVAL(*rparam, 0, errflags);
2449 SSVAL(*rparam, 2, 0); /* converter word */
2450 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2451 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2453 return(True);
2456 /*******************************************************************
2457 Get groups that a user is a member of.
2458 ******************************************************************/
2460 static bool api_NetUserGetGroups(struct smbd_server_connection *sconn,
2461 connection_struct *conn,uint16 vuid,
2462 char *param, int tpscnt,
2463 char *data, int tdscnt,
2464 int mdrcnt,int mprcnt,
2465 char **rdata,char **rparam,
2466 int *rdata_len,int *rparam_len)
2468 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2469 char *str2 = skip_string(param,tpscnt,str1);
2470 char *UserName = skip_string(param,tpscnt,str2);
2471 char *p = skip_string(param,tpscnt,UserName);
2472 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2473 const char *level_string;
2474 int count=0;
2475 bool ret = False;
2476 uint32_t i;
2477 char *endp = NULL;
2479 struct rpc_pipe_client *samr_pipe;
2480 struct policy_handle samr_handle, domain_handle, user_handle;
2481 struct lsa_String name;
2482 struct lsa_Strings names;
2483 struct samr_Ids type, rid;
2484 struct samr_RidWithAttributeArray *rids;
2485 NTSTATUS status;
2487 if (!str1 || !str2 || !UserName || !p) {
2488 return False;
2491 *rparam_len = 8;
2492 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2493 if (!*rparam) {
2494 return False;
2497 /* check it's a supported varient */
2499 if ( strcmp(str1,"zWrLeh") != 0 )
2500 return False;
2502 switch( uLevel ) {
2503 case 0:
2504 level_string = "B21";
2505 break;
2506 default:
2507 return False;
2510 if (strcmp(level_string,str2) != 0)
2511 return False;
2513 *rdata_len = mdrcnt + 1024;
2514 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2515 if (!*rdata) {
2516 return False;
2519 SSVAL(*rparam,0,NERR_Success);
2520 SSVAL(*rparam,2,0); /* converter word */
2522 p = *rdata;
2523 endp = *rdata + *rdata_len;
2525 status = rpc_pipe_open_internal(
2526 talloc_tos(), &ndr_table_samr.syntax_id,
2527 conn->server_info, &samr_pipe);
2528 if (!NT_STATUS_IS_OK(status)) {
2529 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2530 nt_errstr(status)));
2531 return false;
2534 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2535 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2536 if (!NT_STATUS_IS_OK(status)) {
2537 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2538 nt_errstr(status)));
2539 return false;
2542 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2543 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2544 get_global_sam_sid(), &domain_handle);
2545 if (!NT_STATUS_IS_OK(status)) {
2546 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2547 nt_errstr(status)));
2548 goto close_sam;
2551 name.string = UserName;
2553 status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
2554 &domain_handle, 1, &name,
2555 &rid, &type);
2556 if (!NT_STATUS_IS_OK(status)) {
2557 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2558 nt_errstr(status)));
2559 goto close_domain;
2562 if (type.ids[0] != SID_NAME_USER) {
2563 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2564 sid_type_lookup(type.ids[0])));
2565 goto close_domain;
2568 status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
2569 &domain_handle,
2570 SAMR_USER_ACCESS_GET_GROUPS,
2571 rid.ids[0], &user_handle);
2572 if (!NT_STATUS_IS_OK(status)) {
2573 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2574 nt_errstr(status)));
2575 goto close_domain;
2578 status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
2579 &user_handle, &rids);
2580 if (!NT_STATUS_IS_OK(status)) {
2581 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2582 nt_errstr(status)));
2583 goto close_user;
2586 for (i=0; i<rids->count; i++) {
2588 status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
2589 &domain_handle,
2590 1, &rids->rids[i].rid,
2591 &names, &type);
2592 if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
2593 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2594 p += 21;
2595 count++;
2599 *rdata_len = PTR_DIFF(p,*rdata);
2601 SSVAL(*rparam,4,count); /* is this right?? */
2602 SSVAL(*rparam,6,count); /* is this right?? */
2604 ret = True;
2606 close_user:
2607 rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
2608 close_domain:
2609 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2610 close_sam:
2611 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2613 return ret;
2616 /*******************************************************************
2617 Get all users.
2618 ******************************************************************/
2620 static bool api_RNetUserEnum(struct smbd_server_connection *sconn,
2621 connection_struct *conn, uint16 vuid,
2622 char *param, int tpscnt,
2623 char *data, int tdscnt,
2624 int mdrcnt,int mprcnt,
2625 char **rdata,char **rparam,
2626 int *rdata_len,int *rparam_len)
2628 int count_sent=0;
2629 int num_users=0;
2630 int errflags=0;
2631 int i, resume_context, cli_buf_size;
2632 uint32_t resume_handle;
2634 struct rpc_pipe_client *samr_pipe;
2635 struct policy_handle samr_handle, domain_handle;
2636 NTSTATUS status;
2638 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2639 char *str2 = skip_string(param,tpscnt,str1);
2640 char *p = skip_string(param,tpscnt,str2);
2641 char *endp = NULL;
2643 if (!str1 || !str2 || !p) {
2644 return False;
2647 if (strcmp(str1,"WrLeh") != 0)
2648 return False;
2649 /* parameters
2650 * W-> resume context (number of users to skip)
2651 * r -> return parameter pointer to receive buffer
2652 * L -> length of receive buffer
2653 * e -> return parameter number of entries
2654 * h -> return parameter total number of users
2657 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2658 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2659 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2660 resume_context, cli_buf_size));
2662 *rparam_len = 8;
2663 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2664 if (!*rparam) {
2665 return False;
2668 /* check it's a supported varient */
2669 if (strcmp("B21",str2) != 0)
2670 return False;
2672 *rdata_len = cli_buf_size;
2673 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2674 if (!*rdata) {
2675 return False;
2678 p = *rdata;
2679 endp = *rdata + *rdata_len;
2681 status = rpc_pipe_open_internal(
2682 talloc_tos(), &ndr_table_samr.syntax_id,
2683 conn->server_info, &samr_pipe);
2684 if (!NT_STATUS_IS_OK(status)) {
2685 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2686 nt_errstr(status)));
2687 return false;
2690 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2691 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2692 if (!NT_STATUS_IS_OK(status)) {
2693 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2694 nt_errstr(status)));
2695 return false;
2698 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2699 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2700 get_global_sam_sid(), &domain_handle);
2701 if (!NT_STATUS_IS_OK(status)) {
2702 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2703 nt_errstr(status)));
2704 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2705 return false;
2708 errflags=NERR_Success;
2710 resume_handle = 0;
2712 while (true) {
2713 struct samr_SamArray *sam_entries;
2714 uint32_t num_entries;
2716 status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
2717 &domain_handle,
2718 &resume_handle,
2719 0, &sam_entries, 1,
2720 &num_entries);
2722 if (!NT_STATUS_IS_OK(status)) {
2723 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2724 "%s\n", nt_errstr(status)));
2725 break;
2728 if (num_entries == 0) {
2729 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2730 "no entries -- done\n"));
2731 break;
2734 for (i=0; i<num_entries; i++) {
2735 const char *name;
2737 name = sam_entries->entries[i].name.string;
2739 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2740 &&(strlen(name)<=21)) {
2741 strlcpy(p,name,PTR_DIFF(endp,p));
2742 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2743 "username %s\n",count_sent,p));
2744 p += 21;
2745 count_sent++;
2746 } else {
2747 /* set overflow error */
2748 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2749 "username %s\n",count_sent,name));
2750 errflags=234;
2751 break;
2755 if (errflags != NERR_Success) {
2756 break;
2759 TALLOC_FREE(sam_entries);
2762 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2763 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2765 *rdata_len = PTR_DIFF(p,*rdata);
2767 SSVAL(*rparam,0,errflags);
2768 SSVAL(*rparam,2,0); /* converter word */
2769 SSVAL(*rparam,4,count_sent); /* is this right?? */
2770 SSVAL(*rparam,6,num_users); /* is this right?? */
2772 return True;
2775 /****************************************************************************
2776 Get the time of day info.
2777 ****************************************************************************/
2779 static bool api_NetRemoteTOD(struct smbd_server_connection *sconn,
2780 connection_struct *conn,uint16 vuid,
2781 char *param, int tpscnt,
2782 char *data, int tdscnt,
2783 int mdrcnt,int mprcnt,
2784 char **rdata,char **rparam,
2785 int *rdata_len,int *rparam_len)
2787 struct tm *t;
2788 time_t unixdate = time(NULL);
2789 char *p;
2791 *rparam_len = 4;
2792 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2793 if (!*rparam) {
2794 return False;
2797 *rdata_len = 21;
2798 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2799 if (!*rdata) {
2800 return False;
2803 SSVAL(*rparam,0,NERR_Success);
2804 SSVAL(*rparam,2,0); /* converter word */
2806 p = *rdata;
2808 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2809 by NT in a "net time" operation,
2810 it seems to ignore the one below */
2812 /* the client expects to get localtime, not GMT, in this bit
2813 (I think, this needs testing) */
2814 t = localtime(&unixdate);
2815 if (!t) {
2816 return False;
2819 SIVAL(p,4,0); /* msecs ? */
2820 SCVAL(p,8,t->tm_hour);
2821 SCVAL(p,9,t->tm_min);
2822 SCVAL(p,10,t->tm_sec);
2823 SCVAL(p,11,0); /* hundredths of seconds */
2824 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2825 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2826 SCVAL(p,16,t->tm_mday);
2827 SCVAL(p,17,t->tm_mon + 1);
2828 SSVAL(p,18,1900+t->tm_year);
2829 SCVAL(p,20,t->tm_wday);
2831 return True;
2834 /****************************************************************************
2835 Set the user password.
2836 *****************************************************************************/
2838 static bool api_SetUserPassword(struct smbd_server_connection *sconn,
2839 connection_struct *conn,uint16 vuid,
2840 char *param, int tpscnt,
2841 char *data, int tdscnt,
2842 int mdrcnt,int mprcnt,
2843 char **rdata,char **rparam,
2844 int *rdata_len,int *rparam_len)
2846 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2847 char *p = NULL;
2848 fstring user;
2849 fstring pass1,pass2;
2850 TALLOC_CTX *mem_ctx = talloc_tos();
2851 NTSTATUS status;
2852 struct rpc_pipe_client *cli = NULL;
2853 struct policy_handle connect_handle, domain_handle, user_handle;
2854 struct lsa_String domain_name;
2855 struct dom_sid2 *domain_sid;
2856 struct lsa_String names;
2857 struct samr_Ids rids;
2858 struct samr_Ids types;
2859 struct samr_Password old_lm_hash;
2860 struct samr_Password new_lm_hash;
2861 int errcode = NERR_badpass;
2862 uint32_t rid;
2863 int encrypted;
2864 int min_pwd_length;
2866 /* Skip 2 strings. */
2867 p = skip_string(param,tpscnt,np);
2868 p = skip_string(param,tpscnt,p);
2870 if (!np || !p) {
2871 return False;
2874 /* Do we have a string ? */
2875 if (skip_string(param,tpscnt,p) == NULL) {
2876 return False;
2878 pull_ascii_fstring(user,p);
2880 p = skip_string(param,tpscnt,p);
2881 if (!p) {
2882 return False;
2885 memset(pass1,'\0',sizeof(pass1));
2886 memset(pass2,'\0',sizeof(pass2));
2888 * We use 31 here not 32 as we're checking
2889 * the last byte we want to access is safe.
2891 if (!is_offset_safe(param,tpscnt,p,31)) {
2892 return False;
2894 memcpy(pass1,p,16);
2895 memcpy(pass2,p+16,16);
2897 encrypted = get_safe_SVAL(param,tpscnt,p+32,0,-1);
2898 if (encrypted == -1) {
2899 errcode = W_ERROR_V(WERR_INVALID_PARAM);
2900 goto out;
2903 min_pwd_length = get_safe_SVAL(param,tpscnt,p+34,0,-1);
2904 if (min_pwd_length == -1) {
2905 errcode = W_ERROR_V(WERR_INVALID_PARAM);
2906 goto out;
2909 *rparam_len = 4;
2910 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2911 if (!*rparam) {
2912 return False;
2915 *rdata_len = 0;
2917 DEBUG(3,("Set password for <%s> (encrypted: %d, min_pwd_length: %d)\n",
2918 user, encrypted, min_pwd_length));
2920 ZERO_STRUCT(connect_handle);
2921 ZERO_STRUCT(domain_handle);
2922 ZERO_STRUCT(user_handle);
2924 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_samr.syntax_id,
2925 conn->server_info,
2926 &cli);
2927 if (!NT_STATUS_IS_OK(status)) {
2928 DEBUG(0,("api_SetUserPassword: could not connect to samr: %s\n",
2929 nt_errstr(status)));
2930 errcode = W_ERROR_V(ntstatus_to_werror(status));
2931 goto out;
2934 status = rpccli_samr_Connect2(cli, mem_ctx,
2935 global_myname(),
2936 SAMR_ACCESS_CONNECT_TO_SERVER |
2937 SAMR_ACCESS_ENUM_DOMAINS |
2938 SAMR_ACCESS_LOOKUP_DOMAIN,
2939 &connect_handle);
2940 if (!NT_STATUS_IS_OK(status)) {
2941 errcode = W_ERROR_V(ntstatus_to_werror(status));
2942 goto out;
2945 init_lsa_String(&domain_name, get_global_sam_name());
2947 status = rpccli_samr_LookupDomain(cli, mem_ctx,
2948 &connect_handle,
2949 &domain_name,
2950 &domain_sid);
2951 if (!NT_STATUS_IS_OK(status)) {
2952 errcode = W_ERROR_V(ntstatus_to_werror(status));
2953 goto out;
2956 status = rpccli_samr_OpenDomain(cli, mem_ctx,
2957 &connect_handle,
2958 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2959 domain_sid,
2960 &domain_handle);
2961 if (!NT_STATUS_IS_OK(status)) {
2962 errcode = W_ERROR_V(ntstatus_to_werror(status));
2963 goto out;
2966 init_lsa_String(&names, user);
2968 status = rpccli_samr_LookupNames(cli, mem_ctx,
2969 &domain_handle,
2971 &names,
2972 &rids,
2973 &types);
2974 if (!NT_STATUS_IS_OK(status)) {
2975 errcode = W_ERROR_V(ntstatus_to_werror(status));
2976 goto out;
2979 if (rids.count != 1) {
2980 errcode = W_ERROR_V(WERR_NO_SUCH_USER);
2981 goto out;
2983 if (rids.count != types.count) {
2984 errcode = W_ERROR_V(WERR_INVALID_PARAM);
2985 goto out;
2987 if (types.ids[0] != SID_NAME_USER) {
2988 errcode = W_ERROR_V(WERR_INVALID_PARAM);
2989 goto out;
2992 rid = rids.ids[0];
2994 status = rpccli_samr_OpenUser(cli, mem_ctx,
2995 &domain_handle,
2996 SAMR_USER_ACCESS_CHANGE_PASSWORD,
2997 rid,
2998 &user_handle);
2999 if (!NT_STATUS_IS_OK(status)) {
3000 errcode = W_ERROR_V(ntstatus_to_werror(status));
3001 goto out;
3004 if (encrypted == 0) {
3005 E_deshash(pass1, old_lm_hash.hash);
3006 E_deshash(pass2, new_lm_hash.hash);
3007 } else {
3008 ZERO_STRUCT(old_lm_hash);
3009 ZERO_STRUCT(new_lm_hash);
3010 memcpy(old_lm_hash.hash, pass1, MIN(strlen(pass1), 16));
3011 memcpy(new_lm_hash.hash, pass1, MIN(strlen(pass2), 16));
3014 status = rpccli_samr_ChangePasswordUser(cli, mem_ctx,
3015 &user_handle,
3016 true, /* lm_present */
3017 &old_lm_hash,
3018 &new_lm_hash,
3019 false, /* nt_present */
3020 NULL, /* old_nt_crypted */
3021 NULL, /* new_nt_crypted */
3022 false, /* cross1_present */
3023 NULL, /* nt_cross */
3024 false, /* cross2_present */
3025 NULL); /* lm_cross */
3026 if (!NT_STATUS_IS_OK(status)) {
3027 errcode = W_ERROR_V(ntstatus_to_werror(status));
3028 goto out;
3031 errcode = NERR_Success;
3032 out:
3034 if (cli && is_valid_policy_hnd(&user_handle)) {
3035 rpccli_samr_Close(cli, mem_ctx, &user_handle);
3037 if (cli && is_valid_policy_hnd(&domain_handle)) {
3038 rpccli_samr_Close(cli, mem_ctx, &domain_handle);
3040 if (cli && is_valid_policy_hnd(&connect_handle)) {
3041 rpccli_samr_Close(cli, mem_ctx, &connect_handle);
3044 memset((char *)pass1,'\0',sizeof(fstring));
3045 memset((char *)pass2,'\0',sizeof(fstring));
3047 SSVAL(*rparam,0,errcode);
3048 SSVAL(*rparam,2,0); /* converter word */
3049 return(True);
3052 /****************************************************************************
3053 Set the user password (SamOEM version - gets plaintext).
3054 ****************************************************************************/
3056 static bool api_SamOEMChangePassword(struct smbd_server_connection *sconn,
3057 connection_struct *conn,uint16 vuid,
3058 char *param, int tpscnt,
3059 char *data, int tdscnt,
3060 int mdrcnt,int mprcnt,
3061 char **rdata,char **rparam,
3062 int *rdata_len,int *rparam_len)
3064 fstring user;
3065 char *p = get_safe_str_ptr(param,tpscnt,param,2);
3067 TALLOC_CTX *mem_ctx = talloc_tos();
3068 NTSTATUS status;
3069 struct rpc_pipe_client *cli = NULL;
3070 struct lsa_AsciiString server, account;
3071 struct samr_CryptPassword password;
3072 struct samr_Password hash;
3073 int errcode = NERR_badpass;
3074 int bufsize;
3076 *rparam_len = 4;
3077 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3078 if (!*rparam) {
3079 return False;
3082 if (!p) {
3083 return False;
3085 *rdata_len = 0;
3087 SSVAL(*rparam,0,NERR_badpass);
3090 * Check the parameter definition is correct.
3093 /* Do we have a string ? */
3094 if (skip_string(param,tpscnt,p) == 0) {
3095 return False;
3097 if(!strequal(p, "zsT")) {
3098 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
3099 return False;
3101 p = skip_string(param, tpscnt, p);
3102 if (!p) {
3103 return False;
3106 /* Do we have a string ? */
3107 if (skip_string(param,tpscnt,p) == 0) {
3108 return False;
3110 if(!strequal(p, "B516B16")) {
3111 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
3112 return False;
3114 p = skip_string(param,tpscnt,p);
3115 if (!p) {
3116 return False;
3118 /* Do we have a string ? */
3119 if (skip_string(param,tpscnt,p) == 0) {
3120 return False;
3122 p += pull_ascii_fstring(user,p);
3124 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
3126 if (tdscnt != 532) {
3127 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3128 goto out;
3131 bufsize = get_safe_SVAL(param,tpscnt,p,0,-1);
3132 if (bufsize != 532) {
3133 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3134 goto out;
3137 memcpy(password.data, data, 516);
3138 memcpy(hash.hash, data+516, 16);
3140 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_samr.syntax_id,
3141 conn->server_info,
3142 &cli);
3143 if (!NT_STATUS_IS_OK(status)) {
3144 DEBUG(0,("api_SamOEMChangePassword: could not connect to samr: %s\n",
3145 nt_errstr(status)));
3146 errcode = W_ERROR_V(ntstatus_to_werror(status));
3147 goto out;
3150 init_lsa_AsciiString(&server, global_myname());
3151 init_lsa_AsciiString(&account, user);
3153 status = rpccli_samr_OemChangePasswordUser2(cli, mem_ctx,
3154 &server,
3155 &account,
3156 &password,
3157 &hash);
3158 if (!NT_STATUS_IS_OK(status)) {
3159 errcode = W_ERROR_V(ntstatus_to_werror(status));
3160 goto out;
3163 errcode = NERR_Success;
3164 out:
3165 SSVAL(*rparam,0,errcode);
3166 SSVAL(*rparam,2,0); /* converter word */
3168 return(True);
3171 /****************************************************************************
3172 delete a print job
3173 Form: <W> <>
3174 ****************************************************************************/
3176 static bool api_RDosPrintJobDel(struct smbd_server_connection *sconn,
3177 connection_struct *conn,uint16 vuid,
3178 char *param, int tpscnt,
3179 char *data, int tdscnt,
3180 int mdrcnt,int mprcnt,
3181 char **rdata,char **rparam,
3182 int *rdata_len,int *rparam_len)
3184 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3185 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3186 char *str2 = skip_string(param,tpscnt,str1);
3187 char *p = skip_string(param,tpscnt,str2);
3188 uint32 jobid;
3189 fstring sharename;
3190 int errcode;
3191 WERROR werr = WERR_OK;
3193 TALLOC_CTX *mem_ctx = talloc_tos();
3194 NTSTATUS status;
3195 struct rpc_pipe_client *cli = NULL;
3196 struct policy_handle handle;
3197 struct spoolss_DevmodeContainer devmode_ctr;
3198 enum spoolss_JobControl command;
3200 if (!str1 || !str2 || !p) {
3201 return False;
3204 * We use 1 here not 2 as we're checking
3205 * the last byte we want to access is safe.
3207 if (!is_offset_safe(param,tpscnt,p,1)) {
3208 return False;
3210 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3211 return False;
3213 /* check it's a supported varient */
3214 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
3215 return(False);
3217 *rparam_len = 4;
3218 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3219 if (!*rparam) {
3220 return False;
3222 *rdata_len = 0;
3224 ZERO_STRUCT(handle);
3226 status = rpc_connect_spoolss_pipe(conn, &cli);
3227 if (!NT_STATUS_IS_OK(status)) {
3228 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
3229 nt_errstr(status)));
3230 errcode = W_ERROR_V(ntstatus_to_werror(status));
3231 goto out;
3234 ZERO_STRUCT(devmode_ctr);
3236 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3237 sharename,
3238 "RAW",
3239 devmode_ctr,
3240 JOB_ACCESS_ADMINISTER,
3241 &handle,
3242 &werr);
3243 if (!NT_STATUS_IS_OK(status)) {
3244 errcode = W_ERROR_V(ntstatus_to_werror(status));
3245 goto out;
3247 if (!W_ERROR_IS_OK(werr)) {
3248 errcode = W_ERROR_V(werr);
3249 goto out;
3252 /* FIXME: formerly NERR_JobNotFound was returned if job did not exist
3253 * and NERR_DestNotFound if share did not exist */
3255 errcode = NERR_Success;
3257 switch (function) {
3258 case 81: /* delete */
3259 command = SPOOLSS_JOB_CONTROL_DELETE;
3260 break;
3261 case 82: /* pause */
3262 command = SPOOLSS_JOB_CONTROL_PAUSE;
3263 break;
3264 case 83: /* resume */
3265 command = SPOOLSS_JOB_CONTROL_RESUME;
3266 break;
3267 default:
3268 errcode = NERR_notsupported;
3269 goto out;
3272 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3273 &handle,
3274 jobid,
3275 NULL, /* unique ptr ctr */
3276 command,
3277 &werr);
3278 if (!NT_STATUS_IS_OK(status)) {
3279 errcode = W_ERROR_V(ntstatus_to_werror(status));
3280 goto out;
3282 if (!W_ERROR_IS_OK(werr)) {
3283 errcode = W_ERROR_V(werr);
3284 goto out;
3287 out:
3288 if (cli && is_valid_policy_hnd(&handle)) {
3289 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3292 SSVAL(*rparam,0,errcode);
3293 SSVAL(*rparam,2,0); /* converter word */
3295 return(True);
3298 /****************************************************************************
3299 Purge a print queue - or pause or resume it.
3300 ****************************************************************************/
3302 static bool api_WPrintQueueCtrl(struct smbd_server_connection *sconn,
3303 connection_struct *conn,uint16 vuid,
3304 char *param, int tpscnt,
3305 char *data, int tdscnt,
3306 int mdrcnt,int mprcnt,
3307 char **rdata,char **rparam,
3308 int *rdata_len,int *rparam_len)
3310 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3311 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3312 char *str2 = skip_string(param,tpscnt,str1);
3313 char *QueueName = skip_string(param,tpscnt,str2);
3314 int errcode = NERR_notsupported;
3315 WERROR werr = WERR_OK;
3316 NTSTATUS status;
3318 TALLOC_CTX *mem_ctx = talloc_tos();
3319 struct rpc_pipe_client *cli = NULL;
3320 struct policy_handle handle;
3321 struct spoolss_SetPrinterInfoCtr info_ctr;
3322 struct spoolss_DevmodeContainer devmode_ctr;
3323 struct sec_desc_buf secdesc_ctr;
3324 enum spoolss_PrinterControl command;
3326 if (!str1 || !str2 || !QueueName) {
3327 return False;
3330 /* check it's a supported varient */
3331 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3332 return(False);
3334 *rparam_len = 4;
3335 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3336 if (!*rparam) {
3337 return False;
3339 *rdata_len = 0;
3341 if (skip_string(param,tpscnt,QueueName) == NULL) {
3342 return False;
3345 ZERO_STRUCT(handle);
3347 status = rpc_connect_spoolss_pipe(conn, &cli);
3348 if (!NT_STATUS_IS_OK(status)) {
3349 DEBUG(0,("api_WPrintQueueCtrl: could not connect to spoolss: %s\n",
3350 nt_errstr(status)));
3351 errcode = W_ERROR_V(ntstatus_to_werror(status));
3352 goto out;
3355 ZERO_STRUCT(devmode_ctr);
3357 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3358 QueueName,
3359 NULL,
3360 devmode_ctr,
3361 SEC_FLAG_MAXIMUM_ALLOWED,
3362 &handle,
3363 &werr);
3364 if (!NT_STATUS_IS_OK(status)) {
3365 errcode = W_ERROR_V(ntstatus_to_werror(status));
3366 goto out;
3368 if (!W_ERROR_IS_OK(werr)) {
3369 errcode = W_ERROR_V(werr);
3370 goto out;
3373 switch (function) {
3374 case 74: /* Pause queue */
3375 command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3376 break;
3377 case 75: /* Resume queue */
3378 command = SPOOLSS_PRINTER_CONTROL_RESUME;
3379 break;
3380 case 103: /* Purge */
3381 command = SPOOLSS_PRINTER_CONTROL_PURGE;
3382 break;
3383 default:
3384 werr = WERR_NOT_SUPPORTED;
3385 break;
3388 if (!W_ERROR_IS_OK(werr)) {
3389 errcode = W_ERROR_V(werr);
3390 goto out;
3393 ZERO_STRUCT(info_ctr);
3394 ZERO_STRUCT(secdesc_ctr);
3396 status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
3397 &handle,
3398 &info_ctr,
3399 &devmode_ctr,
3400 &secdesc_ctr,
3401 command,
3402 &werr);
3403 if (!NT_STATUS_IS_OK(status)) {
3404 errcode = W_ERROR_V(ntstatus_to_werror(status));
3405 goto out;
3407 if (!W_ERROR_IS_OK(werr)) {
3408 errcode = W_ERROR_V(werr);
3409 goto out;
3412 errcode = W_ERROR_V(werr);
3414 out:
3416 if (cli && is_valid_policy_hnd(&handle)) {
3417 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3420 SSVAL(*rparam,0,errcode);
3421 SSVAL(*rparam,2,0); /* converter word */
3423 return(True);
3426 /****************************************************************************
3427 set the property of a print job (undocumented?)
3428 ? function = 0xb -> set name of print job
3429 ? function = 0x6 -> move print job up/down
3430 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3431 or <WWsTP> <WB21BB16B10zWWzDDz>
3432 ****************************************************************************/
3434 static int check_printjob_info(struct pack_desc* desc,
3435 int uLevel, char* id)
3437 desc->subformat = NULL;
3438 switch( uLevel ) {
3439 case 0: desc->format = "W"; break;
3440 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3441 case 2: desc->format = "WWzWWDDzz"; break;
3442 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3443 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3444 default:
3445 DEBUG(0,("check_printjob_info: invalid level %d\n",
3446 uLevel ));
3447 return False;
3449 if (id == NULL || strcmp(desc->format,id) != 0) {
3450 DEBUG(0,("check_printjob_info: invalid format %s\n",
3451 id ? id : "<NULL>" ));
3452 return False;
3454 return True;
3457 static bool api_PrintJobInfo(struct smbd_server_connection *sconn,
3458 connection_struct *conn, uint16 vuid,
3459 char *param, int tpscnt,
3460 char *data, int tdscnt,
3461 int mdrcnt,int mprcnt,
3462 char **rdata,char **rparam,
3463 int *rdata_len,int *rparam_len)
3465 struct pack_desc desc;
3466 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3467 char *str2 = skip_string(param,tpscnt,str1);
3468 char *p = skip_string(param,tpscnt,str2);
3469 uint32 jobid;
3470 fstring sharename;
3471 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3472 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3473 int errcode;
3475 TALLOC_CTX *mem_ctx = talloc_tos();
3476 WERROR werr;
3477 NTSTATUS status;
3478 struct rpc_pipe_client *cli = NULL;
3479 struct policy_handle handle;
3480 struct spoolss_DevmodeContainer devmode_ctr;
3481 struct spoolss_JobInfoContainer ctr;
3482 union spoolss_JobInfo info;
3483 struct spoolss_SetJobInfo1 info1;
3485 if (!str1 || !str2 || !p) {
3486 return False;
3489 * We use 1 here not 2 as we're checking
3490 * the last byte we want to access is safe.
3492 if (!is_offset_safe(param,tpscnt,p,1)) {
3493 return False;
3495 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3496 return False;
3497 *rparam_len = 4;
3498 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3499 if (!*rparam) {
3500 return False;
3503 *rdata_len = 0;
3505 /* check it's a supported varient */
3506 if ((strcmp(str1,"WWsTP")) ||
3507 (!check_printjob_info(&desc,uLevel,str2)))
3508 return(False);
3510 errcode = NERR_notsupported;
3512 switch (function) {
3513 case 0xb:
3514 /* change print job name, data gives the name */
3515 break;
3516 default:
3517 goto out;
3520 ZERO_STRUCT(handle);
3522 status = rpc_connect_spoolss_pipe(conn, &cli);
3523 if (!NT_STATUS_IS_OK(status)) {
3524 DEBUG(0,("api_PrintJobInfo: could not connect to spoolss: %s\n",
3525 nt_errstr(status)));
3526 errcode = W_ERROR_V(ntstatus_to_werror(status));
3527 goto out;
3530 ZERO_STRUCT(devmode_ctr);
3532 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3533 sharename,
3534 "RAW",
3535 devmode_ctr,
3536 PRINTER_ACCESS_USE,
3537 &handle,
3538 &werr);
3539 if (!NT_STATUS_IS_OK(status)) {
3540 errcode = W_ERROR_V(ntstatus_to_werror(status));
3541 goto out;
3543 if (!W_ERROR_IS_OK(werr)) {
3544 errcode = W_ERROR_V(werr);
3545 goto out;
3548 werr = rpccli_spoolss_getjob(cli, mem_ctx,
3549 &handle,
3550 jobid,
3551 1, /* level */
3552 0, /* offered */
3553 &info);
3554 if (!W_ERROR_IS_OK(werr)) {
3555 errcode = W_ERROR_V(werr);
3556 goto out;
3559 ZERO_STRUCT(ctr);
3561 info1.job_id = info.info1.job_id;
3562 info1.printer_name = info.info1.printer_name;
3563 info1.user_name = info.info1.user_name;
3564 info1.document_name = data;
3565 info1.data_type = info.info1.data_type;
3566 info1.text_status = info.info1.text_status;
3567 info1.status = info.info1.status;
3568 info1.priority = info.info1.priority;
3569 info1.position = info.info1.position;
3570 info1.total_pages = info.info1.total_pages;
3571 info1.pages_printed = info.info1.pages_printed;
3572 info1.submitted = info.info1.submitted;
3574 ctr.level = 1;
3575 ctr.info.info1 = &info1;
3577 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3578 &handle,
3579 jobid,
3580 &ctr,
3582 &werr);
3583 if (!NT_STATUS_IS_OK(status)) {
3584 errcode = W_ERROR_V(ntstatus_to_werror(status));
3585 goto out;
3587 if (!W_ERROR_IS_OK(werr)) {
3588 errcode = W_ERROR_V(werr);
3589 goto out;
3592 errcode = NERR_Success;
3593 out:
3595 if (cli && is_valid_policy_hnd(&handle)) {
3596 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3599 SSVALS(*rparam,0,errcode);
3600 SSVAL(*rparam,2,0); /* converter word */
3602 return(True);
3606 /****************************************************************************
3607 Get info about the server.
3608 ****************************************************************************/
3610 static bool api_RNetServerGetInfo(struct smbd_server_connection *sconn,
3611 connection_struct *conn,uint16 vuid,
3612 char *param, int tpscnt,
3613 char *data, int tdscnt,
3614 int mdrcnt,int mprcnt,
3615 char **rdata,char **rparam,
3616 int *rdata_len,int *rparam_len)
3618 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3619 char *str2 = skip_string(param,tpscnt,str1);
3620 char *p = skip_string(param,tpscnt,str2);
3621 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3622 char *p2;
3623 int struct_len;
3625 NTSTATUS status;
3626 WERROR werr;
3627 TALLOC_CTX *mem_ctx = talloc_tos();
3628 struct rpc_pipe_client *cli = NULL;
3629 union srvsvc_NetSrvInfo info;
3630 int errcode;
3632 if (!str1 || !str2 || !p) {
3633 return False;
3636 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3638 /* check it's a supported varient */
3639 if (!prefix_ok(str1,"WrLh")) {
3640 return False;
3643 switch( uLevel ) {
3644 case 0:
3645 if (strcmp(str2,"B16") != 0) {
3646 return False;
3648 struct_len = 16;
3649 break;
3650 case 1:
3651 if (strcmp(str2,"B16BBDz") != 0) {
3652 return False;
3654 struct_len = 26;
3655 break;
3656 case 2:
3657 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3658 return False;
3660 struct_len = 134;
3661 break;
3662 case 3:
3663 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3664 return False;
3666 struct_len = 144;
3667 break;
3668 case 20:
3669 if (strcmp(str2,"DN") != 0) {
3670 return False;
3672 struct_len = 6;
3673 break;
3674 case 50:
3675 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3676 return False;
3678 struct_len = 42;
3679 break;
3680 default:
3681 return False;
3684 *rdata_len = mdrcnt;
3685 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3686 if (!*rdata) {
3687 return False;
3690 p = *rdata;
3691 p2 = p + struct_len;
3693 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_srvsvc.syntax_id,
3694 conn->server_info,
3695 &cli);
3696 if (!NT_STATUS_IS_OK(status)) {
3697 DEBUG(0,("api_RNetServerGetInfo: could not connect to srvsvc: %s\n",
3698 nt_errstr(status)));
3699 errcode = W_ERROR_V(ntstatus_to_werror(status));
3700 goto out;
3703 status = rpccli_srvsvc_NetSrvGetInfo(cli, mem_ctx,
3704 NULL,
3705 101,
3706 &info,
3707 &werr);
3708 if (!NT_STATUS_IS_OK(status)) {
3709 errcode = W_ERROR_V(ntstatus_to_werror(status));
3710 goto out;
3712 if (!W_ERROR_IS_OK(werr)) {
3713 errcode = W_ERROR_V(werr);
3714 goto out;
3717 if (info.info101 == NULL) {
3718 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3719 goto out;
3722 if (uLevel != 20) {
3723 srvstr_push(NULL, 0, p, info.info101->server_name, 16,
3724 STR_ASCII|STR_UPPER|STR_TERMINATE);
3726 p += 16;
3727 if (uLevel > 0) {
3728 SCVAL(p,0,info.info101->version_major);
3729 SCVAL(p,1,info.info101->version_minor);
3730 SIVAL(p,2,info.info101->server_type);
3732 if (mdrcnt == struct_len) {
3733 SIVAL(p,6,0);
3734 } else {
3735 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3736 if (mdrcnt - struct_len <= 0) {
3737 return false;
3739 push_ascii(p2,
3740 info.info101->comment,
3741 MIN(mdrcnt - struct_len,
3742 MAX_SERVER_STRING_LENGTH),
3743 STR_TERMINATE);
3744 p2 = skip_string(*rdata,*rdata_len,p2);
3745 if (!p2) {
3746 return False;
3751 if (uLevel > 1) {
3752 return False; /* not yet implemented */
3755 errcode = NERR_Success;
3757 out:
3759 *rdata_len = PTR_DIFF(p2,*rdata);
3761 *rparam_len = 6;
3762 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3763 if (!*rparam) {
3764 return False;
3766 SSVAL(*rparam,0,errcode);
3767 SSVAL(*rparam,2,0); /* converter word */
3768 SSVAL(*rparam,4,*rdata_len);
3770 return True;
3773 /****************************************************************************
3774 Get info about the server.
3775 ****************************************************************************/
3777 static bool api_NetWkstaGetInfo(struct smbd_server_connection *sconn,
3778 connection_struct *conn,uint16 vuid,
3779 char *param, int tpscnt,
3780 char *data, int tdscnt,
3781 int mdrcnt,int mprcnt,
3782 char **rdata,char **rparam,
3783 int *rdata_len,int *rparam_len)
3785 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3786 char *str2 = skip_string(param,tpscnt,str1);
3787 char *p = skip_string(param,tpscnt,str2);
3788 char *p2;
3789 char *endp;
3790 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3792 if (!str1 || !str2 || !p) {
3793 return False;
3796 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3798 *rparam_len = 6;
3799 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3800 if (!*rparam) {
3801 return False;
3804 /* check it's a supported varient */
3805 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3806 return False;
3809 *rdata_len = mdrcnt + 1024;
3810 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3811 if (!*rdata) {
3812 return False;
3815 SSVAL(*rparam,0,NERR_Success);
3816 SSVAL(*rparam,2,0); /* converter word */
3818 p = *rdata;
3819 endp = *rdata + *rdata_len;
3821 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3822 if (!p2) {
3823 return False;
3826 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3827 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3828 strupper_m(p2);
3829 p2 = skip_string(*rdata,*rdata_len,p2);
3830 if (!p2) {
3831 return False;
3833 p += 4;
3835 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3836 strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3837 p2 = skip_string(*rdata,*rdata_len,p2);
3838 if (!p2) {
3839 return False;
3841 p += 4;
3843 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3844 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3845 strupper_m(p2);
3846 p2 = skip_string(*rdata,*rdata_len,p2);
3847 if (!p2) {
3848 return False;
3850 p += 4;
3852 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3853 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3854 p += 2;
3856 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3857 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3858 p2 = skip_string(*rdata,*rdata_len,p2);
3859 if (!p2) {
3860 return False;
3862 p += 4;
3864 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3865 strlcpy(p2,"",PTR_DIFF(endp,p2));
3866 p2 = skip_string(*rdata,*rdata_len,p2);
3867 if (!p2) {
3868 return False;
3870 p += 4;
3872 *rdata_len = PTR_DIFF(p2,*rdata);
3874 SSVAL(*rparam,4,*rdata_len);
3876 return True;
3879 /****************************************************************************
3880 get info about a user
3882 struct user_info_11 {
3883 char usri11_name[21]; 0-20
3884 char usri11_pad; 21
3885 char *usri11_comment; 22-25
3886 char *usri11_usr_comment; 26-29
3887 unsigned short usri11_priv; 30-31
3888 unsigned long usri11_auth_flags; 32-35
3889 long usri11_password_age; 36-39
3890 char *usri11_homedir; 40-43
3891 char *usri11_parms; 44-47
3892 long usri11_last_logon; 48-51
3893 long usri11_last_logoff; 52-55
3894 unsigned short usri11_bad_pw_count; 56-57
3895 unsigned short usri11_num_logons; 58-59
3896 char *usri11_logon_server; 60-63
3897 unsigned short usri11_country_code; 64-65
3898 char *usri11_workstations; 66-69
3899 unsigned long usri11_max_storage; 70-73
3900 unsigned short usri11_units_per_week; 74-75
3901 unsigned char *usri11_logon_hours; 76-79
3902 unsigned short usri11_code_page; 80-81
3905 where:
3907 usri11_name specifies the user name for which information is retrieved
3909 usri11_pad aligns the next data structure element to a word boundary
3911 usri11_comment is a null terminated ASCII comment
3913 usri11_user_comment is a null terminated ASCII comment about the user
3915 usri11_priv specifies the level of the privilege assigned to the user.
3916 The possible values are:
3918 Name Value Description
3919 USER_PRIV_GUEST 0 Guest privilege
3920 USER_PRIV_USER 1 User privilege
3921 USER_PRV_ADMIN 2 Administrator privilege
3923 usri11_auth_flags specifies the account operator privileges. The
3924 possible values are:
3926 Name Value Description
3927 AF_OP_PRINT 0 Print operator
3930 Leach, Naik [Page 28]
3934 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3937 AF_OP_COMM 1 Communications operator
3938 AF_OP_SERVER 2 Server operator
3939 AF_OP_ACCOUNTS 3 Accounts operator
3942 usri11_password_age specifies how many seconds have elapsed since the
3943 password was last changed.
3945 usri11_home_dir points to a null terminated ASCII string that contains
3946 the path name of the user's home directory.
3948 usri11_parms points to a null terminated ASCII string that is set
3949 aside for use by applications.
3951 usri11_last_logon specifies the time when the user last logged on.
3952 This value is stored as the number of seconds elapsed since
3953 00:00:00, January 1, 1970.
3955 usri11_last_logoff specifies the time when the user last logged off.
3956 This value is stored as the number of seconds elapsed since
3957 00:00:00, January 1, 1970. A value of 0 means the last logoff
3958 time is unknown.
3960 usri11_bad_pw_count specifies the number of incorrect passwords
3961 entered since the last successful logon.
3963 usri11_log1_num_logons specifies the number of times this user has
3964 logged on. A value of -1 means the number of logons is unknown.
3966 usri11_logon_server points to a null terminated ASCII string that
3967 contains the name of the server to which logon requests are sent.
3968 A null string indicates logon requests should be sent to the
3969 domain controller.
3971 usri11_country_code specifies the country code for the user's language
3972 of choice.
3974 usri11_workstations points to a null terminated ASCII string that
3975 contains the names of workstations the user may log on from.
3976 There may be up to 8 workstations, with the names separated by
3977 commas. A null strings indicates there are no restrictions.
3979 usri11_max_storage specifies the maximum amount of disk space the user
3980 can occupy. A value of 0xffffffff indicates there are no
3981 restrictions.
3983 usri11_units_per_week specifies the equal number of time units into
3984 which a week is divided. This value must be equal to 168.
3986 usri11_logon_hours points to a 21 byte (168 bits) string that
3987 specifies the time during which the user can log on. Each bit
3988 represents one unique hour in a week. The first bit (bit 0, word
3989 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3993 Leach, Naik [Page 29]
3997 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
4000 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
4001 are no restrictions.
4003 usri11_code_page specifies the code page for the user's language of
4004 choice
4006 All of the pointers in this data structure need to be treated
4007 specially. The pointer is a 32 bit pointer. The higher 16 bits need
4008 to be ignored. The converter word returned in the parameters section
4009 needs to be subtracted from the lower 16 bits to calculate an offset
4010 into the return buffer where this ASCII string resides.
4012 There is no auxiliary data in the response.
4014 ****************************************************************************/
4016 #define usri11_name 0
4017 #define usri11_pad 21
4018 #define usri11_comment 22
4019 #define usri11_usr_comment 26
4020 #define usri11_full_name 30
4021 #define usri11_priv 34
4022 #define usri11_auth_flags 36
4023 #define usri11_password_age 40
4024 #define usri11_homedir 44
4025 #define usri11_parms 48
4026 #define usri11_last_logon 52
4027 #define usri11_last_logoff 56
4028 #define usri11_bad_pw_count 60
4029 #define usri11_num_logons 62
4030 #define usri11_logon_server 64
4031 #define usri11_country_code 68
4032 #define usri11_workstations 70
4033 #define usri11_max_storage 74
4034 #define usri11_units_per_week 78
4035 #define usri11_logon_hours 80
4036 #define usri11_code_page 84
4037 #define usri11_end 86
4039 static bool api_RNetUserGetInfo(struct smbd_server_connection *sconn,
4040 connection_struct *conn, uint16 vuid,
4041 char *param, int tpscnt,
4042 char *data, int tdscnt,
4043 int mdrcnt,int mprcnt,
4044 char **rdata,char **rparam,
4045 int *rdata_len,int *rparam_len)
4047 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4048 char *str2 = skip_string(param,tpscnt,str1);
4049 char *UserName = skip_string(param,tpscnt,str2);
4050 char *p = skip_string(param,tpscnt,UserName);
4051 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4052 char *p2;
4053 char *endp;
4054 const char *level_string;
4056 TALLOC_CTX *mem_ctx = talloc_tos();
4057 NTSTATUS status;
4058 struct rpc_pipe_client *cli = NULL;
4059 struct policy_handle connect_handle, domain_handle, user_handle;
4060 struct lsa_String domain_name;
4061 struct dom_sid2 *domain_sid;
4062 struct lsa_String names;
4063 struct samr_Ids rids;
4064 struct samr_Ids types;
4065 int errcode = W_ERROR_V(WERR_USER_NOT_FOUND);
4066 uint32_t rid;
4067 union samr_UserInfo *info;
4069 if (!str1 || !str2 || !UserName || !p) {
4070 return False;
4073 *rparam_len = 6;
4074 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4075 if (!*rparam) {
4076 return False;
4079 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
4081 /* check it's a supported variant */
4082 if (strcmp(str1,"zWrLh") != 0) {
4083 return False;
4085 switch( uLevel ) {
4086 case 0: level_string = "B21"; break;
4087 case 1: level_string = "B21BB16DWzzWz"; break;
4088 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
4089 case 10: level_string = "B21Bzzz"; break;
4090 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
4091 default: return False;
4094 if (strcmp(level_string,str2) != 0) {
4095 return False;
4098 *rdata_len = mdrcnt + 1024;
4099 *rdata = smb_realloc_limit(*rdata,*rdata_len);
4100 if (!*rdata) {
4101 return False;
4104 p = *rdata;
4105 endp = *rdata + *rdata_len;
4106 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
4107 if (!p2) {
4108 return False;
4111 ZERO_STRUCT(connect_handle);
4112 ZERO_STRUCT(domain_handle);
4113 ZERO_STRUCT(user_handle);
4115 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_samr.syntax_id,
4116 conn->server_info,
4117 &cli);
4118 if (!NT_STATUS_IS_OK(status)) {
4119 DEBUG(0,("api_RNetUserGetInfo: could not connect to samr: %s\n",
4120 nt_errstr(status)));
4121 errcode = W_ERROR_V(ntstatus_to_werror(status));
4122 goto out;
4125 status = rpccli_samr_Connect2(cli, mem_ctx,
4126 global_myname(),
4127 SAMR_ACCESS_CONNECT_TO_SERVER |
4128 SAMR_ACCESS_ENUM_DOMAINS |
4129 SAMR_ACCESS_LOOKUP_DOMAIN,
4130 &connect_handle);
4131 if (!NT_STATUS_IS_OK(status)) {
4132 errcode = W_ERROR_V(ntstatus_to_werror(status));
4133 goto out;
4136 init_lsa_String(&domain_name, get_global_sam_name());
4138 status = rpccli_samr_LookupDomain(cli, mem_ctx,
4139 &connect_handle,
4140 &domain_name,
4141 &domain_sid);
4142 if (!NT_STATUS_IS_OK(status)) {
4143 errcode = W_ERROR_V(ntstatus_to_werror(status));
4144 goto out;
4147 status = rpccli_samr_OpenDomain(cli, mem_ctx,
4148 &connect_handle,
4149 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
4150 domain_sid,
4151 &domain_handle);
4152 if (!NT_STATUS_IS_OK(status)) {
4153 errcode = W_ERROR_V(ntstatus_to_werror(status));
4154 goto out;
4157 init_lsa_String(&names, UserName);
4159 status = rpccli_samr_LookupNames(cli, mem_ctx,
4160 &domain_handle,
4162 &names,
4163 &rids,
4164 &types);
4165 if (!NT_STATUS_IS_OK(status)) {
4166 errcode = W_ERROR_V(ntstatus_to_werror(status));
4167 goto out;
4170 if (rids.count != 1) {
4171 errcode = W_ERROR_V(WERR_NO_SUCH_USER);
4172 goto out;
4174 if (rids.count != types.count) {
4175 errcode = W_ERROR_V(WERR_INVALID_PARAM);
4176 goto out;
4178 if (types.ids[0] != SID_NAME_USER) {
4179 errcode = W_ERROR_V(WERR_INVALID_PARAM);
4180 goto out;
4183 rid = rids.ids[0];
4185 status = rpccli_samr_OpenUser(cli, mem_ctx,
4186 &domain_handle,
4187 SAMR_USER_ACCESS_GET_LOCALE |
4188 SAMR_USER_ACCESS_GET_LOGONINFO |
4189 SAMR_USER_ACCESS_GET_ATTRIBUTES |
4190 SAMR_USER_ACCESS_GET_GROUPS |
4191 SAMR_USER_ACCESS_GET_GROUP_MEMBERSHIP |
4192 SEC_STD_READ_CONTROL,
4193 rid,
4194 &user_handle);
4195 if (!NT_STATUS_IS_OK(status)) {
4196 errcode = W_ERROR_V(ntstatus_to_werror(status));
4197 goto out;
4200 status = rpccli_samr_QueryUserInfo2(cli, mem_ctx,
4201 &user_handle,
4202 UserAllInformation,
4203 &info);
4204 if (!NT_STATUS_IS_OK(status)) {
4205 errcode = W_ERROR_V(ntstatus_to_werror(status));
4206 goto out;
4209 memset(p,0,21);
4210 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
4212 if (uLevel > 0) {
4213 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
4214 *p2 = 0;
4217 if (uLevel >= 10) {
4218 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
4219 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
4220 p2 = skip_string(*rdata,*rdata_len,p2);
4221 if (!p2) {
4222 return False;
4225 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
4226 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
4227 p2 = skip_string(*rdata,*rdata_len,p2);
4228 if (!p2) {
4229 return False;
4232 /* EEK! the cifsrap.txt doesn't have this in!!!! */
4233 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
4234 strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4235 p2 = skip_string(*rdata,*rdata_len,p2);
4236 if (!p2) {
4237 return False;
4241 if (uLevel == 11) {
4242 const char *homedir = info->info21.home_directory.string;
4243 /* modelled after NTAS 3.51 reply */
4244 SSVAL(p,usri11_priv,
4245 (get_current_uid(conn) == sec_initial_uid())?
4246 USER_PRIV_ADMIN:USER_PRIV_USER);
4247 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
4248 SIVALS(p,usri11_password_age,-1); /* password age */
4249 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
4250 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
4251 p2 = skip_string(*rdata,*rdata_len,p2);
4252 if (!p2) {
4253 return False;
4255 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
4256 strlcpy(p2,"",PTR_DIFF(endp,p2));
4257 p2 = skip_string(*rdata,*rdata_len,p2);
4258 if (!p2) {
4259 return False;
4261 SIVAL(p,usri11_last_logon,0); /* last logon */
4262 SIVAL(p,usri11_last_logoff,0); /* last logoff */
4263 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
4264 SSVALS(p,usri11_num_logons,-1); /* num logons */
4265 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
4266 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
4267 p2 = skip_string(*rdata,*rdata_len,p2);
4268 if (!p2) {
4269 return False;
4271 SSVAL(p,usri11_country_code,0); /* country code */
4273 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
4274 strlcpy(p2,"",PTR_DIFF(endp,p2));
4275 p2 = skip_string(*rdata,*rdata_len,p2);
4276 if (!p2) {
4277 return False;
4280 SIVALS(p,usri11_max_storage,-1); /* max storage */
4281 SSVAL(p,usri11_units_per_week,168); /* units per week */
4282 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
4284 /* a simple way to get logon hours at all times. */
4285 memset(p2,0xff,21);
4286 SCVAL(p2,21,0); /* fix zero termination */
4287 p2 = skip_string(*rdata,*rdata_len,p2);
4288 if (!p2) {
4289 return False;
4292 SSVAL(p,usri11_code_page,0); /* code page */
4295 if (uLevel == 1 || uLevel == 2) {
4296 memset(p+22,' ',16); /* password */
4297 SIVALS(p,38,-1); /* password age */
4298 SSVAL(p,42,
4299 (get_current_uid(conn) == sec_initial_uid())?
4300 USER_PRIV_ADMIN:USER_PRIV_USER);
4301 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
4302 strlcpy(p2, info->info21.home_directory.string,
4303 PTR_DIFF(endp,p2));
4304 p2 = skip_string(*rdata,*rdata_len,p2);
4305 if (!p2) {
4306 return False;
4308 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
4309 *p2++ = 0;
4310 SSVAL(p,52,0); /* flags */
4311 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
4312 strlcpy(p2, info->info21.logon_script.string,
4313 PTR_DIFF(endp,p2));
4314 p2 = skip_string(*rdata,*rdata_len,p2);
4315 if (!p2) {
4316 return False;
4318 if (uLevel == 2) {
4319 SIVAL(p,58,0); /* auth_flags */
4320 SIVAL(p,62,PTR_DIFF(p2,*rdata)); /* full_name */
4321 strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4322 p2 = skip_string(*rdata,*rdata_len,p2);
4323 if (!p2) {
4324 return False;
4326 SIVAL(p,66,0); /* urs_comment */
4327 SIVAL(p,70,PTR_DIFF(p2,*rdata)); /* parms */
4328 strlcpy(p2,"",PTR_DIFF(endp,p2));
4329 p2 = skip_string(*rdata,*rdata_len,p2);
4330 if (!p2) {
4331 return False;
4333 SIVAL(p,74,0); /* workstations */
4334 SIVAL(p,78,0); /* last_logon */
4335 SIVAL(p,82,0); /* last_logoff */
4336 SIVALS(p,86,-1); /* acct_expires */
4337 SIVALS(p,90,-1); /* max_storage */
4338 SSVAL(p,94,168); /* units_per_week */
4339 SIVAL(p,96,PTR_DIFF(p2,*rdata)); /* logon_hours */
4340 memset(p2,-1,21);
4341 p2 += 21;
4342 SSVALS(p,100,-1); /* bad_pw_count */
4343 SSVALS(p,102,-1); /* num_logons */
4344 SIVAL(p,104,PTR_DIFF(p2,*rdata)); /* logon_server */
4346 TALLOC_CTX *ctx = talloc_tos();
4347 int space_rem = *rdata_len - (p2 - *rdata);
4348 char *tmp;
4350 if (space_rem <= 0) {
4351 return false;
4353 tmp = talloc_strdup(ctx, "\\\\%L");
4354 if (!tmp) {
4355 return false;
4357 tmp = talloc_sub_basic(ctx,
4360 tmp);
4361 if (!tmp) {
4362 return false;
4365 push_ascii(p2,
4366 tmp,
4367 space_rem,
4368 STR_TERMINATE);
4370 p2 = skip_string(*rdata,*rdata_len,p2);
4371 if (!p2) {
4372 return False;
4374 SSVAL(p,108,49); /* country_code */
4375 SSVAL(p,110,860); /* code page */
4379 errcode = NERR_Success;
4381 out:
4382 *rdata_len = PTR_DIFF(p2,*rdata);
4384 if (cli && is_valid_policy_hnd(&user_handle)) {
4385 rpccli_samr_Close(cli, mem_ctx, &user_handle);
4387 if (cli && is_valid_policy_hnd(&domain_handle)) {
4388 rpccli_samr_Close(cli, mem_ctx, &domain_handle);
4390 if (cli && is_valid_policy_hnd(&connect_handle)) {
4391 rpccli_samr_Close(cli, mem_ctx, &connect_handle);
4394 SSVAL(*rparam,0,errcode);
4395 SSVAL(*rparam,2,0); /* converter word */
4396 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
4398 return(True);
4401 static bool api_WWkstaUserLogon(struct smbd_server_connection *sconn,
4402 connection_struct *conn,uint16 vuid,
4403 char *param, int tpscnt,
4404 char *data, int tdscnt,
4405 int mdrcnt,int mprcnt,
4406 char **rdata,char **rparam,
4407 int *rdata_len,int *rparam_len)
4409 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4410 char *str2 = skip_string(param,tpscnt,str1);
4411 char *p = skip_string(param,tpscnt,str2);
4412 int uLevel;
4413 struct pack_desc desc;
4414 char* name;
4415 /* With share level security vuid will always be zero.
4416 Don't depend on vuser being non-null !!. JRA */
4417 user_struct *vuser = get_valid_user_struct(sconn, vuid);
4419 if (!str1 || !str2 || !p) {
4420 return False;
4423 if(vuser != NULL) {
4424 DEBUG(3,(" Username of UID %d is %s\n",
4425 (int)vuser->server_info->utok.uid,
4426 vuser->server_info->unix_name));
4429 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4430 name = get_safe_str_ptr(param,tpscnt,p,2);
4431 if (!name) {
4432 return False;
4435 memset((char *)&desc,'\0',sizeof(desc));
4437 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
4439 /* check it's a supported varient */
4440 if (strcmp(str1,"OOWb54WrLh") != 0) {
4441 return False;
4443 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
4444 return False;
4446 if (mdrcnt > 0) {
4447 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4448 if (!*rdata) {
4449 return False;
4453 desc.base = *rdata;
4454 desc.buflen = mdrcnt;
4455 desc.subformat = NULL;
4456 desc.format = str2;
4458 if (init_package(&desc,1,0)) {
4459 PACKI(&desc,"W",0); /* code */
4460 PACKS(&desc,"B21",name); /* eff. name */
4461 PACKS(&desc,"B",""); /* pad */
4462 PACKI(&desc,"W",
4463 (get_current_uid(conn) == sec_initial_uid())?
4464 USER_PRIV_ADMIN:USER_PRIV_USER);
4465 PACKI(&desc,"D",0); /* auth flags XXX */
4466 PACKI(&desc,"W",0); /* num logons */
4467 PACKI(&desc,"W",0); /* bad pw count */
4468 PACKI(&desc,"D",0); /* last logon */
4469 PACKI(&desc,"D",-1); /* last logoff */
4470 PACKI(&desc,"D",-1); /* logoff time */
4471 PACKI(&desc,"D",-1); /* kickoff time */
4472 PACKI(&desc,"D",0); /* password age */
4473 PACKI(&desc,"D",0); /* password can change */
4474 PACKI(&desc,"D",-1); /* password must change */
4477 fstring mypath;
4478 fstrcpy(mypath,"\\\\");
4479 fstrcat(mypath,get_local_machine_name());
4480 strupper_m(mypath);
4481 PACKS(&desc,"z",mypath); /* computer */
4484 PACKS(&desc,"z",lp_workgroup());/* domain */
4485 PACKS(&desc,"z", vuser ?
4486 vuser->server_info->info3->base.logon_script.string
4487 : ""); /* script path */
4488 PACKI(&desc,"D",0x00000000); /* reserved */
4491 *rdata_len = desc.usedlen;
4492 *rparam_len = 6;
4493 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4494 if (!*rparam) {
4495 return False;
4497 SSVALS(*rparam,0,desc.errcode);
4498 SSVAL(*rparam,2,0);
4499 SSVAL(*rparam,4,desc.neededlen);
4501 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4503 return True;
4506 /****************************************************************************
4507 api_WAccessGetUserPerms
4508 ****************************************************************************/
4510 static bool api_WAccessGetUserPerms(struct smbd_server_connection *sconn,
4511 connection_struct *conn,uint16 vuid,
4512 char *param, int tpscnt,
4513 char *data, int tdscnt,
4514 int mdrcnt,int mprcnt,
4515 char **rdata,char **rparam,
4516 int *rdata_len,int *rparam_len)
4518 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4519 char *str2 = skip_string(param,tpscnt,str1);
4520 char *user = skip_string(param,tpscnt,str2);
4521 char *resource = skip_string(param,tpscnt,user);
4523 if (!str1 || !str2 || !user || !resource) {
4524 return False;
4527 if (skip_string(param,tpscnt,resource) == NULL) {
4528 return False;
4530 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4532 /* check it's a supported varient */
4533 if (strcmp(str1,"zzh") != 0) {
4534 return False;
4536 if (strcmp(str2,"") != 0) {
4537 return False;
4540 *rparam_len = 6;
4541 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4542 if (!*rparam) {
4543 return False;
4545 SSVALS(*rparam,0,0); /* errorcode */
4546 SSVAL(*rparam,2,0); /* converter word */
4547 SSVAL(*rparam,4,0x7f); /* permission flags */
4549 return True;
4552 /****************************************************************************
4553 api_WPrintJobEnumerate
4554 ****************************************************************************/
4556 static bool api_WPrintJobGetInfo(struct smbd_server_connection *sconn,
4557 connection_struct *conn, uint16 vuid,
4558 char *param, int tpscnt,
4559 char *data, int tdscnt,
4560 int mdrcnt,int mprcnt,
4561 char **rdata,char **rparam,
4562 int *rdata_len,int *rparam_len)
4564 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4565 char *str2 = skip_string(param,tpscnt,str1);
4566 char *p = skip_string(param,tpscnt,str2);
4567 int uLevel;
4568 fstring sharename;
4569 uint32 jobid;
4570 struct pack_desc desc;
4571 char *tmpdata=NULL;
4573 TALLOC_CTX *mem_ctx = talloc_tos();
4574 WERROR werr;
4575 NTSTATUS status;
4576 struct rpc_pipe_client *cli = NULL;
4577 struct policy_handle handle;
4578 struct spoolss_DevmodeContainer devmode_ctr;
4579 union spoolss_JobInfo info;
4581 if (!str1 || !str2 || !p) {
4582 return False;
4585 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4587 memset((char *)&desc,'\0',sizeof(desc));
4588 memset((char *)&status,'\0',sizeof(status));
4590 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4592 /* check it's a supported varient */
4593 if (strcmp(str1,"WWrLh") != 0) {
4594 return False;
4596 if (!check_printjob_info(&desc,uLevel,str2)) {
4597 return False;
4600 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4601 return False;
4604 ZERO_STRUCT(handle);
4606 status = rpc_connect_spoolss_pipe(conn, &cli);
4607 if (!NT_STATUS_IS_OK(status)) {
4608 DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n",
4609 nt_errstr(status)));
4610 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4611 goto out;
4614 ZERO_STRUCT(devmode_ctr);
4616 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4617 sharename,
4618 "RAW",
4619 devmode_ctr,
4620 PRINTER_ACCESS_USE,
4621 &handle,
4622 &werr);
4623 if (!NT_STATUS_IS_OK(status)) {
4624 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4625 goto out;
4627 if (!W_ERROR_IS_OK(werr)) {
4628 desc.errcode = W_ERROR_V(werr);
4629 goto out;
4632 werr = rpccli_spoolss_getjob(cli, mem_ctx,
4633 &handle,
4634 jobid,
4635 2, /* level */
4636 0, /* offered */
4637 &info);
4638 if (!W_ERROR_IS_OK(werr)) {
4639 desc.errcode = W_ERROR_V(werr);
4640 goto out;
4643 if (mdrcnt > 0) {
4644 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4645 if (!*rdata) {
4646 return False;
4648 desc.base = *rdata;
4649 desc.buflen = mdrcnt;
4650 } else {
4652 * Don't return data but need to get correct length
4653 * init_package will return wrong size if buflen=0
4655 desc.buflen = getlen(desc.format);
4656 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4659 if (init_package(&desc,1,0)) {
4660 fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position);
4661 *rdata_len = desc.usedlen;
4662 } else {
4663 desc.errcode = NERR_JobNotFound;
4664 *rdata_len = 0;
4666 out:
4667 if (cli && is_valid_policy_hnd(&handle)) {
4668 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4671 *rparam_len = 6;
4672 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4673 if (!*rparam) {
4674 return False;
4676 SSVALS(*rparam,0,desc.errcode);
4677 SSVAL(*rparam,2,0);
4678 SSVAL(*rparam,4,desc.neededlen);
4680 SAFE_FREE(tmpdata);
4682 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4684 return True;
4687 static bool api_WPrintJobEnumerate(struct smbd_server_connection *sconn,
4688 connection_struct *conn, uint16 vuid,
4689 char *param, int tpscnt,
4690 char *data, int tdscnt,
4691 int mdrcnt,int mprcnt,
4692 char **rdata,char **rparam,
4693 int *rdata_len,int *rparam_len)
4695 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4696 char *str2 = skip_string(param,tpscnt,str1);
4697 char *p = skip_string(param,tpscnt,str2);
4698 char *name = p;
4699 int uLevel;
4700 int i, succnt=0;
4701 struct pack_desc desc;
4703 TALLOC_CTX *mem_ctx = talloc_tos();
4704 WERROR werr;
4705 NTSTATUS status;
4706 struct rpc_pipe_client *cli = NULL;
4707 struct policy_handle handle;
4708 struct spoolss_DevmodeContainer devmode_ctr;
4709 uint32_t count = 0;
4710 union spoolss_JobInfo *info;
4712 if (!str1 || !str2 || !p) {
4713 return False;
4716 memset((char *)&desc,'\0',sizeof(desc));
4718 p = skip_string(param,tpscnt,p);
4719 if (!p) {
4720 return False;
4722 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4724 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4726 /* check it's a supported variant */
4727 if (strcmp(str1,"zWrLeh") != 0) {
4728 return False;
4731 if (uLevel > 2) {
4732 return False; /* defined only for uLevel 0,1,2 */
4735 if (!check_printjob_info(&desc,uLevel,str2)) {
4736 return False;
4739 ZERO_STRUCT(handle);
4741 status = rpc_connect_spoolss_pipe(conn, &cli);
4742 if (!NT_STATUS_IS_OK(status)) {
4743 DEBUG(0,("api_WPrintJobEnumerate: could not connect to spoolss: %s\n",
4744 nt_errstr(status)));
4745 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4746 goto out;
4749 ZERO_STRUCT(devmode_ctr);
4751 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4752 name,
4753 NULL,
4754 devmode_ctr,
4755 SEC_FLAG_MAXIMUM_ALLOWED,
4756 &handle,
4757 &werr);
4758 if (!NT_STATUS_IS_OK(status)) {
4759 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4760 goto out;
4762 if (!W_ERROR_IS_OK(werr)) {
4763 desc.errcode = W_ERROR_V(werr);
4764 goto out;
4767 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
4768 &handle,
4769 0, /* firstjob */
4770 0xff, /* numjobs */
4771 2, /* level */
4772 0, /* offered */
4773 &count,
4774 &info);
4775 if (!W_ERROR_IS_OK(werr)) {
4776 desc.errcode = W_ERROR_V(werr);
4777 goto out;
4780 if (mdrcnt > 0) {
4781 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4782 if (!*rdata) {
4783 return False;
4786 desc.base = *rdata;
4787 desc.buflen = mdrcnt;
4789 if (init_package(&desc,count,0)) {
4790 succnt = 0;
4791 for (i = 0; i < count; i++) {
4792 fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i);
4793 if (desc.errcode == NERR_Success) {
4794 succnt = i+1;
4798 out:
4799 if (cli && is_valid_policy_hnd(&handle)) {
4800 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4803 *rdata_len = desc.usedlen;
4805 *rparam_len = 8;
4806 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4807 if (!*rparam) {
4808 return False;
4810 SSVALS(*rparam,0,desc.errcode);
4811 SSVAL(*rparam,2,0);
4812 SSVAL(*rparam,4,succnt);
4813 SSVAL(*rparam,6,count);
4815 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4817 return True;
4820 static int check_printdest_info(struct pack_desc* desc,
4821 int uLevel, char* id)
4823 desc->subformat = NULL;
4824 switch( uLevel ) {
4825 case 0:
4826 desc->format = "B9";
4827 break;
4828 case 1:
4829 desc->format = "B9B21WWzW";
4830 break;
4831 case 2:
4832 desc->format = "z";
4833 break;
4834 case 3:
4835 desc->format = "zzzWWzzzWW";
4836 break;
4837 default:
4838 DEBUG(0,("check_printdest_info: invalid level %d\n",
4839 uLevel));
4840 return False;
4842 if (id == NULL || strcmp(desc->format,id) != 0) {
4843 DEBUG(0,("check_printdest_info: invalid string %s\n",
4844 id ? id : "<NULL>" ));
4845 return False;
4847 return True;
4850 static void fill_printdest_info(struct spoolss_PrinterInfo2 *info2, int uLevel,
4851 struct pack_desc* desc)
4853 char buf[100];
4855 strncpy(buf, info2->printername, sizeof(buf)-1);
4856 buf[sizeof(buf)-1] = 0;
4857 strupper_m(buf);
4859 if (uLevel <= 1) {
4860 PACKS(desc,"B9",buf); /* szName */
4861 if (uLevel == 1) {
4862 PACKS(desc,"B21",""); /* szUserName */
4863 PACKI(desc,"W",0); /* uJobId */
4864 PACKI(desc,"W",0); /* fsStatus */
4865 PACKS(desc,"z",""); /* pszStatus */
4866 PACKI(desc,"W",0); /* time */
4870 if (uLevel == 2 || uLevel == 3) {
4871 PACKS(desc,"z",buf); /* pszPrinterName */
4872 if (uLevel == 3) {
4873 PACKS(desc,"z",""); /* pszUserName */
4874 PACKS(desc,"z",""); /* pszLogAddr */
4875 PACKI(desc,"W",0); /* uJobId */
4876 PACKI(desc,"W",0); /* fsStatus */
4877 PACKS(desc,"z",""); /* pszStatus */
4878 PACKS(desc,"z",""); /* pszComment */
4879 PACKS(desc,"z","NULL"); /* pszDrivers */
4880 PACKI(desc,"W",0); /* time */
4881 PACKI(desc,"W",0); /* pad1 */
4886 static bool api_WPrintDestGetInfo(struct smbd_server_connection *sconn,
4887 connection_struct *conn, uint16 vuid,
4888 char *param, int tpscnt,
4889 char *data, int tdscnt,
4890 int mdrcnt,int mprcnt,
4891 char **rdata,char **rparam,
4892 int *rdata_len,int *rparam_len)
4894 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4895 char *str2 = skip_string(param,tpscnt,str1);
4896 char *p = skip_string(param,tpscnt,str2);
4897 char* PrinterName = p;
4898 int uLevel;
4899 struct pack_desc desc;
4900 char *tmpdata=NULL;
4902 TALLOC_CTX *mem_ctx = talloc_tos();
4903 WERROR werr;
4904 NTSTATUS status;
4905 struct rpc_pipe_client *cli = NULL;
4906 struct policy_handle handle;
4907 struct spoolss_DevmodeContainer devmode_ctr;
4908 union spoolss_PrinterInfo info;
4910 if (!str1 || !str2 || !p) {
4911 return False;
4914 memset((char *)&desc,'\0',sizeof(desc));
4916 p = skip_string(param,tpscnt,p);
4917 if (!p) {
4918 return False;
4920 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4922 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4924 /* check it's a supported varient */
4925 if (strcmp(str1,"zWrLh") != 0) {
4926 return False;
4928 if (!check_printdest_info(&desc,uLevel,str2)) {
4929 return False;
4932 ZERO_STRUCT(handle);
4934 status = rpc_connect_spoolss_pipe(conn, &cli);
4935 if (!NT_STATUS_IS_OK(status)) {
4936 DEBUG(0,("api_WPrintDestGetInfo: could not connect to spoolss: %s\n",
4937 nt_errstr(status)));
4938 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4939 goto out;
4942 ZERO_STRUCT(devmode_ctr);
4944 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4945 PrinterName,
4946 NULL,
4947 devmode_ctr,
4948 SEC_FLAG_MAXIMUM_ALLOWED,
4949 &handle,
4950 &werr);
4951 if (!NT_STATUS_IS_OK(status)) {
4952 *rdata_len = 0;
4953 desc.errcode = NERR_DestNotFound;
4954 desc.neededlen = 0;
4955 goto out;
4957 if (!W_ERROR_IS_OK(werr)) {
4958 *rdata_len = 0;
4959 desc.errcode = NERR_DestNotFound;
4960 desc.neededlen = 0;
4961 goto out;
4964 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
4965 &handle,
4968 &info);
4969 if (!W_ERROR_IS_OK(werr)) {
4970 *rdata_len = 0;
4971 desc.errcode = NERR_DestNotFound;
4972 desc.neededlen = 0;
4973 goto out;
4976 if (mdrcnt > 0) {
4977 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4978 if (!*rdata) {
4979 return False;
4981 desc.base = *rdata;
4982 desc.buflen = mdrcnt;
4983 } else {
4985 * Don't return data but need to get correct length
4986 * init_package will return wrong size if buflen=0
4988 desc.buflen = getlen(desc.format);
4989 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4991 if (init_package(&desc,1,0)) {
4992 fill_printdest_info(&info.info2, uLevel,&desc);
4995 out:
4996 if (cli && is_valid_policy_hnd(&handle)) {
4997 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
5000 *rdata_len = desc.usedlen;
5002 *rparam_len = 6;
5003 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5004 if (!*rparam) {
5005 return False;
5007 SSVALS(*rparam,0,desc.errcode);
5008 SSVAL(*rparam,2,0);
5009 SSVAL(*rparam,4,desc.neededlen);
5011 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
5012 SAFE_FREE(tmpdata);
5014 return True;
5017 static bool api_WPrintDestEnum(struct smbd_server_connection *sconn,
5018 connection_struct *conn, uint16 vuid,
5019 char *param, int tpscnt,
5020 char *data, int tdscnt,
5021 int mdrcnt,int mprcnt,
5022 char **rdata,char **rparam,
5023 int *rdata_len,int *rparam_len)
5025 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5026 char *str2 = skip_string(param,tpscnt,str1);
5027 char *p = skip_string(param,tpscnt,str2);
5028 int uLevel;
5029 int queuecnt;
5030 int i, n, succnt=0;
5031 struct pack_desc desc;
5033 TALLOC_CTX *mem_ctx = talloc_tos();
5034 WERROR werr;
5035 NTSTATUS status;
5036 struct rpc_pipe_client *cli = NULL;
5037 union spoolss_PrinterInfo *info;
5038 uint32_t count;
5040 if (!str1 || !str2 || !p) {
5041 return False;
5044 memset((char *)&desc,'\0',sizeof(desc));
5046 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5048 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
5050 /* check it's a supported varient */
5051 if (strcmp(str1,"WrLeh") != 0) {
5052 return False;
5054 if (!check_printdest_info(&desc,uLevel,str2)) {
5055 return False;
5058 queuecnt = 0;
5060 status = rpc_connect_spoolss_pipe(conn, &cli);
5061 if (!NT_STATUS_IS_OK(status)) {
5062 DEBUG(0,("api_WPrintDestEnum: could not connect to spoolss: %s\n",
5063 nt_errstr(status)));
5064 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5065 goto out;
5068 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
5069 PRINTER_ENUM_LOCAL,
5070 cli->srv_name_slash,
5073 &count,
5074 &info);
5075 if (!W_ERROR_IS_OK(werr)) {
5076 desc.errcode = W_ERROR_V(werr);
5077 *rdata_len = 0;
5078 desc.errcode = NERR_DestNotFound;
5079 desc.neededlen = 0;
5080 goto out;
5083 queuecnt = count;
5085 if (mdrcnt > 0) {
5086 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5087 if (!*rdata) {
5088 return False;
5092 desc.base = *rdata;
5093 desc.buflen = mdrcnt;
5094 if (init_package(&desc,queuecnt,0)) {
5095 succnt = 0;
5096 n = 0;
5097 for (i = 0; i < count; i++) {
5098 fill_printdest_info(&info[i].info2, uLevel,&desc);
5099 n++;
5100 if (desc.errcode == NERR_Success) {
5101 succnt = n;
5105 out:
5106 *rdata_len = desc.usedlen;
5108 *rparam_len = 8;
5109 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5110 if (!*rparam) {
5111 return False;
5113 SSVALS(*rparam,0,desc.errcode);
5114 SSVAL(*rparam,2,0);
5115 SSVAL(*rparam,4,succnt);
5116 SSVAL(*rparam,6,queuecnt);
5118 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
5120 return True;
5123 static bool api_WPrintDriverEnum(struct smbd_server_connection *sconn,
5124 connection_struct *conn, uint16 vuid,
5125 char *param, int tpscnt,
5126 char *data, int tdscnt,
5127 int mdrcnt,int mprcnt,
5128 char **rdata,char **rparam,
5129 int *rdata_len,int *rparam_len)
5131 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5132 char *str2 = skip_string(param,tpscnt,str1);
5133 char *p = skip_string(param,tpscnt,str2);
5134 int uLevel;
5135 int succnt;
5136 struct pack_desc desc;
5138 if (!str1 || !str2 || !p) {
5139 return False;
5142 memset((char *)&desc,'\0',sizeof(desc));
5144 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5146 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
5148 /* check it's a supported varient */
5149 if (strcmp(str1,"WrLeh") != 0) {
5150 return False;
5152 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
5153 return False;
5156 if (mdrcnt > 0) {
5157 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5158 if (!*rdata) {
5159 return False;
5162 desc.base = *rdata;
5163 desc.buflen = mdrcnt;
5164 if (init_package(&desc,1,0)) {
5165 PACKS(&desc,"B41","NULL");
5168 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5170 *rdata_len = desc.usedlen;
5172 *rparam_len = 8;
5173 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5174 if (!*rparam) {
5175 return False;
5177 SSVALS(*rparam,0,desc.errcode);
5178 SSVAL(*rparam,2,0);
5179 SSVAL(*rparam,4,succnt);
5180 SSVAL(*rparam,6,1);
5182 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
5184 return True;
5187 static bool api_WPrintQProcEnum(struct smbd_server_connection *sconn,
5188 connection_struct *conn, uint16 vuid,
5189 char *param, int tpscnt,
5190 char *data, int tdscnt,
5191 int mdrcnt,int mprcnt,
5192 char **rdata,char **rparam,
5193 int *rdata_len,int *rparam_len)
5195 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5196 char *str2 = skip_string(param,tpscnt,str1);
5197 char *p = skip_string(param,tpscnt,str2);
5198 int uLevel;
5199 int succnt;
5200 struct pack_desc desc;
5202 if (!str1 || !str2 || !p) {
5203 return False;
5205 memset((char *)&desc,'\0',sizeof(desc));
5207 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5209 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
5211 /* check it's a supported varient */
5212 if (strcmp(str1,"WrLeh") != 0) {
5213 return False;
5215 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
5216 return False;
5219 if (mdrcnt > 0) {
5220 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5221 if (!*rdata) {
5222 return False;
5225 desc.base = *rdata;
5226 desc.buflen = mdrcnt;
5227 desc.format = str2;
5228 if (init_package(&desc,1,0)) {
5229 PACKS(&desc,"B13","lpd");
5232 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5234 *rdata_len = desc.usedlen;
5236 *rparam_len = 8;
5237 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5238 if (!*rparam) {
5239 return False;
5241 SSVALS(*rparam,0,desc.errcode);
5242 SSVAL(*rparam,2,0);
5243 SSVAL(*rparam,4,succnt);
5244 SSVAL(*rparam,6,1);
5246 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
5248 return True;
5251 static bool api_WPrintPortEnum(struct smbd_server_connection *sconn,
5252 connection_struct *conn, uint16 vuid,
5253 char *param, int tpscnt,
5254 char *data, int tdscnt,
5255 int mdrcnt,int mprcnt,
5256 char **rdata,char **rparam,
5257 int *rdata_len,int *rparam_len)
5259 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5260 char *str2 = skip_string(param,tpscnt,str1);
5261 char *p = skip_string(param,tpscnt,str2);
5262 int uLevel;
5263 int succnt;
5264 struct pack_desc desc;
5266 if (!str1 || !str2 || !p) {
5267 return False;
5270 memset((char *)&desc,'\0',sizeof(desc));
5272 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5274 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
5276 /* check it's a supported varient */
5277 if (strcmp(str1,"WrLeh") != 0) {
5278 return False;
5280 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
5281 return False;
5284 if (mdrcnt > 0) {
5285 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5286 if (!*rdata) {
5287 return False;
5290 memset((char *)&desc,'\0',sizeof(desc));
5291 desc.base = *rdata;
5292 desc.buflen = mdrcnt;
5293 desc.format = str2;
5294 if (init_package(&desc,1,0)) {
5295 PACKS(&desc,"B13","lp0");
5298 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5300 *rdata_len = desc.usedlen;
5302 *rparam_len = 8;
5303 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5304 if (!*rparam) {
5305 return False;
5307 SSVALS(*rparam,0,desc.errcode);
5308 SSVAL(*rparam,2,0);
5309 SSVAL(*rparam,4,succnt);
5310 SSVAL(*rparam,6,1);
5312 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
5314 return True;
5317 /****************************************************************************
5318 List open sessions
5319 ****************************************************************************/
5321 static bool api_RNetSessionEnum(struct smbd_server_connection *sconn,
5322 connection_struct *conn, uint16 vuid,
5323 char *param, int tpscnt,
5324 char *data, int tdscnt,
5325 int mdrcnt,int mprcnt,
5326 char **rdata,char **rparam,
5327 int *rdata_len,int *rparam_len)
5330 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5331 char *str2 = skip_string(param,tpscnt,str1);
5332 char *p = skip_string(param,tpscnt,str2);
5333 int uLevel;
5334 struct pack_desc desc;
5335 struct sessionid *session_list;
5336 int i, num_sessions;
5338 if (!str1 || !str2 || !p) {
5339 return False;
5342 memset((char *)&desc,'\0',sizeof(desc));
5344 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5346 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
5347 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
5348 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
5350 /* check it's a supported varient */
5351 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
5352 return False;
5354 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
5355 return False;
5358 num_sessions = list_sessions(talloc_tos(), &session_list);
5360 if (mdrcnt > 0) {
5361 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5362 if (!*rdata) {
5363 return False;
5366 memset((char *)&desc,'\0',sizeof(desc));
5367 desc.base = *rdata;
5368 desc.buflen = mdrcnt;
5369 desc.format = str2;
5370 if (!init_package(&desc,num_sessions,0)) {
5371 return False;
5374 for(i=0; i<num_sessions; i++) {
5375 PACKS(&desc, "z", session_list[i].remote_machine);
5376 PACKS(&desc, "z", session_list[i].username);
5377 PACKI(&desc, "W", 1); /* num conns */
5378 PACKI(&desc, "W", 0); /* num opens */
5379 PACKI(&desc, "W", 1); /* num users */
5380 PACKI(&desc, "D", 0); /* session time */
5381 PACKI(&desc, "D", 0); /* idle time */
5382 PACKI(&desc, "D", 0); /* flags */
5383 PACKS(&desc, "z", "Unknown Client"); /* client type string */
5386 *rdata_len = desc.usedlen;
5388 *rparam_len = 8;
5389 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5390 if (!*rparam) {
5391 return False;
5393 SSVALS(*rparam,0,desc.errcode);
5394 SSVAL(*rparam,2,0); /* converter */
5395 SSVAL(*rparam,4,num_sessions); /* count */
5397 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
5399 return True;
5403 /****************************************************************************
5404 The buffer was too small.
5405 ****************************************************************************/
5407 static bool api_TooSmall(struct smbd_server_connection *sconn,
5408 connection_struct *conn,uint16 vuid, char *param, char *data,
5409 int mdrcnt, int mprcnt,
5410 char **rdata, char **rparam,
5411 int *rdata_len, int *rparam_len)
5413 *rparam_len = MIN(*rparam_len,mprcnt);
5414 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5415 if (!*rparam) {
5416 return False;
5419 *rdata_len = 0;
5421 SSVAL(*rparam,0,NERR_BufTooSmall);
5423 DEBUG(3,("Supplied buffer too small in API command\n"));
5425 return True;
5428 /****************************************************************************
5429 The request is not supported.
5430 ****************************************************************************/
5432 static bool api_Unsupported(struct smbd_server_connection *sconn,
5433 connection_struct *conn, uint16 vuid,
5434 char *param, int tpscnt,
5435 char *data, int tdscnt,
5436 int mdrcnt, int mprcnt,
5437 char **rdata, char **rparam,
5438 int *rdata_len, int *rparam_len)
5440 *rparam_len = 4;
5441 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5442 if (!*rparam) {
5443 return False;
5446 *rdata_len = 0;
5448 SSVAL(*rparam,0,NERR_notsupported);
5449 SSVAL(*rparam,2,0); /* converter word */
5451 DEBUG(3,("Unsupported API command\n"));
5453 return True;
5456 static const struct {
5457 const char *name;
5458 int id;
5459 bool (*fn)(struct smbd_server_connection *sconn,
5460 connection_struct *, uint16,
5461 char *, int,
5462 char *, int,
5463 int,int,char **,char **,int *,int *);
5464 bool auth_user; /* Deny anonymous access? */
5465 } api_commands[] = {
5466 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
5467 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
5468 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
5469 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
5470 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
5471 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
5472 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
5473 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
5474 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
5475 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
5476 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
5477 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
5478 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
5479 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
5480 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
5481 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
5482 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
5483 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
5484 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
5485 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
5486 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
5487 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
5488 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
5489 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
5490 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
5491 {"NetServerEnum3", RAP_NetServerEnum3, api_RNetServerEnum3}, /* anon OK */
5492 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
5493 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
5494 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
5495 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
5496 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
5497 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
5498 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
5499 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
5500 {NULL, -1, api_Unsupported}
5501 /* The following RAP calls are not implemented by Samba:
5503 RAP_WFileEnum2 - anon not OK
5508 /****************************************************************************
5509 Handle remote api calls.
5510 ****************************************************************************/
5512 void api_reply(connection_struct *conn, uint16 vuid,
5513 struct smb_request *req,
5514 char *data, char *params,
5515 int tdscnt, int tpscnt,
5516 int mdrcnt, int mprcnt)
5518 int api_command;
5519 char *rdata = NULL;
5520 char *rparam = NULL;
5521 const char *name1 = NULL;
5522 const char *name2 = NULL;
5523 int rdata_len = 0;
5524 int rparam_len = 0;
5525 bool reply=False;
5526 int i;
5528 if (!params) {
5529 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
5530 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5531 return;
5534 if (tpscnt < 2) {
5535 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5536 return;
5538 api_command = SVAL(params,0);
5539 /* Is there a string at position params+2 ? */
5540 if (skip_string(params,tpscnt,params+2)) {
5541 name1 = params + 2;
5542 } else {
5543 name1 = "";
5545 name2 = skip_string(params,tpscnt,params+2);
5546 if (!name2) {
5547 name2 = "";
5550 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
5551 api_command,
5552 name1,
5553 name2,
5554 tdscnt,tpscnt,mdrcnt,mprcnt));
5556 for (i=0;api_commands[i].name;i++) {
5557 if (api_commands[i].id == api_command && api_commands[i].fn) {
5558 DEBUG(3,("Doing %s\n",api_commands[i].name));
5559 break;
5563 /* Check whether this api call can be done anonymously */
5565 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
5566 user_struct *user = get_valid_user_struct(req->sconn, vuid);
5568 if (!user || user->server_info->guest) {
5569 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5570 return;
5574 rdata = (char *)SMB_MALLOC(1024);
5575 if (rdata) {
5576 memset(rdata,'\0',1024);
5579 rparam = (char *)SMB_MALLOC(1024);
5580 if (rparam) {
5581 memset(rparam,'\0',1024);
5584 if(!rdata || !rparam) {
5585 DEBUG(0,("api_reply: malloc fail !\n"));
5586 SAFE_FREE(rdata);
5587 SAFE_FREE(rparam);
5588 reply_nterror(req, NT_STATUS_NO_MEMORY);
5589 return;
5592 reply = api_commands[i].fn(req->sconn, conn,
5593 vuid,
5594 params,tpscnt, /* params + length */
5595 data,tdscnt, /* data + length */
5596 mdrcnt,mprcnt,
5597 &rdata,&rparam,&rdata_len,&rparam_len);
5600 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
5601 reply = api_TooSmall(req->sconn,conn,vuid,params,data,
5602 mdrcnt,mprcnt,
5603 &rdata,&rparam,&rdata_len,&rparam_len);
5606 /* if we get False back then it's actually unsupported */
5607 if (!reply) {
5608 reply = api_Unsupported(req->sconn,conn,vuid,params,tpscnt,
5609 data,
5610 tdscnt,mdrcnt,mprcnt,
5611 &rdata,&rparam,&rdata_len,&rparam_len);
5614 /* If api_Unsupported returns false we can't return anything. */
5615 if (reply) {
5616 send_trans_reply(conn, req, rparam, rparam_len,
5617 rdata, rdata_len, False);
5620 SAFE_FREE(rdata);
5621 SAFE_FREE(rparam);
5622 return;