Rever e80ceb1d7355c8c46a2ed90d5721cf367640f4e8 "Remove more uses of "extern struct...
[Samba/gebeck_regimport.git] / source3 / smbd / lanman.c
blobdab26d0abe0dddfead31eee12befdd7b0e4d44f9
1 /*
2 Unix SMB/CIFS implementation.
3 Inter-process communication and named pipe handling
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Jeremy Allison 2007.
7 SMB Version handling
8 Copyright (C) John H Terpstra 1995-1998
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 This file handles the named pipe and mailslot calls
25 in the SMBtrans protocol
28 #include "includes.h"
29 #include "smbd/globals.h"
30 #include "../librpc/gen_ndr/cli_samr.h"
31 #include "../librpc/gen_ndr/srv_samr.h"
32 #include "../lib/util/binsearch.h"
34 #ifdef CHECK_TYPES
35 #undef CHECK_TYPES
36 #endif
37 #define CHECK_TYPES 0
39 #define NERR_Success 0
40 #define NERR_badpass 86
41 #define NERR_notsupported 50
43 #define NERR_BASE (2100)
44 #define NERR_BufTooSmall (NERR_BASE+23)
45 #define NERR_JobNotFound (NERR_BASE+51)
46 #define NERR_DestNotFound (NERR_BASE+52)
48 #define ACCESS_READ 0x01
49 #define ACCESS_WRITE 0x02
50 #define ACCESS_CREATE 0x04
52 #define SHPWLEN 8 /* share password length */
54 /* Limit size of ipc replies */
56 static char *smb_realloc_limit(void *ptr, size_t size)
58 char *val;
60 size = MAX((size),4*1024);
61 val = (char *)SMB_REALLOC(ptr,size);
62 if (val) {
63 memset(val,'\0',size);
65 return val;
68 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
69 char *param, int tpscnt,
70 char *data, int tdscnt,
71 int mdrcnt, int mprcnt,
72 char **rdata, char **rparam,
73 int *rdata_len, int *rparam_len);
75 static bool api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
76 int mdrcnt, int mprcnt,
77 char **rdata, char **rparam,
78 int *rdata_len, int *rparam_len);
81 static int CopyExpanded(connection_struct *conn,
82 int snum, char **dst, char *src, int *p_space_remaining)
84 TALLOC_CTX *ctx = talloc_tos();
85 char *buf = NULL;
86 int l;
88 if (!src || !dst || !p_space_remaining || !(*dst) ||
89 *p_space_remaining <= 0) {
90 return 0;
93 buf = talloc_strdup(ctx, src);
94 if (!buf) {
95 *p_space_remaining = 0;
96 return 0;
98 buf = talloc_string_sub(ctx, buf,"%S",lp_servicename(snum));
99 if (!buf) {
100 *p_space_remaining = 0;
101 return 0;
103 buf = talloc_sub_advanced(ctx,
104 lp_servicename(SNUM(conn)),
105 conn->server_info->unix_name,
106 conn->connectpath,
107 conn->server_info->utok.gid,
108 conn->server_info->sanitized_username,
109 pdb_get_domain(conn->server_info->sam_account),
110 buf);
111 if (!buf) {
112 *p_space_remaining = 0;
113 return 0;
115 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
116 if (l == -1) {
117 return 0;
119 (*dst) += l;
120 (*p_space_remaining) -= l;
121 return l;
124 static int CopyAndAdvance(char **dst, char *src, int *n)
126 int l;
127 if (!src || !dst || !n || !(*dst)) {
128 return 0;
130 l = push_ascii(*dst,src,*n, STR_TERMINATE);
131 if (l == -1) {
132 return 0;
134 (*dst) += l;
135 (*n) -= l;
136 return l;
139 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
141 TALLOC_CTX *ctx = talloc_tos();
142 char *buf = NULL;
143 if (!s) {
144 return 0;
146 buf = talloc_strdup(ctx,s);
147 if (!buf) {
148 return 0;
150 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
151 if (!buf) {
152 return 0;
154 buf = talloc_sub_advanced(ctx,
155 lp_servicename(SNUM(conn)),
156 conn->server_info->unix_name,
157 conn->connectpath,
158 conn->server_info->utok.gid,
159 conn->server_info->sanitized_username,
160 pdb_get_domain(conn->server_info->sam_account),
161 buf);
162 if (!buf) {
163 return 0;
165 return strlen(buf) + 1;
168 static char *Expand(connection_struct *conn, int snum, char *s)
170 TALLOC_CTX *ctx = talloc_tos();
171 char *buf = NULL;
173 if (!s) {
174 return NULL;
176 buf = talloc_strdup(ctx,s);
177 if (!buf) {
178 return 0;
180 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
181 if (!buf) {
182 return 0;
184 return talloc_sub_advanced(ctx,
185 lp_servicename(SNUM(conn)),
186 conn->server_info->unix_name,
187 conn->connectpath,
188 conn->server_info->utok.gid,
189 conn->server_info->sanitized_username,
190 pdb_get_domain(conn->server_info->sam_account),
191 buf);
194 /*******************************************************************
195 Check a API string for validity when we only need to check the prefix.
196 ******************************************************************/
198 static bool prefix_ok(const char *str, const char *prefix)
200 return(strncmp(str,prefix,strlen(prefix)) == 0);
203 struct pack_desc {
204 const char *format; /* formatstring for structure */
205 const char *subformat; /* subformat for structure */
206 char *base; /* baseaddress of buffer */
207 int buflen; /* remaining size for fixed part; on init: length of base */
208 int subcount; /* count of substructures */
209 char *structbuf; /* pointer into buffer for remaining fixed part */
210 int stringlen; /* remaining size for variable part */
211 char *stringbuf; /* pointer into buffer for remaining variable part */
212 int neededlen; /* total needed size */
213 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
214 const char *curpos; /* current position; pointer into format or subformat */
215 int errcode;
218 static int get_counter(const char **p)
220 int i, n;
221 if (!p || !(*p)) {
222 return 1;
224 if (!isdigit((int)**p)) {
225 return 1;
227 for (n = 0;;) {
228 i = **p;
229 if (isdigit(i)) {
230 n = 10 * n + (i - '0');
231 } else {
232 return n;
234 (*p)++;
238 static int getlen(const char *p)
240 int n = 0;
241 if (!p) {
242 return 0;
245 while (*p) {
246 switch( *p++ ) {
247 case 'W': /* word (2 byte) */
248 n += 2;
249 break;
250 case 'K': /* status word? (2 byte) */
251 n += 2;
252 break;
253 case 'N': /* count of substructures (word) at end */
254 n += 2;
255 break;
256 case 'D': /* double word (4 byte) */
257 case 'z': /* offset to zero terminated string (4 byte) */
258 case 'l': /* offset to user data (4 byte) */
259 n += 4;
260 break;
261 case 'b': /* offset to data (with counter) (4 byte) */
262 n += 4;
263 get_counter(&p);
264 break;
265 case 'B': /* byte (with optional counter) */
266 n += get_counter(&p);
267 break;
270 return n;
273 static bool init_package(struct pack_desc *p, int count, int subcount)
275 int n = p->buflen;
276 int i;
278 if (!p->format || !p->base) {
279 return False;
282 i = count * getlen(p->format);
283 if (p->subformat) {
284 i += subcount * getlen(p->subformat);
286 p->structbuf = p->base;
287 p->neededlen = 0;
288 p->usedlen = 0;
289 p->subcount = 0;
290 p->curpos = p->format;
291 if (i > n) {
292 p->neededlen = i;
293 i = n = 0;
294 #if 0
296 * This is the old error code we used. Aparently
297 * WinNT/2k systems return ERRbuftoosmall (2123) and
298 * OS/2 needs this. I'm leaving this here so we can revert
299 * if needed. JRA.
301 p->errcode = ERRmoredata;
302 #else
303 p->errcode = ERRbuftoosmall;
304 #endif
305 } else {
306 p->errcode = NERR_Success;
308 p->buflen = i;
309 n -= i;
310 p->stringbuf = p->base + i;
311 p->stringlen = n;
312 return (p->errcode == NERR_Success);
315 static int package(struct pack_desc *p, ...)
317 va_list args;
318 int needed=0, stringneeded;
319 const char *str=NULL;
320 int is_string=0, stringused;
321 int32 temp;
323 va_start(args,p);
325 if (!*p->curpos) {
326 if (!p->subcount) {
327 p->curpos = p->format;
328 } else {
329 p->curpos = p->subformat;
330 p->subcount--;
333 #if CHECK_TYPES
334 str = va_arg(args,char*);
335 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
336 #endif
337 stringneeded = -1;
339 if (!p->curpos) {
340 va_end(args);
341 return 0;
344 switch( *p->curpos++ ) {
345 case 'W': /* word (2 byte) */
346 needed = 2;
347 temp = va_arg(args,int);
348 if (p->buflen >= needed) {
349 SSVAL(p->structbuf,0,temp);
351 break;
352 case 'K': /* status word? (2 byte) */
353 needed = 2;
354 temp = va_arg(args,int);
355 if (p->buflen >= needed) {
356 SSVAL(p->structbuf,0,temp);
358 break;
359 case 'N': /* count of substructures (word) at end */
360 needed = 2;
361 p->subcount = va_arg(args,int);
362 if (p->buflen >= needed) {
363 SSVAL(p->structbuf,0,p->subcount);
365 break;
366 case 'D': /* double word (4 byte) */
367 needed = 4;
368 temp = va_arg(args,int);
369 if (p->buflen >= needed) {
370 SIVAL(p->structbuf,0,temp);
372 break;
373 case 'B': /* byte (with optional counter) */
374 needed = get_counter(&p->curpos);
376 char *s = va_arg(args,char*);
377 if (p->buflen >= needed) {
378 StrnCpy(p->structbuf,s?s:"",needed-1);
381 break;
382 case 'z': /* offset to zero terminated string (4 byte) */
383 str = va_arg(args,char*);
384 stringneeded = (str ? strlen(str)+1 : 0);
385 is_string = 1;
386 break;
387 case 'l': /* offset to user data (4 byte) */
388 str = va_arg(args,char*);
389 stringneeded = va_arg(args,int);
390 is_string = 0;
391 break;
392 case 'b': /* offset to data (with counter) (4 byte) */
393 str = va_arg(args,char*);
394 stringneeded = get_counter(&p->curpos);
395 is_string = 0;
396 break;
399 va_end(args);
400 if (stringneeded >= 0) {
401 needed = 4;
402 if (p->buflen >= needed) {
403 stringused = stringneeded;
404 if (stringused > p->stringlen) {
405 stringused = (is_string ? p->stringlen : 0);
406 if (p->errcode == NERR_Success) {
407 p->errcode = ERRmoredata;
410 if (!stringused) {
411 SIVAL(p->structbuf,0,0);
412 } else {
413 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
414 memcpy(p->stringbuf,str?str:"",stringused);
415 if (is_string) {
416 p->stringbuf[stringused-1] = '\0';
418 p->stringbuf += stringused;
419 p->stringlen -= stringused;
420 p->usedlen += stringused;
423 p->neededlen += stringneeded;
426 p->neededlen += needed;
427 if (p->buflen >= needed) {
428 p->structbuf += needed;
429 p->buflen -= needed;
430 p->usedlen += needed;
431 } else {
432 if (p->errcode == NERR_Success) {
433 p->errcode = ERRmoredata;
436 return 1;
439 #if CHECK_TYPES
440 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
441 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
442 #else
443 #define PACK(desc,t,v) package(desc,v)
444 #define PACKl(desc,t,v,l) package(desc,v,l)
445 #endif
447 static void PACKI(struct pack_desc* desc, const char *t,int v)
449 PACK(desc,t,v);
452 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
454 PACK(desc,t,v);
457 /****************************************************************************
458 Get a print queue.
459 ****************************************************************************/
461 static void PackDriverData(struct pack_desc* desc)
463 char drivdata[4+4+32];
464 SIVAL(drivdata,0,sizeof drivdata); /* cb */
465 SIVAL(drivdata,4,1000); /* lVersion */
466 memset(drivdata+8,0,32); /* szDeviceName */
467 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
468 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
471 static int check_printq_info(struct pack_desc* desc,
472 unsigned int uLevel, char *id1, char *id2)
474 desc->subformat = NULL;
475 switch( uLevel ) {
476 case 0:
477 desc->format = "B13";
478 break;
479 case 1:
480 desc->format = "B13BWWWzzzzzWW";
481 break;
482 case 2:
483 desc->format = "B13BWWWzzzzzWN";
484 desc->subformat = "WB21BB16B10zWWzDDz";
485 break;
486 case 3:
487 desc->format = "zWWWWzzzzWWzzl";
488 break;
489 case 4:
490 desc->format = "zWWWWzzzzWNzzl";
491 desc->subformat = "WWzWWDDzz";
492 break;
493 case 5:
494 desc->format = "z";
495 break;
496 case 51:
497 desc->format = "K";
498 break;
499 case 52:
500 desc->format = "WzzzzzzzzN";
501 desc->subformat = "z";
502 break;
503 default:
504 DEBUG(0,("check_printq_info: invalid level %d\n",
505 uLevel ));
506 return False;
508 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
509 DEBUG(0,("check_printq_info: invalid format %s\n",
510 id1 ? id1 : "<NULL>" ));
511 return False;
513 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
514 DEBUG(0,("check_printq_info: invalid subformat %s\n",
515 id2 ? id2 : "<NULL>" ));
516 return False;
518 return True;
522 #define RAP_JOB_STATUS_QUEUED 0
523 #define RAP_JOB_STATUS_PAUSED 1
524 #define RAP_JOB_STATUS_SPOOLING 2
525 #define RAP_JOB_STATUS_PRINTING 3
526 #define RAP_JOB_STATUS_PRINTED 4
528 #define RAP_QUEUE_STATUS_PAUSED 1
529 #define RAP_QUEUE_STATUS_ERROR 2
531 /* turn a print job status into a on the wire status
533 static int printj_status(int v)
535 switch (v) {
536 case LPQ_QUEUED:
537 return RAP_JOB_STATUS_QUEUED;
538 case LPQ_PAUSED:
539 return RAP_JOB_STATUS_PAUSED;
540 case LPQ_SPOOLING:
541 return RAP_JOB_STATUS_SPOOLING;
542 case LPQ_PRINTING:
543 return RAP_JOB_STATUS_PRINTING;
545 return 0;
548 /* turn a print queue status into a on the wire status
550 static int printq_status(int v)
552 switch (v) {
553 case LPQ_QUEUED:
554 return 0;
555 case LPQ_PAUSED:
556 return RAP_QUEUE_STATUS_PAUSED;
558 return RAP_QUEUE_STATUS_ERROR;
561 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
562 struct pack_desc *desc,
563 print_queue_struct *queue, int n)
565 time_t t = queue->time;
567 /* the client expects localtime */
568 t -= get_time_zone(t);
570 PACKI(desc,"W",pjobid_to_rap(lp_const_servicename(snum),queue->job)); /* uJobId */
571 if (uLevel == 1) {
572 PACKS(desc,"B21",queue->fs_user); /* szUserName */
573 PACKS(desc,"B",""); /* pad */
574 PACKS(desc,"B16",""); /* szNotifyName */
575 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
576 PACKS(desc,"z",""); /* pszParms */
577 PACKI(desc,"W",n+1); /* uPosition */
578 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
579 PACKS(desc,"z",""); /* pszStatus */
580 PACKI(desc,"D",t); /* ulSubmitted */
581 PACKI(desc,"D",queue->size); /* ulSize */
582 PACKS(desc,"z",queue->fs_file); /* pszComment */
584 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
585 PACKI(desc,"W",queue->priority); /* uPriority */
586 PACKS(desc,"z",queue->fs_user); /* pszUserName */
587 PACKI(desc,"W",n+1); /* uPosition */
588 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
589 PACKI(desc,"D",t); /* ulSubmitted */
590 PACKI(desc,"D",queue->size); /* ulSize */
591 PACKS(desc,"z","Samba"); /* pszComment */
592 PACKS(desc,"z",queue->fs_file); /* pszDocument */
593 if (uLevel == 3) {
594 PACKS(desc,"z",""); /* pszNotifyName */
595 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
596 PACKS(desc,"z",""); /* pszParms */
597 PACKS(desc,"z",""); /* pszStatus */
598 PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
599 PACKS(desc,"z","lpd"); /* pszQProcName */
600 PACKS(desc,"z",""); /* pszQProcParms */
601 PACKS(desc,"z","NULL"); /* pszDriverName */
602 PackDriverData(desc); /* pDriverData */
603 PACKS(desc,"z",""); /* pszPrinterName */
604 } else if (uLevel == 4) { /* OS2 */
605 PACKS(desc,"z",""); /* pszSpoolFileName */
606 PACKS(desc,"z",""); /* pszPortName */
607 PACKS(desc,"z",""); /* pszStatus */
608 PACKI(desc,"D",0); /* ulPagesSpooled */
609 PACKI(desc,"D",0); /* ulPagesSent */
610 PACKI(desc,"D",0); /* ulPagesPrinted */
611 PACKI(desc,"D",0); /* ulTimePrinted */
612 PACKI(desc,"D",0); /* ulExtendJobStatus */
613 PACKI(desc,"D",0); /* ulStartPage */
614 PACKI(desc,"D",0); /* ulEndPage */
619 /********************************************************************
620 Return a driver name given an snum.
621 Returns True if from tdb, False otherwise.
622 ********************************************************************/
624 static bool get_driver_name(int snum, char **pp_drivername)
626 NT_PRINTER_INFO_LEVEL *info = NULL;
627 bool in_tdb = false;
629 get_a_printer (NULL, &info, 2, lp_servicename(snum));
630 if (info != NULL) {
631 *pp_drivername = talloc_strdup(talloc_tos(),
632 info->info_2->drivername);
633 in_tdb = true;
634 free_a_printer(&info, 2);
635 if (!*pp_drivername) {
636 return false;
640 return in_tdb;
643 /********************************************************************
644 Respond to the DosPrintQInfo command with a level of 52
645 This is used to get printer driver information for Win9x clients
646 ********************************************************************/
647 static void fill_printq_info_52(connection_struct *conn, int snum,
648 struct pack_desc* desc, int count )
650 int i;
651 fstring location;
652 struct spoolss_DriverInfo8 *driver = NULL;
653 NT_PRINTER_INFO_LEVEL *printer = NULL;
655 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
656 DEBUG(3,("fill_printq_info_52: Failed to lookup printer [%s]\n",
657 lp_servicename(snum)));
658 goto err;
661 if (!W_ERROR_IS_OK(get_a_printer_driver(talloc_tos(), &driver, printer->info_2->drivername,
662 "Windows 4.0", 0)) )
664 DEBUG(3,("fill_printq_info_52: Failed to lookup driver [%s]\n",
665 printer->info_2->drivername));
666 goto err;
669 trim_string((char *)driver->driver_path, "\\print$\\WIN40\\0\\", 0);
670 trim_string((char *)driver->data_file, "\\print$\\WIN40\\0\\", 0);
671 trim_string((char *)driver->help_file, "\\print$\\WIN40\\0\\", 0);
673 PACKI(desc, "W", 0x0400); /* don't know */
674 PACKS(desc, "z", driver->driver_name); /* long printer name */
675 PACKS(desc, "z", driver->driver_path); /* Driverfile Name */
676 PACKS(desc, "z", driver->data_file); /* Datafile name */
677 PACKS(desc, "z", driver->monitor_name); /* language monitor */
679 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
680 standard_sub_basic( "", "", location, sizeof(location)-1 );
681 PACKS(desc,"z", location); /* share to retrieve files */
683 PACKS(desc,"z", driver->default_datatype); /* default data type */
684 PACKS(desc,"z", driver->help_file); /* helpfile name */
685 PACKS(desc,"z", driver->driver_path); /* driver name */
687 DEBUG(3,("Printer Driver Name: %s:\n",driver->driver_name));
688 DEBUG(3,("Driver: %s:\n",driver->driver_path));
689 DEBUG(3,("Data File: %s:\n",driver->data_file));
690 DEBUG(3,("Language Monitor: %s:\n",driver->monitor_name));
691 DEBUG(3,("Driver Location: %s:\n",location));
692 DEBUG(3,("Data Type: %s:\n",driver->default_datatype));
693 DEBUG(3,("Help File: %s:\n",driver->help_file));
694 PACKI(desc,"N",count); /* number of files to copy */
696 for ( i=0; i<count && driver->dependent_files && *driver->dependent_files[i]; i++)
698 trim_string((char *)driver->dependent_files[i], "\\print$\\WIN40\\0\\", 0);
699 PACKS(desc,"z",driver->dependent_files[i]); /* driver files to copy */
700 DEBUG(3,("Dependent File: %s:\n", driver->dependent_files[i]));
703 /* sanity check */
704 if ( i != count )
705 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
706 count, i));
708 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", SERVICE(snum),i));
710 desc->errcode=NERR_Success;
711 goto done;
713 err:
714 DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
715 desc->errcode=NERR_notsupported;
717 done:
718 if ( printer )
719 free_a_printer( &printer, 2 );
721 free_a_printer_driver(driver);
725 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
726 struct pack_desc* desc,
727 int count, print_queue_struct* queue,
728 print_status_struct* status)
730 switch (uLevel) {
731 case 1:
732 case 2:
733 PACKS(desc,"B13",SERVICE(snum));
734 break;
735 case 3:
736 case 4:
737 case 5:
738 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
739 break;
740 case 51:
741 PACKI(desc,"K",printq_status(status->status));
742 break;
745 if (uLevel == 1 || uLevel == 2) {
746 PACKS(desc,"B",""); /* alignment */
747 PACKI(desc,"W",5); /* priority */
748 PACKI(desc,"W",0); /* start time */
749 PACKI(desc,"W",0); /* until time */
750 PACKS(desc,"z",""); /* pSepFile */
751 PACKS(desc,"z","lpd"); /* pPrProc */
752 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
753 PACKS(desc,"z",""); /* pParms */
754 if (snum < 0) {
755 PACKS(desc,"z","UNKNOWN PRINTER");
756 PACKI(desc,"W",LPSTAT_ERROR);
758 else if (!status || !status->message[0]) {
759 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
760 PACKI(desc,"W",LPSTAT_OK); /* status */
761 } else {
762 PACKS(desc,"z",status->message);
763 PACKI(desc,"W",printq_status(status->status)); /* status */
765 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
768 if (uLevel == 3 || uLevel == 4) {
769 char *drivername = NULL;
771 PACKI(desc,"W",5); /* uPriority */
772 PACKI(desc,"W",0); /* uStarttime */
773 PACKI(desc,"W",0); /* uUntiltime */
774 PACKI(desc,"W",5); /* pad1 */
775 PACKS(desc,"z",""); /* pszSepFile */
776 PACKS(desc,"z","WinPrint"); /* pszPrProc */
777 PACKS(desc,"z",NULL); /* pszParms */
778 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
779 /* "don't ask" that it's done this way to fix corrupted
780 Win9X/ME printer comments. */
781 if (!status) {
782 PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
783 } else {
784 PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
786 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
787 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
788 get_driver_name(snum,&drivername);
789 if (!drivername) {
790 return;
792 PACKS(desc,"z",drivername); /* pszDriverName */
793 PackDriverData(desc); /* pDriverData */
796 if (uLevel == 2 || uLevel == 4) {
797 int i;
798 for (i=0;i<count;i++)
799 fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
802 if (uLevel==52)
803 fill_printq_info_52( conn, snum, desc, count );
806 /* This function returns the number of files for a given driver */
807 static int get_printerdrivernumber(int snum)
809 int result = 0;
810 struct spoolss_DriverInfo8 *driver;
811 NT_PRINTER_INFO_LEVEL *printer = NULL;
813 ZERO_STRUCT(driver);
815 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
816 DEBUG(3,("get_printerdrivernumber: Failed to lookup printer [%s]\n",
817 lp_servicename(snum)));
818 goto done;
821 if (!W_ERROR_IS_OK(get_a_printer_driver(talloc_tos(), &driver, printer->info_2->drivername,
822 "Windows 4.0", 0)) )
824 DEBUG(3,("get_printerdrivernumber: Failed to lookup driver [%s]\n",
825 printer->info_2->drivername));
826 goto done;
829 /* count the number of files */
830 while (driver->dependent_files && *driver->dependent_files[result])
831 result++;
832 done:
833 if ( printer )
834 free_a_printer( &printer, 2 );
836 free_a_printer_driver(driver);
838 return result;
841 static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
842 char *param, int tpscnt,
843 char *data, int tdscnt,
844 int mdrcnt,int mprcnt,
845 char **rdata,char **rparam,
846 int *rdata_len,int *rparam_len)
848 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
849 char *str2 = skip_string(param,tpscnt,str1);
850 char *p = skip_string(param,tpscnt,str2);
851 char *QueueName = p;
852 unsigned int uLevel;
853 int count=0;
854 int snum;
855 char *str3;
856 struct pack_desc desc;
857 print_queue_struct *queue=NULL;
858 print_status_struct status;
859 char* tmpdata=NULL;
861 if (!str1 || !str2 || !p) {
862 return False;
864 memset((char *)&status,'\0',sizeof(status));
865 memset((char *)&desc,'\0',sizeof(desc));
867 p = skip_string(param,tpscnt,p);
868 if (!p) {
869 return False;
871 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
872 str3 = get_safe_str_ptr(param,tpscnt,p,4);
873 /* str3 may be null here and is checked in check_printq_info(). */
875 /* remove any trailing username */
876 if ((p = strchr_m(QueueName,'%')))
877 *p = 0;
879 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
881 /* check it's a supported varient */
882 if (!prefix_ok(str1,"zWrLh"))
883 return False;
884 if (!check_printq_info(&desc,uLevel,str2,str3)) {
886 * Patch from Scott Moomaw <scott@bridgewater.edu>
887 * to return the 'invalid info level' error if an
888 * unknown level was requested.
890 *rdata_len = 0;
891 *rparam_len = 6;
892 *rparam = smb_realloc_limit(*rparam,*rparam_len);
893 if (!*rparam) {
894 return False;
896 SSVALS(*rparam,0,ERRunknownlevel);
897 SSVAL(*rparam,2,0);
898 SSVAL(*rparam,4,0);
899 return(True);
902 snum = find_service(QueueName);
903 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) )
904 return False;
906 if (uLevel==52) {
907 count = get_printerdrivernumber(snum);
908 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
909 } else {
910 count = print_queue_status(snum, &queue,&status);
913 if (mdrcnt > 0) {
914 *rdata = smb_realloc_limit(*rdata,mdrcnt);
915 if (!*rdata) {
916 SAFE_FREE(queue);
917 return False;
919 desc.base = *rdata;
920 desc.buflen = mdrcnt;
921 } else {
923 * Don't return data but need to get correct length
924 * init_package will return wrong size if buflen=0
926 desc.buflen = getlen(desc.format);
927 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
930 if (init_package(&desc,1,count)) {
931 desc.subcount = count;
932 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
935 *rdata_len = desc.usedlen;
938 * We must set the return code to ERRbuftoosmall
939 * in order to support lanman style printing with Win NT/2k
940 * clients --jerry
942 if (!mdrcnt && lp_disable_spoolss())
943 desc.errcode = ERRbuftoosmall;
945 *rdata_len = desc.usedlen;
946 *rparam_len = 6;
947 *rparam = smb_realloc_limit(*rparam,*rparam_len);
948 if (!*rparam) {
949 SAFE_FREE(queue);
950 SAFE_FREE(tmpdata);
951 return False;
953 SSVALS(*rparam,0,desc.errcode);
954 SSVAL(*rparam,2,0);
955 SSVAL(*rparam,4,desc.neededlen);
957 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
959 SAFE_FREE(queue);
960 SAFE_FREE(tmpdata);
962 return(True);
965 /****************************************************************************
966 View list of all print jobs on all queues.
967 ****************************************************************************/
969 static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
970 char *param, int tpscnt,
971 char *data, int tdscnt,
972 int mdrcnt, int mprcnt,
973 char **rdata, char** rparam,
974 int *rdata_len, int *rparam_len)
976 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
977 char *output_format1 = skip_string(param,tpscnt,param_format);
978 char *p = skip_string(param,tpscnt,output_format1);
979 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
980 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
981 int services = lp_numservices();
982 int i, n;
983 struct pack_desc desc;
984 print_queue_struct **queue = NULL;
985 print_status_struct *status = NULL;
986 int *subcntarr = NULL;
987 int queuecnt = 0, subcnt = 0, succnt = 0;
989 if (!param_format || !output_format1 || !p) {
990 return False;
993 memset((char *)&desc,'\0',sizeof(desc));
995 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
997 if (!prefix_ok(param_format,"WrLeh")) {
998 return False;
1000 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
1002 * Patch from Scott Moomaw <scott@bridgewater.edu>
1003 * to return the 'invalid info level' error if an
1004 * unknown level was requested.
1006 *rdata_len = 0;
1007 *rparam_len = 6;
1008 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1009 if (!*rparam) {
1010 return False;
1012 SSVALS(*rparam,0,ERRunknownlevel);
1013 SSVAL(*rparam,2,0);
1014 SSVAL(*rparam,4,0);
1015 return(True);
1018 for (i = 0; i < services; i++) {
1019 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1020 queuecnt++;
1024 if((queue = SMB_MALLOC_ARRAY(print_queue_struct*, queuecnt)) == NULL) {
1025 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1026 goto err;
1028 memset(queue,0,queuecnt*sizeof(print_queue_struct*));
1029 if((status = SMB_MALLOC_ARRAY(print_status_struct,queuecnt)) == NULL) {
1030 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1031 goto err;
1033 memset(status,0,queuecnt*sizeof(print_status_struct));
1034 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1035 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1036 goto err;
1039 subcnt = 0;
1040 n = 0;
1041 for (i = 0; i < services; i++) {
1042 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1043 subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
1044 subcnt += subcntarr[n];
1045 n++;
1049 if (mdrcnt > 0) {
1050 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1051 if (!*rdata) {
1052 goto err;
1055 desc.base = *rdata;
1056 desc.buflen = mdrcnt;
1058 if (init_package(&desc,queuecnt,subcnt)) {
1059 n = 0;
1060 succnt = 0;
1061 for (i = 0; i < services; i++) {
1062 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1063 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1064 n++;
1065 if (desc.errcode == NERR_Success) {
1066 succnt = n;
1072 SAFE_FREE(subcntarr);
1074 *rdata_len = desc.usedlen;
1075 *rparam_len = 8;
1076 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1077 if (!*rparam) {
1078 goto err;
1080 SSVALS(*rparam,0,desc.errcode);
1081 SSVAL(*rparam,2,0);
1082 SSVAL(*rparam,4,succnt);
1083 SSVAL(*rparam,6,queuecnt);
1085 for (i = 0; i < queuecnt; i++) {
1086 if (queue) {
1087 SAFE_FREE(queue[i]);
1091 SAFE_FREE(queue);
1092 SAFE_FREE(status);
1094 return True;
1096 err:
1098 SAFE_FREE(subcntarr);
1099 for (i = 0; i < queuecnt; i++) {
1100 if (queue) {
1101 SAFE_FREE(queue[i]);
1104 SAFE_FREE(queue);
1105 SAFE_FREE(status);
1107 return False;
1110 /****************************************************************************
1111 Get info level for a server list query.
1112 ****************************************************************************/
1114 static bool check_server_info(int uLevel, char* id)
1116 switch( uLevel ) {
1117 case 0:
1118 if (strcmp(id,"B16") != 0) {
1119 return False;
1121 break;
1122 case 1:
1123 if (strcmp(id,"B16BBDz") != 0) {
1124 return False;
1126 break;
1127 default:
1128 return False;
1130 return True;
1133 struct srv_info_struct {
1134 fstring name;
1135 uint32 type;
1136 fstring comment;
1137 fstring domain;
1138 bool server_added;
1141 /*******************************************************************
1142 Get server info lists from the files saved by nmbd. Return the
1143 number of entries.
1144 ******************************************************************/
1146 static int get_server_info(uint32 servertype,
1147 struct srv_info_struct **servers,
1148 const char *domain)
1150 int count=0;
1151 int alloced=0;
1152 char **lines;
1153 bool local_list_only;
1154 int i;
1156 lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
1157 if (!lines) {
1158 DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
1159 return 0;
1162 /* request for everything is code for request all servers */
1163 if (servertype == SV_TYPE_ALL) {
1164 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1167 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1169 DEBUG(4,("Servertype search: %8x\n",servertype));
1171 for (i=0;lines[i];i++) {
1172 fstring stype;
1173 struct srv_info_struct *s;
1174 const char *ptr = lines[i];
1175 bool ok = True;
1176 TALLOC_CTX *frame = NULL;
1177 char *p;
1179 if (!*ptr) {
1180 continue;
1183 if (count == alloced) {
1184 alloced += 10;
1185 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1186 if (!*servers) {
1187 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1188 TALLOC_FREE(lines);
1189 return 0;
1191 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1193 s = &(*servers)[count];
1195 frame = talloc_stackframe();
1196 s->name[0] = '\0';
1197 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1198 TALLOC_FREE(frame);
1199 continue;
1201 fstrcpy(s->name, p);
1203 stype[0] = '\0';
1204 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1205 TALLOC_FREE(frame);
1206 continue;
1208 fstrcpy(stype, p);
1210 s->comment[0] = '\0';
1211 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1212 TALLOC_FREE(frame);
1213 continue;
1215 fstrcpy(s->comment, p);
1216 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1218 s->domain[0] = '\0';
1219 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1220 /* this allows us to cope with an old nmbd */
1221 fstrcpy(s->domain,lp_workgroup());
1222 } else {
1223 fstrcpy(s->domain, p);
1225 TALLOC_FREE(frame);
1227 if (sscanf(stype,"%X",&s->type) != 1) {
1228 DEBUG(4,("r:host file "));
1229 ok = False;
1232 /* Filter the servers/domains we return based on what was asked for. */
1234 /* Check to see if we are being asked for a local list only. */
1235 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1236 DEBUG(4,("r: local list only"));
1237 ok = False;
1240 /* doesn't match up: don't want it */
1241 if (!(servertype & s->type)) {
1242 DEBUG(4,("r:serv type "));
1243 ok = False;
1246 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1247 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1248 DEBUG(4,("s: dom mismatch "));
1249 ok = False;
1252 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1253 ok = False;
1256 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1257 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1259 if (ok) {
1260 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1261 s->name, s->type, s->comment, s->domain));
1262 s->server_added = True;
1263 count++;
1264 } else {
1265 DEBUG(4,("%20s %8x %25s %15s\n",
1266 s->name, s->type, s->comment, s->domain));
1270 TALLOC_FREE(lines);
1271 return count;
1274 /*******************************************************************
1275 Fill in a server info structure.
1276 ******************************************************************/
1278 static int fill_srv_info(struct srv_info_struct *service,
1279 int uLevel, char **buf, int *buflen,
1280 char **stringbuf, int *stringspace, char *baseaddr)
1282 int struct_len;
1283 char* p;
1284 char* p2;
1285 int l2;
1286 int len;
1288 switch (uLevel) {
1289 case 0:
1290 struct_len = 16;
1291 break;
1292 case 1:
1293 struct_len = 26;
1294 break;
1295 default:
1296 return -1;
1299 if (!buf) {
1300 len = 0;
1301 switch (uLevel) {
1302 case 1:
1303 len = strlen(service->comment)+1;
1304 break;
1307 *buflen = struct_len;
1308 *stringspace = len;
1309 return struct_len + len;
1312 len = struct_len;
1313 p = *buf;
1314 if (*buflen < struct_len) {
1315 return -1;
1317 if (stringbuf) {
1318 p2 = *stringbuf;
1319 l2 = *stringspace;
1320 } else {
1321 p2 = p + struct_len;
1322 l2 = *buflen - struct_len;
1324 if (!baseaddr) {
1325 baseaddr = p;
1328 switch (uLevel) {
1329 case 0:
1330 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1331 break;
1333 case 1:
1334 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1335 SIVAL(p,18,service->type);
1336 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1337 len += CopyAndAdvance(&p2,service->comment,&l2);
1338 break;
1341 if (stringbuf) {
1342 *buf = p + struct_len;
1343 *buflen -= struct_len;
1344 *stringbuf = p2;
1345 *stringspace = l2;
1346 } else {
1347 *buf = p2;
1348 *buflen -= len;
1350 return len;
1354 static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1356 return StrCaseCmp(s1->name,s2->name);
1359 /****************************************************************************
1360 View list of servers available (or possibly domains). The info is
1361 extracted from lists saved by nmbd on the local host.
1362 ****************************************************************************/
1364 static bool api_RNetServerEnum2(connection_struct *conn, uint16 vuid,
1365 char *param, int tpscnt,
1366 char *data, int tdscnt,
1367 int mdrcnt, int mprcnt, char **rdata,
1368 char **rparam, int *rdata_len, int *rparam_len)
1370 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1371 char *str2 = skip_string(param,tpscnt,str1);
1372 char *p = skip_string(param,tpscnt,str2);
1373 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1374 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1375 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1376 char *p2;
1377 int data_len, fixed_len, string_len;
1378 int f_len = 0, s_len = 0;
1379 struct srv_info_struct *servers=NULL;
1380 int counted=0,total=0;
1381 int i,missed;
1382 fstring domain;
1383 bool domain_request;
1384 bool local_request;
1386 if (!str1 || !str2 || !p) {
1387 return False;
1390 /* If someone sets all the bits they don't really mean to set
1391 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1392 known servers. */
1394 if (servertype == SV_TYPE_ALL) {
1395 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1398 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1399 any other bit (they may just set this bit on its own) they
1400 want all the locally seen servers. However this bit can be
1401 set on its own so set the requested servers to be
1402 ALL - DOMAIN_ENUM. */
1404 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1405 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1408 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1409 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1411 p += 8;
1413 if (!prefix_ok(str1,"WrLehD")) {
1414 return False;
1416 if (!check_server_info(uLevel,str2)) {
1417 return False;
1420 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1421 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1422 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1424 if (strcmp(str1, "WrLehDz") == 0) {
1425 if (skip_string(param,tpscnt,p) == NULL) {
1426 return False;
1428 pull_ascii_fstring(domain, p);
1429 } else {
1430 fstrcpy(domain, lp_workgroup());
1433 DEBUG(4, ("domain [%s]\n", domain));
1435 if (lp_browse_list()) {
1436 total = get_server_info(servertype,&servers,domain);
1439 data_len = fixed_len = string_len = 0;
1440 missed = 0;
1442 TYPESAFE_QSORT(servers, total, srv_comp);
1445 char *lastname=NULL;
1447 for (i=0;i<total;i++) {
1448 struct srv_info_struct *s = &servers[i];
1450 if (lastname && strequal(lastname,s->name)) {
1451 continue;
1453 lastname = s->name;
1454 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1455 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1456 i, s->name, s->type, s->comment, s->domain));
1458 if (data_len < buf_len) {
1459 counted++;
1460 fixed_len += f_len;
1461 string_len += s_len;
1462 } else {
1463 missed++;
1468 *rdata_len = fixed_len + string_len;
1469 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1470 if (!*rdata) {
1471 return False;
1474 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1475 p = *rdata;
1476 f_len = fixed_len;
1477 s_len = string_len;
1480 char *lastname=NULL;
1481 int count2 = counted;
1483 for (i = 0; i < total && count2;i++) {
1484 struct srv_info_struct *s = &servers[i];
1486 if (lastname && strequal(lastname,s->name)) {
1487 continue;
1489 lastname = s->name;
1490 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1491 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1492 i, s->name, s->type, s->comment, s->domain));
1493 count2--;
1497 *rparam_len = 8;
1498 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1499 if (!*rparam) {
1500 return False;
1502 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1503 SSVAL(*rparam,2,0);
1504 SSVAL(*rparam,4,counted);
1505 SSVAL(*rparam,6,counted+missed);
1507 SAFE_FREE(servers);
1509 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1510 domain,uLevel,counted,counted+missed));
1512 return True;
1515 static int srv_name_match(const char *n1, const char *n2)
1518 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1520 * In Windows, FirstNameToReturn need not be an exact match:
1521 * the server will return a list of servers that exist on
1522 * the network greater than or equal to the FirstNameToReturn.
1524 int ret = StrCaseCmp(n1, n2);
1526 if (ret <= 0) {
1527 return 0;
1530 return ret;
1533 static bool api_RNetServerEnum3(connection_struct *conn, uint16 vuid,
1534 char *param, int tpscnt,
1535 char *data, int tdscnt,
1536 int mdrcnt, int mprcnt, char **rdata,
1537 char **rparam, int *rdata_len, int *rparam_len)
1539 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1540 char *str2 = skip_string(param,tpscnt,str1);
1541 char *p = skip_string(param,tpscnt,str2);
1542 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1543 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1544 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1545 char *p2;
1546 int data_len, fixed_len, string_len;
1547 int f_len = 0, s_len = 0;
1548 struct srv_info_struct *servers=NULL;
1549 int counted=0,first=0,total=0;
1550 int i,missed;
1551 fstring domain;
1552 fstring first_name;
1553 bool domain_request;
1554 bool local_request;
1556 if (!str1 || !str2 || !p) {
1557 return False;
1560 /* If someone sets all the bits they don't really mean to set
1561 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1562 known servers. */
1564 if (servertype == SV_TYPE_ALL) {
1565 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1568 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1569 any other bit (they may just set this bit on its own) they
1570 want all the locally seen servers. However this bit can be
1571 set on its own so set the requested servers to be
1572 ALL - DOMAIN_ENUM. */
1574 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1575 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1578 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1579 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1581 p += 8;
1583 if (strcmp(str1, "WrLehDzz") != 0) {
1584 return false;
1586 if (!check_server_info(uLevel,str2)) {
1587 return False;
1590 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1591 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1592 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1594 if (skip_string(param,tpscnt,p) == NULL) {
1595 return False;
1597 pull_ascii_fstring(domain, p);
1598 if (domain[0] == '\0') {
1599 fstrcpy(domain, lp_workgroup());
1601 p = skip_string(param,tpscnt,p);
1602 if (skip_string(param,tpscnt,p) == NULL) {
1603 return False;
1605 pull_ascii_fstring(first_name, p);
1607 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1608 domain, first_name));
1610 if (lp_browse_list()) {
1611 total = get_server_info(servertype,&servers,domain);
1614 data_len = fixed_len = string_len = 0;
1615 missed = 0;
1617 TYPESAFE_QSORT(servers, total, srv_comp);
1619 if (first_name[0] != '\0') {
1620 struct srv_info_struct *first_server = NULL;
1622 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1623 srv_name_match, first_server);
1624 if (first_server) {
1625 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1627 * The binary search may not find the exact match
1628 * so we need to search backward to find the first match
1630 * This implements the strange matching windows
1631 * implements. (see the comment in srv_name_match().
1633 for (;first > 0;) {
1634 int ret;
1635 ret = StrCaseCmp(first_name,
1636 servers[first-1].name);
1637 if (ret > 0) {
1638 break;
1640 first--;
1642 } else {
1643 /* we should return no entries */
1644 first = total;
1649 char *lastname=NULL;
1651 for (i=first;i<total;i++) {
1652 struct srv_info_struct *s = &servers[i];
1654 if (lastname && strequal(lastname,s->name)) {
1655 continue;
1657 lastname = s->name;
1658 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1659 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1660 i, s->name, s->type, s->comment, s->domain));
1662 if (data_len < buf_len) {
1663 counted++;
1664 fixed_len += f_len;
1665 string_len += s_len;
1666 } else {
1667 missed++;
1672 *rdata_len = fixed_len + string_len;
1673 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1674 if (!*rdata) {
1675 return False;
1678 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1679 p = *rdata;
1680 f_len = fixed_len;
1681 s_len = string_len;
1684 char *lastname=NULL;
1685 int count2 = counted;
1687 for (i = first; i < total && count2;i++) {
1688 struct srv_info_struct *s = &servers[i];
1690 if (lastname && strequal(lastname,s->name)) {
1691 continue;
1693 lastname = s->name;
1694 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1695 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1696 i, s->name, s->type, s->comment, s->domain));
1697 count2--;
1701 *rparam_len = 8;
1702 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1703 if (!*rparam) {
1704 return False;
1706 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1707 SSVAL(*rparam,2,0);
1708 SSVAL(*rparam,4,counted);
1709 SSVAL(*rparam,6,counted+missed);
1711 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1712 domain,uLevel,first,first_name,
1713 first < total ? servers[first].name : "",
1714 counted,counted+missed));
1716 SAFE_FREE(servers);
1718 return True;
1721 /****************************************************************************
1722 command 0x34 - suspected of being a "Lookup Names" stub api
1723 ****************************************************************************/
1725 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1726 char *param, int tpscnt,
1727 char *data, int tdscnt,
1728 int mdrcnt, int mprcnt, char **rdata,
1729 char **rparam, int *rdata_len, int *rparam_len)
1731 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1732 char *str2 = skip_string(param,tpscnt,str1);
1733 char *p = skip_string(param,tpscnt,str2);
1734 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1735 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1736 int counted=0;
1737 int missed=0;
1739 if (!str1 || !str2 || !p) {
1740 return False;
1743 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1744 str1, str2, p, uLevel, buf_len));
1746 if (!prefix_ok(str1,"zWrLeh")) {
1747 return False;
1750 *rdata_len = 0;
1752 *rparam_len = 8;
1753 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1754 if (!*rparam) {
1755 return False;
1758 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1759 SSVAL(*rparam,2,0);
1760 SSVAL(*rparam,4,counted);
1761 SSVAL(*rparam,6,counted+missed);
1763 return True;
1766 /****************************************************************************
1767 get info about a share
1768 ****************************************************************************/
1770 static bool check_share_info(int uLevel, char* id)
1772 switch( uLevel ) {
1773 case 0:
1774 if (strcmp(id,"B13") != 0) {
1775 return False;
1777 break;
1778 case 1:
1779 /* Level-2 descriptor is allowed (and ignored) */
1780 if (strcmp(id,"B13BWz") != 0 &&
1781 strcmp(id,"B13BWzWWWzB9B") != 0) {
1782 return False;
1784 break;
1785 case 2:
1786 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1787 return False;
1789 break;
1790 case 91:
1791 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1792 return False;
1794 break;
1795 default:
1796 return False;
1798 return True;
1801 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1802 char** buf, int* buflen,
1803 char** stringbuf, int* stringspace, char* baseaddr)
1805 int struct_len;
1806 char* p;
1807 char* p2;
1808 int l2;
1809 int len;
1811 switch( uLevel ) {
1812 case 0:
1813 struct_len = 13;
1814 break;
1815 case 1:
1816 struct_len = 20;
1817 break;
1818 case 2:
1819 struct_len = 40;
1820 break;
1821 case 91:
1822 struct_len = 68;
1823 break;
1824 default:
1825 return -1;
1828 if (!buf) {
1829 len = 0;
1831 if (uLevel > 0) {
1832 len += StrlenExpanded(conn,snum,lp_comment(snum));
1834 if (uLevel > 1) {
1835 len += strlen(lp_pathname(snum)) + 1;
1837 if (buflen) {
1838 *buflen = struct_len;
1840 if (stringspace) {
1841 *stringspace = len;
1843 return struct_len + len;
1846 len = struct_len;
1847 p = *buf;
1848 if ((*buflen) < struct_len) {
1849 return -1;
1852 if (stringbuf) {
1853 p2 = *stringbuf;
1854 l2 = *stringspace;
1855 } else {
1856 p2 = p + struct_len;
1857 l2 = (*buflen) - struct_len;
1860 if (!baseaddr) {
1861 baseaddr = p;
1864 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1866 if (uLevel > 0) {
1867 int type;
1869 SCVAL(p,13,0);
1870 type = STYPE_DISKTREE;
1871 if (lp_print_ok(snum)) {
1872 type = STYPE_PRINTQ;
1874 if (strequal("IPC",lp_fstype(snum))) {
1875 type = STYPE_IPC;
1877 SSVAL(p,14,type); /* device type */
1878 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1879 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1882 if (uLevel > 1) {
1883 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1884 SSVALS(p,22,-1); /* max uses */
1885 SSVAL(p,24,1); /* current uses */
1886 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1887 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1888 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1891 if (uLevel > 2) {
1892 memset(p+40,0,SHPWLEN+2);
1893 SSVAL(p,50,0);
1894 SIVAL(p,52,0);
1895 SSVAL(p,56,0);
1896 SSVAL(p,58,0);
1897 SIVAL(p,60,0);
1898 SSVAL(p,64,0);
1899 SSVAL(p,66,0);
1902 if (stringbuf) {
1903 (*buf) = p + struct_len;
1904 (*buflen) -= struct_len;
1905 (*stringbuf) = p2;
1906 (*stringspace) = l2;
1907 } else {
1908 (*buf) = p2;
1909 (*buflen) -= len;
1912 return len;
1915 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1916 char *param, int tpscnt,
1917 char *data, int tdscnt,
1918 int mdrcnt,int mprcnt,
1919 char **rdata,char **rparam,
1920 int *rdata_len,int *rparam_len)
1922 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1923 char *str2 = skip_string(param,tpscnt,str1);
1924 char *netname = skip_string(param,tpscnt,str2);
1925 char *p = skip_string(param,tpscnt,netname);
1926 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1927 int snum;
1929 if (!str1 || !str2 || !netname || !p) {
1930 return False;
1933 snum = find_service(netname);
1934 if (snum < 0) {
1935 return False;
1938 /* check it's a supported varient */
1939 if (!prefix_ok(str1,"zWrLh")) {
1940 return False;
1942 if (!check_share_info(uLevel,str2)) {
1943 return False;
1946 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1947 if (!*rdata) {
1948 return False;
1950 p = *rdata;
1951 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1952 if (*rdata_len < 0) {
1953 return False;
1956 *rparam_len = 6;
1957 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1958 if (!*rparam) {
1959 return False;
1961 SSVAL(*rparam,0,NERR_Success);
1962 SSVAL(*rparam,2,0); /* converter word */
1963 SSVAL(*rparam,4,*rdata_len);
1965 return True;
1968 /****************************************************************************
1969 View the list of available shares.
1971 This function is the server side of the NetShareEnum() RAP call.
1972 It fills the return buffer with share names and share comments.
1973 Note that the return buffer normally (in all known cases) allows only
1974 twelve byte strings for share names (plus one for a nul terminator).
1975 Share names longer than 12 bytes must be skipped.
1976 ****************************************************************************/
1978 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
1979 char *param, int tpscnt,
1980 char *data, int tdscnt,
1981 int mdrcnt,
1982 int mprcnt,
1983 char **rdata,
1984 char **rparam,
1985 int *rdata_len,
1986 int *rparam_len )
1988 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1989 char *str2 = skip_string(param,tpscnt,str1);
1990 char *p = skip_string(param,tpscnt,str2);
1991 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1992 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1993 char *p2;
1994 int count = 0;
1995 int total=0,counted=0;
1996 bool missed = False;
1997 int i;
1998 int data_len, fixed_len, string_len;
1999 int f_len = 0, s_len = 0;
2001 if (!str1 || !str2 || !p) {
2002 return False;
2005 if (!prefix_ok(str1,"WrLeh")) {
2006 return False;
2008 if (!check_share_info(uLevel,str2)) {
2009 return False;
2012 /* Ensure all the usershares are loaded. */
2013 become_root();
2014 load_registry_shares();
2015 count = load_usershare_shares();
2016 unbecome_root();
2018 data_len = fixed_len = string_len = 0;
2019 for (i=0;i<count;i++) {
2020 fstring servicename_dos;
2021 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2022 continue;
2024 push_ascii_fstring(servicename_dos, lp_servicename(i));
2025 /* Maximum name length = 13. */
2026 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
2027 total++;
2028 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
2029 if (data_len < buf_len) {
2030 counted++;
2031 fixed_len += f_len;
2032 string_len += s_len;
2033 } else {
2034 missed = True;
2039 *rdata_len = fixed_len + string_len;
2040 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2041 if (!*rdata) {
2042 return False;
2045 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
2046 p = *rdata;
2047 f_len = fixed_len;
2048 s_len = string_len;
2050 for( i = 0; i < count; i++ ) {
2051 fstring servicename_dos;
2052 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2053 continue;
2056 push_ascii_fstring(servicename_dos, lp_servicename(i));
2057 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2058 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2059 break;
2064 *rparam_len = 8;
2065 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2066 if (!*rparam) {
2067 return False;
2069 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2070 SSVAL(*rparam,2,0);
2071 SSVAL(*rparam,4,counted);
2072 SSVAL(*rparam,6,total);
2074 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2075 counted,total,uLevel,
2076 buf_len,*rdata_len,mdrcnt));
2078 return True;
2081 /****************************************************************************
2082 Add a share
2083 ****************************************************************************/
2085 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
2086 char *param, int tpscnt,
2087 char *data, int tdscnt,
2088 int mdrcnt,int mprcnt,
2089 char **rdata,char **rparam,
2090 int *rdata_len,int *rparam_len)
2092 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2093 char *str2 = skip_string(param,tpscnt,str1);
2094 char *p = skip_string(param,tpscnt,str2);
2095 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2096 fstring sharename;
2097 fstring comment;
2098 char *pathname = NULL;
2099 char *command, *cmdname;
2100 unsigned int offset;
2101 int snum;
2102 int res = ERRunsup;
2103 size_t converted_size;
2105 if (!str1 || !str2 || !p) {
2106 return False;
2109 /* check it's a supported varient */
2110 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2111 return False;
2113 if (!check_share_info(uLevel,str2)) {
2114 return False;
2116 if (uLevel != 2) {
2117 return False;
2120 /* Do we have a string ? */
2121 if (skip_string(data,mdrcnt,data) == NULL) {
2122 return False;
2124 pull_ascii_fstring(sharename,data);
2125 snum = find_service(sharename);
2126 if (snum >= 0) { /* already exists */
2127 res = ERRfilexists;
2128 goto error_exit;
2131 if (mdrcnt < 28) {
2132 return False;
2135 /* only support disk share adds */
2136 if (SVAL(data,14)!=STYPE_DISKTREE) {
2137 return False;
2140 offset = IVAL(data, 16);
2141 if (offset >= mdrcnt) {
2142 res = ERRinvalidparam;
2143 goto error_exit;
2146 /* Do we have a string ? */
2147 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2148 return False;
2150 pull_ascii_fstring(comment, offset? (data+offset) : "");
2152 offset = IVAL(data, 26);
2154 if (offset >= mdrcnt) {
2155 res = ERRinvalidparam;
2156 goto error_exit;
2159 /* Do we have a string ? */
2160 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2161 return False;
2164 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2165 offset ? (data+offset) : "", &converted_size))
2167 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
2168 strerror(errno)));
2171 if (!pathname) {
2172 return false;
2175 string_replace(sharename, '"', ' ');
2176 string_replace(pathname, '"', ' ');
2177 string_replace(comment, '"', ' ');
2179 cmdname = lp_add_share_cmd();
2181 if (!cmdname || *cmdname == '\0') {
2182 return False;
2185 if (asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
2186 lp_add_share_cmd(), get_dyn_CONFIGFILE(), sharename,
2187 pathname, comment) == -1) {
2188 return false;
2191 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
2193 if ((res = smbrun(command, NULL)) != 0) {
2194 DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n",
2195 command, res ));
2196 SAFE_FREE(command);
2197 res = ERRnoaccess;
2198 goto error_exit;
2199 } else {
2200 SAFE_FREE(command);
2201 message_send_all(smbd_messaging_context(),
2202 MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
2205 *rparam_len = 6;
2206 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2207 if (!*rparam) {
2208 return False;
2210 SSVAL(*rparam,0,NERR_Success);
2211 SSVAL(*rparam,2,0); /* converter word */
2212 SSVAL(*rparam,4,*rdata_len);
2213 *rdata_len = 0;
2215 return True;
2217 error_exit:
2219 *rparam_len = 4;
2220 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2221 if (!*rparam) {
2222 return False;
2224 *rdata_len = 0;
2225 SSVAL(*rparam,0,res);
2226 SSVAL(*rparam,2,0);
2227 return True;
2230 /****************************************************************************
2231 view list of groups available
2232 ****************************************************************************/
2234 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
2235 char *param, int tpscnt,
2236 char *data, int tdscnt,
2237 int mdrcnt,int mprcnt,
2238 char **rdata,char **rparam,
2239 int *rdata_len,int *rparam_len)
2241 int i;
2242 int errflags=0;
2243 int resume_context, cli_buf_size;
2244 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2245 char *str2 = skip_string(param,tpscnt,str1);
2246 char *p = skip_string(param,tpscnt,str2);
2248 uint32_t num_groups;
2249 uint32_t resume_handle;
2250 struct rpc_pipe_client *samr_pipe;
2251 struct policy_handle samr_handle, domain_handle;
2252 NTSTATUS status;
2254 if (!str1 || !str2 || !p) {
2255 return False;
2258 if (strcmp(str1,"WrLeh") != 0) {
2259 return False;
2262 /* parameters
2263 * W-> resume context (number of users to skip)
2264 * r -> return parameter pointer to receive buffer
2265 * L -> length of receive buffer
2266 * e -> return parameter number of entries
2267 * h -> return parameter total number of users
2270 if (strcmp("B21",str2) != 0) {
2271 return False;
2274 status = rpc_pipe_open_internal(
2275 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2276 conn->server_info, &samr_pipe);
2277 if (!NT_STATUS_IS_OK(status)) {
2278 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2279 nt_errstr(status)));
2280 return false;
2283 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2284 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2285 if (!NT_STATUS_IS_OK(status)) {
2286 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2287 nt_errstr(status)));
2288 return false;
2291 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2292 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2293 get_global_sam_sid(), &domain_handle);
2294 if (!NT_STATUS_IS_OK(status)) {
2295 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2296 nt_errstr(status)));
2297 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2298 return false;
2301 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2302 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2303 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2304 "%d\n", resume_context, cli_buf_size));
2306 *rdata_len = cli_buf_size;
2307 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2308 if (!*rdata) {
2309 return False;
2312 p = *rdata;
2314 errflags = NERR_Success;
2315 num_groups = 0;
2316 resume_handle = 0;
2318 while (true) {
2319 struct samr_SamArray *sam_entries;
2320 uint32_t num_entries;
2322 status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
2323 &domain_handle,
2324 &resume_handle,
2325 &sam_entries, 1,
2326 &num_entries);
2327 if (!NT_STATUS_IS_OK(status)) {
2328 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2329 "%s\n", nt_errstr(status)));
2330 break;
2333 if (num_entries == 0) {
2334 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2335 "no entries -- done\n"));
2336 break;
2339 for(i=0; i<num_entries; i++) {
2340 const char *name;
2342 name = sam_entries->entries[i].name.string;
2344 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2345 /* set overflow error */
2346 DEBUG(3,("overflow on entry %d group %s\n", i,
2347 name));
2348 errflags=234;
2349 break;
2352 /* truncate the name at 21 chars. */
2353 memset(p, 0, 21);
2354 strlcpy(p, name, 21);
2355 DEBUG(10,("adding entry %d group %s\n", i, p));
2356 p += 21;
2357 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2358 * idea why... */
2359 num_groups += 1;
2362 if (errflags != NERR_Success) {
2363 break;
2366 TALLOC_FREE(sam_entries);
2369 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2370 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2372 *rdata_len = PTR_DIFF(p,*rdata);
2374 *rparam_len = 8;
2375 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2376 if (!*rparam) {
2377 return False;
2379 SSVAL(*rparam, 0, errflags);
2380 SSVAL(*rparam, 2, 0); /* converter word */
2381 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2382 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2384 return(True);
2387 /*******************************************************************
2388 Get groups that a user is a member of.
2389 ******************************************************************/
2391 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2392 char *param, int tpscnt,
2393 char *data, int tdscnt,
2394 int mdrcnt,int mprcnt,
2395 char **rdata,char **rparam,
2396 int *rdata_len,int *rparam_len)
2398 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2399 char *str2 = skip_string(param,tpscnt,str1);
2400 char *UserName = skip_string(param,tpscnt,str2);
2401 char *p = skip_string(param,tpscnt,UserName);
2402 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2403 const char *level_string;
2404 int count=0;
2405 bool ret = False;
2406 uint32_t i;
2407 char *endp = NULL;
2409 struct rpc_pipe_client *samr_pipe;
2410 struct policy_handle samr_handle, domain_handle, user_handle;
2411 struct lsa_String name;
2412 struct lsa_Strings names;
2413 struct samr_Ids type, rid;
2414 struct samr_RidWithAttributeArray *rids;
2415 NTSTATUS status;
2417 if (!str1 || !str2 || !UserName || !p) {
2418 return False;
2421 *rparam_len = 8;
2422 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2423 if (!*rparam) {
2424 return False;
2427 /* check it's a supported varient */
2429 if ( strcmp(str1,"zWrLeh") != 0 )
2430 return False;
2432 switch( uLevel ) {
2433 case 0:
2434 level_string = "B21";
2435 break;
2436 default:
2437 return False;
2440 if (strcmp(level_string,str2) != 0)
2441 return False;
2443 *rdata_len = mdrcnt + 1024;
2444 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2445 if (!*rdata) {
2446 return False;
2449 SSVAL(*rparam,0,NERR_Success);
2450 SSVAL(*rparam,2,0); /* converter word */
2452 p = *rdata;
2453 endp = *rdata + *rdata_len;
2455 status = rpc_pipe_open_internal(
2456 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2457 conn->server_info, &samr_pipe);
2458 if (!NT_STATUS_IS_OK(status)) {
2459 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2460 nt_errstr(status)));
2461 return false;
2464 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2465 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2466 if (!NT_STATUS_IS_OK(status)) {
2467 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2468 nt_errstr(status)));
2469 return false;
2472 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2473 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2474 get_global_sam_sid(), &domain_handle);
2475 if (!NT_STATUS_IS_OK(status)) {
2476 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2477 nt_errstr(status)));
2478 goto close_sam;
2481 name.string = UserName;
2483 status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
2484 &domain_handle, 1, &name,
2485 &rid, &type);
2486 if (!NT_STATUS_IS_OK(status)) {
2487 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2488 nt_errstr(status)));
2489 goto close_domain;
2492 if (type.ids[0] != SID_NAME_USER) {
2493 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2494 sid_type_lookup(type.ids[0])));
2495 goto close_domain;
2498 status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
2499 &domain_handle,
2500 SAMR_USER_ACCESS_GET_GROUPS,
2501 rid.ids[0], &user_handle);
2502 if (!NT_STATUS_IS_OK(status)) {
2503 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2504 nt_errstr(status)));
2505 goto close_domain;
2508 status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
2509 &user_handle, &rids);
2510 if (!NT_STATUS_IS_OK(status)) {
2511 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2512 nt_errstr(status)));
2513 goto close_user;
2516 for (i=0; i<rids->count; i++) {
2518 status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
2519 &domain_handle,
2520 1, &rids->rids[i].rid,
2521 &names, &type);
2522 if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
2523 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2524 p += 21;
2525 count++;
2529 *rdata_len = PTR_DIFF(p,*rdata);
2531 SSVAL(*rparam,4,count); /* is this right?? */
2532 SSVAL(*rparam,6,count); /* is this right?? */
2534 ret = True;
2536 close_user:
2537 rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
2538 close_domain:
2539 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2540 close_sam:
2541 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2543 return ret;
2546 /*******************************************************************
2547 Get all users.
2548 ******************************************************************/
2550 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2551 char *param, int tpscnt,
2552 char *data, int tdscnt,
2553 int mdrcnt,int mprcnt,
2554 char **rdata,char **rparam,
2555 int *rdata_len,int *rparam_len)
2557 int count_sent=0;
2558 int num_users=0;
2559 int errflags=0;
2560 int i, resume_context, cli_buf_size;
2561 uint32_t resume_handle;
2563 struct rpc_pipe_client *samr_pipe;
2564 struct policy_handle samr_handle, domain_handle;
2565 NTSTATUS status;
2567 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2568 char *str2 = skip_string(param,tpscnt,str1);
2569 char *p = skip_string(param,tpscnt,str2);
2570 char *endp = NULL;
2572 if (!str1 || !str2 || !p) {
2573 return False;
2576 if (strcmp(str1,"WrLeh") != 0)
2577 return False;
2578 /* parameters
2579 * W-> resume context (number of users to skip)
2580 * r -> return parameter pointer to receive buffer
2581 * L -> length of receive buffer
2582 * e -> return parameter number of entries
2583 * h -> return parameter total number of users
2586 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2587 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2588 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2589 resume_context, cli_buf_size));
2591 *rparam_len = 8;
2592 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2593 if (!*rparam) {
2594 return False;
2597 /* check it's a supported varient */
2598 if (strcmp("B21",str2) != 0)
2599 return False;
2601 *rdata_len = cli_buf_size;
2602 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2603 if (!*rdata) {
2604 return False;
2607 p = *rdata;
2608 endp = *rdata + *rdata_len;
2610 status = rpc_pipe_open_internal(
2611 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2612 conn->server_info, &samr_pipe);
2613 if (!NT_STATUS_IS_OK(status)) {
2614 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2615 nt_errstr(status)));
2616 return false;
2619 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2620 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2621 if (!NT_STATUS_IS_OK(status)) {
2622 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2623 nt_errstr(status)));
2624 return false;
2627 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2628 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2629 get_global_sam_sid(), &domain_handle);
2630 if (!NT_STATUS_IS_OK(status)) {
2631 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2632 nt_errstr(status)));
2633 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2634 return false;
2637 errflags=NERR_Success;
2639 resume_handle = 0;
2641 while (true) {
2642 struct samr_SamArray *sam_entries;
2643 uint32_t num_entries;
2645 status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
2646 &domain_handle,
2647 &resume_handle,
2648 0, &sam_entries, 1,
2649 &num_entries);
2651 if (!NT_STATUS_IS_OK(status)) {
2652 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2653 "%s\n", nt_errstr(status)));
2654 break;
2657 if (num_entries == 0) {
2658 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2659 "no entries -- done\n"));
2660 break;
2663 for (i=0; i<num_entries; i++) {
2664 const char *name;
2666 name = sam_entries->entries[i].name.string;
2668 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2669 &&(strlen(name)<=21)) {
2670 strlcpy(p,name,PTR_DIFF(endp,p));
2671 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2672 "username %s\n",count_sent,p));
2673 p += 21;
2674 count_sent++;
2675 } else {
2676 /* set overflow error */
2677 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2678 "username %s\n",count_sent,name));
2679 errflags=234;
2680 break;
2684 if (errflags != NERR_Success) {
2685 break;
2688 TALLOC_FREE(sam_entries);
2691 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2692 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2694 *rdata_len = PTR_DIFF(p,*rdata);
2696 SSVAL(*rparam,0,errflags);
2697 SSVAL(*rparam,2,0); /* converter word */
2698 SSVAL(*rparam,4,count_sent); /* is this right?? */
2699 SSVAL(*rparam,6,num_users); /* is this right?? */
2701 return True;
2704 /****************************************************************************
2705 Get the time of day info.
2706 ****************************************************************************/
2708 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2709 char *param, int tpscnt,
2710 char *data, int tdscnt,
2711 int mdrcnt,int mprcnt,
2712 char **rdata,char **rparam,
2713 int *rdata_len,int *rparam_len)
2715 struct tm *t;
2716 time_t unixdate = time(NULL);
2717 char *p;
2719 *rparam_len = 4;
2720 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2721 if (!*rparam) {
2722 return False;
2725 *rdata_len = 21;
2726 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2727 if (!*rdata) {
2728 return False;
2731 SSVAL(*rparam,0,NERR_Success);
2732 SSVAL(*rparam,2,0); /* converter word */
2734 p = *rdata;
2736 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2737 by NT in a "net time" operation,
2738 it seems to ignore the one below */
2740 /* the client expects to get localtime, not GMT, in this bit
2741 (I think, this needs testing) */
2742 t = localtime(&unixdate);
2743 if (!t) {
2744 return False;
2747 SIVAL(p,4,0); /* msecs ? */
2748 SCVAL(p,8,t->tm_hour);
2749 SCVAL(p,9,t->tm_min);
2750 SCVAL(p,10,t->tm_sec);
2751 SCVAL(p,11,0); /* hundredths of seconds */
2752 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2753 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2754 SCVAL(p,16,t->tm_mday);
2755 SCVAL(p,17,t->tm_mon + 1);
2756 SSVAL(p,18,1900+t->tm_year);
2757 SCVAL(p,20,t->tm_wday);
2759 return True;
2762 /****************************************************************************
2763 Set the user password.
2764 *****************************************************************************/
2766 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2767 char *param, int tpscnt,
2768 char *data, int tdscnt,
2769 int mdrcnt,int mprcnt,
2770 char **rdata,char **rparam,
2771 int *rdata_len,int *rparam_len)
2773 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2774 char *p = NULL;
2775 fstring user;
2776 fstring pass1,pass2;
2778 /* Skip 2 strings. */
2779 p = skip_string(param,tpscnt,np);
2780 p = skip_string(param,tpscnt,p);
2782 if (!np || !p) {
2783 return False;
2786 /* Do we have a string ? */
2787 if (skip_string(param,tpscnt,p) == NULL) {
2788 return False;
2790 pull_ascii_fstring(user,p);
2792 p = skip_string(param,tpscnt,p);
2793 if (!p) {
2794 return False;
2797 memset(pass1,'\0',sizeof(pass1));
2798 memset(pass2,'\0',sizeof(pass2));
2800 * We use 31 here not 32 as we're checking
2801 * the last byte we want to access is safe.
2803 if (!is_offset_safe(param,tpscnt,p,31)) {
2804 return False;
2806 memcpy(pass1,p,16);
2807 memcpy(pass2,p+16,16);
2809 *rparam_len = 4;
2810 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2811 if (!*rparam) {
2812 return False;
2815 *rdata_len = 0;
2817 SSVAL(*rparam,0,NERR_badpass);
2818 SSVAL(*rparam,2,0); /* converter word */
2820 DEBUG(3,("Set password for <%s>\n",user));
2823 * Attempt to verify the old password against smbpasswd entries
2824 * Win98 clients send old and new password in plaintext for this call.
2828 struct auth_serversupplied_info *server_info = NULL;
2829 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2831 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2833 become_root();
2834 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2835 SSVAL(*rparam,0,NERR_Success);
2837 unbecome_root();
2839 TALLOC_FREE(server_info);
2841 data_blob_clear_free(&password);
2845 * If the plaintext change failed, attempt
2846 * the old encrypted method. NT will generate this
2847 * after trying the samr method. Note that this
2848 * method is done as a last resort as this
2849 * password change method loses the NT password hash
2850 * and cannot change the UNIX password as no plaintext
2851 * is received.
2854 if(SVAL(*rparam,0) != NERR_Success) {
2855 struct samu *hnd = NULL;
2857 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2858 become_root();
2859 if (change_lanman_password(hnd,(uchar *)pass2)) {
2860 SSVAL(*rparam,0,NERR_Success);
2862 unbecome_root();
2863 TALLOC_FREE(hnd);
2867 memset((char *)pass1,'\0',sizeof(fstring));
2868 memset((char *)pass2,'\0',sizeof(fstring));
2870 return(True);
2873 /****************************************************************************
2874 Set the user password (SamOEM version - gets plaintext).
2875 ****************************************************************************/
2877 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2878 char *param, int tpscnt,
2879 char *data, int tdscnt,
2880 int mdrcnt,int mprcnt,
2881 char **rdata,char **rparam,
2882 int *rdata_len,int *rparam_len)
2884 struct smbd_server_connection *sconn = smbd_server_conn;
2885 fstring user;
2886 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2887 *rparam_len = 2;
2888 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2889 if (!*rparam) {
2890 return False;
2893 if (!p) {
2894 return False;
2896 *rdata_len = 0;
2898 SSVAL(*rparam,0,NERR_badpass);
2901 * Check the parameter definition is correct.
2904 /* Do we have a string ? */
2905 if (skip_string(param,tpscnt,p) == 0) {
2906 return False;
2908 if(!strequal(p, "zsT")) {
2909 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2910 return False;
2912 p = skip_string(param, tpscnt, p);
2913 if (!p) {
2914 return False;
2917 /* Do we have a string ? */
2918 if (skip_string(param,tpscnt,p) == 0) {
2919 return False;
2921 if(!strequal(p, "B516B16")) {
2922 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2923 return False;
2925 p = skip_string(param,tpscnt,p);
2926 if (!p) {
2927 return False;
2929 /* Do we have a string ? */
2930 if (skip_string(param,tpscnt,p) == 0) {
2931 return False;
2933 p += pull_ascii_fstring(user,p);
2935 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2938 * Pass the user through the NT -> unix user mapping
2939 * function.
2942 (void)map_username(sconn, user);
2944 if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2945 SSVAL(*rparam,0,NERR_Success);
2948 return(True);
2951 /****************************************************************************
2952 delete a print job
2953 Form: <W> <>
2954 ****************************************************************************/
2956 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
2957 char *param, int tpscnt,
2958 char *data, int tdscnt,
2959 int mdrcnt,int mprcnt,
2960 char **rdata,char **rparam,
2961 int *rdata_len,int *rparam_len)
2963 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2964 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2965 char *str2 = skip_string(param,tpscnt,str1);
2966 char *p = skip_string(param,tpscnt,str2);
2967 uint32 jobid;
2968 int snum;
2969 fstring sharename;
2970 int errcode;
2971 WERROR werr = WERR_OK;
2973 if (!str1 || !str2 || !p) {
2974 return False;
2977 * We use 1 here not 2 as we're checking
2978 * the last byte we want to access is safe.
2980 if (!is_offset_safe(param,tpscnt,p,1)) {
2981 return False;
2983 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2984 return False;
2986 /* check it's a supported varient */
2987 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2988 return(False);
2990 *rparam_len = 4;
2991 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2992 if (!*rparam) {
2993 return False;
2995 *rdata_len = 0;
2997 if (!print_job_exists(sharename, jobid)) {
2998 errcode = NERR_JobNotFound;
2999 goto out;
3002 snum = lp_servicenumber( sharename);
3003 if (snum == -1) {
3004 errcode = NERR_DestNotFound;
3005 goto out;
3008 errcode = NERR_notsupported;
3010 switch (function) {
3011 case 81: /* delete */
3012 if (print_job_delete(conn->server_info, snum, jobid, &werr))
3013 errcode = NERR_Success;
3014 break;
3015 case 82: /* pause */
3016 if (print_job_pause(conn->server_info, snum, jobid, &werr))
3017 errcode = NERR_Success;
3018 break;
3019 case 83: /* resume */
3020 if (print_job_resume(conn->server_info, snum, jobid, &werr))
3021 errcode = NERR_Success;
3022 break;
3025 if (!W_ERROR_IS_OK(werr))
3026 errcode = W_ERROR_V(werr);
3028 out:
3029 SSVAL(*rparam,0,errcode);
3030 SSVAL(*rparam,2,0); /* converter word */
3032 return(True);
3035 /****************************************************************************
3036 Purge a print queue - or pause or resume it.
3037 ****************************************************************************/
3039 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
3040 char *param, int tpscnt,
3041 char *data, int tdscnt,
3042 int mdrcnt,int mprcnt,
3043 char **rdata,char **rparam,
3044 int *rdata_len,int *rparam_len)
3046 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3047 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3048 char *str2 = skip_string(param,tpscnt,str1);
3049 char *QueueName = skip_string(param,tpscnt,str2);
3050 int errcode = NERR_notsupported;
3051 int snum;
3052 WERROR werr = WERR_OK;
3054 if (!str1 || !str2 || !QueueName) {
3055 return False;
3058 /* check it's a supported varient */
3059 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3060 return(False);
3062 *rparam_len = 4;
3063 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3064 if (!*rparam) {
3065 return False;
3067 *rdata_len = 0;
3069 if (skip_string(param,tpscnt,QueueName) == NULL) {
3070 return False;
3072 snum = print_queue_snum(QueueName);
3074 if (snum == -1) {
3075 errcode = NERR_JobNotFound;
3076 goto out;
3079 switch (function) {
3080 case 74: /* Pause queue */
3081 werr = print_queue_pause(conn->server_info, snum);
3082 break;
3083 case 75: /* Resume queue */
3084 werr = print_queue_resume(conn->server_info, snum);
3085 break;
3086 case 103: /* Purge */
3087 werr = print_queue_purge(conn->server_info, snum);
3088 break;
3089 default:
3090 werr = WERR_NOT_SUPPORTED;
3091 break;
3094 errcode = W_ERROR_V(werr);
3096 out:
3097 SSVAL(*rparam,0,errcode);
3098 SSVAL(*rparam,2,0); /* converter word */
3100 return(True);
3103 /****************************************************************************
3104 set the property of a print job (undocumented?)
3105 ? function = 0xb -> set name of print job
3106 ? function = 0x6 -> move print job up/down
3107 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3108 or <WWsTP> <WB21BB16B10zWWzDDz>
3109 ****************************************************************************/
3111 static int check_printjob_info(struct pack_desc* desc,
3112 int uLevel, char* id)
3114 desc->subformat = NULL;
3115 switch( uLevel ) {
3116 case 0: desc->format = "W"; break;
3117 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3118 case 2: desc->format = "WWzWWDDzz"; break;
3119 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3120 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3121 default:
3122 DEBUG(0,("check_printjob_info: invalid level %d\n",
3123 uLevel ));
3124 return False;
3126 if (id == NULL || strcmp(desc->format,id) != 0) {
3127 DEBUG(0,("check_printjob_info: invalid format %s\n",
3128 id ? id : "<NULL>" ));
3129 return False;
3131 return True;
3134 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
3135 char *param, int tpscnt,
3136 char *data, int tdscnt,
3137 int mdrcnt,int mprcnt,
3138 char **rdata,char **rparam,
3139 int *rdata_len,int *rparam_len)
3141 struct pack_desc desc;
3142 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3143 char *str2 = skip_string(param,tpscnt,str1);
3144 char *p = skip_string(param,tpscnt,str2);
3145 uint32 jobid;
3146 fstring sharename;
3147 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3148 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3149 int place, errcode;
3151 if (!str1 || !str2 || !p) {
3152 return False;
3155 * We use 1 here not 2 as we're checking
3156 * the last byte we want to access is safe.
3158 if (!is_offset_safe(param,tpscnt,p,1)) {
3159 return False;
3161 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3162 return False;
3163 *rparam_len = 4;
3164 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3165 if (!*rparam) {
3166 return False;
3169 if (!share_defined(sharename)) {
3170 DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
3171 sharename));
3172 return False;
3175 *rdata_len = 0;
3177 /* check it's a supported varient */
3178 if ((strcmp(str1,"WWsTP")) ||
3179 (!check_printjob_info(&desc,uLevel,str2)))
3180 return(False);
3182 if (!print_job_exists(sharename, jobid)) {
3183 errcode=NERR_JobNotFound;
3184 goto out;
3187 errcode = NERR_notsupported;
3189 switch (function) {
3190 case 0x6:
3191 /* change job place in the queue,
3192 data gives the new place */
3193 place = SVAL(data,0);
3194 if (print_job_set_place(sharename, jobid, place)) {
3195 errcode=NERR_Success;
3197 break;
3199 case 0xb:
3200 /* change print job name, data gives the name */
3201 if (print_job_set_name(sharename, jobid, data)) {
3202 errcode=NERR_Success;
3204 break;
3206 default:
3207 return False;
3210 out:
3211 SSVALS(*rparam,0,errcode);
3212 SSVAL(*rparam,2,0); /* converter word */
3214 return(True);
3218 /****************************************************************************
3219 Get info about the server.
3220 ****************************************************************************/
3222 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
3223 char *param, int tpscnt,
3224 char *data, int tdscnt,
3225 int mdrcnt,int mprcnt,
3226 char **rdata,char **rparam,
3227 int *rdata_len,int *rparam_len)
3229 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3230 char *str2 = skip_string(param,tpscnt,str1);
3231 char *p = skip_string(param,tpscnt,str2);
3232 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3233 char *p2;
3234 int struct_len;
3236 if (!str1 || !str2 || !p) {
3237 return False;
3240 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3242 /* check it's a supported varient */
3243 if (!prefix_ok(str1,"WrLh")) {
3244 return False;
3247 switch( uLevel ) {
3248 case 0:
3249 if (strcmp(str2,"B16") != 0) {
3250 return False;
3252 struct_len = 16;
3253 break;
3254 case 1:
3255 if (strcmp(str2,"B16BBDz") != 0) {
3256 return False;
3258 struct_len = 26;
3259 break;
3260 case 2:
3261 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3262 return False;
3264 struct_len = 134;
3265 break;
3266 case 3:
3267 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3268 return False;
3270 struct_len = 144;
3271 break;
3272 case 20:
3273 if (strcmp(str2,"DN") != 0) {
3274 return False;
3276 struct_len = 6;
3277 break;
3278 case 50:
3279 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3280 return False;
3282 struct_len = 42;
3283 break;
3284 default:
3285 return False;
3288 *rdata_len = mdrcnt;
3289 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3290 if (!*rdata) {
3291 return False;
3294 p = *rdata;
3295 p2 = p + struct_len;
3296 if (uLevel != 20) {
3297 srvstr_push(NULL, 0, p,global_myname(),16,
3298 STR_ASCII|STR_UPPER|STR_TERMINATE);
3300 p += 16;
3301 if (uLevel > 0) {
3302 struct srv_info_struct *servers=NULL;
3303 int i,count;
3304 char *comment = NULL;
3305 TALLOC_CTX *ctx = talloc_tos();
3306 uint32 servertype= lp_default_server_announce();
3308 comment = talloc_strdup(ctx,lp_serverstring());
3309 if (!comment) {
3310 return false;
3313 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
3314 for (i=0;i<count;i++) {
3315 if (strequal(servers[i].name,global_myname())) {
3316 servertype = servers[i].type;
3317 TALLOC_FREE(comment);
3318 comment = talloc_strdup(ctx,
3319 servers[i].comment);
3320 if (comment) {
3321 return false;
3327 SAFE_FREE(servers);
3329 SCVAL(p,0,lp_major_announce_version());
3330 SCVAL(p,1,lp_minor_announce_version());
3331 SIVAL(p,2,servertype);
3333 if (mdrcnt == struct_len) {
3334 SIVAL(p,6,0);
3335 } else {
3336 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3337 comment = talloc_sub_advanced(
3338 ctx,
3339 lp_servicename(SNUM(conn)),
3340 conn->server_info->unix_name,
3341 conn->connectpath,
3342 conn->server_info->utok.gid,
3343 conn->server_info->sanitized_username,
3344 pdb_get_domain(conn->server_info->sam_account),
3345 comment);
3346 if (comment) {
3347 return false;
3349 if (mdrcnt - struct_len <= 0) {
3350 return false;
3352 push_ascii(p2,
3353 comment,
3354 MIN(mdrcnt - struct_len,
3355 MAX_SERVER_STRING_LENGTH),
3356 STR_TERMINATE);
3357 p2 = skip_string(*rdata,*rdata_len,p2);
3358 if (!p2) {
3359 return False;
3364 if (uLevel > 1) {
3365 return False; /* not yet implemented */
3368 *rdata_len = PTR_DIFF(p2,*rdata);
3370 *rparam_len = 6;
3371 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3372 if (!*rparam) {
3373 return False;
3375 SSVAL(*rparam,0,NERR_Success);
3376 SSVAL(*rparam,2,0); /* converter word */
3377 SSVAL(*rparam,4,*rdata_len);
3379 return True;
3382 /****************************************************************************
3383 Get info about the server.
3384 ****************************************************************************/
3386 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3387 char *param, int tpscnt,
3388 char *data, int tdscnt,
3389 int mdrcnt,int mprcnt,
3390 char **rdata,char **rparam,
3391 int *rdata_len,int *rparam_len)
3393 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3394 char *str2 = skip_string(param,tpscnt,str1);
3395 char *p = skip_string(param,tpscnt,str2);
3396 char *p2;
3397 char *endp;
3398 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3400 if (!str1 || !str2 || !p) {
3401 return False;
3404 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3406 *rparam_len = 6;
3407 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3408 if (!*rparam) {
3409 return False;
3412 /* check it's a supported varient */
3413 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3414 return False;
3417 *rdata_len = mdrcnt + 1024;
3418 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3419 if (!*rdata) {
3420 return False;
3423 SSVAL(*rparam,0,NERR_Success);
3424 SSVAL(*rparam,2,0); /* converter word */
3426 p = *rdata;
3427 endp = *rdata + *rdata_len;
3429 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3430 if (!p2) {
3431 return False;
3434 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3435 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3436 strupper_m(p2);
3437 p2 = skip_string(*rdata,*rdata_len,p2);
3438 if (!p2) {
3439 return False;
3441 p += 4;
3443 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3444 strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3445 p2 = skip_string(*rdata,*rdata_len,p2);
3446 if (!p2) {
3447 return False;
3449 p += 4;
3451 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3452 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3453 strupper_m(p2);
3454 p2 = skip_string(*rdata,*rdata_len,p2);
3455 if (!p2) {
3456 return False;
3458 p += 4;
3460 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3461 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3462 p += 2;
3464 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3465 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3466 p2 = skip_string(*rdata,*rdata_len,p2);
3467 if (!p2) {
3468 return False;
3470 p += 4;
3472 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3473 strlcpy(p2,"",PTR_DIFF(endp,p2));
3474 p2 = skip_string(*rdata,*rdata_len,p2);
3475 if (!p2) {
3476 return False;
3478 p += 4;
3480 *rdata_len = PTR_DIFF(p2,*rdata);
3482 SSVAL(*rparam,4,*rdata_len);
3484 return True;
3487 /****************************************************************************
3488 get info about a user
3490 struct user_info_11 {
3491 char usri11_name[21]; 0-20
3492 char usri11_pad; 21
3493 char *usri11_comment; 22-25
3494 char *usri11_usr_comment; 26-29
3495 unsigned short usri11_priv; 30-31
3496 unsigned long usri11_auth_flags; 32-35
3497 long usri11_password_age; 36-39
3498 char *usri11_homedir; 40-43
3499 char *usri11_parms; 44-47
3500 long usri11_last_logon; 48-51
3501 long usri11_last_logoff; 52-55
3502 unsigned short usri11_bad_pw_count; 56-57
3503 unsigned short usri11_num_logons; 58-59
3504 char *usri11_logon_server; 60-63
3505 unsigned short usri11_country_code; 64-65
3506 char *usri11_workstations; 66-69
3507 unsigned long usri11_max_storage; 70-73
3508 unsigned short usri11_units_per_week; 74-75
3509 unsigned char *usri11_logon_hours; 76-79
3510 unsigned short usri11_code_page; 80-81
3513 where:
3515 usri11_name specifies the user name for which information is retrieved
3517 usri11_pad aligns the next data structure element to a word boundary
3519 usri11_comment is a null terminated ASCII comment
3521 usri11_user_comment is a null terminated ASCII comment about the user
3523 usri11_priv specifies the level of the privilege assigned to the user.
3524 The possible values are:
3526 Name Value Description
3527 USER_PRIV_GUEST 0 Guest privilege
3528 USER_PRIV_USER 1 User privilege
3529 USER_PRV_ADMIN 2 Administrator privilege
3531 usri11_auth_flags specifies the account operator privileges. The
3532 possible values are:
3534 Name Value Description
3535 AF_OP_PRINT 0 Print operator
3538 Leach, Naik [Page 28]
3542 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3545 AF_OP_COMM 1 Communications operator
3546 AF_OP_SERVER 2 Server operator
3547 AF_OP_ACCOUNTS 3 Accounts operator
3550 usri11_password_age specifies how many seconds have elapsed since the
3551 password was last changed.
3553 usri11_home_dir points to a null terminated ASCII string that contains
3554 the path name of the user's home directory.
3556 usri11_parms points to a null terminated ASCII string that is set
3557 aside for use by applications.
3559 usri11_last_logon specifies the time when the user last logged on.
3560 This value is stored as the number of seconds elapsed since
3561 00:00:00, January 1, 1970.
3563 usri11_last_logoff specifies the time when the user last logged off.
3564 This value is stored as the number of seconds elapsed since
3565 00:00:00, January 1, 1970. A value of 0 means the last logoff
3566 time is unknown.
3568 usri11_bad_pw_count specifies the number of incorrect passwords
3569 entered since the last successful logon.
3571 usri11_log1_num_logons specifies the number of times this user has
3572 logged on. A value of -1 means the number of logons is unknown.
3574 usri11_logon_server points to a null terminated ASCII string that
3575 contains the name of the server to which logon requests are sent.
3576 A null string indicates logon requests should be sent to the
3577 domain controller.
3579 usri11_country_code specifies the country code for the user's language
3580 of choice.
3582 usri11_workstations points to a null terminated ASCII string that
3583 contains the names of workstations the user may log on from.
3584 There may be up to 8 workstations, with the names separated by
3585 commas. A null strings indicates there are no restrictions.
3587 usri11_max_storage specifies the maximum amount of disk space the user
3588 can occupy. A value of 0xffffffff indicates there are no
3589 restrictions.
3591 usri11_units_per_week specifies the equal number of time units into
3592 which a week is divided. This value must be equal to 168.
3594 usri11_logon_hours points to a 21 byte (168 bits) string that
3595 specifies the time during which the user can log on. Each bit
3596 represents one unique hour in a week. The first bit (bit 0, word
3597 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3601 Leach, Naik [Page 29]
3605 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3608 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3609 are no restrictions.
3611 usri11_code_page specifies the code page for the user's language of
3612 choice
3614 All of the pointers in this data structure need to be treated
3615 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3616 to be ignored. The converter word returned in the parameters section
3617 needs to be subtracted from the lower 16 bits to calculate an offset
3618 into the return buffer where this ASCII string resides.
3620 There is no auxiliary data in the response.
3622 ****************************************************************************/
3624 #define usri11_name 0
3625 #define usri11_pad 21
3626 #define usri11_comment 22
3627 #define usri11_usr_comment 26
3628 #define usri11_full_name 30
3629 #define usri11_priv 34
3630 #define usri11_auth_flags 36
3631 #define usri11_password_age 40
3632 #define usri11_homedir 44
3633 #define usri11_parms 48
3634 #define usri11_last_logon 52
3635 #define usri11_last_logoff 56
3636 #define usri11_bad_pw_count 60
3637 #define usri11_num_logons 62
3638 #define usri11_logon_server 64
3639 #define usri11_country_code 68
3640 #define usri11_workstations 70
3641 #define usri11_max_storage 74
3642 #define usri11_units_per_week 78
3643 #define usri11_logon_hours 80
3644 #define usri11_code_page 84
3645 #define usri11_end 86
3647 #define USER_PRIV_GUEST 0
3648 #define USER_PRIV_USER 1
3649 #define USER_PRIV_ADMIN 2
3651 #define AF_OP_PRINT 0
3652 #define AF_OP_COMM 1
3653 #define AF_OP_SERVER 2
3654 #define AF_OP_ACCOUNTS 3
3657 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3658 char *param, int tpscnt,
3659 char *data, int tdscnt,
3660 int mdrcnt,int mprcnt,
3661 char **rdata,char **rparam,
3662 int *rdata_len,int *rparam_len)
3664 struct smbd_server_connection *sconn = smbd_server_conn;
3665 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3666 char *str2 = skip_string(param,tpscnt,str1);
3667 char *UserName = skip_string(param,tpscnt,str2);
3668 char *p = skip_string(param,tpscnt,UserName);
3669 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3670 char *p2;
3671 char *endp;
3672 const char *level_string;
3674 /* get NIS home of a previously validated user - simeon */
3675 /* With share level security vuid will always be zero.
3676 Don't depend on vuser being non-null !!. JRA */
3677 user_struct *vuser = get_valid_user_struct(sconn, vuid);
3678 if(vuser != NULL) {
3679 DEBUG(3,(" Username of UID %d is %s\n",
3680 (int)vuser->server_info->utok.uid,
3681 vuser->server_info->unix_name));
3684 if (!str1 || !str2 || !UserName || !p) {
3685 return False;
3688 *rparam_len = 6;
3689 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3690 if (!*rparam) {
3691 return False;
3694 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3696 /* check it's a supported variant */
3697 if (strcmp(str1,"zWrLh") != 0) {
3698 return False;
3700 switch( uLevel ) {
3701 case 0: level_string = "B21"; break;
3702 case 1: level_string = "B21BB16DWzzWz"; break;
3703 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3704 case 10: level_string = "B21Bzzz"; break;
3705 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3706 default: return False;
3709 if (strcmp(level_string,str2) != 0) {
3710 return False;
3713 *rdata_len = mdrcnt + 1024;
3714 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3715 if (!*rdata) {
3716 return False;
3719 SSVAL(*rparam,0,NERR_Success);
3720 SSVAL(*rparam,2,0); /* converter word */
3722 p = *rdata;
3723 endp = *rdata + *rdata_len;
3724 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3725 if (!p2) {
3726 return False;
3729 memset(p,0,21);
3730 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3732 if (uLevel > 0) {
3733 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3734 *p2 = 0;
3737 if (uLevel >= 10) {
3738 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3739 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
3740 p2 = skip_string(*rdata,*rdata_len,p2);
3741 if (!p2) {
3742 return False;
3745 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3746 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
3747 p2 = skip_string(*rdata,*rdata_len,p2);
3748 if (!p2) {
3749 return False;
3752 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3753 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3754 strlcpy(p2,((vuser != NULL)
3755 ? pdb_get_fullname(vuser->server_info->sam_account)
3756 : UserName),PTR_DIFF(endp,p2));
3757 p2 = skip_string(*rdata,*rdata_len,p2);
3758 if (!p2) {
3759 return False;
3763 if (uLevel == 11) {
3764 const char *homedir = "";
3765 if (vuser != NULL) {
3766 homedir = pdb_get_homedir(
3767 vuser->server_info->sam_account);
3769 /* modelled after NTAS 3.51 reply */
3770 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3771 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
3772 SIVALS(p,usri11_password_age,-1); /* password age */
3773 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3774 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
3775 p2 = skip_string(*rdata,*rdata_len,p2);
3776 if (!p2) {
3777 return False;
3779 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3780 strlcpy(p2,"",PTR_DIFF(endp,p2));
3781 p2 = skip_string(*rdata,*rdata_len,p2);
3782 if (!p2) {
3783 return False;
3785 SIVAL(p,usri11_last_logon,0); /* last logon */
3786 SIVAL(p,usri11_last_logoff,0); /* last logoff */
3787 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
3788 SSVALS(p,usri11_num_logons,-1); /* num logons */
3789 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3790 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
3791 p2 = skip_string(*rdata,*rdata_len,p2);
3792 if (!p2) {
3793 return False;
3795 SSVAL(p,usri11_country_code,0); /* country code */
3797 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3798 strlcpy(p2,"",PTR_DIFF(endp,p2));
3799 p2 = skip_string(*rdata,*rdata_len,p2);
3800 if (!p2) {
3801 return False;
3804 SIVALS(p,usri11_max_storage,-1); /* max storage */
3805 SSVAL(p,usri11_units_per_week,168); /* units per week */
3806 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
3808 /* a simple way to get logon hours at all times. */
3809 memset(p2,0xff,21);
3810 SCVAL(p2,21,0); /* fix zero termination */
3811 p2 = skip_string(*rdata,*rdata_len,p2);
3812 if (!p2) {
3813 return False;
3816 SSVAL(p,usri11_code_page,0); /* code page */
3819 if (uLevel == 1 || uLevel == 2) {
3820 memset(p+22,' ',16); /* password */
3821 SIVALS(p,38,-1); /* password age */
3822 SSVAL(p,42,
3823 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3824 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
3825 strlcpy(p2, vuser ? pdb_get_homedir(
3826 vuser->server_info->sam_account) : "",
3827 PTR_DIFF(endp,p2));
3828 p2 = skip_string(*rdata,*rdata_len,p2);
3829 if (!p2) {
3830 return False;
3832 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
3833 *p2++ = 0;
3834 SSVAL(p,52,0); /* flags */
3835 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
3836 strlcpy(p2, vuser ? pdb_get_logon_script(
3837 vuser->server_info->sam_account) : "",
3838 PTR_DIFF(endp,p2));
3839 p2 = skip_string(*rdata,*rdata_len,p2);
3840 if (!p2) {
3841 return False;
3843 if (uLevel == 2) {
3844 SIVAL(p,60,0); /* auth_flags */
3845 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
3846 strlcpy(p2,((vuser != NULL)
3847 ? pdb_get_fullname(vuser->server_info->sam_account)
3848 : UserName),PTR_DIFF(endp,p2));
3849 p2 = skip_string(*rdata,*rdata_len,p2);
3850 if (!p2) {
3851 return False;
3853 SIVAL(p,68,0); /* urs_comment */
3854 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
3855 strlcpy(p2,"",PTR_DIFF(endp,p2));
3856 p2 = skip_string(*rdata,*rdata_len,p2);
3857 if (!p2) {
3858 return False;
3860 SIVAL(p,76,0); /* workstations */
3861 SIVAL(p,80,0); /* last_logon */
3862 SIVAL(p,84,0); /* last_logoff */
3863 SIVALS(p,88,-1); /* acct_expires */
3864 SIVALS(p,92,-1); /* max_storage */
3865 SSVAL(p,96,168); /* units_per_week */
3866 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
3867 memset(p2,-1,21);
3868 p2 += 21;
3869 SSVALS(p,102,-1); /* bad_pw_count */
3870 SSVALS(p,104,-1); /* num_logons */
3871 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
3873 TALLOC_CTX *ctx = talloc_tos();
3874 int space_rem = *rdata_len - (p2 - *rdata);
3875 char *tmp;
3877 if (space_rem <= 0) {
3878 return false;
3880 tmp = talloc_strdup(ctx, "\\\\%L");
3881 if (!tmp) {
3882 return false;
3884 tmp = talloc_sub_basic(ctx,
3887 tmp);
3888 if (!tmp) {
3889 return false;
3892 push_ascii(p2,
3893 tmp,
3894 space_rem,
3895 STR_TERMINATE);
3897 p2 = skip_string(*rdata,*rdata_len,p2);
3898 if (!p2) {
3899 return False;
3901 SSVAL(p,110,49); /* country_code */
3902 SSVAL(p,112,860); /* code page */
3906 *rdata_len = PTR_DIFF(p2,*rdata);
3908 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
3910 return(True);
3913 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
3914 char *param, int tpscnt,
3915 char *data, int tdscnt,
3916 int mdrcnt,int mprcnt,
3917 char **rdata,char **rparam,
3918 int *rdata_len,int *rparam_len)
3920 struct smbd_server_connection *sconn = smbd_server_conn;
3921 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3922 char *str2 = skip_string(param,tpscnt,str1);
3923 char *p = skip_string(param,tpscnt,str2);
3924 int uLevel;
3925 struct pack_desc desc;
3926 char* name;
3927 /* With share level security vuid will always be zero.
3928 Don't depend on vuser being non-null !!. JRA */
3929 user_struct *vuser = get_valid_user_struct(sconn, vuid);
3931 if (!str1 || !str2 || !p) {
3932 return False;
3935 if(vuser != NULL) {
3936 DEBUG(3,(" Username of UID %d is %s\n",
3937 (int)vuser->server_info->utok.uid,
3938 vuser->server_info->unix_name));
3941 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3942 name = get_safe_str_ptr(param,tpscnt,p,2);
3943 if (!name) {
3944 return False;
3947 memset((char *)&desc,'\0',sizeof(desc));
3949 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
3951 /* check it's a supported varient */
3952 if (strcmp(str1,"OOWb54WrLh") != 0) {
3953 return False;
3955 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
3956 return False;
3958 if (mdrcnt > 0) {
3959 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3960 if (!*rdata) {
3961 return False;
3965 desc.base = *rdata;
3966 desc.buflen = mdrcnt;
3967 desc.subformat = NULL;
3968 desc.format = str2;
3970 if (init_package(&desc,1,0)) {
3971 PACKI(&desc,"W",0); /* code */
3972 PACKS(&desc,"B21",name); /* eff. name */
3973 PACKS(&desc,"B",""); /* pad */
3974 PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3975 PACKI(&desc,"D",0); /* auth flags XXX */
3976 PACKI(&desc,"W",0); /* num logons */
3977 PACKI(&desc,"W",0); /* bad pw count */
3978 PACKI(&desc,"D",0); /* last logon */
3979 PACKI(&desc,"D",-1); /* last logoff */
3980 PACKI(&desc,"D",-1); /* logoff time */
3981 PACKI(&desc,"D",-1); /* kickoff time */
3982 PACKI(&desc,"D",0); /* password age */
3983 PACKI(&desc,"D",0); /* password can change */
3984 PACKI(&desc,"D",-1); /* password must change */
3987 fstring mypath;
3988 fstrcpy(mypath,"\\\\");
3989 fstrcat(mypath,get_local_machine_name());
3990 strupper_m(mypath);
3991 PACKS(&desc,"z",mypath); /* computer */
3994 PACKS(&desc,"z",lp_workgroup());/* domain */
3995 PACKS(&desc,"z", vuser ? pdb_get_logon_script(
3996 vuser->server_info->sam_account) : ""); /* script path */
3997 PACKI(&desc,"D",0x00000000); /* reserved */
4000 *rdata_len = desc.usedlen;
4001 *rparam_len = 6;
4002 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4003 if (!*rparam) {
4004 return False;
4006 SSVALS(*rparam,0,desc.errcode);
4007 SSVAL(*rparam,2,0);
4008 SSVAL(*rparam,4,desc.neededlen);
4010 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4012 return True;
4015 /****************************************************************************
4016 api_WAccessGetUserPerms
4017 ****************************************************************************/
4019 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
4020 char *param, int tpscnt,
4021 char *data, int tdscnt,
4022 int mdrcnt,int mprcnt,
4023 char **rdata,char **rparam,
4024 int *rdata_len,int *rparam_len)
4026 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4027 char *str2 = skip_string(param,tpscnt,str1);
4028 char *user = skip_string(param,tpscnt,str2);
4029 char *resource = skip_string(param,tpscnt,user);
4031 if (!str1 || !str2 || !user || !resource) {
4032 return False;
4035 if (skip_string(param,tpscnt,resource) == NULL) {
4036 return False;
4038 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4040 /* check it's a supported varient */
4041 if (strcmp(str1,"zzh") != 0) {
4042 return False;
4044 if (strcmp(str2,"") != 0) {
4045 return False;
4048 *rparam_len = 6;
4049 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4050 if (!*rparam) {
4051 return False;
4053 SSVALS(*rparam,0,0); /* errorcode */
4054 SSVAL(*rparam,2,0); /* converter word */
4055 SSVAL(*rparam,4,0x7f); /* permission flags */
4057 return True;
4060 /****************************************************************************
4061 api_WPrintJobEnumerate
4062 ****************************************************************************/
4064 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
4065 char *param, int tpscnt,
4066 char *data, int tdscnt,
4067 int mdrcnt,int mprcnt,
4068 char **rdata,char **rparam,
4069 int *rdata_len,int *rparam_len)
4071 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4072 char *str2 = skip_string(param,tpscnt,str1);
4073 char *p = skip_string(param,tpscnt,str2);
4074 int uLevel;
4075 int count;
4076 int i;
4077 int snum;
4078 fstring sharename;
4079 uint32 jobid;
4080 struct pack_desc desc;
4081 print_queue_struct *queue=NULL;
4082 print_status_struct status;
4083 char *tmpdata=NULL;
4085 if (!str1 || !str2 || !p) {
4086 return False;
4089 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4091 memset((char *)&desc,'\0',sizeof(desc));
4092 memset((char *)&status,'\0',sizeof(status));
4094 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4096 /* check it's a supported varient */
4097 if (strcmp(str1,"WWrLh") != 0) {
4098 return False;
4100 if (!check_printjob_info(&desc,uLevel,str2)) {
4101 return False;
4104 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4105 return False;
4108 snum = lp_servicenumber( sharename);
4109 if (snum < 0 || !VALID_SNUM(snum)) {
4110 return(False);
4113 count = print_queue_status(snum,&queue,&status);
4114 for (i = 0; i < count; i++) {
4115 if (queue[i].job == jobid) {
4116 break;
4120 if (mdrcnt > 0) {
4121 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4122 if (!*rdata) {
4123 return False;
4125 desc.base = *rdata;
4126 desc.buflen = mdrcnt;
4127 } else {
4129 * Don't return data but need to get correct length
4130 * init_package will return wrong size if buflen=0
4132 desc.buflen = getlen(desc.format);
4133 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4136 if (init_package(&desc,1,0)) {
4137 if (i < count) {
4138 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
4139 *rdata_len = desc.usedlen;
4140 } else {
4141 desc.errcode = NERR_JobNotFound;
4142 *rdata_len = 0;
4146 *rparam_len = 6;
4147 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4148 if (!*rparam) {
4149 return False;
4151 SSVALS(*rparam,0,desc.errcode);
4152 SSVAL(*rparam,2,0);
4153 SSVAL(*rparam,4,desc.neededlen);
4155 SAFE_FREE(queue);
4156 SAFE_FREE(tmpdata);
4158 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4160 return True;
4163 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
4164 char *param, int tpscnt,
4165 char *data, int tdscnt,
4166 int mdrcnt,int mprcnt,
4167 char **rdata,char **rparam,
4168 int *rdata_len,int *rparam_len)
4170 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4171 char *str2 = skip_string(param,tpscnt,str1);
4172 char *p = skip_string(param,tpscnt,str2);
4173 char *name = p;
4174 int uLevel;
4175 int count;
4176 int i, succnt=0;
4177 int snum;
4178 struct pack_desc desc;
4179 print_queue_struct *queue=NULL;
4180 print_status_struct status;
4182 if (!str1 || !str2 || !p) {
4183 return False;
4186 memset((char *)&desc,'\0',sizeof(desc));
4187 memset((char *)&status,'\0',sizeof(status));
4189 p = skip_string(param,tpscnt,p);
4190 if (!p) {
4191 return False;
4193 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4195 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4197 /* check it's a supported variant */
4198 if (strcmp(str1,"zWrLeh") != 0) {
4199 return False;
4202 if (uLevel > 2) {
4203 return False; /* defined only for uLevel 0,1,2 */
4206 if (!check_printjob_info(&desc,uLevel,str2)) {
4207 return False;
4210 snum = find_service(name);
4211 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
4212 return False;
4215 count = print_queue_status(snum,&queue,&status);
4216 if (mdrcnt > 0) {
4217 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4218 if (!*rdata) {
4219 return False;
4222 desc.base = *rdata;
4223 desc.buflen = mdrcnt;
4225 if (init_package(&desc,count,0)) {
4226 succnt = 0;
4227 for (i = 0; i < count; i++) {
4228 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
4229 if (desc.errcode == NERR_Success) {
4230 succnt = i+1;
4235 *rdata_len = desc.usedlen;
4237 *rparam_len = 8;
4238 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4239 if (!*rparam) {
4240 return False;
4242 SSVALS(*rparam,0,desc.errcode);
4243 SSVAL(*rparam,2,0);
4244 SSVAL(*rparam,4,succnt);
4245 SSVAL(*rparam,6,count);
4247 SAFE_FREE(queue);
4249 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4251 return True;
4254 static int check_printdest_info(struct pack_desc* desc,
4255 int uLevel, char* id)
4257 desc->subformat = NULL;
4258 switch( uLevel ) {
4259 case 0:
4260 desc->format = "B9";
4261 break;
4262 case 1:
4263 desc->format = "B9B21WWzW";
4264 break;
4265 case 2:
4266 desc->format = "z";
4267 break;
4268 case 3:
4269 desc->format = "zzzWWzzzWW";
4270 break;
4271 default:
4272 DEBUG(0,("check_printdest_info: invalid level %d\n",
4273 uLevel));
4274 return False;
4276 if (id == NULL || strcmp(desc->format,id) != 0) {
4277 DEBUG(0,("check_printdest_info: invalid string %s\n",
4278 id ? id : "<NULL>" ));
4279 return False;
4281 return True;
4284 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
4285 struct pack_desc* desc)
4287 char buf[100];
4289 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
4290 buf[sizeof(buf)-1] = 0;
4291 strupper_m(buf);
4293 if (uLevel <= 1) {
4294 PACKS(desc,"B9",buf); /* szName */
4295 if (uLevel == 1) {
4296 PACKS(desc,"B21",""); /* szUserName */
4297 PACKI(desc,"W",0); /* uJobId */
4298 PACKI(desc,"W",0); /* fsStatus */
4299 PACKS(desc,"z",""); /* pszStatus */
4300 PACKI(desc,"W",0); /* time */
4304 if (uLevel == 2 || uLevel == 3) {
4305 PACKS(desc,"z",buf); /* pszPrinterName */
4306 if (uLevel == 3) {
4307 PACKS(desc,"z",""); /* pszUserName */
4308 PACKS(desc,"z",""); /* pszLogAddr */
4309 PACKI(desc,"W",0); /* uJobId */
4310 PACKI(desc,"W",0); /* fsStatus */
4311 PACKS(desc,"z",""); /* pszStatus */
4312 PACKS(desc,"z",""); /* pszComment */
4313 PACKS(desc,"z","NULL"); /* pszDrivers */
4314 PACKI(desc,"W",0); /* time */
4315 PACKI(desc,"W",0); /* pad1 */
4320 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
4321 char *param, int tpscnt,
4322 char *data, int tdscnt,
4323 int mdrcnt,int mprcnt,
4324 char **rdata,char **rparam,
4325 int *rdata_len,int *rparam_len)
4327 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4328 char *str2 = skip_string(param,tpscnt,str1);
4329 char *p = skip_string(param,tpscnt,str2);
4330 char* PrinterName = p;
4331 int uLevel;
4332 struct pack_desc desc;
4333 int snum;
4334 char *tmpdata=NULL;
4336 if (!str1 || !str2 || !p) {
4337 return False;
4340 memset((char *)&desc,'\0',sizeof(desc));
4342 p = skip_string(param,tpscnt,p);
4343 if (!p) {
4344 return False;
4346 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4348 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4350 /* check it's a supported varient */
4351 if (strcmp(str1,"zWrLh") != 0) {
4352 return False;
4354 if (!check_printdest_info(&desc,uLevel,str2)) {
4355 return False;
4358 snum = find_service(PrinterName);
4359 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
4360 *rdata_len = 0;
4361 desc.errcode = NERR_DestNotFound;
4362 desc.neededlen = 0;
4363 } else {
4364 if (mdrcnt > 0) {
4365 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4366 if (!*rdata) {
4367 return False;
4369 desc.base = *rdata;
4370 desc.buflen = mdrcnt;
4371 } else {
4373 * Don't return data but need to get correct length
4374 * init_package will return wrong size if buflen=0
4376 desc.buflen = getlen(desc.format);
4377 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4379 if (init_package(&desc,1,0)) {
4380 fill_printdest_info(conn,snum,uLevel,&desc);
4382 *rdata_len = desc.usedlen;
4385 *rparam_len = 6;
4386 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4387 if (!*rparam) {
4388 return False;
4390 SSVALS(*rparam,0,desc.errcode);
4391 SSVAL(*rparam,2,0);
4392 SSVAL(*rparam,4,desc.neededlen);
4394 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4395 SAFE_FREE(tmpdata);
4397 return True;
4400 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4401 char *param, int tpscnt,
4402 char *data, int tdscnt,
4403 int mdrcnt,int mprcnt,
4404 char **rdata,char **rparam,
4405 int *rdata_len,int *rparam_len)
4407 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4408 char *str2 = skip_string(param,tpscnt,str1);
4409 char *p = skip_string(param,tpscnt,str2);
4410 int uLevel;
4411 int queuecnt;
4412 int i, n, succnt=0;
4413 struct pack_desc desc;
4414 int services = lp_numservices();
4416 if (!str1 || !str2 || !p) {
4417 return False;
4420 memset((char *)&desc,'\0',sizeof(desc));
4422 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4424 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4426 /* check it's a supported varient */
4427 if (strcmp(str1,"WrLeh") != 0) {
4428 return False;
4430 if (!check_printdest_info(&desc,uLevel,str2)) {
4431 return False;
4434 queuecnt = 0;
4435 for (i = 0; i < services; i++) {
4436 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4437 queuecnt++;
4441 if (mdrcnt > 0) {
4442 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4443 if (!*rdata) {
4444 return False;
4448 desc.base = *rdata;
4449 desc.buflen = mdrcnt;
4450 if (init_package(&desc,queuecnt,0)) {
4451 succnt = 0;
4452 n = 0;
4453 for (i = 0; i < services; i++) {
4454 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4455 fill_printdest_info(conn,i,uLevel,&desc);
4456 n++;
4457 if (desc.errcode == NERR_Success) {
4458 succnt = n;
4464 *rdata_len = desc.usedlen;
4466 *rparam_len = 8;
4467 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4468 if (!*rparam) {
4469 return False;
4471 SSVALS(*rparam,0,desc.errcode);
4472 SSVAL(*rparam,2,0);
4473 SSVAL(*rparam,4,succnt);
4474 SSVAL(*rparam,6,queuecnt);
4476 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4478 return True;
4481 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4482 char *param, int tpscnt,
4483 char *data, int tdscnt,
4484 int mdrcnt,int mprcnt,
4485 char **rdata,char **rparam,
4486 int *rdata_len,int *rparam_len)
4488 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4489 char *str2 = skip_string(param,tpscnt,str1);
4490 char *p = skip_string(param,tpscnt,str2);
4491 int uLevel;
4492 int succnt;
4493 struct pack_desc desc;
4495 if (!str1 || !str2 || !p) {
4496 return False;
4499 memset((char *)&desc,'\0',sizeof(desc));
4501 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4503 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4505 /* check it's a supported varient */
4506 if (strcmp(str1,"WrLeh") != 0) {
4507 return False;
4509 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4510 return False;
4513 if (mdrcnt > 0) {
4514 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4515 if (!*rdata) {
4516 return False;
4519 desc.base = *rdata;
4520 desc.buflen = mdrcnt;
4521 if (init_package(&desc,1,0)) {
4522 PACKS(&desc,"B41","NULL");
4525 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4527 *rdata_len = desc.usedlen;
4529 *rparam_len = 8;
4530 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4531 if (!*rparam) {
4532 return False;
4534 SSVALS(*rparam,0,desc.errcode);
4535 SSVAL(*rparam,2,0);
4536 SSVAL(*rparam,4,succnt);
4537 SSVAL(*rparam,6,1);
4539 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4541 return True;
4544 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4545 char *param, int tpscnt,
4546 char *data, int tdscnt,
4547 int mdrcnt,int mprcnt,
4548 char **rdata,char **rparam,
4549 int *rdata_len,int *rparam_len)
4551 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4552 char *str2 = skip_string(param,tpscnt,str1);
4553 char *p = skip_string(param,tpscnt,str2);
4554 int uLevel;
4555 int succnt;
4556 struct pack_desc desc;
4558 if (!str1 || !str2 || !p) {
4559 return False;
4561 memset((char *)&desc,'\0',sizeof(desc));
4563 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4565 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4567 /* check it's a supported varient */
4568 if (strcmp(str1,"WrLeh") != 0) {
4569 return False;
4571 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4572 return False;
4575 if (mdrcnt > 0) {
4576 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4577 if (!*rdata) {
4578 return False;
4581 desc.base = *rdata;
4582 desc.buflen = mdrcnt;
4583 desc.format = str2;
4584 if (init_package(&desc,1,0)) {
4585 PACKS(&desc,"B13","lpd");
4588 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4590 *rdata_len = desc.usedlen;
4592 *rparam_len = 8;
4593 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4594 if (!*rparam) {
4595 return False;
4597 SSVALS(*rparam,0,desc.errcode);
4598 SSVAL(*rparam,2,0);
4599 SSVAL(*rparam,4,succnt);
4600 SSVAL(*rparam,6,1);
4602 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4604 return True;
4607 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4608 char *param, int tpscnt,
4609 char *data, int tdscnt,
4610 int mdrcnt,int mprcnt,
4611 char **rdata,char **rparam,
4612 int *rdata_len,int *rparam_len)
4614 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4615 char *str2 = skip_string(param,tpscnt,str1);
4616 char *p = skip_string(param,tpscnt,str2);
4617 int uLevel;
4618 int succnt;
4619 struct pack_desc desc;
4621 if (!str1 || !str2 || !p) {
4622 return False;
4625 memset((char *)&desc,'\0',sizeof(desc));
4627 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4629 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4631 /* check it's a supported varient */
4632 if (strcmp(str1,"WrLeh") != 0) {
4633 return False;
4635 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
4636 return False;
4639 if (mdrcnt > 0) {
4640 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4641 if (!*rdata) {
4642 return False;
4645 memset((char *)&desc,'\0',sizeof(desc));
4646 desc.base = *rdata;
4647 desc.buflen = mdrcnt;
4648 desc.format = str2;
4649 if (init_package(&desc,1,0)) {
4650 PACKS(&desc,"B13","lp0");
4653 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4655 *rdata_len = desc.usedlen;
4657 *rparam_len = 8;
4658 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4659 if (!*rparam) {
4660 return False;
4662 SSVALS(*rparam,0,desc.errcode);
4663 SSVAL(*rparam,2,0);
4664 SSVAL(*rparam,4,succnt);
4665 SSVAL(*rparam,6,1);
4667 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
4669 return True;
4672 /****************************************************************************
4673 List open sessions
4674 ****************************************************************************/
4676 static bool api_RNetSessionEnum(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)
4684 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4685 char *str2 = skip_string(param,tpscnt,str1);
4686 char *p = skip_string(param,tpscnt,str2);
4687 int uLevel;
4688 struct pack_desc desc;
4689 struct sessionid *session_list;
4690 int i, num_sessions;
4692 if (!str1 || !str2 || !p) {
4693 return False;
4696 memset((char *)&desc,'\0',sizeof(desc));
4698 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4700 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
4701 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
4702 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
4704 /* check it's a supported varient */
4705 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
4706 return False;
4708 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
4709 return False;
4712 num_sessions = list_sessions(talloc_tos(), &session_list);
4714 if (mdrcnt > 0) {
4715 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4716 if (!*rdata) {
4717 return False;
4720 memset((char *)&desc,'\0',sizeof(desc));
4721 desc.base = *rdata;
4722 desc.buflen = mdrcnt;
4723 desc.format = str2;
4724 if (!init_package(&desc,num_sessions,0)) {
4725 return False;
4728 for(i=0; i<num_sessions; i++) {
4729 PACKS(&desc, "z", session_list[i].remote_machine);
4730 PACKS(&desc, "z", session_list[i].username);
4731 PACKI(&desc, "W", 1); /* num conns */
4732 PACKI(&desc, "W", 0); /* num opens */
4733 PACKI(&desc, "W", 1); /* num users */
4734 PACKI(&desc, "D", 0); /* session time */
4735 PACKI(&desc, "D", 0); /* idle time */
4736 PACKI(&desc, "D", 0); /* flags */
4737 PACKS(&desc, "z", "Unknown Client"); /* client type string */
4740 *rdata_len = desc.usedlen;
4742 *rparam_len = 8;
4743 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4744 if (!*rparam) {
4745 return False;
4747 SSVALS(*rparam,0,desc.errcode);
4748 SSVAL(*rparam,2,0); /* converter */
4749 SSVAL(*rparam,4,num_sessions); /* count */
4751 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
4753 return True;
4757 /****************************************************************************
4758 The buffer was too small.
4759 ****************************************************************************/
4761 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
4762 int mdrcnt, int mprcnt,
4763 char **rdata, char **rparam,
4764 int *rdata_len, int *rparam_len)
4766 *rparam_len = MIN(*rparam_len,mprcnt);
4767 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4768 if (!*rparam) {
4769 return False;
4772 *rdata_len = 0;
4774 SSVAL(*rparam,0,NERR_BufTooSmall);
4776 DEBUG(3,("Supplied buffer too small in API command\n"));
4778 return True;
4781 /****************************************************************************
4782 The request is not supported.
4783 ****************************************************************************/
4785 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
4786 char *param, int tpscnt,
4787 char *data, int tdscnt,
4788 int mdrcnt, int mprcnt,
4789 char **rdata, char **rparam,
4790 int *rdata_len, int *rparam_len)
4792 *rparam_len = 4;
4793 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4794 if (!*rparam) {
4795 return False;
4798 *rdata_len = 0;
4800 SSVAL(*rparam,0,NERR_notsupported);
4801 SSVAL(*rparam,2,0); /* converter word */
4803 DEBUG(3,("Unsupported API command\n"));
4805 return True;
4808 static const struct {
4809 const char *name;
4810 int id;
4811 bool (*fn)(connection_struct *, uint16,
4812 char *, int,
4813 char *, int,
4814 int,int,char **,char **,int *,int *);
4815 bool auth_user; /* Deny anonymous access? */
4816 } api_commands[] = {
4817 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
4818 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
4819 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
4820 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
4821 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
4822 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
4823 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
4824 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
4825 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
4826 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
4827 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
4828 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
4829 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
4830 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
4831 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
4832 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
4833 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
4834 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
4835 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
4836 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
4837 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
4838 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
4839 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
4840 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
4841 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
4842 {"NetServerEnum3", RAP_NetServerEnum3, api_RNetServerEnum3}, /* anon OK */
4843 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
4844 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
4845 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
4846 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
4847 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
4848 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
4849 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
4850 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
4851 {NULL, -1, api_Unsupported}
4852 /* The following RAP calls are not implemented by Samba:
4854 RAP_WFileEnum2 - anon not OK
4859 /****************************************************************************
4860 Handle remote api calls.
4861 ****************************************************************************/
4863 void api_reply(connection_struct *conn, uint16 vuid,
4864 struct smb_request *req,
4865 char *data, char *params,
4866 int tdscnt, int tpscnt,
4867 int mdrcnt, int mprcnt)
4869 struct smbd_server_connection *sconn = smbd_server_conn;
4870 int api_command;
4871 char *rdata = NULL;
4872 char *rparam = NULL;
4873 const char *name1 = NULL;
4874 const char *name2 = NULL;
4875 int rdata_len = 0;
4876 int rparam_len = 0;
4877 bool reply=False;
4878 int i;
4880 if (!params) {
4881 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
4882 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4883 return;
4886 if (tpscnt < 2) {
4887 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4888 return;
4890 api_command = SVAL(params,0);
4891 /* Is there a string at position params+2 ? */
4892 if (skip_string(params,tpscnt,params+2)) {
4893 name1 = params + 2;
4894 } else {
4895 name1 = "";
4897 name2 = skip_string(params,tpscnt,params+2);
4898 if (!name2) {
4899 name2 = "";
4902 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
4903 api_command,
4904 name1,
4905 name2,
4906 tdscnt,tpscnt,mdrcnt,mprcnt));
4908 for (i=0;api_commands[i].name;i++) {
4909 if (api_commands[i].id == api_command && api_commands[i].fn) {
4910 DEBUG(3,("Doing %s\n",api_commands[i].name));
4911 break;
4915 /* Check whether this api call can be done anonymously */
4917 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
4918 user_struct *user = get_valid_user_struct(sconn, vuid);
4920 if (!user || user->server_info->guest) {
4921 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4922 return;
4926 rdata = (char *)SMB_MALLOC(1024);
4927 if (rdata) {
4928 memset(rdata,'\0',1024);
4931 rparam = (char *)SMB_MALLOC(1024);
4932 if (rparam) {
4933 memset(rparam,'\0',1024);
4936 if(!rdata || !rparam) {
4937 DEBUG(0,("api_reply: malloc fail !\n"));
4938 SAFE_FREE(rdata);
4939 SAFE_FREE(rparam);
4940 reply_nterror(req, NT_STATUS_NO_MEMORY);
4941 return;
4944 reply = api_commands[i].fn(conn,
4945 vuid,
4946 params,tpscnt, /* params + length */
4947 data,tdscnt, /* data + length */
4948 mdrcnt,mprcnt,
4949 &rdata,&rparam,&rdata_len,&rparam_len);
4952 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
4953 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
4954 &rdata,&rparam,&rdata_len,&rparam_len);
4957 /* if we get False back then it's actually unsupported */
4958 if (!reply) {
4959 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
4960 &rdata,&rparam,&rdata_len,&rparam_len);
4963 /* If api_Unsupported returns false we can't return anything. */
4964 if (reply) {
4965 send_trans_reply(conn, req, rparam, rparam_len,
4966 rdata, rdata_len, False);
4969 SAFE_FREE(rdata);
4970 SAFE_FREE(rparam);
4971 return;