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.
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
29 #include "smbd/globals.h"
30 #include "../librpc/gen_ndr/cli_samr.h"
31 #include "../librpc/gen_ndr/cli_spoolss.h"
32 #include "../librpc/gen_ndr/srv_samr.h"
33 #include "../librpc/gen_ndr/srv_spoolss.h"
34 #include "../lib/util/binsearch.h"
41 #define NERR_Success 0
42 #define NERR_badpass 86
43 #define NERR_notsupported 50
45 #define NERR_BASE (2100)
46 #define NERR_BufTooSmall (NERR_BASE+23)
47 #define NERR_JobNotFound (NERR_BASE+51)
48 #define NERR_DestNotFound (NERR_BASE+52)
50 #define ACCESS_READ 0x01
51 #define ACCESS_WRITE 0x02
52 #define ACCESS_CREATE 0x04
54 #define SHPWLEN 8 /* share password length */
56 /* Limit size of ipc replies */
58 static char *smb_realloc_limit(void *ptr, size_t size)
62 size = MAX((size),4*1024);
63 val = (char *)SMB_REALLOC(ptr,size);
65 memset(val,'\0',size);
70 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
71 char *param, int tpscnt,
72 char *data, int tdscnt,
73 int mdrcnt, int mprcnt,
74 char **rdata, char **rparam,
75 int *rdata_len, int *rparam_len);
77 static bool api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
78 int mdrcnt, int mprcnt,
79 char **rdata, char **rparam,
80 int *rdata_len, int *rparam_len);
83 static int CopyExpanded(connection_struct *conn,
84 int snum, char **dst, char *src, int *p_space_remaining)
86 TALLOC_CTX *ctx = talloc_tos();
90 if (!src || !dst || !p_space_remaining || !(*dst) ||
91 *p_space_remaining <= 0) {
95 buf = talloc_strdup(ctx, src);
97 *p_space_remaining = 0;
100 buf = talloc_string_sub(ctx, buf,"%S",lp_servicename(snum));
102 *p_space_remaining = 0;
105 buf = talloc_sub_advanced(ctx,
106 lp_servicename(SNUM(conn)),
107 conn->server_info->unix_name,
109 conn->server_info->utok.gid,
110 conn->server_info->sanitized_username,
111 pdb_get_domain(conn->server_info->sam_account),
114 *p_space_remaining = 0;
117 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
122 (*p_space_remaining) -= l;
126 static int CopyAndAdvance(char **dst, char *src, int *n)
129 if (!src || !dst || !n || !(*dst)) {
132 l = push_ascii(*dst,src,*n, STR_TERMINATE);
141 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
143 TALLOC_CTX *ctx = talloc_tos();
148 buf = talloc_strdup(ctx,s);
152 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
156 buf = talloc_sub_advanced(ctx,
157 lp_servicename(SNUM(conn)),
158 conn->server_info->unix_name,
160 conn->server_info->utok.gid,
161 conn->server_info->sanitized_username,
162 pdb_get_domain(conn->server_info->sam_account),
167 return strlen(buf) + 1;
170 static char *Expand(connection_struct *conn, int snum, char *s)
172 TALLOC_CTX *ctx = talloc_tos();
178 buf = talloc_strdup(ctx,s);
182 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
186 return talloc_sub_advanced(ctx,
187 lp_servicename(SNUM(conn)),
188 conn->server_info->unix_name,
190 conn->server_info->utok.gid,
191 conn->server_info->sanitized_username,
192 pdb_get_domain(conn->server_info->sam_account),
196 /*******************************************************************
197 Check a API string for validity when we only need to check the prefix.
198 ******************************************************************/
200 static bool prefix_ok(const char *str, const char *prefix)
202 return(strncmp(str,prefix,strlen(prefix)) == 0);
206 const char *format; /* formatstring for structure */
207 const char *subformat; /* subformat for structure */
208 char *base; /* baseaddress of buffer */
209 int buflen; /* remaining size for fixed part; on init: length of base */
210 int subcount; /* count of substructures */
211 char *structbuf; /* pointer into buffer for remaining fixed part */
212 int stringlen; /* remaining size for variable part */
213 char *stringbuf; /* pointer into buffer for remaining variable part */
214 int neededlen; /* total needed size */
215 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
216 const char *curpos; /* current position; pointer into format or subformat */
220 static int get_counter(const char **p)
226 if (!isdigit((int)**p)) {
232 n = 10 * n + (i - '0');
240 static int getlen(const char *p)
249 case 'W': /* word (2 byte) */
252 case 'K': /* status word? (2 byte) */
255 case 'N': /* count of substructures (word) at end */
258 case 'D': /* double word (4 byte) */
259 case 'z': /* offset to zero terminated string (4 byte) */
260 case 'l': /* offset to user data (4 byte) */
263 case 'b': /* offset to data (with counter) (4 byte) */
267 case 'B': /* byte (with optional counter) */
268 n += get_counter(&p);
275 static bool init_package(struct pack_desc *p, int count, int subcount)
280 if (!p->format || !p->base) {
284 i = count * getlen(p->format);
286 i += subcount * getlen(p->subformat);
288 p->structbuf = p->base;
292 p->curpos = p->format;
298 * This is the old error code we used. Aparently
299 * WinNT/2k systems return ERRbuftoosmall (2123) and
300 * OS/2 needs this. I'm leaving this here so we can revert
303 p->errcode = ERRmoredata;
305 p->errcode = ERRbuftoosmall;
308 p->errcode = NERR_Success;
312 p->stringbuf = p->base + i;
314 return (p->errcode == NERR_Success);
317 static int package(struct pack_desc *p, ...)
320 int needed=0, stringneeded;
321 const char *str=NULL;
322 int is_string=0, stringused;
329 p->curpos = p->format;
331 p->curpos = p->subformat;
336 str = va_arg(args,char*);
337 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
346 switch( *p->curpos++ ) {
347 case 'W': /* word (2 byte) */
349 temp = va_arg(args,int);
350 if (p->buflen >= needed) {
351 SSVAL(p->structbuf,0,temp);
354 case 'K': /* status word? (2 byte) */
356 temp = va_arg(args,int);
357 if (p->buflen >= needed) {
358 SSVAL(p->structbuf,0,temp);
361 case 'N': /* count of substructures (word) at end */
363 p->subcount = va_arg(args,int);
364 if (p->buflen >= needed) {
365 SSVAL(p->structbuf,0,p->subcount);
368 case 'D': /* double word (4 byte) */
370 temp = va_arg(args,int);
371 if (p->buflen >= needed) {
372 SIVAL(p->structbuf,0,temp);
375 case 'B': /* byte (with optional counter) */
376 needed = get_counter(&p->curpos);
378 char *s = va_arg(args,char*);
379 if (p->buflen >= needed) {
380 StrnCpy(p->structbuf,s?s:"",needed-1);
384 case 'z': /* offset to zero terminated string (4 byte) */
385 str = va_arg(args,char*);
386 stringneeded = (str ? strlen(str)+1 : 0);
389 case 'l': /* offset to user data (4 byte) */
390 str = va_arg(args,char*);
391 stringneeded = va_arg(args,int);
394 case 'b': /* offset to data (with counter) (4 byte) */
395 str = va_arg(args,char*);
396 stringneeded = get_counter(&p->curpos);
402 if (stringneeded >= 0) {
404 if (p->buflen >= needed) {
405 stringused = stringneeded;
406 if (stringused > p->stringlen) {
407 stringused = (is_string ? p->stringlen : 0);
408 if (p->errcode == NERR_Success) {
409 p->errcode = ERRmoredata;
413 SIVAL(p->structbuf,0,0);
415 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
416 memcpy(p->stringbuf,str?str:"",stringused);
418 p->stringbuf[stringused-1] = '\0';
420 p->stringbuf += stringused;
421 p->stringlen -= stringused;
422 p->usedlen += stringused;
425 p->neededlen += stringneeded;
428 p->neededlen += needed;
429 if (p->buflen >= needed) {
430 p->structbuf += needed;
432 p->usedlen += needed;
434 if (p->errcode == NERR_Success) {
435 p->errcode = ERRmoredata;
442 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
443 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
445 #define PACK(desc,t,v) package(desc,v)
446 #define PACKl(desc,t,v,l) package(desc,v,l)
449 static void PACKI(struct pack_desc* desc, const char *t,int v)
454 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
459 /****************************************************************************
461 ****************************************************************************/
463 static void PackDriverData(struct pack_desc* desc)
465 char drivdata[4+4+32];
466 SIVAL(drivdata,0,sizeof drivdata); /* cb */
467 SIVAL(drivdata,4,1000); /* lVersion */
468 memset(drivdata+8,0,32); /* szDeviceName */
469 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
470 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
473 static int check_printq_info(struct pack_desc* desc,
474 unsigned int uLevel, char *id1, char *id2)
476 desc->subformat = NULL;
479 desc->format = "B13";
482 desc->format = "B13BWWWzzzzzWW";
485 desc->format = "B13BWWWzzzzzWN";
486 desc->subformat = "WB21BB16B10zWWzDDz";
489 desc->format = "zWWWWzzzzWWzzl";
492 desc->format = "zWWWWzzzzWNzzl";
493 desc->subformat = "WWzWWDDzz";
502 desc->format = "WzzzzzzzzN";
503 desc->subformat = "z";
506 DEBUG(0,("check_printq_info: invalid level %d\n",
510 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
511 DEBUG(0,("check_printq_info: invalid format %s\n",
512 id1 ? id1 : "<NULL>" ));
515 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
516 DEBUG(0,("check_printq_info: invalid subformat %s\n",
517 id2 ? id2 : "<NULL>" ));
524 #define RAP_JOB_STATUS_QUEUED 0
525 #define RAP_JOB_STATUS_PAUSED 1
526 #define RAP_JOB_STATUS_SPOOLING 2
527 #define RAP_JOB_STATUS_PRINTING 3
528 #define RAP_JOB_STATUS_PRINTED 4
530 #define RAP_QUEUE_STATUS_PAUSED 1
531 #define RAP_QUEUE_STATUS_ERROR 2
533 /* turn a print job status into a on the wire status
535 static int printj_status(int v)
539 return RAP_JOB_STATUS_QUEUED;
541 return RAP_JOB_STATUS_PAUSED;
543 return RAP_JOB_STATUS_SPOOLING;
545 return RAP_JOB_STATUS_PRINTING;
550 static int printj_spoolss_status(int v)
552 if (v == JOB_STATUS_QUEUED)
553 return RAP_JOB_STATUS_QUEUED;
554 if (v & JOB_STATUS_PAUSED)
555 return RAP_JOB_STATUS_PAUSED;
556 if (v & JOB_STATUS_SPOOLING)
557 return RAP_JOB_STATUS_SPOOLING;
558 if (v & JOB_STATUS_PRINTING)
559 return RAP_JOB_STATUS_PRINTING;
563 /* turn a print queue status into a on the wire status
565 static int printq_status(int v)
571 return RAP_QUEUE_STATUS_PAUSED;
573 return RAP_QUEUE_STATUS_ERROR;
576 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
577 struct pack_desc *desc,
578 print_queue_struct *queue, int n)
580 time_t t = queue->time;
582 /* the client expects localtime */
583 t -= get_time_zone(t);
585 PACKI(desc,"W",pjobid_to_rap(lp_const_servicename(snum),queue->job)); /* uJobId */
587 PACKS(desc,"B21",queue->fs_user); /* szUserName */
588 PACKS(desc,"B",""); /* pad */
589 PACKS(desc,"B16",""); /* szNotifyName */
590 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
591 PACKS(desc,"z",""); /* pszParms */
592 PACKI(desc,"W",n+1); /* uPosition */
593 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
594 PACKS(desc,"z",""); /* pszStatus */
595 PACKI(desc,"D",t); /* ulSubmitted */
596 PACKI(desc,"D",queue->size); /* ulSize */
597 PACKS(desc,"z",queue->fs_file); /* pszComment */
599 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
600 PACKI(desc,"W",queue->priority); /* uPriority */
601 PACKS(desc,"z",queue->fs_user); /* pszUserName */
602 PACKI(desc,"W",n+1); /* uPosition */
603 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
604 PACKI(desc,"D",t); /* ulSubmitted */
605 PACKI(desc,"D",queue->size); /* ulSize */
606 PACKS(desc,"z","Samba"); /* pszComment */
607 PACKS(desc,"z",queue->fs_file); /* pszDocument */
609 PACKS(desc,"z",""); /* pszNotifyName */
610 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
611 PACKS(desc,"z",""); /* pszParms */
612 PACKS(desc,"z",""); /* pszStatus */
613 PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
614 PACKS(desc,"z","lpd"); /* pszQProcName */
615 PACKS(desc,"z",""); /* pszQProcParms */
616 PACKS(desc,"z","NULL"); /* pszDriverName */
617 PackDriverData(desc); /* pDriverData */
618 PACKS(desc,"z",""); /* pszPrinterName */
619 } else if (uLevel == 4) { /* OS2 */
620 PACKS(desc,"z",""); /* pszSpoolFileName */
621 PACKS(desc,"z",""); /* pszPortName */
622 PACKS(desc,"z",""); /* pszStatus */
623 PACKI(desc,"D",0); /* ulPagesSpooled */
624 PACKI(desc,"D",0); /* ulPagesSent */
625 PACKI(desc,"D",0); /* ulPagesPrinted */
626 PACKI(desc,"D",0); /* ulTimePrinted */
627 PACKI(desc,"D",0); /* ulExtendJobStatus */
628 PACKI(desc,"D",0); /* ulStartPage */
629 PACKI(desc,"D",0); /* ulEndPage */
634 static time_t spoolss_Time_to_time_t(const struct spoolss_Time *r)
638 unixtime.tm_year = r->year - 1900;
639 unixtime.tm_mon = r->month - 1;
640 unixtime.tm_wday = r->day_of_week;
641 unixtime.tm_mday = r->day;
642 unixtime.tm_hour = r->hour;
643 unixtime.tm_min = r->minute;
644 unixtime.tm_sec = r->second;
646 return mktime(&unixtime);
649 static void fill_spoolss_printjob_info(int uLevel,
650 struct pack_desc *desc,
651 struct spoolss_JobInfo2 *info2,
654 time_t t = spoolss_Time_to_time_t(&info2->submitted);
656 /* the client expects localtime */
657 t -= get_time_zone(t);
659 PACKI(desc,"W",pjobid_to_rap(info2->printer_name, info2->job_id)); /* uJobId */
661 PACKS(desc,"B21", info2->user_name); /* szUserName */
662 PACKS(desc,"B",""); /* pad */
663 PACKS(desc,"B16",""); /* szNotifyName */
664 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
665 PACKS(desc,"z",""); /* pszParms */
666 PACKI(desc,"W",n+1); /* uPosition */
667 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
668 PACKS(desc,"z",""); /* pszStatus */
669 PACKI(desc,"D", t); /* ulSubmitted */
670 PACKI(desc,"D", info2->size); /* ulSize */
671 PACKS(desc,"z", info2->document_name); /* pszComment */
673 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
674 PACKI(desc,"W", info2->priority); /* uPriority */
675 PACKS(desc,"z", info2->user_name); /* pszUserName */
676 PACKI(desc,"W",n+1); /* uPosition */
677 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
678 PACKI(desc,"D",t); /* ulSubmitted */
679 PACKI(desc,"D", info2->size); /* ulSize */
680 PACKS(desc,"z","Samba"); /* pszComment */
681 PACKS(desc,"z", info2->document_name); /* pszDocument */
683 PACKS(desc,"z",""); /* pszNotifyName */
684 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
685 PACKS(desc,"z",""); /* pszParms */
686 PACKS(desc,"z",""); /* pszStatus */
687 PACKS(desc,"z", info2->printer_name); /* pszQueue */
688 PACKS(desc,"z","lpd"); /* pszQProcName */
689 PACKS(desc,"z",""); /* pszQProcParms */
690 PACKS(desc,"z","NULL"); /* pszDriverName */
691 PackDriverData(desc); /* pDriverData */
692 PACKS(desc,"z",""); /* pszPrinterName */
693 } else if (uLevel == 4) { /* OS2 */
694 PACKS(desc,"z",""); /* pszSpoolFileName */
695 PACKS(desc,"z",""); /* pszPortName */
696 PACKS(desc,"z",""); /* pszStatus */
697 PACKI(desc,"D",0); /* ulPagesSpooled */
698 PACKI(desc,"D",0); /* ulPagesSent */
699 PACKI(desc,"D",0); /* ulPagesPrinted */
700 PACKI(desc,"D",0); /* ulTimePrinted */
701 PACKI(desc,"D",0); /* ulExtendJobStatus */
702 PACKI(desc,"D",0); /* ulStartPage */
703 PACKI(desc,"D",0); /* ulEndPage */
708 /********************************************************************
709 Return a driver name given an snum.
710 Returns True if from tdb, False otherwise.
711 ********************************************************************/
713 static bool get_driver_name(int snum, char **pp_drivername)
715 NT_PRINTER_INFO_LEVEL *info = NULL;
718 get_a_printer (NULL, &info, 2, lp_servicename(snum));
720 *pp_drivername = talloc_strdup(talloc_tos(),
721 info->info_2->drivername);
723 free_a_printer(&info, 2);
724 if (!*pp_drivername) {
732 /********************************************************************
733 Respond to the DosPrintQInfo command with a level of 52
734 This is used to get printer driver information for Win9x clients
735 ********************************************************************/
736 static void fill_printq_info_52(connection_struct *conn, int snum,
737 struct pack_desc* desc, int count )
741 struct spoolss_DriverInfo8 *driver = NULL;
742 NT_PRINTER_INFO_LEVEL *printer = NULL;
744 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
745 DEBUG(3,("fill_printq_info_52: Failed to lookup printer [%s]\n",
746 lp_servicename(snum)));
750 if (!W_ERROR_IS_OK(get_a_printer_driver(talloc_tos(), &driver, printer->info_2->drivername,
753 DEBUG(3,("fill_printq_info_52: Failed to lookup driver [%s]\n",
754 printer->info_2->drivername));
758 trim_string((char *)driver->driver_path, "\\print$\\WIN40\\0\\", 0);
759 trim_string((char *)driver->data_file, "\\print$\\WIN40\\0\\", 0);
760 trim_string((char *)driver->help_file, "\\print$\\WIN40\\0\\", 0);
762 PACKI(desc, "W", 0x0400); /* don't know */
763 PACKS(desc, "z", driver->driver_name); /* long printer name */
764 PACKS(desc, "z", driver->driver_path); /* Driverfile Name */
765 PACKS(desc, "z", driver->data_file); /* Datafile name */
766 PACKS(desc, "z", driver->monitor_name); /* language monitor */
768 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
769 standard_sub_basic( "", "", location, sizeof(location)-1 );
770 PACKS(desc,"z", location); /* share to retrieve files */
772 PACKS(desc,"z", driver->default_datatype); /* default data type */
773 PACKS(desc,"z", driver->help_file); /* helpfile name */
774 PACKS(desc,"z", driver->driver_path); /* driver name */
776 DEBUG(3,("Printer Driver Name: %s:\n",driver->driver_name));
777 DEBUG(3,("Driver: %s:\n",driver->driver_path));
778 DEBUG(3,("Data File: %s:\n",driver->data_file));
779 DEBUG(3,("Language Monitor: %s:\n",driver->monitor_name));
780 DEBUG(3,("Driver Location: %s:\n",location));
781 DEBUG(3,("Data Type: %s:\n",driver->default_datatype));
782 DEBUG(3,("Help File: %s:\n",driver->help_file));
783 PACKI(desc,"N",count); /* number of files to copy */
785 for ( i=0; i<count && driver->dependent_files && *driver->dependent_files[i]; i++)
787 trim_string((char *)driver->dependent_files[i], "\\print$\\WIN40\\0\\", 0);
788 PACKS(desc,"z",driver->dependent_files[i]); /* driver files to copy */
789 DEBUG(3,("Dependent File: %s:\n", driver->dependent_files[i]));
794 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
797 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", SERVICE(snum),i));
799 desc->errcode=NERR_Success;
803 DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
804 desc->errcode=NERR_notsupported;
808 free_a_printer( &printer, 2 );
810 free_a_printer_driver(driver);
814 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
815 struct pack_desc* desc,
816 int count, print_queue_struct* queue,
817 print_status_struct* status)
822 PACKS(desc,"B13",SERVICE(snum));
827 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
830 PACKI(desc,"K",printq_status(status->status));
834 if (uLevel == 1 || uLevel == 2) {
835 PACKS(desc,"B",""); /* alignment */
836 PACKI(desc,"W",5); /* priority */
837 PACKI(desc,"W",0); /* start time */
838 PACKI(desc,"W",0); /* until time */
839 PACKS(desc,"z",""); /* pSepFile */
840 PACKS(desc,"z","lpd"); /* pPrProc */
841 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
842 PACKS(desc,"z",""); /* pParms */
844 PACKS(desc,"z","UNKNOWN PRINTER");
845 PACKI(desc,"W",LPSTAT_ERROR);
847 else if (!status || !status->message[0]) {
848 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
849 PACKI(desc,"W",LPSTAT_OK); /* status */
851 PACKS(desc,"z",status->message);
852 PACKI(desc,"W",printq_status(status->status)); /* status */
854 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
857 if (uLevel == 3 || uLevel == 4) {
858 char *drivername = NULL;
860 PACKI(desc,"W",5); /* uPriority */
861 PACKI(desc,"W",0); /* uStarttime */
862 PACKI(desc,"W",0); /* uUntiltime */
863 PACKI(desc,"W",5); /* pad1 */
864 PACKS(desc,"z",""); /* pszSepFile */
865 PACKS(desc,"z","WinPrint"); /* pszPrProc */
866 PACKS(desc,"z",NULL); /* pszParms */
867 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
868 /* "don't ask" that it's done this way to fix corrupted
869 Win9X/ME printer comments. */
871 PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
873 PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
875 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
876 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
877 get_driver_name(snum,&drivername);
881 PACKS(desc,"z",drivername); /* pszDriverName */
882 PackDriverData(desc); /* pDriverData */
885 if (uLevel == 2 || uLevel == 4) {
887 for (i=0;i<count;i++)
888 fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
892 fill_printq_info_52( conn, snum, desc, count );
895 /* This function returns the number of files for a given driver */
896 static int get_printerdrivernumber(int snum)
899 struct spoolss_DriverInfo8 *driver;
900 NT_PRINTER_INFO_LEVEL *printer = NULL;
904 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
905 DEBUG(3,("get_printerdrivernumber: Failed to lookup printer [%s]\n",
906 lp_servicename(snum)));
910 if (!W_ERROR_IS_OK(get_a_printer_driver(talloc_tos(), &driver, printer->info_2->drivername,
913 DEBUG(3,("get_printerdrivernumber: Failed to lookup driver [%s]\n",
914 printer->info_2->drivername));
918 /* count the number of files */
919 while (driver->dependent_files && *driver->dependent_files[result])
923 free_a_printer( &printer, 2 );
925 free_a_printer_driver(driver);
930 static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
931 char *param, int tpscnt,
932 char *data, int tdscnt,
933 int mdrcnt,int mprcnt,
934 char **rdata,char **rparam,
935 int *rdata_len,int *rparam_len)
937 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
938 char *str2 = skip_string(param,tpscnt,str1);
939 char *p = skip_string(param,tpscnt,str2);
945 struct pack_desc desc;
946 print_queue_struct *queue=NULL;
947 print_status_struct status;
950 if (!str1 || !str2 || !p) {
953 memset((char *)&status,'\0',sizeof(status));
954 memset((char *)&desc,'\0',sizeof(desc));
956 p = skip_string(param,tpscnt,p);
960 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
961 str3 = get_safe_str_ptr(param,tpscnt,p,4);
962 /* str3 may be null here and is checked in check_printq_info(). */
964 /* remove any trailing username */
965 if ((p = strchr_m(QueueName,'%')))
968 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
970 /* check it's a supported varient */
971 if (!prefix_ok(str1,"zWrLh"))
973 if (!check_printq_info(&desc,uLevel,str2,str3)) {
975 * Patch from Scott Moomaw <scott@bridgewater.edu>
976 * to return the 'invalid info level' error if an
977 * unknown level was requested.
981 *rparam = smb_realloc_limit(*rparam,*rparam_len);
985 SSVALS(*rparam,0,ERRunknownlevel);
991 snum = find_service(QueueName);
992 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) )
996 count = get_printerdrivernumber(snum);
997 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
999 count = print_queue_status(snum, &queue,&status);
1003 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1009 desc.buflen = mdrcnt;
1012 * Don't return data but need to get correct length
1013 * init_package will return wrong size if buflen=0
1015 desc.buflen = getlen(desc.format);
1016 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
1019 if (init_package(&desc,1,count)) {
1020 desc.subcount = count;
1021 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
1024 *rdata_len = desc.usedlen;
1027 * We must set the return code to ERRbuftoosmall
1028 * in order to support lanman style printing with Win NT/2k
1031 if (!mdrcnt && lp_disable_spoolss())
1032 desc.errcode = ERRbuftoosmall;
1034 *rdata_len = desc.usedlen;
1036 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1042 SSVALS(*rparam,0,desc.errcode);
1044 SSVAL(*rparam,4,desc.neededlen);
1046 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
1054 /****************************************************************************
1055 View list of all print jobs on all queues.
1056 ****************************************************************************/
1058 static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
1059 char *param, int tpscnt,
1060 char *data, int tdscnt,
1061 int mdrcnt, int mprcnt,
1062 char **rdata, char** rparam,
1063 int *rdata_len, int *rparam_len)
1065 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
1066 char *output_format1 = skip_string(param,tpscnt,param_format);
1067 char *p = skip_string(param,tpscnt,output_format1);
1068 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1069 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
1070 int services = lp_numservices();
1072 struct pack_desc desc;
1073 print_queue_struct **queue = NULL;
1074 print_status_struct *status = NULL;
1075 int *subcntarr = NULL;
1076 int queuecnt = 0, subcnt = 0, succnt = 0;
1078 if (!param_format || !output_format1 || !p) {
1082 memset((char *)&desc,'\0',sizeof(desc));
1084 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
1086 if (!prefix_ok(param_format,"WrLeh")) {
1089 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
1091 * Patch from Scott Moomaw <scott@bridgewater.edu>
1092 * to return the 'invalid info level' error if an
1093 * unknown level was requested.
1097 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1101 SSVALS(*rparam,0,ERRunknownlevel);
1107 for (i = 0; i < services; i++) {
1108 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1113 if((queue = SMB_MALLOC_ARRAY(print_queue_struct*, queuecnt)) == NULL) {
1114 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1117 memset(queue,0,queuecnt*sizeof(print_queue_struct*));
1118 if((status = SMB_MALLOC_ARRAY(print_status_struct,queuecnt)) == NULL) {
1119 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1122 memset(status,0,queuecnt*sizeof(print_status_struct));
1123 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1124 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1130 for (i = 0; i < services; i++) {
1131 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1132 subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
1133 subcnt += subcntarr[n];
1139 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1145 desc.buflen = mdrcnt;
1147 if (init_package(&desc,queuecnt,subcnt)) {
1150 for (i = 0; i < services; i++) {
1151 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1152 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1154 if (desc.errcode == NERR_Success) {
1161 SAFE_FREE(subcntarr);
1163 *rdata_len = desc.usedlen;
1165 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1169 SSVALS(*rparam,0,desc.errcode);
1171 SSVAL(*rparam,4,succnt);
1172 SSVAL(*rparam,6,queuecnt);
1174 for (i = 0; i < queuecnt; i++) {
1176 SAFE_FREE(queue[i]);
1187 SAFE_FREE(subcntarr);
1188 for (i = 0; i < queuecnt; i++) {
1190 SAFE_FREE(queue[i]);
1199 /****************************************************************************
1200 Get info level for a server list query.
1201 ****************************************************************************/
1203 static bool check_server_info(int uLevel, char* id)
1207 if (strcmp(id,"B16") != 0) {
1212 if (strcmp(id,"B16BBDz") != 0) {
1222 struct srv_info_struct {
1230 /*******************************************************************
1231 Get server info lists from the files saved by nmbd. Return the
1233 ******************************************************************/
1235 static int get_server_info(uint32 servertype,
1236 struct srv_info_struct **servers,
1242 bool local_list_only;
1245 lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
1247 DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
1251 /* request for everything is code for request all servers */
1252 if (servertype == SV_TYPE_ALL) {
1253 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1256 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1258 DEBUG(4,("Servertype search: %8x\n",servertype));
1260 for (i=0;lines[i];i++) {
1262 struct srv_info_struct *s;
1263 const char *ptr = lines[i];
1265 TALLOC_CTX *frame = NULL;
1272 if (count == alloced) {
1274 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1276 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1280 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1282 s = &(*servers)[count];
1284 frame = talloc_stackframe();
1286 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1290 fstrcpy(s->name, p);
1293 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1299 s->comment[0] = '\0';
1300 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1304 fstrcpy(s->comment, p);
1305 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1307 s->domain[0] = '\0';
1308 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1309 /* this allows us to cope with an old nmbd */
1310 fstrcpy(s->domain,lp_workgroup());
1312 fstrcpy(s->domain, p);
1316 if (sscanf(stype,"%X",&s->type) != 1) {
1317 DEBUG(4,("r:host file "));
1321 /* Filter the servers/domains we return based on what was asked for. */
1323 /* Check to see if we are being asked for a local list only. */
1324 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1325 DEBUG(4,("r: local list only"));
1329 /* doesn't match up: don't want it */
1330 if (!(servertype & s->type)) {
1331 DEBUG(4,("r:serv type "));
1335 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1336 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1337 DEBUG(4,("s: dom mismatch "));
1341 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1345 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1346 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1349 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1350 s->name, s->type, s->comment, s->domain));
1351 s->server_added = True;
1354 DEBUG(4,("%20s %8x %25s %15s\n",
1355 s->name, s->type, s->comment, s->domain));
1363 /*******************************************************************
1364 Fill in a server info structure.
1365 ******************************************************************/
1367 static int fill_srv_info(struct srv_info_struct *service,
1368 int uLevel, char **buf, int *buflen,
1369 char **stringbuf, int *stringspace, char *baseaddr)
1392 len = strlen(service->comment)+1;
1396 *buflen = struct_len;
1398 return struct_len + len;
1403 if (*buflen < struct_len) {
1410 p2 = p + struct_len;
1411 l2 = *buflen - struct_len;
1419 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1423 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1424 SIVAL(p,18,service->type);
1425 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1426 len += CopyAndAdvance(&p2,service->comment,&l2);
1431 *buf = p + struct_len;
1432 *buflen -= struct_len;
1443 static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1445 return StrCaseCmp(s1->name,s2->name);
1448 /****************************************************************************
1449 View list of servers available (or possibly domains). The info is
1450 extracted from lists saved by nmbd on the local host.
1451 ****************************************************************************/
1453 static bool api_RNetServerEnum2(connection_struct *conn, uint16 vuid,
1454 char *param, int tpscnt,
1455 char *data, int tdscnt,
1456 int mdrcnt, int mprcnt, char **rdata,
1457 char **rparam, int *rdata_len, int *rparam_len)
1459 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1460 char *str2 = skip_string(param,tpscnt,str1);
1461 char *p = skip_string(param,tpscnt,str2);
1462 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1463 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1464 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1466 int data_len, fixed_len, string_len;
1467 int f_len = 0, s_len = 0;
1468 struct srv_info_struct *servers=NULL;
1469 int counted=0,total=0;
1472 bool domain_request;
1475 if (!str1 || !str2 || !p) {
1479 /* If someone sets all the bits they don't really mean to set
1480 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1483 if (servertype == SV_TYPE_ALL) {
1484 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1487 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1488 any other bit (they may just set this bit on its own) they
1489 want all the locally seen servers. However this bit can be
1490 set on its own so set the requested servers to be
1491 ALL - DOMAIN_ENUM. */
1493 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1494 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1497 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1498 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1502 if (!prefix_ok(str1,"WrLehD")) {
1505 if (!check_server_info(uLevel,str2)) {
1509 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1510 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1511 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1513 if (strcmp(str1, "WrLehDz") == 0) {
1514 if (skip_string(param,tpscnt,p) == NULL) {
1517 pull_ascii_fstring(domain, p);
1519 fstrcpy(domain, lp_workgroup());
1522 DEBUG(4, ("domain [%s]\n", domain));
1524 if (lp_browse_list()) {
1525 total = get_server_info(servertype,&servers,domain);
1528 data_len = fixed_len = string_len = 0;
1531 TYPESAFE_QSORT(servers, total, srv_comp);
1534 char *lastname=NULL;
1536 for (i=0;i<total;i++) {
1537 struct srv_info_struct *s = &servers[i];
1539 if (lastname && strequal(lastname,s->name)) {
1543 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1544 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1545 i, s->name, s->type, s->comment, s->domain));
1547 if (data_len < buf_len) {
1550 string_len += s_len;
1557 *rdata_len = fixed_len + string_len;
1558 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1563 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1569 char *lastname=NULL;
1570 int count2 = counted;
1572 for (i = 0; i < total && count2;i++) {
1573 struct srv_info_struct *s = &servers[i];
1575 if (lastname && strequal(lastname,s->name)) {
1579 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1580 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1581 i, s->name, s->type, s->comment, s->domain));
1587 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1591 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1593 SSVAL(*rparam,4,counted);
1594 SSVAL(*rparam,6,counted+missed);
1598 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1599 domain,uLevel,counted,counted+missed));
1604 static int srv_name_match(const char *n1, const char *n2)
1607 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1609 * In Windows, FirstNameToReturn need not be an exact match:
1610 * the server will return a list of servers that exist on
1611 * the network greater than or equal to the FirstNameToReturn.
1613 int ret = StrCaseCmp(n1, n2);
1622 static bool api_RNetServerEnum3(connection_struct *conn, uint16 vuid,
1623 char *param, int tpscnt,
1624 char *data, int tdscnt,
1625 int mdrcnt, int mprcnt, char **rdata,
1626 char **rparam, int *rdata_len, int *rparam_len)
1628 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1629 char *str2 = skip_string(param,tpscnt,str1);
1630 char *p = skip_string(param,tpscnt,str2);
1631 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1632 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1633 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1635 int data_len, fixed_len, string_len;
1636 int f_len = 0, s_len = 0;
1637 struct srv_info_struct *servers=NULL;
1638 int counted=0,first=0,total=0;
1642 bool domain_request;
1645 if (!str1 || !str2 || !p) {
1649 /* If someone sets all the bits they don't really mean to set
1650 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1653 if (servertype == SV_TYPE_ALL) {
1654 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1657 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1658 any other bit (they may just set this bit on its own) they
1659 want all the locally seen servers. However this bit can be
1660 set on its own so set the requested servers to be
1661 ALL - DOMAIN_ENUM. */
1663 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1664 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1667 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1668 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1672 if (strcmp(str1, "WrLehDzz") != 0) {
1675 if (!check_server_info(uLevel,str2)) {
1679 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1680 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1681 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1683 if (skip_string(param,tpscnt,p) == NULL) {
1686 pull_ascii_fstring(domain, p);
1687 if (domain[0] == '\0') {
1688 fstrcpy(domain, lp_workgroup());
1690 p = skip_string(param,tpscnt,p);
1691 if (skip_string(param,tpscnt,p) == NULL) {
1694 pull_ascii_fstring(first_name, p);
1696 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1697 domain, first_name));
1699 if (lp_browse_list()) {
1700 total = get_server_info(servertype,&servers,domain);
1703 data_len = fixed_len = string_len = 0;
1706 TYPESAFE_QSORT(servers, total, srv_comp);
1708 if (first_name[0] != '\0') {
1709 struct srv_info_struct *first_server = NULL;
1711 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1712 srv_name_match, first_server);
1714 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1716 * The binary search may not find the exact match
1717 * so we need to search backward to find the first match
1719 * This implements the strange matching windows
1720 * implements. (see the comment in srv_name_match().
1724 ret = StrCaseCmp(first_name,
1725 servers[first-1].name);
1732 /* we should return no entries */
1738 char *lastname=NULL;
1740 for (i=first;i<total;i++) {
1741 struct srv_info_struct *s = &servers[i];
1743 if (lastname && strequal(lastname,s->name)) {
1747 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1748 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1749 i, s->name, s->type, s->comment, s->domain));
1751 if (data_len < buf_len) {
1754 string_len += s_len;
1761 *rdata_len = fixed_len + string_len;
1762 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1767 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1773 char *lastname=NULL;
1774 int count2 = counted;
1776 for (i = first; i < total && count2;i++) {
1777 struct srv_info_struct *s = &servers[i];
1779 if (lastname && strequal(lastname,s->name)) {
1783 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1784 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1785 i, s->name, s->type, s->comment, s->domain));
1791 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1795 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1797 SSVAL(*rparam,4,counted);
1798 SSVAL(*rparam,6,counted+missed);
1800 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1801 domain,uLevel,first,first_name,
1802 first < total ? servers[first].name : "",
1803 counted,counted+missed));
1810 /****************************************************************************
1811 command 0x34 - suspected of being a "Lookup Names" stub api
1812 ****************************************************************************/
1814 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1815 char *param, int tpscnt,
1816 char *data, int tdscnt,
1817 int mdrcnt, int mprcnt, char **rdata,
1818 char **rparam, int *rdata_len, int *rparam_len)
1820 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1821 char *str2 = skip_string(param,tpscnt,str1);
1822 char *p = skip_string(param,tpscnt,str2);
1823 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1824 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1828 if (!str1 || !str2 || !p) {
1832 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1833 str1, str2, p, uLevel, buf_len));
1835 if (!prefix_ok(str1,"zWrLeh")) {
1842 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1847 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1849 SSVAL(*rparam,4,counted);
1850 SSVAL(*rparam,6,counted+missed);
1855 /****************************************************************************
1856 get info about a share
1857 ****************************************************************************/
1859 static bool check_share_info(int uLevel, char* id)
1863 if (strcmp(id,"B13") != 0) {
1868 /* Level-2 descriptor is allowed (and ignored) */
1869 if (strcmp(id,"B13BWz") != 0 &&
1870 strcmp(id,"B13BWzWWWzB9B") != 0) {
1875 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1880 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1890 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1891 char** buf, int* buflen,
1892 char** stringbuf, int* stringspace, char* baseaddr)
1921 len += StrlenExpanded(conn,snum,lp_comment(snum));
1924 len += strlen(lp_pathname(snum)) + 1;
1927 *buflen = struct_len;
1932 return struct_len + len;
1937 if ((*buflen) < struct_len) {
1945 p2 = p + struct_len;
1946 l2 = (*buflen) - struct_len;
1953 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1959 type = STYPE_DISKTREE;
1960 if (lp_print_ok(snum)) {
1961 type = STYPE_PRINTQ;
1963 if (strequal("IPC",lp_fstype(snum))) {
1966 SSVAL(p,14,type); /* device type */
1967 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1968 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1972 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1973 SSVALS(p,22,-1); /* max uses */
1974 SSVAL(p,24,1); /* current uses */
1975 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1976 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1977 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1981 memset(p+40,0,SHPWLEN+2);
1992 (*buf) = p + struct_len;
1993 (*buflen) -= struct_len;
1995 (*stringspace) = l2;
2004 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
2005 char *param, int tpscnt,
2006 char *data, int tdscnt,
2007 int mdrcnt,int mprcnt,
2008 char **rdata,char **rparam,
2009 int *rdata_len,int *rparam_len)
2011 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2012 char *str2 = skip_string(param,tpscnt,str1);
2013 char *netname = skip_string(param,tpscnt,str2);
2014 char *p = skip_string(param,tpscnt,netname);
2015 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2018 if (!str1 || !str2 || !netname || !p) {
2022 snum = find_service(netname);
2027 /* check it's a supported varient */
2028 if (!prefix_ok(str1,"zWrLh")) {
2031 if (!check_share_info(uLevel,str2)) {
2035 *rdata = smb_realloc_limit(*rdata,mdrcnt);
2040 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
2041 if (*rdata_len < 0) {
2046 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2050 SSVAL(*rparam,0,NERR_Success);
2051 SSVAL(*rparam,2,0); /* converter word */
2052 SSVAL(*rparam,4,*rdata_len);
2057 /****************************************************************************
2058 View the list of available shares.
2060 This function is the server side of the NetShareEnum() RAP call.
2061 It fills the return buffer with share names and share comments.
2062 Note that the return buffer normally (in all known cases) allows only
2063 twelve byte strings for share names (plus one for a nul terminator).
2064 Share names longer than 12 bytes must be skipped.
2065 ****************************************************************************/
2067 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
2068 char *param, int tpscnt,
2069 char *data, int tdscnt,
2077 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2078 char *str2 = skip_string(param,tpscnt,str1);
2079 char *p = skip_string(param,tpscnt,str2);
2080 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2081 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
2084 int total=0,counted=0;
2085 bool missed = False;
2087 int data_len, fixed_len, string_len;
2088 int f_len = 0, s_len = 0;
2090 if (!str1 || !str2 || !p) {
2094 if (!prefix_ok(str1,"WrLeh")) {
2097 if (!check_share_info(uLevel,str2)) {
2101 /* Ensure all the usershares are loaded. */
2103 load_registry_shares();
2104 count = load_usershare_shares();
2107 data_len = fixed_len = string_len = 0;
2108 for (i=0;i<count;i++) {
2109 fstring servicename_dos;
2110 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2113 push_ascii_fstring(servicename_dos, lp_servicename(i));
2114 /* Maximum name length = 13. */
2115 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
2117 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
2118 if (data_len < buf_len) {
2121 string_len += s_len;
2128 *rdata_len = fixed_len + string_len;
2129 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2134 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
2139 for( i = 0; i < count; i++ ) {
2140 fstring servicename_dos;
2141 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2145 push_ascii_fstring(servicename_dos, lp_servicename(i));
2146 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2147 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2154 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2158 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2160 SSVAL(*rparam,4,counted);
2161 SSVAL(*rparam,6,total);
2163 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2164 counted,total,uLevel,
2165 buf_len,*rdata_len,mdrcnt));
2170 /****************************************************************************
2172 ****************************************************************************/
2174 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
2175 char *param, int tpscnt,
2176 char *data, int tdscnt,
2177 int mdrcnt,int mprcnt,
2178 char **rdata,char **rparam,
2179 int *rdata_len,int *rparam_len)
2181 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2182 char *str2 = skip_string(param,tpscnt,str1);
2183 char *p = skip_string(param,tpscnt,str2);
2184 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2187 char *pathname = NULL;
2188 char *command, *cmdname;
2189 unsigned int offset;
2192 size_t converted_size;
2194 if (!str1 || !str2 || !p) {
2198 /* check it's a supported varient */
2199 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2202 if (!check_share_info(uLevel,str2)) {
2209 /* Do we have a string ? */
2210 if (skip_string(data,mdrcnt,data) == NULL) {
2213 pull_ascii_fstring(sharename,data);
2214 snum = find_service(sharename);
2215 if (snum >= 0) { /* already exists */
2224 /* only support disk share adds */
2225 if (SVAL(data,14)!=STYPE_DISKTREE) {
2229 offset = IVAL(data, 16);
2230 if (offset >= mdrcnt) {
2231 res = ERRinvalidparam;
2235 /* Do we have a string ? */
2236 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2239 pull_ascii_fstring(comment, offset? (data+offset) : "");
2241 offset = IVAL(data, 26);
2243 if (offset >= mdrcnt) {
2244 res = ERRinvalidparam;
2248 /* Do we have a string ? */
2249 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2253 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2254 offset ? (data+offset) : "", &converted_size))
2256 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
2264 string_replace(sharename, '"', ' ');
2265 string_replace(pathname, '"', ' ');
2266 string_replace(comment, '"', ' ');
2268 cmdname = lp_add_share_cmd();
2270 if (!cmdname || *cmdname == '\0') {
2274 if (asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
2275 lp_add_share_cmd(), get_dyn_CONFIGFILE(), sharename,
2276 pathname, comment) == -1) {
2280 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
2282 if ((res = smbrun(command, NULL)) != 0) {
2283 DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n",
2290 message_send_all(smbd_messaging_context(),
2291 MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
2295 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2299 SSVAL(*rparam,0,NERR_Success);
2300 SSVAL(*rparam,2,0); /* converter word */
2301 SSVAL(*rparam,4,*rdata_len);
2309 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2314 SSVAL(*rparam,0,res);
2319 /****************************************************************************
2320 view list of groups available
2321 ****************************************************************************/
2323 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
2324 char *param, int tpscnt,
2325 char *data, int tdscnt,
2326 int mdrcnt,int mprcnt,
2327 char **rdata,char **rparam,
2328 int *rdata_len,int *rparam_len)
2332 int resume_context, cli_buf_size;
2333 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2334 char *str2 = skip_string(param,tpscnt,str1);
2335 char *p = skip_string(param,tpscnt,str2);
2337 uint32_t num_groups;
2338 uint32_t resume_handle;
2339 struct rpc_pipe_client *samr_pipe;
2340 struct policy_handle samr_handle, domain_handle;
2343 if (!str1 || !str2 || !p) {
2347 if (strcmp(str1,"WrLeh") != 0) {
2352 * W-> resume context (number of users to skip)
2353 * r -> return parameter pointer to receive buffer
2354 * L -> length of receive buffer
2355 * e -> return parameter number of entries
2356 * h -> return parameter total number of users
2359 if (strcmp("B21",str2) != 0) {
2363 status = rpc_pipe_open_internal(
2364 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2365 conn->server_info, &samr_pipe);
2366 if (!NT_STATUS_IS_OK(status)) {
2367 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2368 nt_errstr(status)));
2372 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2373 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2374 if (!NT_STATUS_IS_OK(status)) {
2375 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2376 nt_errstr(status)));
2380 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2381 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2382 get_global_sam_sid(), &domain_handle);
2383 if (!NT_STATUS_IS_OK(status)) {
2384 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2385 nt_errstr(status)));
2386 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2390 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2391 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2392 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2393 "%d\n", resume_context, cli_buf_size));
2395 *rdata_len = cli_buf_size;
2396 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2403 errflags = NERR_Success;
2408 struct samr_SamArray *sam_entries;
2409 uint32_t num_entries;
2411 status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
2416 if (!NT_STATUS_IS_OK(status)) {
2417 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2418 "%s\n", nt_errstr(status)));
2422 if (num_entries == 0) {
2423 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2424 "no entries -- done\n"));
2428 for(i=0; i<num_entries; i++) {
2431 name = sam_entries->entries[i].name.string;
2433 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2434 /* set overflow error */
2435 DEBUG(3,("overflow on entry %d group %s\n", i,
2441 /* truncate the name at 21 chars. */
2443 strlcpy(p, name, 21);
2444 DEBUG(10,("adding entry %d group %s\n", i, p));
2446 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2451 if (errflags != NERR_Success) {
2455 TALLOC_FREE(sam_entries);
2458 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2459 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2461 *rdata_len = PTR_DIFF(p,*rdata);
2464 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2468 SSVAL(*rparam, 0, errflags);
2469 SSVAL(*rparam, 2, 0); /* converter word */
2470 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2471 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2476 /*******************************************************************
2477 Get groups that a user is a member of.
2478 ******************************************************************/
2480 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2481 char *param, int tpscnt,
2482 char *data, int tdscnt,
2483 int mdrcnt,int mprcnt,
2484 char **rdata,char **rparam,
2485 int *rdata_len,int *rparam_len)
2487 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2488 char *str2 = skip_string(param,tpscnt,str1);
2489 char *UserName = skip_string(param,tpscnt,str2);
2490 char *p = skip_string(param,tpscnt,UserName);
2491 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2492 const char *level_string;
2498 struct rpc_pipe_client *samr_pipe;
2499 struct policy_handle samr_handle, domain_handle, user_handle;
2500 struct lsa_String name;
2501 struct lsa_Strings names;
2502 struct samr_Ids type, rid;
2503 struct samr_RidWithAttributeArray *rids;
2506 if (!str1 || !str2 || !UserName || !p) {
2511 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2516 /* check it's a supported varient */
2518 if ( strcmp(str1,"zWrLeh") != 0 )
2523 level_string = "B21";
2529 if (strcmp(level_string,str2) != 0)
2532 *rdata_len = mdrcnt + 1024;
2533 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2538 SSVAL(*rparam,0,NERR_Success);
2539 SSVAL(*rparam,2,0); /* converter word */
2542 endp = *rdata + *rdata_len;
2544 status = rpc_pipe_open_internal(
2545 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2546 conn->server_info, &samr_pipe);
2547 if (!NT_STATUS_IS_OK(status)) {
2548 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2549 nt_errstr(status)));
2553 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2554 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2555 if (!NT_STATUS_IS_OK(status)) {
2556 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2557 nt_errstr(status)));
2561 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2562 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2563 get_global_sam_sid(), &domain_handle);
2564 if (!NT_STATUS_IS_OK(status)) {
2565 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2566 nt_errstr(status)));
2570 name.string = UserName;
2572 status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
2573 &domain_handle, 1, &name,
2575 if (!NT_STATUS_IS_OK(status)) {
2576 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2577 nt_errstr(status)));
2581 if (type.ids[0] != SID_NAME_USER) {
2582 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2583 sid_type_lookup(type.ids[0])));
2587 status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
2589 SAMR_USER_ACCESS_GET_GROUPS,
2590 rid.ids[0], &user_handle);
2591 if (!NT_STATUS_IS_OK(status)) {
2592 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2593 nt_errstr(status)));
2597 status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
2598 &user_handle, &rids);
2599 if (!NT_STATUS_IS_OK(status)) {
2600 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2601 nt_errstr(status)));
2605 for (i=0; i<rids->count; i++) {
2607 status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
2609 1, &rids->rids[i].rid,
2611 if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
2612 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2618 *rdata_len = PTR_DIFF(p,*rdata);
2620 SSVAL(*rparam,4,count); /* is this right?? */
2621 SSVAL(*rparam,6,count); /* is this right?? */
2626 rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
2628 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2630 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2635 /*******************************************************************
2637 ******************************************************************/
2639 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2640 char *param, int tpscnt,
2641 char *data, int tdscnt,
2642 int mdrcnt,int mprcnt,
2643 char **rdata,char **rparam,
2644 int *rdata_len,int *rparam_len)
2649 int i, resume_context, cli_buf_size;
2650 uint32_t resume_handle;
2652 struct rpc_pipe_client *samr_pipe;
2653 struct policy_handle samr_handle, domain_handle;
2656 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2657 char *str2 = skip_string(param,tpscnt,str1);
2658 char *p = skip_string(param,tpscnt,str2);
2661 if (!str1 || !str2 || !p) {
2665 if (strcmp(str1,"WrLeh") != 0)
2668 * W-> resume context (number of users to skip)
2669 * r -> return parameter pointer to receive buffer
2670 * L -> length of receive buffer
2671 * e -> return parameter number of entries
2672 * h -> return parameter total number of users
2675 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2676 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2677 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2678 resume_context, cli_buf_size));
2681 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2686 /* check it's a supported varient */
2687 if (strcmp("B21",str2) != 0)
2690 *rdata_len = cli_buf_size;
2691 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2697 endp = *rdata + *rdata_len;
2699 status = rpc_pipe_open_internal(
2700 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2701 conn->server_info, &samr_pipe);
2702 if (!NT_STATUS_IS_OK(status)) {
2703 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2704 nt_errstr(status)));
2708 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2709 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2710 if (!NT_STATUS_IS_OK(status)) {
2711 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2712 nt_errstr(status)));
2716 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2717 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2718 get_global_sam_sid(), &domain_handle);
2719 if (!NT_STATUS_IS_OK(status)) {
2720 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2721 nt_errstr(status)));
2722 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2726 errflags=NERR_Success;
2731 struct samr_SamArray *sam_entries;
2732 uint32_t num_entries;
2734 status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
2740 if (!NT_STATUS_IS_OK(status)) {
2741 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2742 "%s\n", nt_errstr(status)));
2746 if (num_entries == 0) {
2747 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2748 "no entries -- done\n"));
2752 for (i=0; i<num_entries; i++) {
2755 name = sam_entries->entries[i].name.string;
2757 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2758 &&(strlen(name)<=21)) {
2759 strlcpy(p,name,PTR_DIFF(endp,p));
2760 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2761 "username %s\n",count_sent,p));
2765 /* set overflow error */
2766 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2767 "username %s\n",count_sent,name));
2773 if (errflags != NERR_Success) {
2777 TALLOC_FREE(sam_entries);
2780 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2781 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2783 *rdata_len = PTR_DIFF(p,*rdata);
2785 SSVAL(*rparam,0,errflags);
2786 SSVAL(*rparam,2,0); /* converter word */
2787 SSVAL(*rparam,4,count_sent); /* is this right?? */
2788 SSVAL(*rparam,6,num_users); /* is this right?? */
2793 /****************************************************************************
2794 Get the time of day info.
2795 ****************************************************************************/
2797 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2798 char *param, int tpscnt,
2799 char *data, int tdscnt,
2800 int mdrcnt,int mprcnt,
2801 char **rdata,char **rparam,
2802 int *rdata_len,int *rparam_len)
2805 time_t unixdate = time(NULL);
2809 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2815 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2820 SSVAL(*rparam,0,NERR_Success);
2821 SSVAL(*rparam,2,0); /* converter word */
2825 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2826 by NT in a "net time" operation,
2827 it seems to ignore the one below */
2829 /* the client expects to get localtime, not GMT, in this bit
2830 (I think, this needs testing) */
2831 t = localtime(&unixdate);
2836 SIVAL(p,4,0); /* msecs ? */
2837 SCVAL(p,8,t->tm_hour);
2838 SCVAL(p,9,t->tm_min);
2839 SCVAL(p,10,t->tm_sec);
2840 SCVAL(p,11,0); /* hundredths of seconds */
2841 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2842 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2843 SCVAL(p,16,t->tm_mday);
2844 SCVAL(p,17,t->tm_mon + 1);
2845 SSVAL(p,18,1900+t->tm_year);
2846 SCVAL(p,20,t->tm_wday);
2851 /****************************************************************************
2852 Set the user password.
2853 *****************************************************************************/
2855 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2856 char *param, int tpscnt,
2857 char *data, int tdscnt,
2858 int mdrcnt,int mprcnt,
2859 char **rdata,char **rparam,
2860 int *rdata_len,int *rparam_len)
2862 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2865 fstring pass1,pass2;
2867 /* Skip 2 strings. */
2868 p = skip_string(param,tpscnt,np);
2869 p = skip_string(param,tpscnt,p);
2875 /* Do we have a string ? */
2876 if (skip_string(param,tpscnt,p) == NULL) {
2879 pull_ascii_fstring(user,p);
2881 p = skip_string(param,tpscnt,p);
2886 memset(pass1,'\0',sizeof(pass1));
2887 memset(pass2,'\0',sizeof(pass2));
2889 * We use 31 here not 32 as we're checking
2890 * the last byte we want to access is safe.
2892 if (!is_offset_safe(param,tpscnt,p,31)) {
2896 memcpy(pass2,p+16,16);
2899 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2906 SSVAL(*rparam,0,NERR_badpass);
2907 SSVAL(*rparam,2,0); /* converter word */
2909 DEBUG(3,("Set password for <%s>\n",user));
2912 * Attempt to verify the old password against smbpasswd entries
2913 * Win98 clients send old and new password in plaintext for this call.
2917 struct auth_serversupplied_info *server_info = NULL;
2918 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2920 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2923 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2924 SSVAL(*rparam,0,NERR_Success);
2928 TALLOC_FREE(server_info);
2930 data_blob_clear_free(&password);
2934 * If the plaintext change failed, attempt
2935 * the old encrypted method. NT will generate this
2936 * after trying the samr method. Note that this
2937 * method is done as a last resort as this
2938 * password change method loses the NT password hash
2939 * and cannot change the UNIX password as no plaintext
2943 if(SVAL(*rparam,0) != NERR_Success) {
2944 struct samu *hnd = NULL;
2946 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2948 if (change_lanman_password(hnd,(uchar *)pass2)) {
2949 SSVAL(*rparam,0,NERR_Success);
2956 memset((char *)pass1,'\0',sizeof(fstring));
2957 memset((char *)pass2,'\0',sizeof(fstring));
2962 /****************************************************************************
2963 Set the user password (SamOEM version - gets plaintext).
2964 ****************************************************************************/
2966 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2967 char *param, int tpscnt,
2968 char *data, int tdscnt,
2969 int mdrcnt,int mprcnt,
2970 char **rdata,char **rparam,
2971 int *rdata_len,int *rparam_len)
2973 struct smbd_server_connection *sconn = smbd_server_conn;
2975 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2977 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2987 SSVAL(*rparam,0,NERR_badpass);
2990 * Check the parameter definition is correct.
2993 /* Do we have a string ? */
2994 if (skip_string(param,tpscnt,p) == 0) {
2997 if(!strequal(p, "zsT")) {
2998 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
3001 p = skip_string(param, tpscnt, p);
3006 /* Do we have a string ? */
3007 if (skip_string(param,tpscnt,p) == 0) {
3010 if(!strequal(p, "B516B16")) {
3011 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
3014 p = skip_string(param,tpscnt,p);
3018 /* Do we have a string ? */
3019 if (skip_string(param,tpscnt,p) == 0) {
3022 p += pull_ascii_fstring(user,p);
3024 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
3027 * Pass the user through the NT -> unix user mapping
3031 (void)map_username(sconn, user);
3033 if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
3034 SSVAL(*rparam,0,NERR_Success);
3040 /****************************************************************************
3043 ****************************************************************************/
3045 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
3046 char *param, int tpscnt,
3047 char *data, int tdscnt,
3048 int mdrcnt,int mprcnt,
3049 char **rdata,char **rparam,
3050 int *rdata_len,int *rparam_len)
3052 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3053 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3054 char *str2 = skip_string(param,tpscnt,str1);
3055 char *p = skip_string(param,tpscnt,str2);
3059 WERROR werr = WERR_OK;
3061 TALLOC_CTX *mem_ctx = talloc_tos();
3063 struct rpc_pipe_client *cli = NULL;
3064 struct policy_handle handle;
3065 struct spoolss_DevmodeContainer devmode_ctr;
3066 enum spoolss_JobControl command;
3068 if (!str1 || !str2 || !p) {
3072 * We use 1 here not 2 as we're checking
3073 * the last byte we want to access is safe.
3075 if (!is_offset_safe(param,tpscnt,p,1)) {
3078 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3081 /* check it's a supported varient */
3082 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
3086 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3092 ZERO_STRUCT(handle);
3094 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3095 rpc_spoolss_dispatch, conn->server_info,
3097 if (!NT_STATUS_IS_OK(status)) {
3098 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
3099 nt_errstr(status)));
3100 errcode = W_ERROR_V(ntstatus_to_werror(status));
3104 ZERO_STRUCT(devmode_ctr);
3106 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3110 SEC_FLAG_MAXIMUM_ALLOWED,
3113 if (!NT_STATUS_IS_OK(status)) {
3114 errcode = W_ERROR_V(ntstatus_to_werror(status));
3117 if (!W_ERROR_IS_OK(werr)) {
3118 errcode = W_ERROR_V(werr);
3122 /* FIXME: formerly NERR_JobNotFound was returned if job did not exist
3123 * and NERR_DestNotFound if share did not exist */
3125 errcode = NERR_Success;
3128 case 81: /* delete */
3129 command = SPOOLSS_JOB_CONTROL_DELETE;
3131 case 82: /* pause */
3132 command = SPOOLSS_JOB_CONTROL_PAUSE;
3134 case 83: /* resume */
3135 command = SPOOLSS_JOB_CONTROL_RESUME;
3138 errcode = NERR_notsupported;
3142 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3145 NULL, /* unique ptr ctr */
3148 if (!NT_STATUS_IS_OK(status)) {
3149 errcode = W_ERROR_V(ntstatus_to_werror(status));
3152 if (!W_ERROR_IS_OK(werr)) {
3153 errcode = W_ERROR_V(werr);
3158 if (is_valid_policy_hnd(&handle)) {
3159 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3162 SSVAL(*rparam,0,errcode);
3163 SSVAL(*rparam,2,0); /* converter word */
3168 /****************************************************************************
3169 Purge a print queue - or pause or resume it.
3170 ****************************************************************************/
3172 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
3173 char *param, int tpscnt,
3174 char *data, int tdscnt,
3175 int mdrcnt,int mprcnt,
3176 char **rdata,char **rparam,
3177 int *rdata_len,int *rparam_len)
3179 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3180 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3181 char *str2 = skip_string(param,tpscnt,str1);
3182 char *QueueName = skip_string(param,tpscnt,str2);
3183 int errcode = NERR_notsupported;
3184 WERROR werr = WERR_OK;
3187 TALLOC_CTX *mem_ctx = talloc_tos();
3188 struct rpc_pipe_client *cli = NULL;
3189 struct policy_handle handle;
3190 struct spoolss_SetPrinterInfoCtr info_ctr;
3191 struct spoolss_DevmodeContainer devmode_ctr;
3192 struct sec_desc_buf secdesc_ctr;
3193 enum spoolss_PrinterControl command;
3195 if (!str1 || !str2 || !QueueName) {
3199 /* check it's a supported varient */
3200 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3204 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3210 if (skip_string(param,tpscnt,QueueName) == NULL) {
3214 ZERO_STRUCT(handle);
3216 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3217 rpc_spoolss_dispatch, conn->server_info,
3219 if (!NT_STATUS_IS_OK(status)) {
3220 DEBUG(0,("api_WPrintQueueCtrl: could not connect to spoolss: %s\n",
3221 nt_errstr(status)));
3222 errcode = W_ERROR_V(ntstatus_to_werror(status));
3226 ZERO_STRUCT(devmode_ctr);
3228 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3232 SEC_FLAG_MAXIMUM_ALLOWED,
3235 if (!NT_STATUS_IS_OK(status)) {
3236 errcode = W_ERROR_V(ntstatus_to_werror(status));
3239 if (!W_ERROR_IS_OK(werr)) {
3240 errcode = W_ERROR_V(werr);
3245 case 74: /* Pause queue */
3246 command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3248 case 75: /* Resume queue */
3249 command = SPOOLSS_PRINTER_CONTROL_RESUME;
3251 case 103: /* Purge */
3252 command = SPOOLSS_PRINTER_CONTROL_PURGE;
3255 werr = WERR_NOT_SUPPORTED;
3259 if (!W_ERROR_IS_OK(werr)) {
3260 errcode = W_ERROR_V(werr);
3264 ZERO_STRUCT(info_ctr);
3265 ZERO_STRUCT(secdesc_ctr);
3267 status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
3274 if (!NT_STATUS_IS_OK(status)) {
3275 errcode = W_ERROR_V(ntstatus_to_werror(status));
3278 if (!W_ERROR_IS_OK(werr)) {
3279 errcode = W_ERROR_V(werr);
3283 errcode = W_ERROR_V(werr);
3287 if (is_valid_policy_hnd(&handle)) {
3288 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3291 SSVAL(*rparam,0,errcode);
3292 SSVAL(*rparam,2,0); /* converter word */
3297 /****************************************************************************
3298 set the property of a print job (undocumented?)
3299 ? function = 0xb -> set name of print job
3300 ? function = 0x6 -> move print job up/down
3301 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3302 or <WWsTP> <WB21BB16B10zWWzDDz>
3303 ****************************************************************************/
3305 static int check_printjob_info(struct pack_desc* desc,
3306 int uLevel, char* id)
3308 desc->subformat = NULL;
3310 case 0: desc->format = "W"; break;
3311 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3312 case 2: desc->format = "WWzWWDDzz"; break;
3313 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3314 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3316 DEBUG(0,("check_printjob_info: invalid level %d\n",
3320 if (id == NULL || strcmp(desc->format,id) != 0) {
3321 DEBUG(0,("check_printjob_info: invalid format %s\n",
3322 id ? id : "<NULL>" ));
3328 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
3329 char *param, int tpscnt,
3330 char *data, int tdscnt,
3331 int mdrcnt,int mprcnt,
3332 char **rdata,char **rparam,
3333 int *rdata_len,int *rparam_len)
3335 struct pack_desc desc;
3336 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3337 char *str2 = skip_string(param,tpscnt,str1);
3338 char *p = skip_string(param,tpscnt,str2);
3341 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3342 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3345 if (!str1 || !str2 || !p) {
3349 * We use 1 here not 2 as we're checking
3350 * the last byte we want to access is safe.
3352 if (!is_offset_safe(param,tpscnt,p,1)) {
3355 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3358 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3363 if (!share_defined(sharename)) {
3364 DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
3371 /* check it's a supported varient */
3372 if ((strcmp(str1,"WWsTP")) ||
3373 (!check_printjob_info(&desc,uLevel,str2)))
3376 if (!print_job_exists(sharename, jobid)) {
3377 errcode=NERR_JobNotFound;
3381 errcode = NERR_notsupported;
3385 /* change job place in the queue,
3386 data gives the new place */
3387 place = SVAL(data,0);
3388 if (print_job_set_place(sharename, jobid, place)) {
3389 errcode=NERR_Success;
3394 /* change print job name, data gives the name */
3395 if (print_job_set_name(sharename, jobid, data)) {
3396 errcode=NERR_Success;
3405 SSVALS(*rparam,0,errcode);
3406 SSVAL(*rparam,2,0); /* converter word */
3412 /****************************************************************************
3413 Get info about the server.
3414 ****************************************************************************/
3416 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
3417 char *param, int tpscnt,
3418 char *data, int tdscnt,
3419 int mdrcnt,int mprcnt,
3420 char **rdata,char **rparam,
3421 int *rdata_len,int *rparam_len)
3423 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3424 char *str2 = skip_string(param,tpscnt,str1);
3425 char *p = skip_string(param,tpscnt,str2);
3426 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3430 if (!str1 || !str2 || !p) {
3434 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3436 /* check it's a supported varient */
3437 if (!prefix_ok(str1,"WrLh")) {
3443 if (strcmp(str2,"B16") != 0) {
3449 if (strcmp(str2,"B16BBDz") != 0) {
3455 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3461 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3467 if (strcmp(str2,"DN") != 0) {
3473 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3482 *rdata_len = mdrcnt;
3483 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3489 p2 = p + struct_len;
3491 srvstr_push(NULL, 0, p,global_myname(),16,
3492 STR_ASCII|STR_UPPER|STR_TERMINATE);
3496 struct srv_info_struct *servers=NULL;
3498 char *comment = NULL;
3499 TALLOC_CTX *ctx = talloc_tos();
3500 uint32 servertype= lp_default_server_announce();
3502 comment = talloc_strdup(ctx,lp_serverstring());
3507 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
3508 for (i=0;i<count;i++) {
3509 if (strequal(servers[i].name,global_myname())) {
3510 servertype = servers[i].type;
3511 TALLOC_FREE(comment);
3512 comment = talloc_strdup(ctx,
3513 servers[i].comment);
3523 SCVAL(p,0,lp_major_announce_version());
3524 SCVAL(p,1,lp_minor_announce_version());
3525 SIVAL(p,2,servertype);
3527 if (mdrcnt == struct_len) {
3530 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3531 comment = talloc_sub_advanced(
3533 lp_servicename(SNUM(conn)),
3534 conn->server_info->unix_name,
3536 conn->server_info->utok.gid,
3537 conn->server_info->sanitized_username,
3538 pdb_get_domain(conn->server_info->sam_account),
3543 if (mdrcnt - struct_len <= 0) {
3548 MIN(mdrcnt - struct_len,
3549 MAX_SERVER_STRING_LENGTH),
3551 p2 = skip_string(*rdata,*rdata_len,p2);
3559 return False; /* not yet implemented */
3562 *rdata_len = PTR_DIFF(p2,*rdata);
3565 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3569 SSVAL(*rparam,0,NERR_Success);
3570 SSVAL(*rparam,2,0); /* converter word */
3571 SSVAL(*rparam,4,*rdata_len);
3576 /****************************************************************************
3577 Get info about the server.
3578 ****************************************************************************/
3580 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3581 char *param, int tpscnt,
3582 char *data, int tdscnt,
3583 int mdrcnt,int mprcnt,
3584 char **rdata,char **rparam,
3585 int *rdata_len,int *rparam_len)
3587 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3588 char *str2 = skip_string(param,tpscnt,str1);
3589 char *p = skip_string(param,tpscnt,str2);
3592 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3594 if (!str1 || !str2 || !p) {
3598 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3601 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3606 /* check it's a supported varient */
3607 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3611 *rdata_len = mdrcnt + 1024;
3612 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3617 SSVAL(*rparam,0,NERR_Success);
3618 SSVAL(*rparam,2,0); /* converter word */
3621 endp = *rdata + *rdata_len;
3623 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3628 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3629 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3631 p2 = skip_string(*rdata,*rdata_len,p2);
3637 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3638 strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3639 p2 = skip_string(*rdata,*rdata_len,p2);
3645 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3646 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3648 p2 = skip_string(*rdata,*rdata_len,p2);
3654 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3655 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3658 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3659 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3660 p2 = skip_string(*rdata,*rdata_len,p2);
3666 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3667 strlcpy(p2,"",PTR_DIFF(endp,p2));
3668 p2 = skip_string(*rdata,*rdata_len,p2);
3674 *rdata_len = PTR_DIFF(p2,*rdata);
3676 SSVAL(*rparam,4,*rdata_len);
3681 /****************************************************************************
3682 get info about a user
3684 struct user_info_11 {
3685 char usri11_name[21]; 0-20
3687 char *usri11_comment; 22-25
3688 char *usri11_usr_comment; 26-29
3689 unsigned short usri11_priv; 30-31
3690 unsigned long usri11_auth_flags; 32-35
3691 long usri11_password_age; 36-39
3692 char *usri11_homedir; 40-43
3693 char *usri11_parms; 44-47
3694 long usri11_last_logon; 48-51
3695 long usri11_last_logoff; 52-55
3696 unsigned short usri11_bad_pw_count; 56-57
3697 unsigned short usri11_num_logons; 58-59
3698 char *usri11_logon_server; 60-63
3699 unsigned short usri11_country_code; 64-65
3700 char *usri11_workstations; 66-69
3701 unsigned long usri11_max_storage; 70-73
3702 unsigned short usri11_units_per_week; 74-75
3703 unsigned char *usri11_logon_hours; 76-79
3704 unsigned short usri11_code_page; 80-81
3709 usri11_name specifies the user name for which information is retrieved
3711 usri11_pad aligns the next data structure element to a word boundary
3713 usri11_comment is a null terminated ASCII comment
3715 usri11_user_comment is a null terminated ASCII comment about the user
3717 usri11_priv specifies the level of the privilege assigned to the user.
3718 The possible values are:
3720 Name Value Description
3721 USER_PRIV_GUEST 0 Guest privilege
3722 USER_PRIV_USER 1 User privilege
3723 USER_PRV_ADMIN 2 Administrator privilege
3725 usri11_auth_flags specifies the account operator privileges. The
3726 possible values are:
3728 Name Value Description
3729 AF_OP_PRINT 0 Print operator
3732 Leach, Naik [Page 28]
3736 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3739 AF_OP_COMM 1 Communications operator
3740 AF_OP_SERVER 2 Server operator
3741 AF_OP_ACCOUNTS 3 Accounts operator
3744 usri11_password_age specifies how many seconds have elapsed since the
3745 password was last changed.
3747 usri11_home_dir points to a null terminated ASCII string that contains
3748 the path name of the user's home directory.
3750 usri11_parms points to a null terminated ASCII string that is set
3751 aside for use by applications.
3753 usri11_last_logon specifies the time when the user last logged on.
3754 This value is stored as the number of seconds elapsed since
3755 00:00:00, January 1, 1970.
3757 usri11_last_logoff specifies the time when the user last logged off.
3758 This value is stored as the number of seconds elapsed since
3759 00:00:00, January 1, 1970. A value of 0 means the last logoff
3762 usri11_bad_pw_count specifies the number of incorrect passwords
3763 entered since the last successful logon.
3765 usri11_log1_num_logons specifies the number of times this user has
3766 logged on. A value of -1 means the number of logons is unknown.
3768 usri11_logon_server points to a null terminated ASCII string that
3769 contains the name of the server to which logon requests are sent.
3770 A null string indicates logon requests should be sent to the
3773 usri11_country_code specifies the country code for the user's language
3776 usri11_workstations points to a null terminated ASCII string that
3777 contains the names of workstations the user may log on from.
3778 There may be up to 8 workstations, with the names separated by
3779 commas. A null strings indicates there are no restrictions.
3781 usri11_max_storage specifies the maximum amount of disk space the user
3782 can occupy. A value of 0xffffffff indicates there are no
3785 usri11_units_per_week specifies the equal number of time units into
3786 which a week is divided. This value must be equal to 168.
3788 usri11_logon_hours points to a 21 byte (168 bits) string that
3789 specifies the time during which the user can log on. Each bit
3790 represents one unique hour in a week. The first bit (bit 0, word
3791 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3795 Leach, Naik [Page 29]
3799 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3802 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3803 are no restrictions.
3805 usri11_code_page specifies the code page for the user's language of
3808 All of the pointers in this data structure need to be treated
3809 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3810 to be ignored. The converter word returned in the parameters section
3811 needs to be subtracted from the lower 16 bits to calculate an offset
3812 into the return buffer where this ASCII string resides.
3814 There is no auxiliary data in the response.
3816 ****************************************************************************/
3818 #define usri11_name 0
3819 #define usri11_pad 21
3820 #define usri11_comment 22
3821 #define usri11_usr_comment 26
3822 #define usri11_full_name 30
3823 #define usri11_priv 34
3824 #define usri11_auth_flags 36
3825 #define usri11_password_age 40
3826 #define usri11_homedir 44
3827 #define usri11_parms 48
3828 #define usri11_last_logon 52
3829 #define usri11_last_logoff 56
3830 #define usri11_bad_pw_count 60
3831 #define usri11_num_logons 62
3832 #define usri11_logon_server 64
3833 #define usri11_country_code 68
3834 #define usri11_workstations 70
3835 #define usri11_max_storage 74
3836 #define usri11_units_per_week 78
3837 #define usri11_logon_hours 80
3838 #define usri11_code_page 84
3839 #define usri11_end 86
3841 #define USER_PRIV_GUEST 0
3842 #define USER_PRIV_USER 1
3843 #define USER_PRIV_ADMIN 2
3845 #define AF_OP_PRINT 0
3846 #define AF_OP_COMM 1
3847 #define AF_OP_SERVER 2
3848 #define AF_OP_ACCOUNTS 3
3851 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3852 char *param, int tpscnt,
3853 char *data, int tdscnt,
3854 int mdrcnt,int mprcnt,
3855 char **rdata,char **rparam,
3856 int *rdata_len,int *rparam_len)
3858 struct smbd_server_connection *sconn = smbd_server_conn;
3859 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3860 char *str2 = skip_string(param,tpscnt,str1);
3861 char *UserName = skip_string(param,tpscnt,str2);
3862 char *p = skip_string(param,tpscnt,UserName);
3863 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3866 const char *level_string;
3868 /* get NIS home of a previously validated user - simeon */
3869 /* With share level security vuid will always be zero.
3870 Don't depend on vuser being non-null !!. JRA */
3871 user_struct *vuser = get_valid_user_struct(sconn, vuid);
3873 DEBUG(3,(" Username of UID %d is %s\n",
3874 (int)vuser->server_info->utok.uid,
3875 vuser->server_info->unix_name));
3878 if (!str1 || !str2 || !UserName || !p) {
3883 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3888 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3890 /* check it's a supported variant */
3891 if (strcmp(str1,"zWrLh") != 0) {
3895 case 0: level_string = "B21"; break;
3896 case 1: level_string = "B21BB16DWzzWz"; break;
3897 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3898 case 10: level_string = "B21Bzzz"; break;
3899 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3900 default: return False;
3903 if (strcmp(level_string,str2) != 0) {
3907 *rdata_len = mdrcnt + 1024;
3908 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3913 SSVAL(*rparam,0,NERR_Success);
3914 SSVAL(*rparam,2,0); /* converter word */
3917 endp = *rdata + *rdata_len;
3918 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3924 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3927 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3932 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3933 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
3934 p2 = skip_string(*rdata,*rdata_len,p2);
3939 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3940 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
3941 p2 = skip_string(*rdata,*rdata_len,p2);
3946 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3947 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3948 strlcpy(p2,((vuser != NULL)
3949 ? pdb_get_fullname(vuser->server_info->sam_account)
3950 : UserName),PTR_DIFF(endp,p2));
3951 p2 = skip_string(*rdata,*rdata_len,p2);
3958 const char *homedir = "";
3959 if (vuser != NULL) {
3960 homedir = pdb_get_homedir(
3961 vuser->server_info->sam_account);
3963 /* modelled after NTAS 3.51 reply */
3964 SSVAL(p,usri11_priv,
3965 (get_current_uid(conn) == sec_initial_uid())?
3966 USER_PRIV_ADMIN:USER_PRIV_USER);
3967 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
3968 SIVALS(p,usri11_password_age,-1); /* password age */
3969 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3970 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
3971 p2 = skip_string(*rdata,*rdata_len,p2);
3975 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3976 strlcpy(p2,"",PTR_DIFF(endp,p2));
3977 p2 = skip_string(*rdata,*rdata_len,p2);
3981 SIVAL(p,usri11_last_logon,0); /* last logon */
3982 SIVAL(p,usri11_last_logoff,0); /* last logoff */
3983 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
3984 SSVALS(p,usri11_num_logons,-1); /* num logons */
3985 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3986 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
3987 p2 = skip_string(*rdata,*rdata_len,p2);
3991 SSVAL(p,usri11_country_code,0); /* country code */
3993 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3994 strlcpy(p2,"",PTR_DIFF(endp,p2));
3995 p2 = skip_string(*rdata,*rdata_len,p2);
4000 SIVALS(p,usri11_max_storage,-1); /* max storage */
4001 SSVAL(p,usri11_units_per_week,168); /* units per week */
4002 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
4004 /* a simple way to get logon hours at all times. */
4006 SCVAL(p2,21,0); /* fix zero termination */
4007 p2 = skip_string(*rdata,*rdata_len,p2);
4012 SSVAL(p,usri11_code_page,0); /* code page */
4015 if (uLevel == 1 || uLevel == 2) {
4016 memset(p+22,' ',16); /* password */
4017 SIVALS(p,38,-1); /* password age */
4019 (get_current_uid(conn) == sec_initial_uid())?
4020 USER_PRIV_ADMIN:USER_PRIV_USER);
4021 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
4022 strlcpy(p2, vuser ? pdb_get_homedir(
4023 vuser->server_info->sam_account) : "",
4025 p2 = skip_string(*rdata,*rdata_len,p2);
4029 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
4031 SSVAL(p,52,0); /* flags */
4032 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
4033 strlcpy(p2, vuser ? pdb_get_logon_script(
4034 vuser->server_info->sam_account) : "",
4036 p2 = skip_string(*rdata,*rdata_len,p2);
4041 SIVAL(p,60,0); /* auth_flags */
4042 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
4043 strlcpy(p2,((vuser != NULL)
4044 ? pdb_get_fullname(vuser->server_info->sam_account)
4045 : UserName),PTR_DIFF(endp,p2));
4046 p2 = skip_string(*rdata,*rdata_len,p2);
4050 SIVAL(p,68,0); /* urs_comment */
4051 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
4052 strlcpy(p2,"",PTR_DIFF(endp,p2));
4053 p2 = skip_string(*rdata,*rdata_len,p2);
4057 SIVAL(p,76,0); /* workstations */
4058 SIVAL(p,80,0); /* last_logon */
4059 SIVAL(p,84,0); /* last_logoff */
4060 SIVALS(p,88,-1); /* acct_expires */
4061 SIVALS(p,92,-1); /* max_storage */
4062 SSVAL(p,96,168); /* units_per_week */
4063 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
4066 SSVALS(p,102,-1); /* bad_pw_count */
4067 SSVALS(p,104,-1); /* num_logons */
4068 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
4070 TALLOC_CTX *ctx = talloc_tos();
4071 int space_rem = *rdata_len - (p2 - *rdata);
4074 if (space_rem <= 0) {
4077 tmp = talloc_strdup(ctx, "\\\\%L");
4081 tmp = talloc_sub_basic(ctx,
4094 p2 = skip_string(*rdata,*rdata_len,p2);
4098 SSVAL(p,110,49); /* country_code */
4099 SSVAL(p,112,860); /* code page */
4103 *rdata_len = PTR_DIFF(p2,*rdata);
4105 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
4110 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
4111 char *param, int tpscnt,
4112 char *data, int tdscnt,
4113 int mdrcnt,int mprcnt,
4114 char **rdata,char **rparam,
4115 int *rdata_len,int *rparam_len)
4117 struct smbd_server_connection *sconn = smbd_server_conn;
4118 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4119 char *str2 = skip_string(param,tpscnt,str1);
4120 char *p = skip_string(param,tpscnt,str2);
4122 struct pack_desc desc;
4124 /* With share level security vuid will always be zero.
4125 Don't depend on vuser being non-null !!. JRA */
4126 user_struct *vuser = get_valid_user_struct(sconn, vuid);
4128 if (!str1 || !str2 || !p) {
4133 DEBUG(3,(" Username of UID %d is %s\n",
4134 (int)vuser->server_info->utok.uid,
4135 vuser->server_info->unix_name));
4138 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4139 name = get_safe_str_ptr(param,tpscnt,p,2);
4144 memset((char *)&desc,'\0',sizeof(desc));
4146 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
4148 /* check it's a supported varient */
4149 if (strcmp(str1,"OOWb54WrLh") != 0) {
4152 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
4156 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4163 desc.buflen = mdrcnt;
4164 desc.subformat = NULL;
4167 if (init_package(&desc,1,0)) {
4168 PACKI(&desc,"W",0); /* code */
4169 PACKS(&desc,"B21",name); /* eff. name */
4170 PACKS(&desc,"B",""); /* pad */
4172 (get_current_uid(conn) == sec_initial_uid())?
4173 USER_PRIV_ADMIN:USER_PRIV_USER);
4174 PACKI(&desc,"D",0); /* auth flags XXX */
4175 PACKI(&desc,"W",0); /* num logons */
4176 PACKI(&desc,"W",0); /* bad pw count */
4177 PACKI(&desc,"D",0); /* last logon */
4178 PACKI(&desc,"D",-1); /* last logoff */
4179 PACKI(&desc,"D",-1); /* logoff time */
4180 PACKI(&desc,"D",-1); /* kickoff time */
4181 PACKI(&desc,"D",0); /* password age */
4182 PACKI(&desc,"D",0); /* password can change */
4183 PACKI(&desc,"D",-1); /* password must change */
4187 fstrcpy(mypath,"\\\\");
4188 fstrcat(mypath,get_local_machine_name());
4190 PACKS(&desc,"z",mypath); /* computer */
4193 PACKS(&desc,"z",lp_workgroup());/* domain */
4194 PACKS(&desc,"z", vuser ? pdb_get_logon_script(
4195 vuser->server_info->sam_account) : ""); /* script path */
4196 PACKI(&desc,"D",0x00000000); /* reserved */
4199 *rdata_len = desc.usedlen;
4201 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4205 SSVALS(*rparam,0,desc.errcode);
4207 SSVAL(*rparam,4,desc.neededlen);
4209 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4214 /****************************************************************************
4215 api_WAccessGetUserPerms
4216 ****************************************************************************/
4218 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
4219 char *param, int tpscnt,
4220 char *data, int tdscnt,
4221 int mdrcnt,int mprcnt,
4222 char **rdata,char **rparam,
4223 int *rdata_len,int *rparam_len)
4225 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4226 char *str2 = skip_string(param,tpscnt,str1);
4227 char *user = skip_string(param,tpscnt,str2);
4228 char *resource = skip_string(param,tpscnt,user);
4230 if (!str1 || !str2 || !user || !resource) {
4234 if (skip_string(param,tpscnt,resource) == NULL) {
4237 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4239 /* check it's a supported varient */
4240 if (strcmp(str1,"zzh") != 0) {
4243 if (strcmp(str2,"") != 0) {
4248 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4252 SSVALS(*rparam,0,0); /* errorcode */
4253 SSVAL(*rparam,2,0); /* converter word */
4254 SSVAL(*rparam,4,0x7f); /* permission flags */
4259 /****************************************************************************
4260 api_WPrintJobEnumerate
4261 ****************************************************************************/
4263 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
4264 char *param, int tpscnt,
4265 char *data, int tdscnt,
4266 int mdrcnt,int mprcnt,
4267 char **rdata,char **rparam,
4268 int *rdata_len,int *rparam_len)
4270 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4271 char *str2 = skip_string(param,tpscnt,str1);
4272 char *p = skip_string(param,tpscnt,str2);
4276 struct pack_desc desc;
4279 TALLOC_CTX *mem_ctx = talloc_tos();
4282 struct rpc_pipe_client *cli = NULL;
4283 struct policy_handle handle;
4284 struct spoolss_DevmodeContainer devmode_ctr;
4285 union spoolss_JobInfo info;
4287 if (!str1 || !str2 || !p) {
4291 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4293 memset((char *)&desc,'\0',sizeof(desc));
4294 memset((char *)&status,'\0',sizeof(status));
4296 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4298 /* check it's a supported varient */
4299 if (strcmp(str1,"WWrLh") != 0) {
4302 if (!check_printjob_info(&desc,uLevel,str2)) {
4306 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4310 ZERO_STRUCT(handle);
4312 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4313 rpc_spoolss_dispatch, conn->server_info,
4315 if (!NT_STATUS_IS_OK(status)) {
4316 DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n",
4317 nt_errstr(status)));
4318 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4322 ZERO_STRUCT(devmode_ctr);
4324 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4328 SEC_FLAG_MAXIMUM_ALLOWED,
4331 if (!NT_STATUS_IS_OK(status)) {
4332 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4335 if (!W_ERROR_IS_OK(werr)) {
4336 desc.errcode = W_ERROR_V(werr);
4340 werr = rpccli_spoolss_getjob(cli, mem_ctx,
4346 if (!W_ERROR_IS_OK(werr)) {
4347 desc.errcode = W_ERROR_V(werr);
4352 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4357 desc.buflen = mdrcnt;
4360 * Don't return data but need to get correct length
4361 * init_package will return wrong size if buflen=0
4363 desc.buflen = getlen(desc.format);
4364 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4367 if (init_package(&desc,1,0)) {
4368 fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position);
4369 *rdata_len = desc.usedlen;
4371 desc.errcode = NERR_JobNotFound;
4375 if (is_valid_policy_hnd(&handle)) {
4376 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4380 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4384 SSVALS(*rparam,0,desc.errcode);
4386 SSVAL(*rparam,4,desc.neededlen);
4390 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4395 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
4396 char *param, int tpscnt,
4397 char *data, int tdscnt,
4398 int mdrcnt,int mprcnt,
4399 char **rdata,char **rparam,
4400 int *rdata_len,int *rparam_len)
4402 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4403 char *str2 = skip_string(param,tpscnt,str1);
4404 char *p = skip_string(param,tpscnt,str2);
4408 struct pack_desc desc;
4410 TALLOC_CTX *mem_ctx = talloc_tos();
4413 struct rpc_pipe_client *cli = NULL;
4414 struct policy_handle handle;
4415 struct spoolss_DevmodeContainer devmode_ctr;
4417 union spoolss_JobInfo *info;
4419 if (!str1 || !str2 || !p) {
4423 memset((char *)&desc,'\0',sizeof(desc));
4424 memset((char *)&status,'\0',sizeof(status));
4426 p = skip_string(param,tpscnt,p);
4430 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4432 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4434 /* check it's a supported variant */
4435 if (strcmp(str1,"zWrLeh") != 0) {
4440 return False; /* defined only for uLevel 0,1,2 */
4443 if (!check_printjob_info(&desc,uLevel,str2)) {
4447 ZERO_STRUCT(handle);
4449 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4450 rpc_spoolss_dispatch, conn->server_info,
4452 if (!NT_STATUS_IS_OK(status)) {
4453 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
4454 nt_errstr(status)));
4455 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4459 ZERO_STRUCT(devmode_ctr);
4461 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4465 SEC_FLAG_MAXIMUM_ALLOWED,
4468 if (!NT_STATUS_IS_OK(status)) {
4469 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4472 if (!W_ERROR_IS_OK(werr)) {
4473 desc.errcode = W_ERROR_V(werr);
4477 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
4485 if (!W_ERROR_IS_OK(werr)) {
4486 desc.errcode = W_ERROR_V(werr);
4491 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4497 desc.buflen = mdrcnt;
4499 if (init_package(&desc,count,0)) {
4501 for (i = 0; i < count; i++) {
4502 fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i);
4503 if (desc.errcode == NERR_Success) {
4509 if (is_valid_policy_hnd(&handle)) {
4510 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4513 *rdata_len = desc.usedlen;
4516 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4520 SSVALS(*rparam,0,desc.errcode);
4522 SSVAL(*rparam,4,succnt);
4523 SSVAL(*rparam,6,count);
4525 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4530 static int check_printdest_info(struct pack_desc* desc,
4531 int uLevel, char* id)
4533 desc->subformat = NULL;
4536 desc->format = "B9";
4539 desc->format = "B9B21WWzW";
4545 desc->format = "zzzWWzzzWW";
4548 DEBUG(0,("check_printdest_info: invalid level %d\n",
4552 if (id == NULL || strcmp(desc->format,id) != 0) {
4553 DEBUG(0,("check_printdest_info: invalid string %s\n",
4554 id ? id : "<NULL>" ));
4560 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
4561 struct pack_desc* desc)
4565 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
4566 buf[sizeof(buf)-1] = 0;
4570 PACKS(desc,"B9",buf); /* szName */
4572 PACKS(desc,"B21",""); /* szUserName */
4573 PACKI(desc,"W",0); /* uJobId */
4574 PACKI(desc,"W",0); /* fsStatus */
4575 PACKS(desc,"z",""); /* pszStatus */
4576 PACKI(desc,"W",0); /* time */
4580 if (uLevel == 2 || uLevel == 3) {
4581 PACKS(desc,"z",buf); /* pszPrinterName */
4583 PACKS(desc,"z",""); /* pszUserName */
4584 PACKS(desc,"z",""); /* pszLogAddr */
4585 PACKI(desc,"W",0); /* uJobId */
4586 PACKI(desc,"W",0); /* fsStatus */
4587 PACKS(desc,"z",""); /* pszStatus */
4588 PACKS(desc,"z",""); /* pszComment */
4589 PACKS(desc,"z","NULL"); /* pszDrivers */
4590 PACKI(desc,"W",0); /* time */
4591 PACKI(desc,"W",0); /* pad1 */
4596 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
4597 char *param, int tpscnt,
4598 char *data, int tdscnt,
4599 int mdrcnt,int mprcnt,
4600 char **rdata,char **rparam,
4601 int *rdata_len,int *rparam_len)
4603 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4604 char *str2 = skip_string(param,tpscnt,str1);
4605 char *p = skip_string(param,tpscnt,str2);
4606 char* PrinterName = p;
4608 struct pack_desc desc;
4612 if (!str1 || !str2 || !p) {
4616 memset((char *)&desc,'\0',sizeof(desc));
4618 p = skip_string(param,tpscnt,p);
4622 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4624 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4626 /* check it's a supported varient */
4627 if (strcmp(str1,"zWrLh") != 0) {
4630 if (!check_printdest_info(&desc,uLevel,str2)) {
4634 snum = find_service(PrinterName);
4635 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
4637 desc.errcode = NERR_DestNotFound;
4641 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4646 desc.buflen = mdrcnt;
4649 * Don't return data but need to get correct length
4650 * init_package will return wrong size if buflen=0
4652 desc.buflen = getlen(desc.format);
4653 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4655 if (init_package(&desc,1,0)) {
4656 fill_printdest_info(conn,snum,uLevel,&desc);
4658 *rdata_len = desc.usedlen;
4662 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4666 SSVALS(*rparam,0,desc.errcode);
4668 SSVAL(*rparam,4,desc.neededlen);
4670 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4676 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4677 char *param, int tpscnt,
4678 char *data, int tdscnt,
4679 int mdrcnt,int mprcnt,
4680 char **rdata,char **rparam,
4681 int *rdata_len,int *rparam_len)
4683 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4684 char *str2 = skip_string(param,tpscnt,str1);
4685 char *p = skip_string(param,tpscnt,str2);
4689 struct pack_desc desc;
4690 int services = lp_numservices();
4692 if (!str1 || !str2 || !p) {
4696 memset((char *)&desc,'\0',sizeof(desc));
4698 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4700 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4702 /* check it's a supported varient */
4703 if (strcmp(str1,"WrLeh") != 0) {
4706 if (!check_printdest_info(&desc,uLevel,str2)) {
4711 for (i = 0; i < services; i++) {
4712 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4718 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4725 desc.buflen = mdrcnt;
4726 if (init_package(&desc,queuecnt,0)) {
4729 for (i = 0; i < services; i++) {
4730 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4731 fill_printdest_info(conn,i,uLevel,&desc);
4733 if (desc.errcode == NERR_Success) {
4740 *rdata_len = desc.usedlen;
4743 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4747 SSVALS(*rparam,0,desc.errcode);
4749 SSVAL(*rparam,4,succnt);
4750 SSVAL(*rparam,6,queuecnt);
4752 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4757 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4758 char *param, int tpscnt,
4759 char *data, int tdscnt,
4760 int mdrcnt,int mprcnt,
4761 char **rdata,char **rparam,
4762 int *rdata_len,int *rparam_len)
4764 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4765 char *str2 = skip_string(param,tpscnt,str1);
4766 char *p = skip_string(param,tpscnt,str2);
4769 struct pack_desc desc;
4771 if (!str1 || !str2 || !p) {
4775 memset((char *)&desc,'\0',sizeof(desc));
4777 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4779 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4781 /* check it's a supported varient */
4782 if (strcmp(str1,"WrLeh") != 0) {
4785 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4790 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4796 desc.buflen = mdrcnt;
4797 if (init_package(&desc,1,0)) {
4798 PACKS(&desc,"B41","NULL");
4801 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4803 *rdata_len = desc.usedlen;
4806 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4810 SSVALS(*rparam,0,desc.errcode);
4812 SSVAL(*rparam,4,succnt);
4815 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4820 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4821 char *param, int tpscnt,
4822 char *data, int tdscnt,
4823 int mdrcnt,int mprcnt,
4824 char **rdata,char **rparam,
4825 int *rdata_len,int *rparam_len)
4827 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4828 char *str2 = skip_string(param,tpscnt,str1);
4829 char *p = skip_string(param,tpscnt,str2);
4832 struct pack_desc desc;
4834 if (!str1 || !str2 || !p) {
4837 memset((char *)&desc,'\0',sizeof(desc));
4839 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4841 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4843 /* check it's a supported varient */
4844 if (strcmp(str1,"WrLeh") != 0) {
4847 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4852 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4858 desc.buflen = mdrcnt;
4860 if (init_package(&desc,1,0)) {
4861 PACKS(&desc,"B13","lpd");
4864 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4866 *rdata_len = desc.usedlen;
4869 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4873 SSVALS(*rparam,0,desc.errcode);
4875 SSVAL(*rparam,4,succnt);
4878 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4883 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4884 char *param, int tpscnt,
4885 char *data, int tdscnt,
4886 int mdrcnt,int mprcnt,
4887 char **rdata,char **rparam,
4888 int *rdata_len,int *rparam_len)
4890 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4891 char *str2 = skip_string(param,tpscnt,str1);
4892 char *p = skip_string(param,tpscnt,str2);
4895 struct pack_desc desc;
4897 if (!str1 || !str2 || !p) {
4901 memset((char *)&desc,'\0',sizeof(desc));
4903 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4905 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4907 /* check it's a supported varient */
4908 if (strcmp(str1,"WrLeh") != 0) {
4911 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
4916 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4921 memset((char *)&desc,'\0',sizeof(desc));
4923 desc.buflen = mdrcnt;
4925 if (init_package(&desc,1,0)) {
4926 PACKS(&desc,"B13","lp0");
4929 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4931 *rdata_len = desc.usedlen;
4934 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4938 SSVALS(*rparam,0,desc.errcode);
4940 SSVAL(*rparam,4,succnt);
4943 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
4948 /****************************************************************************
4950 ****************************************************************************/
4952 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
4953 char *param, int tpscnt,
4954 char *data, int tdscnt,
4955 int mdrcnt,int mprcnt,
4956 char **rdata,char **rparam,
4957 int *rdata_len,int *rparam_len)
4960 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4961 char *str2 = skip_string(param,tpscnt,str1);
4962 char *p = skip_string(param,tpscnt,str2);
4964 struct pack_desc desc;
4965 struct sessionid *session_list;
4966 int i, num_sessions;
4968 if (!str1 || !str2 || !p) {
4972 memset((char *)&desc,'\0',sizeof(desc));
4974 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4976 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
4977 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
4978 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
4980 /* check it's a supported varient */
4981 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
4984 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
4988 num_sessions = list_sessions(talloc_tos(), &session_list);
4991 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4996 memset((char *)&desc,'\0',sizeof(desc));
4998 desc.buflen = mdrcnt;
5000 if (!init_package(&desc,num_sessions,0)) {
5004 for(i=0; i<num_sessions; i++) {
5005 PACKS(&desc, "z", session_list[i].remote_machine);
5006 PACKS(&desc, "z", session_list[i].username);
5007 PACKI(&desc, "W", 1); /* num conns */
5008 PACKI(&desc, "W", 0); /* num opens */
5009 PACKI(&desc, "W", 1); /* num users */
5010 PACKI(&desc, "D", 0); /* session time */
5011 PACKI(&desc, "D", 0); /* idle time */
5012 PACKI(&desc, "D", 0); /* flags */
5013 PACKS(&desc, "z", "Unknown Client"); /* client type string */
5016 *rdata_len = desc.usedlen;
5019 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5023 SSVALS(*rparam,0,desc.errcode);
5024 SSVAL(*rparam,2,0); /* converter */
5025 SSVAL(*rparam,4,num_sessions); /* count */
5027 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
5033 /****************************************************************************
5034 The buffer was too small.
5035 ****************************************************************************/
5037 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
5038 int mdrcnt, int mprcnt,
5039 char **rdata, char **rparam,
5040 int *rdata_len, int *rparam_len)
5042 *rparam_len = MIN(*rparam_len,mprcnt);
5043 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5050 SSVAL(*rparam,0,NERR_BufTooSmall);
5052 DEBUG(3,("Supplied buffer too small in API command\n"));
5057 /****************************************************************************
5058 The request is not supported.
5059 ****************************************************************************/
5061 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
5062 char *param, int tpscnt,
5063 char *data, int tdscnt,
5064 int mdrcnt, int mprcnt,
5065 char **rdata, char **rparam,
5066 int *rdata_len, int *rparam_len)
5069 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5076 SSVAL(*rparam,0,NERR_notsupported);
5077 SSVAL(*rparam,2,0); /* converter word */
5079 DEBUG(3,("Unsupported API command\n"));
5084 static const struct {
5087 bool (*fn)(connection_struct *, uint16,
5090 int,int,char **,char **,int *,int *);
5091 bool auth_user; /* Deny anonymous access? */
5092 } api_commands[] = {
5093 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
5094 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
5095 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
5096 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
5097 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
5098 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
5099 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
5100 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
5101 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
5102 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
5103 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
5104 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
5105 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
5106 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
5107 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
5108 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
5109 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
5110 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
5111 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
5112 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
5113 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
5114 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
5115 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
5116 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
5117 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
5118 {"NetServerEnum3", RAP_NetServerEnum3, api_RNetServerEnum3}, /* anon OK */
5119 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
5120 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
5121 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
5122 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
5123 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
5124 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
5125 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
5126 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
5127 {NULL, -1, api_Unsupported}
5128 /* The following RAP calls are not implemented by Samba:
5130 RAP_WFileEnum2 - anon not OK
5135 /****************************************************************************
5136 Handle remote api calls.
5137 ****************************************************************************/
5139 void api_reply(connection_struct *conn, uint16 vuid,
5140 struct smb_request *req,
5141 char *data, char *params,
5142 int tdscnt, int tpscnt,
5143 int mdrcnt, int mprcnt)
5145 struct smbd_server_connection *sconn = smbd_server_conn;
5148 char *rparam = NULL;
5149 const char *name1 = NULL;
5150 const char *name2 = NULL;
5157 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
5158 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5163 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5166 api_command = SVAL(params,0);
5167 /* Is there a string at position params+2 ? */
5168 if (skip_string(params,tpscnt,params+2)) {
5173 name2 = skip_string(params,tpscnt,params+2);
5178 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
5182 tdscnt,tpscnt,mdrcnt,mprcnt));
5184 for (i=0;api_commands[i].name;i++) {
5185 if (api_commands[i].id == api_command && api_commands[i].fn) {
5186 DEBUG(3,("Doing %s\n",api_commands[i].name));
5191 /* Check whether this api call can be done anonymously */
5193 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
5194 user_struct *user = get_valid_user_struct(sconn, vuid);
5196 if (!user || user->server_info->guest) {
5197 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5202 rdata = (char *)SMB_MALLOC(1024);
5204 memset(rdata,'\0',1024);
5207 rparam = (char *)SMB_MALLOC(1024);
5209 memset(rparam,'\0',1024);
5212 if(!rdata || !rparam) {
5213 DEBUG(0,("api_reply: malloc fail !\n"));
5216 reply_nterror(req, NT_STATUS_NO_MEMORY);
5220 reply = api_commands[i].fn(conn,
5222 params,tpscnt, /* params + length */
5223 data,tdscnt, /* data + length */
5225 &rdata,&rparam,&rdata_len,&rparam_len);
5228 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
5229 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
5230 &rdata,&rparam,&rdata_len,&rparam_len);
5233 /* if we get False back then it's actually unsupported */
5235 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
5236 &rdata,&rparam,&rdata_len,&rparam_len);
5239 /* If api_Unsupported returns false we can't return anything. */
5241 send_trans_reply(conn, req, rparam, rparam_len,
5242 rdata, rdata_len, False);