s3: Remove some unused code
[Samba.git] / source3 / smbd / lanman.c
blob7ee6c9b59c377763f3010112ac9cfa458ba977ff
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"
33 #ifdef CHECK_TYPES
34 #undef CHECK_TYPES
35 #endif
36 #define CHECK_TYPES 0
38 #define NERR_Success 0
39 #define NERR_badpass 86
40 #define NERR_notsupported 50
42 #define NERR_BASE (2100)
43 #define NERR_BufTooSmall (NERR_BASE+23)
44 #define NERR_JobNotFound (NERR_BASE+51)
45 #define NERR_DestNotFound (NERR_BASE+52)
47 #define ACCESS_READ 0x01
48 #define ACCESS_WRITE 0x02
49 #define ACCESS_CREATE 0x04
51 #define SHPWLEN 8 /* share password length */
53 /* Limit size of ipc replies */
55 static char *smb_realloc_limit(void *ptr, size_t size)
57 char *val;
59 size = MAX((size),4*1024);
60 val = (char *)SMB_REALLOC(ptr,size);
61 if (val) {
62 memset(val,'\0',size);
64 return val;
67 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
68 char *param, int tpscnt,
69 char *data, int tdscnt,
70 int mdrcnt, int mprcnt,
71 char **rdata, char **rparam,
72 int *rdata_len, int *rparam_len);
74 static bool api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
75 int mdrcnt, int mprcnt,
76 char **rdata, char **rparam,
77 int *rdata_len, int *rparam_len);
80 static int CopyExpanded(connection_struct *conn,
81 int snum, char **dst, char *src, int *p_space_remaining)
83 TALLOC_CTX *ctx = talloc_tos();
84 char *buf = NULL;
85 int l;
87 if (!src || !dst || !p_space_remaining || !(*dst) ||
88 *p_space_remaining <= 0) {
89 return 0;
92 buf = talloc_strdup(ctx, src);
93 if (!buf) {
94 *p_space_remaining = 0;
95 return 0;
97 buf = talloc_string_sub(ctx, buf,"%S",lp_servicename(snum));
98 if (!buf) {
99 *p_space_remaining = 0;
100 return 0;
102 buf = talloc_sub_advanced(ctx,
103 lp_servicename(SNUM(conn)),
104 conn->server_info->unix_name,
105 conn->connectpath,
106 conn->server_info->utok.gid,
107 conn->server_info->sanitized_username,
108 pdb_get_domain(conn->server_info->sam_account),
109 buf);
110 if (!buf) {
111 *p_space_remaining = 0;
112 return 0;
114 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
115 if (l == -1) {
116 return 0;
118 (*dst) += l;
119 (*p_space_remaining) -= l;
120 return l;
123 static int CopyAndAdvance(char **dst, char *src, int *n)
125 int l;
126 if (!src || !dst || !n || !(*dst)) {
127 return 0;
129 l = push_ascii(*dst,src,*n, STR_TERMINATE);
130 if (l == -1) {
131 return 0;
133 (*dst) += l;
134 (*n) -= l;
135 return l;
138 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
140 TALLOC_CTX *ctx = talloc_tos();
141 char *buf = NULL;
142 if (!s) {
143 return 0;
145 buf = talloc_strdup(ctx,s);
146 if (!buf) {
147 return 0;
149 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
150 if (!buf) {
151 return 0;
153 buf = talloc_sub_advanced(ctx,
154 lp_servicename(SNUM(conn)),
155 conn->server_info->unix_name,
156 conn->connectpath,
157 conn->server_info->utok.gid,
158 conn->server_info->sanitized_username,
159 pdb_get_domain(conn->server_info->sam_account),
160 buf);
161 if (!buf) {
162 return 0;
164 return strlen(buf) + 1;
167 static char *Expand(connection_struct *conn, int snum, char *s)
169 TALLOC_CTX *ctx = talloc_tos();
170 char *buf = NULL;
172 if (!s) {
173 return NULL;
175 buf = talloc_strdup(ctx,s);
176 if (!buf) {
177 return 0;
179 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
180 if (!buf) {
181 return 0;
183 return talloc_sub_advanced(ctx,
184 lp_servicename(SNUM(conn)),
185 conn->server_info->unix_name,
186 conn->connectpath,
187 conn->server_info->utok.gid,
188 conn->server_info->sanitized_username,
189 pdb_get_domain(conn->server_info->sam_account),
190 buf);
193 /*******************************************************************
194 Check a API string for validity when we only need to check the prefix.
195 ******************************************************************/
197 static bool prefix_ok(const char *str, const char *prefix)
199 return(strncmp(str,prefix,strlen(prefix)) == 0);
202 struct pack_desc {
203 const char *format; /* formatstring for structure */
204 const char *subformat; /* subformat for structure */
205 char *base; /* baseaddress of buffer */
206 int buflen; /* remaining size for fixed part; on init: length of base */
207 int subcount; /* count of substructures */
208 char *structbuf; /* pointer into buffer for remaining fixed part */
209 int stringlen; /* remaining size for variable part */
210 char *stringbuf; /* pointer into buffer for remaining variable part */
211 int neededlen; /* total needed size */
212 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
213 const char *curpos; /* current position; pointer into format or subformat */
214 int errcode;
217 static int get_counter(const char **p)
219 int i, n;
220 if (!p || !(*p)) {
221 return 1;
223 if (!isdigit((int)**p)) {
224 return 1;
226 for (n = 0;;) {
227 i = **p;
228 if (isdigit(i)) {
229 n = 10 * n + (i - '0');
230 } else {
231 return n;
233 (*p)++;
237 static int getlen(const char *p)
239 int n = 0;
240 if (!p) {
241 return 0;
244 while (*p) {
245 switch( *p++ ) {
246 case 'W': /* word (2 byte) */
247 n += 2;
248 break;
249 case 'K': /* status word? (2 byte) */
250 n += 2;
251 break;
252 case 'N': /* count of substructures (word) at end */
253 n += 2;
254 break;
255 case 'D': /* double word (4 byte) */
256 case 'z': /* offset to zero terminated string (4 byte) */
257 case 'l': /* offset to user data (4 byte) */
258 n += 4;
259 break;
260 case 'b': /* offset to data (with counter) (4 byte) */
261 n += 4;
262 get_counter(&p);
263 break;
264 case 'B': /* byte (with optional counter) */
265 n += get_counter(&p);
266 break;
269 return n;
272 static bool init_package(struct pack_desc *p, int count, int subcount)
274 int n = p->buflen;
275 int i;
277 if (!p->format || !p->base) {
278 return False;
281 i = count * getlen(p->format);
282 if (p->subformat) {
283 i += subcount * getlen(p->subformat);
285 p->structbuf = p->base;
286 p->neededlen = 0;
287 p->usedlen = 0;
288 p->subcount = 0;
289 p->curpos = p->format;
290 if (i > n) {
291 p->neededlen = i;
292 i = n = 0;
293 #if 0
295 * This is the old error code we used. Aparently
296 * WinNT/2k systems return ERRbuftoosmall (2123) and
297 * OS/2 needs this. I'm leaving this here so we can revert
298 * if needed. JRA.
300 p->errcode = ERRmoredata;
301 #else
302 p->errcode = ERRbuftoosmall;
303 #endif
304 } else {
305 p->errcode = NERR_Success;
307 p->buflen = i;
308 n -= i;
309 p->stringbuf = p->base + i;
310 p->stringlen = n;
311 return (p->errcode == NERR_Success);
314 static int package(struct pack_desc *p, ...)
316 va_list args;
317 int needed=0, stringneeded;
318 const char *str=NULL;
319 int is_string=0, stringused;
320 int32 temp;
322 va_start(args,p);
324 if (!*p->curpos) {
325 if (!p->subcount) {
326 p->curpos = p->format;
327 } else {
328 p->curpos = p->subformat;
329 p->subcount--;
332 #if CHECK_TYPES
333 str = va_arg(args,char*);
334 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
335 #endif
336 stringneeded = -1;
338 if (!p->curpos) {
339 va_end(args);
340 return 0;
343 switch( *p->curpos++ ) {
344 case 'W': /* word (2 byte) */
345 needed = 2;
346 temp = va_arg(args,int);
347 if (p->buflen >= needed) {
348 SSVAL(p->structbuf,0,temp);
350 break;
351 case 'K': /* status word? (2 byte) */
352 needed = 2;
353 temp = va_arg(args,int);
354 if (p->buflen >= needed) {
355 SSVAL(p->structbuf,0,temp);
357 break;
358 case 'N': /* count of substructures (word) at end */
359 needed = 2;
360 p->subcount = va_arg(args,int);
361 if (p->buflen >= needed) {
362 SSVAL(p->structbuf,0,p->subcount);
364 break;
365 case 'D': /* double word (4 byte) */
366 needed = 4;
367 temp = va_arg(args,int);
368 if (p->buflen >= needed) {
369 SIVAL(p->structbuf,0,temp);
371 break;
372 case 'B': /* byte (with optional counter) */
373 needed = get_counter(&p->curpos);
375 char *s = va_arg(args,char*);
376 if (p->buflen >= needed) {
377 StrnCpy(p->structbuf,s?s:"",needed-1);
380 break;
381 case 'z': /* offset to zero terminated string (4 byte) */
382 str = va_arg(args,char*);
383 stringneeded = (str ? strlen(str)+1 : 0);
384 is_string = 1;
385 break;
386 case 'l': /* offset to user data (4 byte) */
387 str = va_arg(args,char*);
388 stringneeded = va_arg(args,int);
389 is_string = 0;
390 break;
391 case 'b': /* offset to data (with counter) (4 byte) */
392 str = va_arg(args,char*);
393 stringneeded = get_counter(&p->curpos);
394 is_string = 0;
395 break;
398 va_end(args);
399 if (stringneeded >= 0) {
400 needed = 4;
401 if (p->buflen >= needed) {
402 stringused = stringneeded;
403 if (stringused > p->stringlen) {
404 stringused = (is_string ? p->stringlen : 0);
405 if (p->errcode == NERR_Success) {
406 p->errcode = ERRmoredata;
409 if (!stringused) {
410 SIVAL(p->structbuf,0,0);
411 } else {
412 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
413 memcpy(p->stringbuf,str?str:"",stringused);
414 if (is_string) {
415 p->stringbuf[stringused-1] = '\0';
417 p->stringbuf += stringused;
418 p->stringlen -= stringused;
419 p->usedlen += stringused;
422 p->neededlen += stringneeded;
425 p->neededlen += needed;
426 if (p->buflen >= needed) {
427 p->structbuf += needed;
428 p->buflen -= needed;
429 p->usedlen += needed;
430 } else {
431 if (p->errcode == NERR_Success) {
432 p->errcode = ERRmoredata;
435 return 1;
438 #if CHECK_TYPES
439 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
440 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
441 #else
442 #define PACK(desc,t,v) package(desc,v)
443 #define PACKl(desc,t,v,l) package(desc,v,l)
444 #endif
446 static void PACKI(struct pack_desc* desc, const char *t,int v)
448 PACK(desc,t,v);
451 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
453 PACK(desc,t,v);
456 /****************************************************************************
457 Get a print queue.
458 ****************************************************************************/
460 static void PackDriverData(struct pack_desc* desc)
462 char drivdata[4+4+32];
463 SIVAL(drivdata,0,sizeof drivdata); /* cb */
464 SIVAL(drivdata,4,1000); /* lVersion */
465 memset(drivdata+8,0,32); /* szDeviceName */
466 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
467 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
470 static int check_printq_info(struct pack_desc* desc,
471 unsigned int uLevel, char *id1, char *id2)
473 desc->subformat = NULL;
474 switch( uLevel ) {
475 case 0:
476 desc->format = "B13";
477 break;
478 case 1:
479 desc->format = "B13BWWWzzzzzWW";
480 break;
481 case 2:
482 desc->format = "B13BWWWzzzzzWN";
483 desc->subformat = "WB21BB16B10zWWzDDz";
484 break;
485 case 3:
486 desc->format = "zWWWWzzzzWWzzl";
487 break;
488 case 4:
489 desc->format = "zWWWWzzzzWNzzl";
490 desc->subformat = "WWzWWDDzz";
491 break;
492 case 5:
493 desc->format = "z";
494 break;
495 case 51:
496 desc->format = "K";
497 break;
498 case 52:
499 desc->format = "WzzzzzzzzN";
500 desc->subformat = "z";
501 break;
502 default:
503 DEBUG(0,("check_printq_info: invalid level %d\n",
504 uLevel ));
505 return False;
507 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
508 DEBUG(0,("check_printq_info: invalid format %s\n",
509 id1 ? id1 : "<NULL>" ));
510 return False;
512 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
513 DEBUG(0,("check_printq_info: invalid subformat %s\n",
514 id2 ? id2 : "<NULL>" ));
515 return False;
517 return True;
521 #define RAP_JOB_STATUS_QUEUED 0
522 #define RAP_JOB_STATUS_PAUSED 1
523 #define RAP_JOB_STATUS_SPOOLING 2
524 #define RAP_JOB_STATUS_PRINTING 3
525 #define RAP_JOB_STATUS_PRINTED 4
527 #define RAP_QUEUE_STATUS_PAUSED 1
528 #define RAP_QUEUE_STATUS_ERROR 2
530 /* turn a print job status into a on the wire status
532 static int printj_status(int v)
534 switch (v) {
535 case LPQ_QUEUED:
536 return RAP_JOB_STATUS_QUEUED;
537 case LPQ_PAUSED:
538 return RAP_JOB_STATUS_PAUSED;
539 case LPQ_SPOOLING:
540 return RAP_JOB_STATUS_SPOOLING;
541 case LPQ_PRINTING:
542 return RAP_JOB_STATUS_PRINTING;
544 return 0;
547 /* turn a print queue status into a on the wire status
549 static int printq_status(int v)
551 switch (v) {
552 case LPQ_QUEUED:
553 return 0;
554 case LPQ_PAUSED:
555 return RAP_QUEUE_STATUS_PAUSED;
557 return RAP_QUEUE_STATUS_ERROR;
560 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
561 struct pack_desc *desc,
562 print_queue_struct *queue, int n)
564 time_t t = queue->time;
566 /* the client expects localtime */
567 t -= get_time_zone(t);
569 PACKI(desc,"W",pjobid_to_rap(lp_const_servicename(snum),queue->job)); /* uJobId */
570 if (uLevel == 1) {
571 PACKS(desc,"B21",queue->fs_user); /* szUserName */
572 PACKS(desc,"B",""); /* pad */
573 PACKS(desc,"B16",""); /* szNotifyName */
574 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
575 PACKS(desc,"z",""); /* pszParms */
576 PACKI(desc,"W",n+1); /* uPosition */
577 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
578 PACKS(desc,"z",""); /* pszStatus */
579 PACKI(desc,"D",t); /* ulSubmitted */
580 PACKI(desc,"D",queue->size); /* ulSize */
581 PACKS(desc,"z",queue->fs_file); /* pszComment */
583 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
584 PACKI(desc,"W",queue->priority); /* uPriority */
585 PACKS(desc,"z",queue->fs_user); /* pszUserName */
586 PACKI(desc,"W",n+1); /* uPosition */
587 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
588 PACKI(desc,"D",t); /* ulSubmitted */
589 PACKI(desc,"D",queue->size); /* ulSize */
590 PACKS(desc,"z","Samba"); /* pszComment */
591 PACKS(desc,"z",queue->fs_file); /* pszDocument */
592 if (uLevel == 3) {
593 PACKS(desc,"z",""); /* pszNotifyName */
594 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
595 PACKS(desc,"z",""); /* pszParms */
596 PACKS(desc,"z",""); /* pszStatus */
597 PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
598 PACKS(desc,"z","lpd"); /* pszQProcName */
599 PACKS(desc,"z",""); /* pszQProcParms */
600 PACKS(desc,"z","NULL"); /* pszDriverName */
601 PackDriverData(desc); /* pDriverData */
602 PACKS(desc,"z",""); /* pszPrinterName */
603 } else if (uLevel == 4) { /* OS2 */
604 PACKS(desc,"z",""); /* pszSpoolFileName */
605 PACKS(desc,"z",""); /* pszPortName */
606 PACKS(desc,"z",""); /* pszStatus */
607 PACKI(desc,"D",0); /* ulPagesSpooled */
608 PACKI(desc,"D",0); /* ulPagesSent */
609 PACKI(desc,"D",0); /* ulPagesPrinted */
610 PACKI(desc,"D",0); /* ulTimePrinted */
611 PACKI(desc,"D",0); /* ulExtendJobStatus */
612 PACKI(desc,"D",0); /* ulStartPage */
613 PACKI(desc,"D",0); /* ulEndPage */
618 /********************************************************************
619 Return a driver name given an snum.
620 Returns True if from tdb, False otherwise.
621 ********************************************************************/
623 static bool get_driver_name(int snum, char **pp_drivername)
625 NT_PRINTER_INFO_LEVEL *info = NULL;
626 bool in_tdb = false;
628 get_a_printer (NULL, &info, 2, lp_servicename(snum));
629 if (info != NULL) {
630 *pp_drivername = talloc_strdup(talloc_tos(),
631 info->info_2->drivername);
632 in_tdb = true;
633 free_a_printer(&info, 2);
634 if (!*pp_drivername) {
635 return false;
639 return in_tdb;
642 /********************************************************************
643 Respond to the DosPrintQInfo command with a level of 52
644 This is used to get printer driver information for Win9x clients
645 ********************************************************************/
646 static void fill_printq_info_52(connection_struct *conn, int snum,
647 struct pack_desc* desc, int count )
649 int i;
650 fstring location;
651 struct spoolss_DriverInfo8 *driver = NULL;
652 NT_PRINTER_INFO_LEVEL *printer = NULL;
654 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
655 DEBUG(3,("fill_printq_info_52: Failed to lookup printer [%s]\n",
656 lp_servicename(snum)));
657 goto err;
660 if (!W_ERROR_IS_OK(get_a_printer_driver(talloc_tos(), &driver, printer->info_2->drivername,
661 "Windows 4.0", 0)) )
663 DEBUG(3,("fill_printq_info_52: Failed to lookup driver [%s]\n",
664 printer->info_2->drivername));
665 goto err;
668 trim_string((char *)driver->driver_path, "\\print$\\WIN40\\0\\", 0);
669 trim_string((char *)driver->data_file, "\\print$\\WIN40\\0\\", 0);
670 trim_string((char *)driver->help_file, "\\print$\\WIN40\\0\\", 0);
672 PACKI(desc, "W", 0x0400); /* don't know */
673 PACKS(desc, "z", driver->driver_name); /* long printer name */
674 PACKS(desc, "z", driver->driver_path); /* Driverfile Name */
675 PACKS(desc, "z", driver->data_file); /* Datafile name */
676 PACKS(desc, "z", driver->monitor_name); /* language monitor */
678 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
679 standard_sub_basic( "", "", location, sizeof(location)-1 );
680 PACKS(desc,"z", location); /* share to retrieve files */
682 PACKS(desc,"z", driver->default_datatype); /* default data type */
683 PACKS(desc,"z", driver->help_file); /* helpfile name */
684 PACKS(desc,"z", driver->driver_path); /* driver name */
686 DEBUG(3,("Printer Driver Name: %s:\n",driver->driver_name));
687 DEBUG(3,("Driver: %s:\n",driver->driver_path));
688 DEBUG(3,("Data File: %s:\n",driver->data_file));
689 DEBUG(3,("Language Monitor: %s:\n",driver->monitor_name));
690 DEBUG(3,("Driver Location: %s:\n",location));
691 DEBUG(3,("Data Type: %s:\n",driver->default_datatype));
692 DEBUG(3,("Help File: %s:\n",driver->help_file));
693 PACKI(desc,"N",count); /* number of files to copy */
695 for ( i=0; i<count && driver->dependent_files && *driver->dependent_files[i]; i++)
697 trim_string((char *)driver->dependent_files[i], "\\print$\\WIN40\\0\\", 0);
698 PACKS(desc,"z",driver->dependent_files[i]); /* driver files to copy */
699 DEBUG(3,("Dependent File: %s:\n", driver->dependent_files[i]));
702 /* sanity check */
703 if ( i != count )
704 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
705 count, i));
707 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", SERVICE(snum),i));
709 desc->errcode=NERR_Success;
710 goto done;
712 err:
713 DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
714 desc->errcode=NERR_notsupported;
716 done:
717 if ( printer )
718 free_a_printer( &printer, 2 );
720 free_a_printer_driver(driver);
724 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
725 struct pack_desc* desc,
726 int count, print_queue_struct* queue,
727 print_status_struct* status)
729 switch (uLevel) {
730 case 1:
731 case 2:
732 PACKS(desc,"B13",SERVICE(snum));
733 break;
734 case 3:
735 case 4:
736 case 5:
737 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
738 break;
739 case 51:
740 PACKI(desc,"K",printq_status(status->status));
741 break;
744 if (uLevel == 1 || uLevel == 2) {
745 PACKS(desc,"B",""); /* alignment */
746 PACKI(desc,"W",5); /* priority */
747 PACKI(desc,"W",0); /* start time */
748 PACKI(desc,"W",0); /* until time */
749 PACKS(desc,"z",""); /* pSepFile */
750 PACKS(desc,"z","lpd"); /* pPrProc */
751 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
752 PACKS(desc,"z",""); /* pParms */
753 if (snum < 0) {
754 PACKS(desc,"z","UNKNOWN PRINTER");
755 PACKI(desc,"W",LPSTAT_ERROR);
757 else if (!status || !status->message[0]) {
758 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
759 PACKI(desc,"W",LPSTAT_OK); /* status */
760 } else {
761 PACKS(desc,"z",status->message);
762 PACKI(desc,"W",printq_status(status->status)); /* status */
764 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
767 if (uLevel == 3 || uLevel == 4) {
768 char *drivername = NULL;
770 PACKI(desc,"W",5); /* uPriority */
771 PACKI(desc,"W",0); /* uStarttime */
772 PACKI(desc,"W",0); /* uUntiltime */
773 PACKI(desc,"W",5); /* pad1 */
774 PACKS(desc,"z",""); /* pszSepFile */
775 PACKS(desc,"z","WinPrint"); /* pszPrProc */
776 PACKS(desc,"z",NULL); /* pszParms */
777 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
778 /* "don't ask" that it's done this way to fix corrupted
779 Win9X/ME printer comments. */
780 if (!status) {
781 PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
782 } else {
783 PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
785 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
786 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
787 get_driver_name(snum,&drivername);
788 if (!drivername) {
789 return;
791 PACKS(desc,"z",drivername); /* pszDriverName */
792 PackDriverData(desc); /* pDriverData */
795 if (uLevel == 2 || uLevel == 4) {
796 int i;
797 for (i=0;i<count;i++)
798 fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
801 if (uLevel==52)
802 fill_printq_info_52( conn, snum, desc, count );
805 /* This function returns the number of files for a given driver */
806 static int get_printerdrivernumber(int snum)
808 int result = 0;
809 struct spoolss_DriverInfo8 *driver;
810 NT_PRINTER_INFO_LEVEL *printer = NULL;
812 ZERO_STRUCT(driver);
814 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
815 DEBUG(3,("get_printerdrivernumber: Failed to lookup printer [%s]\n",
816 lp_servicename(snum)));
817 goto done;
820 if (!W_ERROR_IS_OK(get_a_printer_driver(talloc_tos(), &driver, printer->info_2->drivername,
821 "Windows 4.0", 0)) )
823 DEBUG(3,("get_printerdrivernumber: Failed to lookup driver [%s]\n",
824 printer->info_2->drivername));
825 goto done;
828 /* count the number of files */
829 while (driver->dependent_files && *driver->dependent_files[result])
830 result++;
831 done:
832 if ( printer )
833 free_a_printer( &printer, 2 );
835 free_a_printer_driver(driver);
837 return result;
840 static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
841 char *param, int tpscnt,
842 char *data, int tdscnt,
843 int mdrcnt,int mprcnt,
844 char **rdata,char **rparam,
845 int *rdata_len,int *rparam_len)
847 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
848 char *str2 = skip_string(param,tpscnt,str1);
849 char *p = skip_string(param,tpscnt,str2);
850 char *QueueName = p;
851 unsigned int uLevel;
852 int count=0;
853 int snum;
854 char *str3;
855 struct pack_desc desc;
856 print_queue_struct *queue=NULL;
857 print_status_struct status;
858 char* tmpdata=NULL;
860 if (!str1 || !str2 || !p) {
861 return False;
863 memset((char *)&status,'\0',sizeof(status));
864 memset((char *)&desc,'\0',sizeof(desc));
866 p = skip_string(param,tpscnt,p);
867 if (!p) {
868 return False;
870 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
871 str3 = get_safe_str_ptr(param,tpscnt,p,4);
872 /* str3 may be null here and is checked in check_printq_info(). */
874 /* remove any trailing username */
875 if ((p = strchr_m(QueueName,'%')))
876 *p = 0;
878 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
880 /* check it's a supported varient */
881 if (!prefix_ok(str1,"zWrLh"))
882 return False;
883 if (!check_printq_info(&desc,uLevel,str2,str3)) {
885 * Patch from Scott Moomaw <scott@bridgewater.edu>
886 * to return the 'invalid info level' error if an
887 * unknown level was requested.
889 *rdata_len = 0;
890 *rparam_len = 6;
891 *rparam = smb_realloc_limit(*rparam,*rparam_len);
892 if (!*rparam) {
893 return False;
895 SSVALS(*rparam,0,ERRunknownlevel);
896 SSVAL(*rparam,2,0);
897 SSVAL(*rparam,4,0);
898 return(True);
901 snum = find_service(QueueName);
902 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) )
903 return False;
905 if (uLevel==52) {
906 count = get_printerdrivernumber(snum);
907 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
908 } else {
909 count = print_queue_status(snum, &queue,&status);
912 if (mdrcnt > 0) {
913 *rdata = smb_realloc_limit(*rdata,mdrcnt);
914 if (!*rdata) {
915 SAFE_FREE(queue);
916 return False;
918 desc.base = *rdata;
919 desc.buflen = mdrcnt;
920 } else {
922 * Don't return data but need to get correct length
923 * init_package will return wrong size if buflen=0
925 desc.buflen = getlen(desc.format);
926 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
929 if (init_package(&desc,1,count)) {
930 desc.subcount = count;
931 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
934 *rdata_len = desc.usedlen;
937 * We must set the return code to ERRbuftoosmall
938 * in order to support lanman style printing with Win NT/2k
939 * clients --jerry
941 if (!mdrcnt && lp_disable_spoolss())
942 desc.errcode = ERRbuftoosmall;
944 *rdata_len = desc.usedlen;
945 *rparam_len = 6;
946 *rparam = smb_realloc_limit(*rparam,*rparam_len);
947 if (!*rparam) {
948 SAFE_FREE(queue);
949 SAFE_FREE(tmpdata);
950 return False;
952 SSVALS(*rparam,0,desc.errcode);
953 SSVAL(*rparam,2,0);
954 SSVAL(*rparam,4,desc.neededlen);
956 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
958 SAFE_FREE(queue);
959 SAFE_FREE(tmpdata);
961 return(True);
964 /****************************************************************************
965 View list of all print jobs on all queues.
966 ****************************************************************************/
968 static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
969 char *param, int tpscnt,
970 char *data, int tdscnt,
971 int mdrcnt, int mprcnt,
972 char **rdata, char** rparam,
973 int *rdata_len, int *rparam_len)
975 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
976 char *output_format1 = skip_string(param,tpscnt,param_format);
977 char *p = skip_string(param,tpscnt,output_format1);
978 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
979 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
980 int services = lp_numservices();
981 int i, n;
982 struct pack_desc desc;
983 print_queue_struct **queue = NULL;
984 print_status_struct *status = NULL;
985 int *subcntarr = NULL;
986 int queuecnt = 0, subcnt = 0, succnt = 0;
988 if (!param_format || !output_format1 || !p) {
989 return False;
992 memset((char *)&desc,'\0',sizeof(desc));
994 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
996 if (!prefix_ok(param_format,"WrLeh")) {
997 return False;
999 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
1001 * Patch from Scott Moomaw <scott@bridgewater.edu>
1002 * to return the 'invalid info level' error if an
1003 * unknown level was requested.
1005 *rdata_len = 0;
1006 *rparam_len = 6;
1007 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1008 if (!*rparam) {
1009 return False;
1011 SSVALS(*rparam,0,ERRunknownlevel);
1012 SSVAL(*rparam,2,0);
1013 SSVAL(*rparam,4,0);
1014 return(True);
1017 for (i = 0; i < services; i++) {
1018 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1019 queuecnt++;
1023 if((queue = SMB_MALLOC_ARRAY(print_queue_struct*, queuecnt)) == NULL) {
1024 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1025 goto err;
1027 memset(queue,0,queuecnt*sizeof(print_queue_struct*));
1028 if((status = SMB_MALLOC_ARRAY(print_status_struct,queuecnt)) == NULL) {
1029 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1030 goto err;
1032 memset(status,0,queuecnt*sizeof(print_status_struct));
1033 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1034 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1035 goto err;
1038 subcnt = 0;
1039 n = 0;
1040 for (i = 0; i < services; i++) {
1041 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1042 subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
1043 subcnt += subcntarr[n];
1044 n++;
1048 if (mdrcnt > 0) {
1049 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1050 if (!*rdata) {
1051 goto err;
1054 desc.base = *rdata;
1055 desc.buflen = mdrcnt;
1057 if (init_package(&desc,queuecnt,subcnt)) {
1058 n = 0;
1059 succnt = 0;
1060 for (i = 0; i < services; i++) {
1061 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1062 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1063 n++;
1064 if (desc.errcode == NERR_Success) {
1065 succnt = n;
1071 SAFE_FREE(subcntarr);
1073 *rdata_len = desc.usedlen;
1074 *rparam_len = 8;
1075 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1076 if (!*rparam) {
1077 goto err;
1079 SSVALS(*rparam,0,desc.errcode);
1080 SSVAL(*rparam,2,0);
1081 SSVAL(*rparam,4,succnt);
1082 SSVAL(*rparam,6,queuecnt);
1084 for (i = 0; i < queuecnt; i++) {
1085 if (queue) {
1086 SAFE_FREE(queue[i]);
1090 SAFE_FREE(queue);
1091 SAFE_FREE(status);
1093 return True;
1095 err:
1097 SAFE_FREE(subcntarr);
1098 for (i = 0; i < queuecnt; i++) {
1099 if (queue) {
1100 SAFE_FREE(queue[i]);
1103 SAFE_FREE(queue);
1104 SAFE_FREE(status);
1106 return False;
1109 /****************************************************************************
1110 Get info level for a server list query.
1111 ****************************************************************************/
1113 static bool check_server_info(int uLevel, char* id)
1115 switch( uLevel ) {
1116 case 0:
1117 if (strcmp(id,"B16") != 0) {
1118 return False;
1120 break;
1121 case 1:
1122 if (strcmp(id,"B16BBDz") != 0) {
1123 return False;
1125 break;
1126 default:
1127 return False;
1129 return True;
1132 struct srv_info_struct {
1133 fstring name;
1134 uint32 type;
1135 fstring comment;
1136 fstring domain;
1137 bool server_added;
1140 /*******************************************************************
1141 Get server info lists from the files saved by nmbd. Return the
1142 number of entries.
1143 ******************************************************************/
1145 static int get_server_info(uint32 servertype,
1146 struct srv_info_struct **servers,
1147 const char *domain)
1149 int count=0;
1150 int alloced=0;
1151 char **lines;
1152 bool local_list_only;
1153 int i;
1155 lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
1156 if (!lines) {
1157 DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
1158 return 0;
1161 /* request for everything is code for request all servers */
1162 if (servertype == SV_TYPE_ALL) {
1163 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1166 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1168 DEBUG(4,("Servertype search: %8x\n",servertype));
1170 for (i=0;lines[i];i++) {
1171 fstring stype;
1172 struct srv_info_struct *s;
1173 const char *ptr = lines[i];
1174 bool ok = True;
1175 TALLOC_CTX *frame = NULL;
1176 char *p;
1178 if (!*ptr) {
1179 continue;
1182 if (count == alloced) {
1183 alloced += 10;
1184 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1185 if (!*servers) {
1186 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1187 TALLOC_FREE(lines);
1188 return 0;
1190 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1192 s = &(*servers)[count];
1194 frame = talloc_stackframe();
1195 s->name[0] = '\0';
1196 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1197 TALLOC_FREE(frame);
1198 continue;
1200 fstrcpy(s->name, p);
1202 stype[0] = '\0';
1203 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1204 TALLOC_FREE(frame);
1205 continue;
1207 fstrcpy(stype, p);
1209 s->comment[0] = '\0';
1210 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1211 TALLOC_FREE(frame);
1212 continue;
1214 fstrcpy(s->comment, p);
1215 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1217 s->domain[0] = '\0';
1218 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1219 /* this allows us to cope with an old nmbd */
1220 fstrcpy(s->domain,lp_workgroup());
1221 } else {
1222 fstrcpy(s->domain, p);
1224 TALLOC_FREE(frame);
1226 if (sscanf(stype,"%X",&s->type) != 1) {
1227 DEBUG(4,("r:host file "));
1228 ok = False;
1231 /* Filter the servers/domains we return based on what was asked for. */
1233 /* Check to see if we are being asked for a local list only. */
1234 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1235 DEBUG(4,("r: local list only"));
1236 ok = False;
1239 /* doesn't match up: don't want it */
1240 if (!(servertype & s->type)) {
1241 DEBUG(4,("r:serv type "));
1242 ok = False;
1245 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1246 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1247 DEBUG(4,("s: dom mismatch "));
1248 ok = False;
1251 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1252 ok = False;
1255 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1256 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1258 if (ok) {
1259 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1260 s->name, s->type, s->comment, s->domain));
1261 s->server_added = True;
1262 count++;
1263 } else {
1264 DEBUG(4,("%20s %8x %25s %15s\n",
1265 s->name, s->type, s->comment, s->domain));
1269 TALLOC_FREE(lines);
1270 return count;
1273 /*******************************************************************
1274 Fill in a server info structure.
1275 ******************************************************************/
1277 static int fill_srv_info(struct srv_info_struct *service,
1278 int uLevel, char **buf, int *buflen,
1279 char **stringbuf, int *stringspace, char *baseaddr)
1281 int struct_len;
1282 char* p;
1283 char* p2;
1284 int l2;
1285 int len;
1287 switch (uLevel) {
1288 case 0:
1289 struct_len = 16;
1290 break;
1291 case 1:
1292 struct_len = 26;
1293 break;
1294 default:
1295 return -1;
1298 if (!buf) {
1299 len = 0;
1300 switch (uLevel) {
1301 case 1:
1302 len = strlen(service->comment)+1;
1303 break;
1306 *buflen = struct_len;
1307 *stringspace = len;
1308 return struct_len + len;
1311 len = struct_len;
1312 p = *buf;
1313 if (*buflen < struct_len) {
1314 return -1;
1316 if (stringbuf) {
1317 p2 = *stringbuf;
1318 l2 = *stringspace;
1319 } else {
1320 p2 = p + struct_len;
1321 l2 = *buflen - struct_len;
1323 if (!baseaddr) {
1324 baseaddr = p;
1327 switch (uLevel) {
1328 case 0:
1329 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1330 break;
1332 case 1:
1333 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1334 SIVAL(p,18,service->type);
1335 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1336 len += CopyAndAdvance(&p2,service->comment,&l2);
1337 break;
1340 if (stringbuf) {
1341 *buf = p + struct_len;
1342 *buflen -= struct_len;
1343 *stringbuf = p2;
1344 *stringspace = l2;
1345 } else {
1346 *buf = p2;
1347 *buflen -= len;
1349 return len;
1353 static bool srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1355 return(strcmp(s1->name,s2->name));
1358 /****************************************************************************
1359 View list of servers available (or possibly domains). The info is
1360 extracted from lists saved by nmbd on the local host.
1361 ****************************************************************************/
1363 static bool api_RNetServerEnum(connection_struct *conn, uint16 vuid,
1364 char *param, int tpscnt,
1365 char *data, int tdscnt,
1366 int mdrcnt, int mprcnt, char **rdata,
1367 char **rparam, int *rdata_len, int *rparam_len)
1369 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1370 char *str2 = skip_string(param,tpscnt,str1);
1371 char *p = skip_string(param,tpscnt,str2);
1372 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1373 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1374 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1375 char *p2;
1376 int data_len, fixed_len, string_len;
1377 int f_len = 0, s_len = 0;
1378 struct srv_info_struct *servers=NULL;
1379 int counted=0,total=0;
1380 int i,missed;
1381 fstring domain;
1382 bool domain_request;
1383 bool local_request;
1385 if (!str1 || !str2 || !p) {
1386 return False;
1389 /* If someone sets all the bits they don't really mean to set
1390 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1391 known servers. */
1393 if (servertype == SV_TYPE_ALL) {
1394 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1397 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1398 any other bit (they may just set this bit on its own) they
1399 want all the locally seen servers. However this bit can be
1400 set on its own so set the requested servers to be
1401 ALL - DOMAIN_ENUM. */
1403 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1404 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1407 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1408 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1410 p += 8;
1412 if (!prefix_ok(str1,"WrLehD")) {
1413 return False;
1415 if (!check_server_info(uLevel,str2)) {
1416 return False;
1419 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1420 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1421 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1423 if (strcmp(str1, "WrLehDz") == 0) {
1424 if (skip_string(param,tpscnt,p) == NULL) {
1425 return False;
1427 pull_ascii_fstring(domain, p);
1428 } else {
1429 fstrcpy(domain, lp_workgroup());
1432 if (lp_browse_list()) {
1433 total = get_server_info(servertype,&servers,domain);
1436 data_len = fixed_len = string_len = 0;
1437 missed = 0;
1439 if (total > 0) {
1440 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1444 char *lastname=NULL;
1446 for (i=0;i<total;i++) {
1447 struct srv_info_struct *s = &servers[i];
1449 if (lastname && strequal(lastname,s->name)) {
1450 continue;
1452 lastname = s->name;
1453 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1454 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1455 s->name, s->type, s->comment, s->domain));
1457 if (data_len <= buf_len) {
1458 counted++;
1459 fixed_len += f_len;
1460 string_len += s_len;
1461 } else {
1462 missed++;
1467 *rdata_len = fixed_len + string_len;
1468 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1469 if (!*rdata) {
1470 return False;
1473 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1474 p = *rdata;
1475 f_len = fixed_len;
1476 s_len = string_len;
1479 char *lastname=NULL;
1480 int count2 = counted;
1482 for (i = 0; i < total && count2;i++) {
1483 struct srv_info_struct *s = &servers[i];
1485 if (lastname && strequal(lastname,s->name)) {
1486 continue;
1488 lastname = s->name;
1489 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1490 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1491 s->name, s->type, s->comment, s->domain));
1492 count2--;
1496 *rparam_len = 8;
1497 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1498 if (!*rparam) {
1499 return False;
1501 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1502 SSVAL(*rparam,2,0);
1503 SSVAL(*rparam,4,counted);
1504 SSVAL(*rparam,6,counted+missed);
1506 SAFE_FREE(servers);
1508 DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1509 domain,uLevel,counted,counted+missed));
1511 return True;
1514 /****************************************************************************
1515 command 0x34 - suspected of being a "Lookup Names" stub api
1516 ****************************************************************************/
1518 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1519 char *param, int tpscnt,
1520 char *data, int tdscnt,
1521 int mdrcnt, int mprcnt, char **rdata,
1522 char **rparam, int *rdata_len, int *rparam_len)
1524 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1525 char *str2 = skip_string(param,tpscnt,str1);
1526 char *p = skip_string(param,tpscnt,str2);
1527 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1528 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1529 int counted=0;
1530 int missed=0;
1532 if (!str1 || !str2 || !p) {
1533 return False;
1536 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1537 str1, str2, p, uLevel, buf_len));
1539 if (!prefix_ok(str1,"zWrLeh")) {
1540 return False;
1543 *rdata_len = 0;
1545 *rparam_len = 8;
1546 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1547 if (!*rparam) {
1548 return False;
1551 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1552 SSVAL(*rparam,2,0);
1553 SSVAL(*rparam,4,counted);
1554 SSVAL(*rparam,6,counted+missed);
1556 return True;
1559 /****************************************************************************
1560 get info about a share
1561 ****************************************************************************/
1563 static bool check_share_info(int uLevel, char* id)
1565 switch( uLevel ) {
1566 case 0:
1567 if (strcmp(id,"B13") != 0) {
1568 return False;
1570 break;
1571 case 1:
1572 if (strcmp(id,"B13BWz") != 0) {
1573 return False;
1575 break;
1576 case 2:
1577 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1578 return False;
1580 break;
1581 case 91:
1582 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1583 return False;
1585 break;
1586 default:
1587 return False;
1589 return True;
1592 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1593 char** buf, int* buflen,
1594 char** stringbuf, int* stringspace, char* baseaddr)
1596 int struct_len;
1597 char* p;
1598 char* p2;
1599 int l2;
1600 int len;
1602 switch( uLevel ) {
1603 case 0:
1604 struct_len = 13;
1605 break;
1606 case 1:
1607 struct_len = 20;
1608 break;
1609 case 2:
1610 struct_len = 40;
1611 break;
1612 case 91:
1613 struct_len = 68;
1614 break;
1615 default:
1616 return -1;
1619 if (!buf) {
1620 len = 0;
1622 if (uLevel > 0) {
1623 len += StrlenExpanded(conn,snum,lp_comment(snum));
1625 if (uLevel > 1) {
1626 len += strlen(lp_pathname(snum)) + 1;
1628 if (buflen) {
1629 *buflen = struct_len;
1631 if (stringspace) {
1632 *stringspace = len;
1634 return struct_len + len;
1637 len = struct_len;
1638 p = *buf;
1639 if ((*buflen) < struct_len) {
1640 return -1;
1643 if (stringbuf) {
1644 p2 = *stringbuf;
1645 l2 = *stringspace;
1646 } else {
1647 p2 = p + struct_len;
1648 l2 = (*buflen) - struct_len;
1651 if (!baseaddr) {
1652 baseaddr = p;
1655 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1657 if (uLevel > 0) {
1658 int type;
1660 SCVAL(p,13,0);
1661 type = STYPE_DISKTREE;
1662 if (lp_print_ok(snum)) {
1663 type = STYPE_PRINTQ;
1665 if (strequal("IPC",lp_fstype(snum))) {
1666 type = STYPE_IPC;
1668 SSVAL(p,14,type); /* device type */
1669 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1670 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1673 if (uLevel > 1) {
1674 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1675 SSVALS(p,22,-1); /* max uses */
1676 SSVAL(p,24,1); /* current uses */
1677 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1678 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1679 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1682 if (uLevel > 2) {
1683 memset(p+40,0,SHPWLEN+2);
1684 SSVAL(p,50,0);
1685 SIVAL(p,52,0);
1686 SSVAL(p,56,0);
1687 SSVAL(p,58,0);
1688 SIVAL(p,60,0);
1689 SSVAL(p,64,0);
1690 SSVAL(p,66,0);
1693 if (stringbuf) {
1694 (*buf) = p + struct_len;
1695 (*buflen) -= struct_len;
1696 (*stringbuf) = p2;
1697 (*stringspace) = l2;
1698 } else {
1699 (*buf) = p2;
1700 (*buflen) -= len;
1703 return len;
1706 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1707 char *param, int tpscnt,
1708 char *data, int tdscnt,
1709 int mdrcnt,int mprcnt,
1710 char **rdata,char **rparam,
1711 int *rdata_len,int *rparam_len)
1713 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1714 char *str2 = skip_string(param,tpscnt,str1);
1715 char *netname = skip_string(param,tpscnt,str2);
1716 char *p = skip_string(param,tpscnt,netname);
1717 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1718 int snum;
1720 if (!str1 || !str2 || !netname || !p) {
1721 return False;
1724 snum = find_service(netname);
1725 if (snum < 0) {
1726 return False;
1729 /* check it's a supported varient */
1730 if (!prefix_ok(str1,"zWrLh")) {
1731 return False;
1733 if (!check_share_info(uLevel,str2)) {
1734 return False;
1737 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1738 if (!*rdata) {
1739 return False;
1741 p = *rdata;
1742 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1743 if (*rdata_len < 0) {
1744 return False;
1747 *rparam_len = 6;
1748 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1749 if (!*rparam) {
1750 return False;
1752 SSVAL(*rparam,0,NERR_Success);
1753 SSVAL(*rparam,2,0); /* converter word */
1754 SSVAL(*rparam,4,*rdata_len);
1756 return True;
1759 /****************************************************************************
1760 View the list of available shares.
1762 This function is the server side of the NetShareEnum() RAP call.
1763 It fills the return buffer with share names and share comments.
1764 Note that the return buffer normally (in all known cases) allows only
1765 twelve byte strings for share names (plus one for a nul terminator).
1766 Share names longer than 12 bytes must be skipped.
1767 ****************************************************************************/
1769 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
1770 char *param, int tpscnt,
1771 char *data, int tdscnt,
1772 int mdrcnt,
1773 int mprcnt,
1774 char **rdata,
1775 char **rparam,
1776 int *rdata_len,
1777 int *rparam_len )
1779 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1780 char *str2 = skip_string(param,tpscnt,str1);
1781 char *p = skip_string(param,tpscnt,str2);
1782 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1783 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1784 char *p2;
1785 int count = 0;
1786 int total=0,counted=0;
1787 bool missed = False;
1788 int i;
1789 int data_len, fixed_len, string_len;
1790 int f_len = 0, s_len = 0;
1792 if (!str1 || !str2 || !p) {
1793 return False;
1796 if (!prefix_ok(str1,"WrLeh")) {
1797 return False;
1799 if (!check_share_info(uLevel,str2)) {
1800 return False;
1803 /* Ensure all the usershares are loaded. */
1804 become_root();
1805 load_registry_shares();
1806 count = load_usershare_shares();
1807 unbecome_root();
1809 data_len = fixed_len = string_len = 0;
1810 for (i=0;i<count;i++) {
1811 fstring servicename_dos;
1812 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1813 continue;
1815 push_ascii_fstring(servicename_dos, lp_servicename(i));
1816 /* Maximum name length = 13. */
1817 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
1818 total++;
1819 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1820 if (data_len <= buf_len) {
1821 counted++;
1822 fixed_len += f_len;
1823 string_len += s_len;
1824 } else {
1825 missed = True;
1830 *rdata_len = fixed_len + string_len;
1831 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1832 if (!*rdata) {
1833 return False;
1836 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
1837 p = *rdata;
1838 f_len = fixed_len;
1839 s_len = string_len;
1841 for( i = 0; i < count; i++ ) {
1842 fstring servicename_dos;
1843 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1844 continue;
1847 push_ascii_fstring(servicename_dos, lp_servicename(i));
1848 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
1849 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
1850 break;
1855 *rparam_len = 8;
1856 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1857 if (!*rparam) {
1858 return False;
1860 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1861 SSVAL(*rparam,2,0);
1862 SSVAL(*rparam,4,counted);
1863 SSVAL(*rparam,6,total);
1865 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1866 counted,total,uLevel,
1867 buf_len,*rdata_len,mdrcnt));
1869 return True;
1872 /****************************************************************************
1873 Add a share
1874 ****************************************************************************/
1876 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
1877 char *param, int tpscnt,
1878 char *data, int tdscnt,
1879 int mdrcnt,int mprcnt,
1880 char **rdata,char **rparam,
1881 int *rdata_len,int *rparam_len)
1883 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1884 char *str2 = skip_string(param,tpscnt,str1);
1885 char *p = skip_string(param,tpscnt,str2);
1886 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1887 fstring sharename;
1888 fstring comment;
1889 char *pathname = NULL;
1890 char *command, *cmdname;
1891 unsigned int offset;
1892 int snum;
1893 int res = ERRunsup;
1894 size_t converted_size;
1896 if (!str1 || !str2 || !p) {
1897 return False;
1900 /* check it's a supported varient */
1901 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
1902 return False;
1904 if (!check_share_info(uLevel,str2)) {
1905 return False;
1907 if (uLevel != 2) {
1908 return False;
1911 /* Do we have a string ? */
1912 if (skip_string(data,mdrcnt,data) == NULL) {
1913 return False;
1915 pull_ascii_fstring(sharename,data);
1916 snum = find_service(sharename);
1917 if (snum >= 0) { /* already exists */
1918 res = ERRfilexists;
1919 goto error_exit;
1922 if (mdrcnt < 28) {
1923 return False;
1926 /* only support disk share adds */
1927 if (SVAL(data,14)!=STYPE_DISKTREE) {
1928 return False;
1931 offset = IVAL(data, 16);
1932 if (offset >= mdrcnt) {
1933 res = ERRinvalidparam;
1934 goto error_exit;
1937 /* Do we have a string ? */
1938 if (skip_string(data,mdrcnt,data+offset) == NULL) {
1939 return False;
1941 pull_ascii_fstring(comment, offset? (data+offset) : "");
1943 offset = IVAL(data, 26);
1945 if (offset >= mdrcnt) {
1946 res = ERRinvalidparam;
1947 goto error_exit;
1950 /* Do we have a string ? */
1951 if (skip_string(data,mdrcnt,data+offset) == NULL) {
1952 return False;
1955 if (!pull_ascii_talloc(talloc_tos(), &pathname,
1956 offset ? (data+offset) : "", &converted_size))
1958 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
1959 strerror(errno)));
1962 if (!pathname) {
1963 return false;
1966 string_replace(sharename, '"', ' ');
1967 string_replace(pathname, '"', ' ');
1968 string_replace(comment, '"', ' ');
1970 cmdname = lp_add_share_cmd();
1972 if (!cmdname || *cmdname == '\0') {
1973 return False;
1976 if (asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
1977 lp_add_share_cmd(), get_dyn_CONFIGFILE(), sharename,
1978 pathname, comment) == -1) {
1979 return false;
1982 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
1984 if ((res = smbrun(command, NULL)) != 0) {
1985 DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n",
1986 command, res ));
1987 SAFE_FREE(command);
1988 res = ERRnoaccess;
1989 goto error_exit;
1990 } else {
1991 SAFE_FREE(command);
1992 message_send_all(smbd_messaging_context(),
1993 MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
1996 *rparam_len = 6;
1997 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1998 if (!*rparam) {
1999 return False;
2001 SSVAL(*rparam,0,NERR_Success);
2002 SSVAL(*rparam,2,0); /* converter word */
2003 SSVAL(*rparam,4,*rdata_len);
2004 *rdata_len = 0;
2006 return True;
2008 error_exit:
2010 *rparam_len = 4;
2011 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2012 if (!*rparam) {
2013 return False;
2015 *rdata_len = 0;
2016 SSVAL(*rparam,0,res);
2017 SSVAL(*rparam,2,0);
2018 return True;
2021 /****************************************************************************
2022 view list of groups available
2023 ****************************************************************************/
2025 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
2026 char *param, int tpscnt,
2027 char *data, int tdscnt,
2028 int mdrcnt,int mprcnt,
2029 char **rdata,char **rparam,
2030 int *rdata_len,int *rparam_len)
2032 int i;
2033 int errflags=0;
2034 int resume_context, cli_buf_size;
2035 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2036 char *str2 = skip_string(param,tpscnt,str1);
2037 char *p = skip_string(param,tpscnt,str2);
2039 uint32_t num_groups;
2040 uint32_t resume_handle;
2041 struct rpc_pipe_client *samr_pipe;
2042 struct policy_handle samr_handle, domain_handle;
2043 NTSTATUS status;
2045 if (!str1 || !str2 || !p) {
2046 return False;
2049 if (strcmp(str1,"WrLeh") != 0) {
2050 return False;
2053 /* parameters
2054 * W-> resume context (number of users to skip)
2055 * r -> return parameter pointer to receive buffer
2056 * L -> length of receive buffer
2057 * e -> return parameter number of entries
2058 * h -> return parameter total number of users
2061 if (strcmp("B21",str2) != 0) {
2062 return False;
2065 status = rpc_pipe_open_internal(
2066 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2067 conn->server_info, &samr_pipe);
2068 if (!NT_STATUS_IS_OK(status)) {
2069 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2070 nt_errstr(status)));
2071 return false;
2074 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2075 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2076 if (!NT_STATUS_IS_OK(status)) {
2077 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2078 nt_errstr(status)));
2079 return false;
2082 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2083 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2084 get_global_sam_sid(), &domain_handle);
2085 if (!NT_STATUS_IS_OK(status)) {
2086 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2087 nt_errstr(status)));
2088 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2089 return false;
2092 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2093 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2094 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2095 "%d\n", resume_context, cli_buf_size));
2097 *rdata_len = cli_buf_size;
2098 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2099 if (!*rdata) {
2100 return False;
2103 p = *rdata;
2105 errflags = NERR_Success;
2106 num_groups = 0;
2107 resume_handle = 0;
2109 while (true) {
2110 struct samr_SamArray *sam_entries;
2111 uint32_t num_entries;
2113 status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
2114 &domain_handle,
2115 &resume_handle,
2116 &sam_entries, 1,
2117 &num_entries);
2118 if (!NT_STATUS_IS_OK(status)) {
2119 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2120 "%s\n", nt_errstr(status)));
2121 break;
2124 if (num_entries == 0) {
2125 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2126 "no entries -- done\n"));
2127 break;
2130 for(i=0; i<num_entries; i++) {
2131 const char *name;
2133 name = sam_entries->entries[i].name.string;
2135 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2136 /* set overflow error */
2137 DEBUG(3,("overflow on entry %d group %s\n", i,
2138 name));
2139 errflags=234;
2140 break;
2143 /* truncate the name at 21 chars. */
2144 memset(p, 0, 21);
2145 strlcpy(p, name, 21);
2146 DEBUG(10,("adding entry %d group %s\n", i, p));
2147 p += 21;
2148 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2149 * idea why... */
2150 num_groups += 1;
2153 if (errflags != NERR_Success) {
2154 break;
2157 TALLOC_FREE(sam_entries);
2160 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2161 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2163 *rdata_len = PTR_DIFF(p,*rdata);
2165 *rparam_len = 8;
2166 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2167 if (!*rparam) {
2168 return False;
2170 SSVAL(*rparam, 0, errflags);
2171 SSVAL(*rparam, 2, 0); /* converter word */
2172 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2173 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2175 return(True);
2178 /*******************************************************************
2179 Get groups that a user is a member of.
2180 ******************************************************************/
2182 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2183 char *param, int tpscnt,
2184 char *data, int tdscnt,
2185 int mdrcnt,int mprcnt,
2186 char **rdata,char **rparam,
2187 int *rdata_len,int *rparam_len)
2189 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2190 char *str2 = skip_string(param,tpscnt,str1);
2191 char *UserName = skip_string(param,tpscnt,str2);
2192 char *p = skip_string(param,tpscnt,UserName);
2193 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2194 const char *level_string;
2195 int count=0;
2196 bool ret = False;
2197 uint32_t i;
2198 char *endp = NULL;
2200 struct rpc_pipe_client *samr_pipe;
2201 struct policy_handle samr_handle, domain_handle, user_handle;
2202 struct lsa_String name;
2203 struct lsa_Strings names;
2204 struct samr_Ids type, rid;
2205 struct samr_RidWithAttributeArray *rids;
2206 NTSTATUS status;
2208 if (!str1 || !str2 || !UserName || !p) {
2209 return False;
2212 *rparam_len = 8;
2213 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2214 if (!*rparam) {
2215 return False;
2218 /* check it's a supported varient */
2220 if ( strcmp(str1,"zWrLeh") != 0 )
2221 return False;
2223 switch( uLevel ) {
2224 case 0:
2225 level_string = "B21";
2226 break;
2227 default:
2228 return False;
2231 if (strcmp(level_string,str2) != 0)
2232 return False;
2234 *rdata_len = mdrcnt + 1024;
2235 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2236 if (!*rdata) {
2237 return False;
2240 SSVAL(*rparam,0,NERR_Success);
2241 SSVAL(*rparam,2,0); /* converter word */
2243 p = *rdata;
2244 endp = *rdata + *rdata_len;
2246 status = rpc_pipe_open_internal(
2247 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2248 conn->server_info, &samr_pipe);
2249 if (!NT_STATUS_IS_OK(status)) {
2250 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2251 nt_errstr(status)));
2252 return false;
2255 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2256 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2257 if (!NT_STATUS_IS_OK(status)) {
2258 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2259 nt_errstr(status)));
2260 return false;
2263 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2264 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2265 get_global_sam_sid(), &domain_handle);
2266 if (!NT_STATUS_IS_OK(status)) {
2267 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2268 nt_errstr(status)));
2269 goto close_sam;
2272 name.string = UserName;
2274 status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
2275 &domain_handle, 1, &name,
2276 &rid, &type);
2277 if (!NT_STATUS_IS_OK(status)) {
2278 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2279 nt_errstr(status)));
2280 goto close_domain;
2283 if (type.ids[0] != SID_NAME_USER) {
2284 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2285 sid_type_lookup(type.ids[0])));
2286 goto close_domain;
2289 status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
2290 &domain_handle,
2291 SAMR_USER_ACCESS_GET_GROUPS,
2292 rid.ids[0], &user_handle);
2293 if (!NT_STATUS_IS_OK(status)) {
2294 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2295 nt_errstr(status)));
2296 goto close_domain;
2299 status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
2300 &user_handle, &rids);
2301 if (!NT_STATUS_IS_OK(status)) {
2302 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2303 nt_errstr(status)));
2304 goto close_user;
2307 for (i=0; i<rids->count; i++) {
2309 status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
2310 &domain_handle,
2311 1, &rids->rids[i].rid,
2312 &names, &type);
2313 if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
2314 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2315 p += 21;
2316 count++;
2320 *rdata_len = PTR_DIFF(p,*rdata);
2322 SSVAL(*rparam,4,count); /* is this right?? */
2323 SSVAL(*rparam,6,count); /* is this right?? */
2325 ret = True;
2327 close_user:
2328 rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
2329 close_domain:
2330 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2331 close_sam:
2332 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2334 return ret;
2337 /*******************************************************************
2338 Get all users.
2339 ******************************************************************/
2341 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2342 char *param, int tpscnt,
2343 char *data, int tdscnt,
2344 int mdrcnt,int mprcnt,
2345 char **rdata,char **rparam,
2346 int *rdata_len,int *rparam_len)
2348 int count_sent=0;
2349 int num_users=0;
2350 int errflags=0;
2351 int i, resume_context, cli_buf_size;
2352 uint32_t resume_handle;
2354 struct rpc_pipe_client *samr_pipe;
2355 struct policy_handle samr_handle, domain_handle;
2356 NTSTATUS status;
2358 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2359 char *str2 = skip_string(param,tpscnt,str1);
2360 char *p = skip_string(param,tpscnt,str2);
2361 char *endp = NULL;
2363 if (!str1 || !str2 || !p) {
2364 return False;
2367 if (strcmp(str1,"WrLeh") != 0)
2368 return False;
2369 /* parameters
2370 * W-> resume context (number of users to skip)
2371 * r -> return parameter pointer to receive buffer
2372 * L -> length of receive buffer
2373 * e -> return parameter number of entries
2374 * h -> return parameter total number of users
2377 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2378 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2379 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2380 resume_context, cli_buf_size));
2382 *rparam_len = 8;
2383 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2384 if (!*rparam) {
2385 return False;
2388 /* check it's a supported varient */
2389 if (strcmp("B21",str2) != 0)
2390 return False;
2392 *rdata_len = cli_buf_size;
2393 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2394 if (!*rdata) {
2395 return False;
2398 p = *rdata;
2399 endp = *rdata + *rdata_len;
2401 status = rpc_pipe_open_internal(
2402 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2403 conn->server_info, &samr_pipe);
2404 if (!NT_STATUS_IS_OK(status)) {
2405 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2406 nt_errstr(status)));
2407 return false;
2410 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2411 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2412 if (!NT_STATUS_IS_OK(status)) {
2413 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2414 nt_errstr(status)));
2415 return false;
2418 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2419 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2420 get_global_sam_sid(), &domain_handle);
2421 if (!NT_STATUS_IS_OK(status)) {
2422 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2423 nt_errstr(status)));
2424 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2425 return false;
2428 errflags=NERR_Success;
2430 resume_handle = 0;
2432 while (true) {
2433 struct samr_SamArray *sam_entries;
2434 uint32_t num_entries;
2436 status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
2437 &domain_handle,
2438 &resume_handle,
2439 0, &sam_entries, 1,
2440 &num_entries);
2442 if (!NT_STATUS_IS_OK(status)) {
2443 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2444 "%s\n", nt_errstr(status)));
2445 break;
2448 if (num_entries == 0) {
2449 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2450 "no entries -- done\n"));
2451 break;
2454 for (i=0; i<num_entries; i++) {
2455 const char *name;
2457 name = sam_entries->entries[i].name.string;
2459 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2460 &&(strlen(name)<=21)) {
2461 strlcpy(p,name,PTR_DIFF(endp,p));
2462 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2463 "username %s\n",count_sent,p));
2464 p += 21;
2465 count_sent++;
2466 } else {
2467 /* set overflow error */
2468 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2469 "username %s\n",count_sent,name));
2470 errflags=234;
2471 break;
2475 if (errflags != NERR_Success) {
2476 break;
2479 TALLOC_FREE(sam_entries);
2482 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2483 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2485 *rdata_len = PTR_DIFF(p,*rdata);
2487 SSVAL(*rparam,0,errflags);
2488 SSVAL(*rparam,2,0); /* converter word */
2489 SSVAL(*rparam,4,count_sent); /* is this right?? */
2490 SSVAL(*rparam,6,num_users); /* is this right?? */
2492 return True;
2495 /****************************************************************************
2496 Get the time of day info.
2497 ****************************************************************************/
2499 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2500 char *param, int tpscnt,
2501 char *data, int tdscnt,
2502 int mdrcnt,int mprcnt,
2503 char **rdata,char **rparam,
2504 int *rdata_len,int *rparam_len)
2506 struct tm *t;
2507 time_t unixdate = time(NULL);
2508 char *p;
2510 *rparam_len = 4;
2511 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2512 if (!*rparam) {
2513 return False;
2516 *rdata_len = 21;
2517 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2518 if (!*rdata) {
2519 return False;
2522 SSVAL(*rparam,0,NERR_Success);
2523 SSVAL(*rparam,2,0); /* converter word */
2525 p = *rdata;
2527 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2528 by NT in a "net time" operation,
2529 it seems to ignore the one below */
2531 /* the client expects to get localtime, not GMT, in this bit
2532 (I think, this needs testing) */
2533 t = localtime(&unixdate);
2534 if (!t) {
2535 return False;
2538 SIVAL(p,4,0); /* msecs ? */
2539 SCVAL(p,8,t->tm_hour);
2540 SCVAL(p,9,t->tm_min);
2541 SCVAL(p,10,t->tm_sec);
2542 SCVAL(p,11,0); /* hundredths of seconds */
2543 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2544 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2545 SCVAL(p,16,t->tm_mday);
2546 SCVAL(p,17,t->tm_mon + 1);
2547 SSVAL(p,18,1900+t->tm_year);
2548 SCVAL(p,20,t->tm_wday);
2550 return True;
2553 /****************************************************************************
2554 Set the user password.
2555 *****************************************************************************/
2557 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2558 char *param, int tpscnt,
2559 char *data, int tdscnt,
2560 int mdrcnt,int mprcnt,
2561 char **rdata,char **rparam,
2562 int *rdata_len,int *rparam_len)
2564 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2565 char *p = NULL;
2566 fstring user;
2567 fstring pass1,pass2;
2569 /* Skip 2 strings. */
2570 p = skip_string(param,tpscnt,np);
2571 p = skip_string(param,tpscnt,p);
2573 if (!np || !p) {
2574 return False;
2577 /* Do we have a string ? */
2578 if (skip_string(param,tpscnt,p) == NULL) {
2579 return False;
2581 pull_ascii_fstring(user,p);
2583 p = skip_string(param,tpscnt,p);
2584 if (!p) {
2585 return False;
2588 memset(pass1,'\0',sizeof(pass1));
2589 memset(pass2,'\0',sizeof(pass2));
2591 * We use 31 here not 32 as we're checking
2592 * the last byte we want to access is safe.
2594 if (!is_offset_safe(param,tpscnt,p,31)) {
2595 return False;
2597 memcpy(pass1,p,16);
2598 memcpy(pass2,p+16,16);
2600 *rparam_len = 4;
2601 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2602 if (!*rparam) {
2603 return False;
2606 *rdata_len = 0;
2608 SSVAL(*rparam,0,NERR_badpass);
2609 SSVAL(*rparam,2,0); /* converter word */
2611 DEBUG(3,("Set password for <%s>\n",user));
2614 * Attempt to verify the old password against smbpasswd entries
2615 * Win98 clients send old and new password in plaintext for this call.
2619 auth_serversupplied_info *server_info = NULL;
2620 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2622 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2624 become_root();
2625 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2626 SSVAL(*rparam,0,NERR_Success);
2628 unbecome_root();
2630 TALLOC_FREE(server_info);
2632 data_blob_clear_free(&password);
2636 * If the plaintext change failed, attempt
2637 * the old encrypted method. NT will generate this
2638 * after trying the samr method. Note that this
2639 * method is done as a last resort as this
2640 * password change method loses the NT password hash
2641 * and cannot change the UNIX password as no plaintext
2642 * is received.
2645 if(SVAL(*rparam,0) != NERR_Success) {
2646 struct samu *hnd = NULL;
2648 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2649 become_root();
2650 if (change_lanman_password(hnd,(uchar *)pass2)) {
2651 SSVAL(*rparam,0,NERR_Success);
2653 unbecome_root();
2654 TALLOC_FREE(hnd);
2658 memset((char *)pass1,'\0',sizeof(fstring));
2659 memset((char *)pass2,'\0',sizeof(fstring));
2661 return(True);
2664 /****************************************************************************
2665 Set the user password (SamOEM version - gets plaintext).
2666 ****************************************************************************/
2668 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2669 char *param, int tpscnt,
2670 char *data, int tdscnt,
2671 int mdrcnt,int mprcnt,
2672 char **rdata,char **rparam,
2673 int *rdata_len,int *rparam_len)
2675 struct smbd_server_connection *sconn = smbd_server_conn;
2676 fstring user;
2677 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2678 *rparam_len = 2;
2679 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2680 if (!*rparam) {
2681 return False;
2684 if (!p) {
2685 return False;
2687 *rdata_len = 0;
2689 SSVAL(*rparam,0,NERR_badpass);
2692 * Check the parameter definition is correct.
2695 /* Do we have a string ? */
2696 if (skip_string(param,tpscnt,p) == 0) {
2697 return False;
2699 if(!strequal(p, "zsT")) {
2700 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2701 return False;
2703 p = skip_string(param, tpscnt, p);
2704 if (!p) {
2705 return False;
2708 /* Do we have a string ? */
2709 if (skip_string(param,tpscnt,p) == 0) {
2710 return False;
2712 if(!strequal(p, "B516B16")) {
2713 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2714 return False;
2716 p = skip_string(param,tpscnt,p);
2717 if (!p) {
2718 return False;
2720 /* Do we have a string ? */
2721 if (skip_string(param,tpscnt,p) == 0) {
2722 return False;
2724 p += pull_ascii_fstring(user,p);
2726 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2729 * Pass the user through the NT -> unix user mapping
2730 * function.
2733 (void)map_username(sconn, user);
2735 if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2736 SSVAL(*rparam,0,NERR_Success);
2739 return(True);
2742 /****************************************************************************
2743 delete a print job
2744 Form: <W> <>
2745 ****************************************************************************/
2747 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
2748 char *param, int tpscnt,
2749 char *data, int tdscnt,
2750 int mdrcnt,int mprcnt,
2751 char **rdata,char **rparam,
2752 int *rdata_len,int *rparam_len)
2754 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2755 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2756 char *str2 = skip_string(param,tpscnt,str1);
2757 char *p = skip_string(param,tpscnt,str2);
2758 uint32 jobid;
2759 int snum;
2760 fstring sharename;
2761 int errcode;
2762 WERROR werr = WERR_OK;
2764 if (!str1 || !str2 || !p) {
2765 return False;
2768 * We use 1 here not 2 as we're checking
2769 * the last byte we want to access is safe.
2771 if (!is_offset_safe(param,tpscnt,p,1)) {
2772 return False;
2774 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2775 return False;
2777 /* check it's a supported varient */
2778 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2779 return(False);
2781 *rparam_len = 4;
2782 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2783 if (!*rparam) {
2784 return False;
2786 *rdata_len = 0;
2788 if (!print_job_exists(sharename, jobid)) {
2789 errcode = NERR_JobNotFound;
2790 goto out;
2793 snum = lp_servicenumber( sharename);
2794 if (snum == -1) {
2795 errcode = NERR_DestNotFound;
2796 goto out;
2799 errcode = NERR_notsupported;
2801 switch (function) {
2802 case 81: /* delete */
2803 if (print_job_delete(conn->server_info, snum, jobid, &werr))
2804 errcode = NERR_Success;
2805 break;
2806 case 82: /* pause */
2807 if (print_job_pause(conn->server_info, snum, jobid, &werr))
2808 errcode = NERR_Success;
2809 break;
2810 case 83: /* resume */
2811 if (print_job_resume(conn->server_info, snum, jobid, &werr))
2812 errcode = NERR_Success;
2813 break;
2816 if (!W_ERROR_IS_OK(werr))
2817 errcode = W_ERROR_V(werr);
2819 out:
2820 SSVAL(*rparam,0,errcode);
2821 SSVAL(*rparam,2,0); /* converter word */
2823 return(True);
2826 /****************************************************************************
2827 Purge a print queue - or pause or resume it.
2828 ****************************************************************************/
2830 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
2831 char *param, int tpscnt,
2832 char *data, int tdscnt,
2833 int mdrcnt,int mprcnt,
2834 char **rdata,char **rparam,
2835 int *rdata_len,int *rparam_len)
2837 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2838 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2839 char *str2 = skip_string(param,tpscnt,str1);
2840 char *QueueName = skip_string(param,tpscnt,str2);
2841 int errcode = NERR_notsupported;
2842 int snum;
2843 WERROR werr = WERR_OK;
2845 if (!str1 || !str2 || !QueueName) {
2846 return False;
2849 /* check it's a supported varient */
2850 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
2851 return(False);
2853 *rparam_len = 4;
2854 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2855 if (!*rparam) {
2856 return False;
2858 *rdata_len = 0;
2860 if (skip_string(param,tpscnt,QueueName) == NULL) {
2861 return False;
2863 snum = print_queue_snum(QueueName);
2865 if (snum == -1) {
2866 errcode = NERR_JobNotFound;
2867 goto out;
2870 switch (function) {
2871 case 74: /* Pause queue */
2872 werr = print_queue_pause(conn->server_info, snum);
2873 break;
2874 case 75: /* Resume queue */
2875 werr = print_queue_resume(conn->server_info, snum);
2876 break;
2877 case 103: /* Purge */
2878 werr = print_queue_purge(conn->server_info, snum);
2879 break;
2880 default:
2881 werr = WERR_NOT_SUPPORTED;
2882 break;
2885 errcode = W_ERROR_V(werr);
2887 out:
2888 SSVAL(*rparam,0,errcode);
2889 SSVAL(*rparam,2,0); /* converter word */
2891 return(True);
2894 /****************************************************************************
2895 set the property of a print job (undocumented?)
2896 ? function = 0xb -> set name of print job
2897 ? function = 0x6 -> move print job up/down
2898 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
2899 or <WWsTP> <WB21BB16B10zWWzDDz>
2900 ****************************************************************************/
2902 static int check_printjob_info(struct pack_desc* desc,
2903 int uLevel, char* id)
2905 desc->subformat = NULL;
2906 switch( uLevel ) {
2907 case 0: desc->format = "W"; break;
2908 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2909 case 2: desc->format = "WWzWWDDzz"; break;
2910 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2911 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2912 default:
2913 DEBUG(0,("check_printjob_info: invalid level %d\n",
2914 uLevel ));
2915 return False;
2917 if (id == NULL || strcmp(desc->format,id) != 0) {
2918 DEBUG(0,("check_printjob_info: invalid format %s\n",
2919 id ? id : "<NULL>" ));
2920 return False;
2922 return True;
2925 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
2926 char *param, int tpscnt,
2927 char *data, int tdscnt,
2928 int mdrcnt,int mprcnt,
2929 char **rdata,char **rparam,
2930 int *rdata_len,int *rparam_len)
2932 struct pack_desc desc;
2933 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2934 char *str2 = skip_string(param,tpscnt,str1);
2935 char *p = skip_string(param,tpscnt,str2);
2936 uint32 jobid;
2937 fstring sharename;
2938 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
2939 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
2940 int place, errcode;
2942 if (!str1 || !str2 || !p) {
2943 return False;
2946 * We use 1 here not 2 as we're checking
2947 * the last byte we want to access is safe.
2949 if (!is_offset_safe(param,tpscnt,p,1)) {
2950 return False;
2952 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2953 return False;
2954 *rparam_len = 4;
2955 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2956 if (!*rparam) {
2957 return False;
2960 if (!share_defined(sharename)) {
2961 DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
2962 sharename));
2963 return False;
2966 *rdata_len = 0;
2968 /* check it's a supported varient */
2969 if ((strcmp(str1,"WWsTP")) ||
2970 (!check_printjob_info(&desc,uLevel,str2)))
2971 return(False);
2973 if (!print_job_exists(sharename, jobid)) {
2974 errcode=NERR_JobNotFound;
2975 goto out;
2978 errcode = NERR_notsupported;
2980 switch (function) {
2981 case 0x6:
2982 /* change job place in the queue,
2983 data gives the new place */
2984 place = SVAL(data,0);
2985 if (print_job_set_place(sharename, jobid, place)) {
2986 errcode=NERR_Success;
2988 break;
2990 case 0xb:
2991 /* change print job name, data gives the name */
2992 if (print_job_set_name(sharename, jobid, data)) {
2993 errcode=NERR_Success;
2995 break;
2997 default:
2998 return False;
3001 out:
3002 SSVALS(*rparam,0,errcode);
3003 SSVAL(*rparam,2,0); /* converter word */
3005 return(True);
3009 /****************************************************************************
3010 Get info about the server.
3011 ****************************************************************************/
3013 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
3014 char *param, int tpscnt,
3015 char *data, int tdscnt,
3016 int mdrcnt,int mprcnt,
3017 char **rdata,char **rparam,
3018 int *rdata_len,int *rparam_len)
3020 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3021 char *str2 = skip_string(param,tpscnt,str1);
3022 char *p = skip_string(param,tpscnt,str2);
3023 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3024 char *p2;
3025 int struct_len;
3027 if (!str1 || !str2 || !p) {
3028 return False;
3031 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3033 /* check it's a supported varient */
3034 if (!prefix_ok(str1,"WrLh")) {
3035 return False;
3038 switch( uLevel ) {
3039 case 0:
3040 if (strcmp(str2,"B16") != 0) {
3041 return False;
3043 struct_len = 16;
3044 break;
3045 case 1:
3046 if (strcmp(str2,"B16BBDz") != 0) {
3047 return False;
3049 struct_len = 26;
3050 break;
3051 case 2:
3052 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3053 return False;
3055 struct_len = 134;
3056 break;
3057 case 3:
3058 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3059 return False;
3061 struct_len = 144;
3062 break;
3063 case 20:
3064 if (strcmp(str2,"DN") != 0) {
3065 return False;
3067 struct_len = 6;
3068 break;
3069 case 50:
3070 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3071 return False;
3073 struct_len = 42;
3074 break;
3075 default:
3076 return False;
3079 *rdata_len = mdrcnt;
3080 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3081 if (!*rdata) {
3082 return False;
3085 p = *rdata;
3086 p2 = p + struct_len;
3087 if (uLevel != 20) {
3088 srvstr_push(NULL, 0, p,global_myname(),16,
3089 STR_ASCII|STR_UPPER|STR_TERMINATE);
3091 p += 16;
3092 if (uLevel > 0) {
3093 struct srv_info_struct *servers=NULL;
3094 int i,count;
3095 char *comment = NULL;
3096 TALLOC_CTX *ctx = talloc_tos();
3097 uint32 servertype= lp_default_server_announce();
3099 comment = talloc_strdup(ctx,lp_serverstring());
3100 if (!comment) {
3101 return false;
3104 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
3105 for (i=0;i<count;i++) {
3106 if (strequal(servers[i].name,global_myname())) {
3107 servertype = servers[i].type;
3108 TALLOC_FREE(comment);
3109 comment = talloc_strdup(ctx,
3110 servers[i].comment);
3111 if (comment) {
3112 return false;
3118 SAFE_FREE(servers);
3120 SCVAL(p,0,lp_major_announce_version());
3121 SCVAL(p,1,lp_minor_announce_version());
3122 SIVAL(p,2,servertype);
3124 if (mdrcnt == struct_len) {
3125 SIVAL(p,6,0);
3126 } else {
3127 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3128 comment = talloc_sub_advanced(
3129 ctx,
3130 lp_servicename(SNUM(conn)),
3131 conn->server_info->unix_name,
3132 conn->connectpath,
3133 conn->server_info->utok.gid,
3134 conn->server_info->sanitized_username,
3135 pdb_get_domain(conn->server_info->sam_account),
3136 comment);
3137 if (comment) {
3138 return false;
3140 if (mdrcnt - struct_len <= 0) {
3141 return false;
3143 push_ascii(p2,
3144 comment,
3145 MIN(mdrcnt - struct_len,
3146 MAX_SERVER_STRING_LENGTH),
3147 STR_TERMINATE);
3148 p2 = skip_string(*rdata,*rdata_len,p2);
3149 if (!p2) {
3150 return False;
3155 if (uLevel > 1) {
3156 return False; /* not yet implemented */
3159 *rdata_len = PTR_DIFF(p2,*rdata);
3161 *rparam_len = 6;
3162 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3163 if (!*rparam) {
3164 return False;
3166 SSVAL(*rparam,0,NERR_Success);
3167 SSVAL(*rparam,2,0); /* converter word */
3168 SSVAL(*rparam,4,*rdata_len);
3170 return True;
3173 /****************************************************************************
3174 Get info about the server.
3175 ****************************************************************************/
3177 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3178 char *param, int tpscnt,
3179 char *data, int tdscnt,
3180 int mdrcnt,int mprcnt,
3181 char **rdata,char **rparam,
3182 int *rdata_len,int *rparam_len)
3184 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3185 char *str2 = skip_string(param,tpscnt,str1);
3186 char *p = skip_string(param,tpscnt,str2);
3187 char *p2;
3188 char *endp;
3189 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3191 if (!str1 || !str2 || !p) {
3192 return False;
3195 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3197 *rparam_len = 6;
3198 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3199 if (!*rparam) {
3200 return False;
3203 /* check it's a supported varient */
3204 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3205 return False;
3208 *rdata_len = mdrcnt + 1024;
3209 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3210 if (!*rdata) {
3211 return False;
3214 SSVAL(*rparam,0,NERR_Success);
3215 SSVAL(*rparam,2,0); /* converter word */
3217 p = *rdata;
3218 endp = *rdata + *rdata_len;
3220 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3221 if (!p2) {
3222 return False;
3225 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3226 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3227 strupper_m(p2);
3228 p2 = skip_string(*rdata,*rdata_len,p2);
3229 if (!p2) {
3230 return False;
3232 p += 4;
3234 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3235 strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3236 p2 = skip_string(*rdata,*rdata_len,p2);
3237 if (!p2) {
3238 return False;
3240 p += 4;
3242 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3243 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3244 strupper_m(p2);
3245 p2 = skip_string(*rdata,*rdata_len,p2);
3246 if (!p2) {
3247 return False;
3249 p += 4;
3251 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3252 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3253 p += 2;
3255 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3256 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3257 p2 = skip_string(*rdata,*rdata_len,p2);
3258 if (!p2) {
3259 return False;
3261 p += 4;
3263 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3264 strlcpy(p2,"",PTR_DIFF(endp,p2));
3265 p2 = skip_string(*rdata,*rdata_len,p2);
3266 if (!p2) {
3267 return False;
3269 p += 4;
3271 *rdata_len = PTR_DIFF(p2,*rdata);
3273 SSVAL(*rparam,4,*rdata_len);
3275 return True;
3278 /****************************************************************************
3279 get info about a user
3281 struct user_info_11 {
3282 char usri11_name[21]; 0-20
3283 char usri11_pad; 21
3284 char *usri11_comment; 22-25
3285 char *usri11_usr_comment; 26-29
3286 unsigned short usri11_priv; 30-31
3287 unsigned long usri11_auth_flags; 32-35
3288 long usri11_password_age; 36-39
3289 char *usri11_homedir; 40-43
3290 char *usri11_parms; 44-47
3291 long usri11_last_logon; 48-51
3292 long usri11_last_logoff; 52-55
3293 unsigned short usri11_bad_pw_count; 56-57
3294 unsigned short usri11_num_logons; 58-59
3295 char *usri11_logon_server; 60-63
3296 unsigned short usri11_country_code; 64-65
3297 char *usri11_workstations; 66-69
3298 unsigned long usri11_max_storage; 70-73
3299 unsigned short usri11_units_per_week; 74-75
3300 unsigned char *usri11_logon_hours; 76-79
3301 unsigned short usri11_code_page; 80-81
3304 where:
3306 usri11_name specifies the user name for which information is retrieved
3308 usri11_pad aligns the next data structure element to a word boundary
3310 usri11_comment is a null terminated ASCII comment
3312 usri11_user_comment is a null terminated ASCII comment about the user
3314 usri11_priv specifies the level of the privilege assigned to the user.
3315 The possible values are:
3317 Name Value Description
3318 USER_PRIV_GUEST 0 Guest privilege
3319 USER_PRIV_USER 1 User privilege
3320 USER_PRV_ADMIN 2 Administrator privilege
3322 usri11_auth_flags specifies the account operator privileges. The
3323 possible values are:
3325 Name Value Description
3326 AF_OP_PRINT 0 Print operator
3329 Leach, Naik [Page 28]
3333 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3336 AF_OP_COMM 1 Communications operator
3337 AF_OP_SERVER 2 Server operator
3338 AF_OP_ACCOUNTS 3 Accounts operator
3341 usri11_password_age specifies how many seconds have elapsed since the
3342 password was last changed.
3344 usri11_home_dir points to a null terminated ASCII string that contains
3345 the path name of the user's home directory.
3347 usri11_parms points to a null terminated ASCII string that is set
3348 aside for use by applications.
3350 usri11_last_logon specifies the time when the user last logged on.
3351 This value is stored as the number of seconds elapsed since
3352 00:00:00, January 1, 1970.
3354 usri11_last_logoff specifies the time when the user last logged off.
3355 This value is stored as the number of seconds elapsed since
3356 00:00:00, January 1, 1970. A value of 0 means the last logoff
3357 time is unknown.
3359 usri11_bad_pw_count specifies the number of incorrect passwords
3360 entered since the last successful logon.
3362 usri11_log1_num_logons specifies the number of times this user has
3363 logged on. A value of -1 means the number of logons is unknown.
3365 usri11_logon_server points to a null terminated ASCII string that
3366 contains the name of the server to which logon requests are sent.
3367 A null string indicates logon requests should be sent to the
3368 domain controller.
3370 usri11_country_code specifies the country code for the user's language
3371 of choice.
3373 usri11_workstations points to a null terminated ASCII string that
3374 contains the names of workstations the user may log on from.
3375 There may be up to 8 workstations, with the names separated by
3376 commas. A null strings indicates there are no restrictions.
3378 usri11_max_storage specifies the maximum amount of disk space the user
3379 can occupy. A value of 0xffffffff indicates there are no
3380 restrictions.
3382 usri11_units_per_week specifies the equal number of time units into
3383 which a week is divided. This value must be equal to 168.
3385 usri11_logon_hours points to a 21 byte (168 bits) string that
3386 specifies the time during which the user can log on. Each bit
3387 represents one unique hour in a week. The first bit (bit 0, word
3388 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3392 Leach, Naik [Page 29]
3396 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3399 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3400 are no restrictions.
3402 usri11_code_page specifies the code page for the user's language of
3403 choice
3405 All of the pointers in this data structure need to be treated
3406 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3407 to be ignored. The converter word returned in the parameters section
3408 needs to be subtracted from the lower 16 bits to calculate an offset
3409 into the return buffer where this ASCII string resides.
3411 There is no auxiliary data in the response.
3413 ****************************************************************************/
3415 #define usri11_name 0
3416 #define usri11_pad 21
3417 #define usri11_comment 22
3418 #define usri11_usr_comment 26
3419 #define usri11_full_name 30
3420 #define usri11_priv 34
3421 #define usri11_auth_flags 36
3422 #define usri11_password_age 40
3423 #define usri11_homedir 44
3424 #define usri11_parms 48
3425 #define usri11_last_logon 52
3426 #define usri11_last_logoff 56
3427 #define usri11_bad_pw_count 60
3428 #define usri11_num_logons 62
3429 #define usri11_logon_server 64
3430 #define usri11_country_code 68
3431 #define usri11_workstations 70
3432 #define usri11_max_storage 74
3433 #define usri11_units_per_week 78
3434 #define usri11_logon_hours 80
3435 #define usri11_code_page 84
3436 #define usri11_end 86
3438 #define USER_PRIV_GUEST 0
3439 #define USER_PRIV_USER 1
3440 #define USER_PRIV_ADMIN 2
3442 #define AF_OP_PRINT 0
3443 #define AF_OP_COMM 1
3444 #define AF_OP_SERVER 2
3445 #define AF_OP_ACCOUNTS 3
3448 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3449 char *param, int tpscnt,
3450 char *data, int tdscnt,
3451 int mdrcnt,int mprcnt,
3452 char **rdata,char **rparam,
3453 int *rdata_len,int *rparam_len)
3455 struct smbd_server_connection *sconn = smbd_server_conn;
3456 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3457 char *str2 = skip_string(param,tpscnt,str1);
3458 char *UserName = skip_string(param,tpscnt,str2);
3459 char *p = skip_string(param,tpscnt,UserName);
3460 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3461 char *p2;
3462 char *endp;
3463 const char *level_string;
3465 /* get NIS home of a previously validated user - simeon */
3466 /* With share level security vuid will always be zero.
3467 Don't depend on vuser being non-null !!. JRA */
3468 user_struct *vuser = get_valid_user_struct(sconn, vuid);
3469 if(vuser != NULL) {
3470 DEBUG(3,(" Username of UID %d is %s\n",
3471 (int)vuser->server_info->utok.uid,
3472 vuser->server_info->unix_name));
3475 if (!str1 || !str2 || !UserName || !p) {
3476 return False;
3479 *rparam_len = 6;
3480 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3481 if (!*rparam) {
3482 return False;
3485 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3487 /* check it's a supported variant */
3488 if (strcmp(str1,"zWrLh") != 0) {
3489 return False;
3491 switch( uLevel ) {
3492 case 0: level_string = "B21"; break;
3493 case 1: level_string = "B21BB16DWzzWz"; break;
3494 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3495 case 10: level_string = "B21Bzzz"; break;
3496 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3497 default: return False;
3500 if (strcmp(level_string,str2) != 0) {
3501 return False;
3504 *rdata_len = mdrcnt + 1024;
3505 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3506 if (!*rdata) {
3507 return False;
3510 SSVAL(*rparam,0,NERR_Success);
3511 SSVAL(*rparam,2,0); /* converter word */
3513 p = *rdata;
3514 endp = *rdata + *rdata_len;
3515 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3516 if (!p2) {
3517 return False;
3520 memset(p,0,21);
3521 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3523 if (uLevel > 0) {
3524 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3525 *p2 = 0;
3528 if (uLevel >= 10) {
3529 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3530 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
3531 p2 = skip_string(*rdata,*rdata_len,p2);
3532 if (!p2) {
3533 return False;
3536 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3537 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
3538 p2 = skip_string(*rdata,*rdata_len,p2);
3539 if (!p2) {
3540 return False;
3543 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3544 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3545 strlcpy(p2,((vuser != NULL)
3546 ? pdb_get_fullname(vuser->server_info->sam_account)
3547 : UserName),PTR_DIFF(endp,p2));
3548 p2 = skip_string(*rdata,*rdata_len,p2);
3549 if (!p2) {
3550 return False;
3554 if (uLevel == 11) {
3555 const char *homedir = "";
3556 if (vuser != NULL) {
3557 homedir = pdb_get_homedir(
3558 vuser->server_info->sam_account);
3560 /* modelled after NTAS 3.51 reply */
3561 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3562 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
3563 SIVALS(p,usri11_password_age,-1); /* password age */
3564 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3565 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
3566 p2 = skip_string(*rdata,*rdata_len,p2);
3567 if (!p2) {
3568 return False;
3570 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3571 strlcpy(p2,"",PTR_DIFF(endp,p2));
3572 p2 = skip_string(*rdata,*rdata_len,p2);
3573 if (!p2) {
3574 return False;
3576 SIVAL(p,usri11_last_logon,0); /* last logon */
3577 SIVAL(p,usri11_last_logoff,0); /* last logoff */
3578 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
3579 SSVALS(p,usri11_num_logons,-1); /* num logons */
3580 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3581 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
3582 p2 = skip_string(*rdata,*rdata_len,p2);
3583 if (!p2) {
3584 return False;
3586 SSVAL(p,usri11_country_code,0); /* country code */
3588 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3589 strlcpy(p2,"",PTR_DIFF(endp,p2));
3590 p2 = skip_string(*rdata,*rdata_len,p2);
3591 if (!p2) {
3592 return False;
3595 SIVALS(p,usri11_max_storage,-1); /* max storage */
3596 SSVAL(p,usri11_units_per_week,168); /* units per week */
3597 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
3599 /* a simple way to get logon hours at all times. */
3600 memset(p2,0xff,21);
3601 SCVAL(p2,21,0); /* fix zero termination */
3602 p2 = skip_string(*rdata,*rdata_len,p2);
3603 if (!p2) {
3604 return False;
3607 SSVAL(p,usri11_code_page,0); /* code page */
3610 if (uLevel == 1 || uLevel == 2) {
3611 memset(p+22,' ',16); /* password */
3612 SIVALS(p,38,-1); /* password age */
3613 SSVAL(p,42,
3614 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3615 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
3616 strlcpy(p2, vuser ? pdb_get_homedir(
3617 vuser->server_info->sam_account) : "",
3618 PTR_DIFF(endp,p2));
3619 p2 = skip_string(*rdata,*rdata_len,p2);
3620 if (!p2) {
3621 return False;
3623 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
3624 *p2++ = 0;
3625 SSVAL(p,52,0); /* flags */
3626 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
3627 strlcpy(p2, vuser ? pdb_get_logon_script(
3628 vuser->server_info->sam_account) : "",
3629 PTR_DIFF(endp,p2));
3630 p2 = skip_string(*rdata,*rdata_len,p2);
3631 if (!p2) {
3632 return False;
3634 if (uLevel == 2) {
3635 SIVAL(p,60,0); /* auth_flags */
3636 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
3637 strlcpy(p2,((vuser != NULL)
3638 ? pdb_get_fullname(vuser->server_info->sam_account)
3639 : UserName),PTR_DIFF(endp,p2));
3640 p2 = skip_string(*rdata,*rdata_len,p2);
3641 if (!p2) {
3642 return False;
3644 SIVAL(p,68,0); /* urs_comment */
3645 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
3646 strlcpy(p2,"",PTR_DIFF(endp,p2));
3647 p2 = skip_string(*rdata,*rdata_len,p2);
3648 if (!p2) {
3649 return False;
3651 SIVAL(p,76,0); /* workstations */
3652 SIVAL(p,80,0); /* last_logon */
3653 SIVAL(p,84,0); /* last_logoff */
3654 SIVALS(p,88,-1); /* acct_expires */
3655 SIVALS(p,92,-1); /* max_storage */
3656 SSVAL(p,96,168); /* units_per_week */
3657 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
3658 memset(p2,-1,21);
3659 p2 += 21;
3660 SSVALS(p,102,-1); /* bad_pw_count */
3661 SSVALS(p,104,-1); /* num_logons */
3662 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
3664 TALLOC_CTX *ctx = talloc_tos();
3665 int space_rem = *rdata_len - (p2 - *rdata);
3666 char *tmp;
3668 if (space_rem <= 0) {
3669 return false;
3671 tmp = talloc_strdup(ctx, "\\\\%L");
3672 if (!tmp) {
3673 return false;
3675 tmp = talloc_sub_basic(ctx,
3678 tmp);
3679 if (!tmp) {
3680 return false;
3683 push_ascii(p2,
3684 tmp,
3685 space_rem,
3686 STR_TERMINATE);
3688 p2 = skip_string(*rdata,*rdata_len,p2);
3689 if (!p2) {
3690 return False;
3692 SSVAL(p,110,49); /* country_code */
3693 SSVAL(p,112,860); /* code page */
3697 *rdata_len = PTR_DIFF(p2,*rdata);
3699 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
3701 return(True);
3704 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
3705 char *param, int tpscnt,
3706 char *data, int tdscnt,
3707 int mdrcnt,int mprcnt,
3708 char **rdata,char **rparam,
3709 int *rdata_len,int *rparam_len)
3711 struct smbd_server_connection *sconn = smbd_server_conn;
3712 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3713 char *str2 = skip_string(param,tpscnt,str1);
3714 char *p = skip_string(param,tpscnt,str2);
3715 int uLevel;
3716 struct pack_desc desc;
3717 char* name;
3718 /* With share level security vuid will always be zero.
3719 Don't depend on vuser being non-null !!. JRA */
3720 user_struct *vuser = get_valid_user_struct(sconn, vuid);
3722 if (!str1 || !str2 || !p) {
3723 return False;
3726 if(vuser != NULL) {
3727 DEBUG(3,(" Username of UID %d is %s\n",
3728 (int)vuser->server_info->utok.uid,
3729 vuser->server_info->unix_name));
3732 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3733 name = get_safe_str_ptr(param,tpscnt,p,2);
3734 if (!name) {
3735 return False;
3738 memset((char *)&desc,'\0',sizeof(desc));
3740 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
3742 /* check it's a supported varient */
3743 if (strcmp(str1,"OOWb54WrLh") != 0) {
3744 return False;
3746 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
3747 return False;
3749 if (mdrcnt > 0) {
3750 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3751 if (!*rdata) {
3752 return False;
3756 desc.base = *rdata;
3757 desc.buflen = mdrcnt;
3758 desc.subformat = NULL;
3759 desc.format = str2;
3761 if (init_package(&desc,1,0)) {
3762 PACKI(&desc,"W",0); /* code */
3763 PACKS(&desc,"B21",name); /* eff. name */
3764 PACKS(&desc,"B",""); /* pad */
3765 PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3766 PACKI(&desc,"D",0); /* auth flags XXX */
3767 PACKI(&desc,"W",0); /* num logons */
3768 PACKI(&desc,"W",0); /* bad pw count */
3769 PACKI(&desc,"D",0); /* last logon */
3770 PACKI(&desc,"D",-1); /* last logoff */
3771 PACKI(&desc,"D",-1); /* logoff time */
3772 PACKI(&desc,"D",-1); /* kickoff time */
3773 PACKI(&desc,"D",0); /* password age */
3774 PACKI(&desc,"D",0); /* password can change */
3775 PACKI(&desc,"D",-1); /* password must change */
3778 fstring mypath;
3779 fstrcpy(mypath,"\\\\");
3780 fstrcat(mypath,get_local_machine_name());
3781 strupper_m(mypath);
3782 PACKS(&desc,"z",mypath); /* computer */
3785 PACKS(&desc,"z",lp_workgroup());/* domain */
3786 PACKS(&desc,"z", vuser ? pdb_get_logon_script(
3787 vuser->server_info->sam_account) : ""); /* script path */
3788 PACKI(&desc,"D",0x00000000); /* reserved */
3791 *rdata_len = desc.usedlen;
3792 *rparam_len = 6;
3793 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3794 if (!*rparam) {
3795 return False;
3797 SSVALS(*rparam,0,desc.errcode);
3798 SSVAL(*rparam,2,0);
3799 SSVAL(*rparam,4,desc.neededlen);
3801 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
3803 return True;
3806 /****************************************************************************
3807 api_WAccessGetUserPerms
3808 ****************************************************************************/
3810 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
3811 char *param, int tpscnt,
3812 char *data, int tdscnt,
3813 int mdrcnt,int mprcnt,
3814 char **rdata,char **rparam,
3815 int *rdata_len,int *rparam_len)
3817 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3818 char *str2 = skip_string(param,tpscnt,str1);
3819 char *user = skip_string(param,tpscnt,str2);
3820 char *resource = skip_string(param,tpscnt,user);
3822 if (!str1 || !str2 || !user || !resource) {
3823 return False;
3826 if (skip_string(param,tpscnt,resource) == NULL) {
3827 return False;
3829 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
3831 /* check it's a supported varient */
3832 if (strcmp(str1,"zzh") != 0) {
3833 return False;
3835 if (strcmp(str2,"") != 0) {
3836 return False;
3839 *rparam_len = 6;
3840 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3841 if (!*rparam) {
3842 return False;
3844 SSVALS(*rparam,0,0); /* errorcode */
3845 SSVAL(*rparam,2,0); /* converter word */
3846 SSVAL(*rparam,4,0x7f); /* permission flags */
3848 return True;
3851 /****************************************************************************
3852 api_WPrintJobEnumerate
3853 ****************************************************************************/
3855 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
3856 char *param, int tpscnt,
3857 char *data, int tdscnt,
3858 int mdrcnt,int mprcnt,
3859 char **rdata,char **rparam,
3860 int *rdata_len,int *rparam_len)
3862 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3863 char *str2 = skip_string(param,tpscnt,str1);
3864 char *p = skip_string(param,tpscnt,str2);
3865 int uLevel;
3866 int count;
3867 int i;
3868 int snum;
3869 fstring sharename;
3870 uint32 jobid;
3871 struct pack_desc desc;
3872 print_queue_struct *queue=NULL;
3873 print_status_struct status;
3874 char *tmpdata=NULL;
3876 if (!str1 || !str2 || !p) {
3877 return False;
3880 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3882 memset((char *)&desc,'\0',sizeof(desc));
3883 memset((char *)&status,'\0',sizeof(status));
3885 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
3887 /* check it's a supported varient */
3888 if (strcmp(str1,"WWrLh") != 0) {
3889 return False;
3891 if (!check_printjob_info(&desc,uLevel,str2)) {
3892 return False;
3895 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
3896 return False;
3899 snum = lp_servicenumber( sharename);
3900 if (snum < 0 || !VALID_SNUM(snum)) {
3901 return(False);
3904 count = print_queue_status(snum,&queue,&status);
3905 for (i = 0; i < count; i++) {
3906 if (queue[i].job == jobid) {
3907 break;
3911 if (mdrcnt > 0) {
3912 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3913 if (!*rdata) {
3914 return False;
3916 desc.base = *rdata;
3917 desc.buflen = mdrcnt;
3918 } else {
3920 * Don't return data but need to get correct length
3921 * init_package will return wrong size if buflen=0
3923 desc.buflen = getlen(desc.format);
3924 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3927 if (init_package(&desc,1,0)) {
3928 if (i < count) {
3929 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3930 *rdata_len = desc.usedlen;
3931 } else {
3932 desc.errcode = NERR_JobNotFound;
3933 *rdata_len = 0;
3937 *rparam_len = 6;
3938 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3939 if (!*rparam) {
3940 return False;
3942 SSVALS(*rparam,0,desc.errcode);
3943 SSVAL(*rparam,2,0);
3944 SSVAL(*rparam,4,desc.neededlen);
3946 SAFE_FREE(queue);
3947 SAFE_FREE(tmpdata);
3949 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
3951 return True;
3954 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
3955 char *param, int tpscnt,
3956 char *data, int tdscnt,
3957 int mdrcnt,int mprcnt,
3958 char **rdata,char **rparam,
3959 int *rdata_len,int *rparam_len)
3961 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3962 char *str2 = skip_string(param,tpscnt,str1);
3963 char *p = skip_string(param,tpscnt,str2);
3964 char *name = p;
3965 int uLevel;
3966 int count;
3967 int i, succnt=0;
3968 int snum;
3969 struct pack_desc desc;
3970 print_queue_struct *queue=NULL;
3971 print_status_struct status;
3973 if (!str1 || !str2 || !p) {
3974 return False;
3977 memset((char *)&desc,'\0',sizeof(desc));
3978 memset((char *)&status,'\0',sizeof(status));
3980 p = skip_string(param,tpscnt,p);
3981 if (!p) {
3982 return False;
3984 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3986 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
3988 /* check it's a supported variant */
3989 if (strcmp(str1,"zWrLeh") != 0) {
3990 return False;
3993 if (uLevel > 2) {
3994 return False; /* defined only for uLevel 0,1,2 */
3997 if (!check_printjob_info(&desc,uLevel,str2)) {
3998 return False;
4001 snum = find_service(name);
4002 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
4003 return False;
4006 count = print_queue_status(snum,&queue,&status);
4007 if (mdrcnt > 0) {
4008 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4009 if (!*rdata) {
4010 return False;
4013 desc.base = *rdata;
4014 desc.buflen = mdrcnt;
4016 if (init_package(&desc,count,0)) {
4017 succnt = 0;
4018 for (i = 0; i < count; i++) {
4019 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
4020 if (desc.errcode == NERR_Success) {
4021 succnt = i+1;
4026 *rdata_len = desc.usedlen;
4028 *rparam_len = 8;
4029 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4030 if (!*rparam) {
4031 return False;
4033 SSVALS(*rparam,0,desc.errcode);
4034 SSVAL(*rparam,2,0);
4035 SSVAL(*rparam,4,succnt);
4036 SSVAL(*rparam,6,count);
4038 SAFE_FREE(queue);
4040 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4042 return True;
4045 static int check_printdest_info(struct pack_desc* desc,
4046 int uLevel, char* id)
4048 desc->subformat = NULL;
4049 switch( uLevel ) {
4050 case 0:
4051 desc->format = "B9";
4052 break;
4053 case 1:
4054 desc->format = "B9B21WWzW";
4055 break;
4056 case 2:
4057 desc->format = "z";
4058 break;
4059 case 3:
4060 desc->format = "zzzWWzzzWW";
4061 break;
4062 default:
4063 DEBUG(0,("check_printdest_info: invalid level %d\n",
4064 uLevel));
4065 return False;
4067 if (id == NULL || strcmp(desc->format,id) != 0) {
4068 DEBUG(0,("check_printdest_info: invalid string %s\n",
4069 id ? id : "<NULL>" ));
4070 return False;
4072 return True;
4075 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
4076 struct pack_desc* desc)
4078 char buf[100];
4080 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
4081 buf[sizeof(buf)-1] = 0;
4082 strupper_m(buf);
4084 if (uLevel <= 1) {
4085 PACKS(desc,"B9",buf); /* szName */
4086 if (uLevel == 1) {
4087 PACKS(desc,"B21",""); /* szUserName */
4088 PACKI(desc,"W",0); /* uJobId */
4089 PACKI(desc,"W",0); /* fsStatus */
4090 PACKS(desc,"z",""); /* pszStatus */
4091 PACKI(desc,"W",0); /* time */
4095 if (uLevel == 2 || uLevel == 3) {
4096 PACKS(desc,"z",buf); /* pszPrinterName */
4097 if (uLevel == 3) {
4098 PACKS(desc,"z",""); /* pszUserName */
4099 PACKS(desc,"z",""); /* pszLogAddr */
4100 PACKI(desc,"W",0); /* uJobId */
4101 PACKI(desc,"W",0); /* fsStatus */
4102 PACKS(desc,"z",""); /* pszStatus */
4103 PACKS(desc,"z",""); /* pszComment */
4104 PACKS(desc,"z","NULL"); /* pszDrivers */
4105 PACKI(desc,"W",0); /* time */
4106 PACKI(desc,"W",0); /* pad1 */
4111 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
4112 char *param, int tpscnt,
4113 char *data, int tdscnt,
4114 int mdrcnt,int mprcnt,
4115 char **rdata,char **rparam,
4116 int *rdata_len,int *rparam_len)
4118 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4119 char *str2 = skip_string(param,tpscnt,str1);
4120 char *p = skip_string(param,tpscnt,str2);
4121 char* PrinterName = p;
4122 int uLevel;
4123 struct pack_desc desc;
4124 int snum;
4125 char *tmpdata=NULL;
4127 if (!str1 || !str2 || !p) {
4128 return False;
4131 memset((char *)&desc,'\0',sizeof(desc));
4133 p = skip_string(param,tpscnt,p);
4134 if (!p) {
4135 return False;
4137 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4139 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4141 /* check it's a supported varient */
4142 if (strcmp(str1,"zWrLh") != 0) {
4143 return False;
4145 if (!check_printdest_info(&desc,uLevel,str2)) {
4146 return False;
4149 snum = find_service(PrinterName);
4150 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
4151 *rdata_len = 0;
4152 desc.errcode = NERR_DestNotFound;
4153 desc.neededlen = 0;
4154 } else {
4155 if (mdrcnt > 0) {
4156 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4157 if (!*rdata) {
4158 return False;
4160 desc.base = *rdata;
4161 desc.buflen = mdrcnt;
4162 } else {
4164 * Don't return data but need to get correct length
4165 * init_package will return wrong size if buflen=0
4167 desc.buflen = getlen(desc.format);
4168 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4170 if (init_package(&desc,1,0)) {
4171 fill_printdest_info(conn,snum,uLevel,&desc);
4173 *rdata_len = desc.usedlen;
4176 *rparam_len = 6;
4177 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4178 if (!*rparam) {
4179 return False;
4181 SSVALS(*rparam,0,desc.errcode);
4182 SSVAL(*rparam,2,0);
4183 SSVAL(*rparam,4,desc.neededlen);
4185 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4186 SAFE_FREE(tmpdata);
4188 return True;
4191 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4192 char *param, int tpscnt,
4193 char *data, int tdscnt,
4194 int mdrcnt,int mprcnt,
4195 char **rdata,char **rparam,
4196 int *rdata_len,int *rparam_len)
4198 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4199 char *str2 = skip_string(param,tpscnt,str1);
4200 char *p = skip_string(param,tpscnt,str2);
4201 int uLevel;
4202 int queuecnt;
4203 int i, n, succnt=0;
4204 struct pack_desc desc;
4205 int services = lp_numservices();
4207 if (!str1 || !str2 || !p) {
4208 return False;
4211 memset((char *)&desc,'\0',sizeof(desc));
4213 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4215 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4217 /* check it's a supported varient */
4218 if (strcmp(str1,"WrLeh") != 0) {
4219 return False;
4221 if (!check_printdest_info(&desc,uLevel,str2)) {
4222 return False;
4225 queuecnt = 0;
4226 for (i = 0; i < services; i++) {
4227 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4228 queuecnt++;
4232 if (mdrcnt > 0) {
4233 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4234 if (!*rdata) {
4235 return False;
4239 desc.base = *rdata;
4240 desc.buflen = mdrcnt;
4241 if (init_package(&desc,queuecnt,0)) {
4242 succnt = 0;
4243 n = 0;
4244 for (i = 0; i < services; i++) {
4245 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4246 fill_printdest_info(conn,i,uLevel,&desc);
4247 n++;
4248 if (desc.errcode == NERR_Success) {
4249 succnt = n;
4255 *rdata_len = desc.usedlen;
4257 *rparam_len = 8;
4258 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4259 if (!*rparam) {
4260 return False;
4262 SSVALS(*rparam,0,desc.errcode);
4263 SSVAL(*rparam,2,0);
4264 SSVAL(*rparam,4,succnt);
4265 SSVAL(*rparam,6,queuecnt);
4267 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4269 return True;
4272 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4273 char *param, int tpscnt,
4274 char *data, int tdscnt,
4275 int mdrcnt,int mprcnt,
4276 char **rdata,char **rparam,
4277 int *rdata_len,int *rparam_len)
4279 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4280 char *str2 = skip_string(param,tpscnt,str1);
4281 char *p = skip_string(param,tpscnt,str2);
4282 int uLevel;
4283 int succnt;
4284 struct pack_desc desc;
4286 if (!str1 || !str2 || !p) {
4287 return False;
4290 memset((char *)&desc,'\0',sizeof(desc));
4292 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4294 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4296 /* check it's a supported varient */
4297 if (strcmp(str1,"WrLeh") != 0) {
4298 return False;
4300 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4301 return False;
4304 if (mdrcnt > 0) {
4305 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4306 if (!*rdata) {
4307 return False;
4310 desc.base = *rdata;
4311 desc.buflen = mdrcnt;
4312 if (init_package(&desc,1,0)) {
4313 PACKS(&desc,"B41","NULL");
4316 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4318 *rdata_len = desc.usedlen;
4320 *rparam_len = 8;
4321 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4322 if (!*rparam) {
4323 return False;
4325 SSVALS(*rparam,0,desc.errcode);
4326 SSVAL(*rparam,2,0);
4327 SSVAL(*rparam,4,succnt);
4328 SSVAL(*rparam,6,1);
4330 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4332 return True;
4335 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4336 char *param, int tpscnt,
4337 char *data, int tdscnt,
4338 int mdrcnt,int mprcnt,
4339 char **rdata,char **rparam,
4340 int *rdata_len,int *rparam_len)
4342 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4343 char *str2 = skip_string(param,tpscnt,str1);
4344 char *p = skip_string(param,tpscnt,str2);
4345 int uLevel;
4346 int succnt;
4347 struct pack_desc desc;
4349 if (!str1 || !str2 || !p) {
4350 return False;
4352 memset((char *)&desc,'\0',sizeof(desc));
4354 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4356 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4358 /* check it's a supported varient */
4359 if (strcmp(str1,"WrLeh") != 0) {
4360 return False;
4362 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4363 return False;
4366 if (mdrcnt > 0) {
4367 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4368 if (!*rdata) {
4369 return False;
4372 desc.base = *rdata;
4373 desc.buflen = mdrcnt;
4374 desc.format = str2;
4375 if (init_package(&desc,1,0)) {
4376 PACKS(&desc,"B13","lpd");
4379 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4381 *rdata_len = desc.usedlen;
4383 *rparam_len = 8;
4384 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4385 if (!*rparam) {
4386 return False;
4388 SSVALS(*rparam,0,desc.errcode);
4389 SSVAL(*rparam,2,0);
4390 SSVAL(*rparam,4,succnt);
4391 SSVAL(*rparam,6,1);
4393 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4395 return True;
4398 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4399 char *param, int tpscnt,
4400 char *data, int tdscnt,
4401 int mdrcnt,int mprcnt,
4402 char **rdata,char **rparam,
4403 int *rdata_len,int *rparam_len)
4405 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4406 char *str2 = skip_string(param,tpscnt,str1);
4407 char *p = skip_string(param,tpscnt,str2);
4408 int uLevel;
4409 int succnt;
4410 struct pack_desc desc;
4412 if (!str1 || !str2 || !p) {
4413 return False;
4416 memset((char *)&desc,'\0',sizeof(desc));
4418 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4420 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4422 /* check it's a supported varient */
4423 if (strcmp(str1,"WrLeh") != 0) {
4424 return False;
4426 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
4427 return False;
4430 if (mdrcnt > 0) {
4431 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4432 if (!*rdata) {
4433 return False;
4436 memset((char *)&desc,'\0',sizeof(desc));
4437 desc.base = *rdata;
4438 desc.buflen = mdrcnt;
4439 desc.format = str2;
4440 if (init_package(&desc,1,0)) {
4441 PACKS(&desc,"B13","lp0");
4444 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4446 *rdata_len = desc.usedlen;
4448 *rparam_len = 8;
4449 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4450 if (!*rparam) {
4451 return False;
4453 SSVALS(*rparam,0,desc.errcode);
4454 SSVAL(*rparam,2,0);
4455 SSVAL(*rparam,4,succnt);
4456 SSVAL(*rparam,6,1);
4458 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
4460 return True;
4463 /****************************************************************************
4464 List open sessions
4465 ****************************************************************************/
4467 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
4468 char *param, int tpscnt,
4469 char *data, int tdscnt,
4470 int mdrcnt,int mprcnt,
4471 char **rdata,char **rparam,
4472 int *rdata_len,int *rparam_len)
4475 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4476 char *str2 = skip_string(param,tpscnt,str1);
4477 char *p = skip_string(param,tpscnt,str2);
4478 int uLevel;
4479 struct pack_desc desc;
4480 struct sessionid *session_list;
4481 int i, num_sessions;
4483 if (!str1 || !str2 || !p) {
4484 return False;
4487 memset((char *)&desc,'\0',sizeof(desc));
4489 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4491 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
4492 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
4493 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
4495 /* check it's a supported varient */
4496 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
4497 return False;
4499 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
4500 return False;
4503 num_sessions = list_sessions(talloc_tos(), &session_list);
4505 if (mdrcnt > 0) {
4506 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4507 if (!*rdata) {
4508 return False;
4511 memset((char *)&desc,'\0',sizeof(desc));
4512 desc.base = *rdata;
4513 desc.buflen = mdrcnt;
4514 desc.format = str2;
4515 if (!init_package(&desc,num_sessions,0)) {
4516 return False;
4519 for(i=0; i<num_sessions; i++) {
4520 PACKS(&desc, "z", session_list[i].remote_machine);
4521 PACKS(&desc, "z", session_list[i].username);
4522 PACKI(&desc, "W", 1); /* num conns */
4523 PACKI(&desc, "W", 0); /* num opens */
4524 PACKI(&desc, "W", 1); /* num users */
4525 PACKI(&desc, "D", 0); /* session time */
4526 PACKI(&desc, "D", 0); /* idle time */
4527 PACKI(&desc, "D", 0); /* flags */
4528 PACKS(&desc, "z", "Unknown Client"); /* client type string */
4531 *rdata_len = desc.usedlen;
4533 *rparam_len = 8;
4534 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4535 if (!*rparam) {
4536 return False;
4538 SSVALS(*rparam,0,desc.errcode);
4539 SSVAL(*rparam,2,0); /* converter */
4540 SSVAL(*rparam,4,num_sessions); /* count */
4542 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
4544 return True;
4548 /****************************************************************************
4549 The buffer was too small.
4550 ****************************************************************************/
4552 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
4553 int mdrcnt, int mprcnt,
4554 char **rdata, char **rparam,
4555 int *rdata_len, int *rparam_len)
4557 *rparam_len = MIN(*rparam_len,mprcnt);
4558 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4559 if (!*rparam) {
4560 return False;
4563 *rdata_len = 0;
4565 SSVAL(*rparam,0,NERR_BufTooSmall);
4567 DEBUG(3,("Supplied buffer too small in API command\n"));
4569 return True;
4572 /****************************************************************************
4573 The request is not supported.
4574 ****************************************************************************/
4576 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
4577 char *param, int tpscnt,
4578 char *data, int tdscnt,
4579 int mdrcnt, int mprcnt,
4580 char **rdata, char **rparam,
4581 int *rdata_len, int *rparam_len)
4583 *rparam_len = 4;
4584 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4585 if (!*rparam) {
4586 return False;
4589 *rdata_len = 0;
4591 SSVAL(*rparam,0,NERR_notsupported);
4592 SSVAL(*rparam,2,0); /* converter word */
4594 DEBUG(3,("Unsupported API command\n"));
4596 return True;
4599 static const struct {
4600 const char *name;
4601 int id;
4602 bool (*fn)(connection_struct *, uint16,
4603 char *, int,
4604 char *, int,
4605 int,int,char **,char **,int *,int *);
4606 bool auth_user; /* Deny anonymous access? */
4607 } api_commands[] = {
4608 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
4609 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
4610 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
4611 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
4612 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
4613 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
4614 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
4615 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
4616 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
4617 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
4618 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
4619 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
4620 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
4621 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
4622 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
4623 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
4624 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
4625 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
4626 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
4627 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
4628 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
4629 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
4630 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
4631 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
4632 {"NetServerEnum", RAP_NetServerEnum2, api_RNetServerEnum}, /* anon OK */
4633 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
4634 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
4635 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
4636 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
4637 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
4638 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
4639 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
4640 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
4641 {NULL, -1, api_Unsupported}
4642 /* The following RAP calls are not implemented by Samba:
4644 RAP_WFileEnum2 - anon not OK
4649 /****************************************************************************
4650 Handle remote api calls.
4651 ****************************************************************************/
4653 void api_reply(connection_struct *conn, uint16 vuid,
4654 struct smb_request *req,
4655 char *data, char *params,
4656 int tdscnt, int tpscnt,
4657 int mdrcnt, int mprcnt)
4659 struct smbd_server_connection *sconn = smbd_server_conn;
4660 int api_command;
4661 char *rdata = NULL;
4662 char *rparam = NULL;
4663 const char *name1 = NULL;
4664 const char *name2 = NULL;
4665 int rdata_len = 0;
4666 int rparam_len = 0;
4667 bool reply=False;
4668 int i;
4670 if (!params) {
4671 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
4672 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4673 return;
4676 if (tpscnt < 2) {
4677 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4678 return;
4680 api_command = SVAL(params,0);
4681 /* Is there a string at position params+2 ? */
4682 if (skip_string(params,tpscnt,params+2)) {
4683 name1 = params + 2;
4684 } else {
4685 name1 = "";
4687 name2 = skip_string(params,tpscnt,params+2);
4688 if (!name2) {
4689 name2 = "";
4692 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
4693 api_command,
4694 name1,
4695 name2,
4696 tdscnt,tpscnt,mdrcnt,mprcnt));
4698 for (i=0;api_commands[i].name;i++) {
4699 if (api_commands[i].id == api_command && api_commands[i].fn) {
4700 DEBUG(3,("Doing %s\n",api_commands[i].name));
4701 break;
4705 /* Check whether this api call can be done anonymously */
4707 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
4708 user_struct *user = get_valid_user_struct(sconn, vuid);
4710 if (!user || user->server_info->guest) {
4711 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4712 return;
4716 rdata = (char *)SMB_MALLOC(1024);
4717 if (rdata) {
4718 memset(rdata,'\0',1024);
4721 rparam = (char *)SMB_MALLOC(1024);
4722 if (rparam) {
4723 memset(rparam,'\0',1024);
4726 if(!rdata || !rparam) {
4727 DEBUG(0,("api_reply: malloc fail !\n"));
4728 SAFE_FREE(rdata);
4729 SAFE_FREE(rparam);
4730 reply_nterror(req, NT_STATUS_NO_MEMORY);
4731 return;
4734 reply = api_commands[i].fn(conn,
4735 vuid,
4736 params,tpscnt, /* params + length */
4737 data,tdscnt, /* data + length */
4738 mdrcnt,mprcnt,
4739 &rdata,&rparam,&rdata_len,&rparam_len);
4742 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
4743 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
4744 &rdata,&rparam,&rdata_len,&rparam_len);
4747 /* if we get False back then it's actually unsupported */
4748 if (!reply) {
4749 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
4750 &rdata,&rparam,&rdata_len,&rparam_len);
4753 /* If api_Unsupported returns false we can't return anything. */
4754 if (reply) {
4755 send_trans_reply(conn, req, rparam, rparam_len,
4756 rdata, rdata_len, False);
4759 SAFE_FREE(rdata);
4760 SAFE_FREE(rparam);
4761 return;