Do not use the file system GET_REAL_FILENAME for mangled names
[Samba.git] / source3 / smbd / lanman.c
blob979e5b57a44d495b8d1d8a83c4ac8550618059c0
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"
30 #ifdef CHECK_TYPES
31 #undef CHECK_TYPES
32 #endif
33 #define CHECK_TYPES 0
35 #define NERR_Success 0
36 #define NERR_badpass 86
37 #define NERR_notsupported 50
39 #define NERR_BASE (2100)
40 #define NERR_BufTooSmall (NERR_BASE+23)
41 #define NERR_JobNotFound (NERR_BASE+51)
42 #define NERR_DestNotFound (NERR_BASE+52)
44 #define ACCESS_READ 0x01
45 #define ACCESS_WRITE 0x02
46 #define ACCESS_CREATE 0x04
48 #define SHPWLEN 8 /* share password length */
50 /* Limit size of ipc replies */
52 static char *smb_realloc_limit(void *ptr, size_t size)
54 char *val;
56 size = MAX((size),4*1024);
57 val = (char *)SMB_REALLOC(ptr,size);
58 if (val) {
59 memset(val,'\0',size);
61 return val;
64 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
65 char *param, int tpscnt,
66 char *data, int tdscnt,
67 int mdrcnt, int mprcnt,
68 char **rdata, char **rparam,
69 int *rdata_len, int *rparam_len);
71 static bool api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
72 int mdrcnt, int mprcnt,
73 char **rdata, char **rparam,
74 int *rdata_len, int *rparam_len);
77 static int CopyExpanded(connection_struct *conn,
78 int snum, char **dst, char *src, int *p_space_remaining)
80 TALLOC_CTX *ctx = talloc_tos();
81 char *buf = NULL;
82 int l;
84 if (!src || !dst || !p_space_remaining || !(*dst) ||
85 *p_space_remaining <= 0) {
86 return 0;
89 buf = talloc_strdup(ctx, src);
90 if (!buf) {
91 *p_space_remaining = 0;
92 return 0;
94 buf = talloc_string_sub(ctx, buf,"%S",lp_servicename(snum));
95 if (!buf) {
96 *p_space_remaining = 0;
97 return 0;
99 buf = talloc_sub_advanced(ctx,
100 lp_servicename(SNUM(conn)),
101 conn->server_info->unix_name,
102 conn->connectpath,
103 conn->server_info->utok.gid,
104 conn->server_info->sanitized_username,
105 pdb_get_domain(conn->server_info->sam_account),
106 buf);
107 if (!buf) {
108 *p_space_remaining = 0;
109 return 0;
111 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
112 if (l == -1) {
113 return 0;
115 (*dst) += l;
116 (*p_space_remaining) -= l;
117 return l;
120 static int CopyAndAdvance(char **dst, char *src, int *n)
122 int l;
123 if (!src || !dst || !n || !(*dst)) {
124 return 0;
126 l = push_ascii(*dst,src,*n, STR_TERMINATE);
127 if (l == -1) {
128 return 0;
130 (*dst) += l;
131 (*n) -= l;
132 return l;
135 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
137 TALLOC_CTX *ctx = talloc_tos();
138 char *buf = NULL;
139 if (!s) {
140 return 0;
142 buf = talloc_strdup(ctx,s);
143 if (!buf) {
144 return 0;
146 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
147 if (!buf) {
148 return 0;
150 buf = talloc_sub_advanced(ctx,
151 lp_servicename(SNUM(conn)),
152 conn->server_info->unix_name,
153 conn->connectpath,
154 conn->server_info->utok.gid,
155 conn->server_info->sanitized_username,
156 pdb_get_domain(conn->server_info->sam_account),
157 buf);
158 if (!buf) {
159 return 0;
161 return strlen(buf) + 1;
164 static char *Expand(connection_struct *conn, int snum, char *s)
166 TALLOC_CTX *ctx = talloc_tos();
167 char *buf = NULL;
169 if (!s) {
170 return NULL;
172 buf = talloc_strdup(ctx,s);
173 if (!buf) {
174 return 0;
176 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
177 if (!buf) {
178 return 0;
180 return talloc_sub_advanced(ctx,
181 lp_servicename(SNUM(conn)),
182 conn->server_info->unix_name,
183 conn->connectpath,
184 conn->server_info->utok.gid,
185 conn->server_info->sanitized_username,
186 pdb_get_domain(conn->server_info->sam_account),
187 buf);
190 /*******************************************************************
191 Check a API string for validity when we only need to check the prefix.
192 ******************************************************************/
194 static bool prefix_ok(const char *str, const char *prefix)
196 return(strncmp(str,prefix,strlen(prefix)) == 0);
199 struct pack_desc {
200 const char *format; /* formatstring for structure */
201 const char *subformat; /* subformat for structure */
202 char *base; /* baseaddress of buffer */
203 int buflen; /* remaining size for fixed part; on init: length of base */
204 int subcount; /* count of substructures */
205 char *structbuf; /* pointer into buffer for remaining fixed part */
206 int stringlen; /* remaining size for variable part */
207 char *stringbuf; /* pointer into buffer for remaining variable part */
208 int neededlen; /* total needed size */
209 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
210 const char *curpos; /* current position; pointer into format or subformat */
211 int errcode;
214 static int get_counter(const char **p)
216 int i, n;
217 if (!p || !(*p)) {
218 return 1;
220 if (!isdigit((int)**p)) {
221 return 1;
223 for (n = 0;;) {
224 i = **p;
225 if (isdigit(i)) {
226 n = 10 * n + (i - '0');
227 } else {
228 return n;
230 (*p)++;
234 static int getlen(const char *p)
236 int n = 0;
237 if (!p) {
238 return 0;
241 while (*p) {
242 switch( *p++ ) {
243 case 'W': /* word (2 byte) */
244 n += 2;
245 break;
246 case 'K': /* status word? (2 byte) */
247 n += 2;
248 break;
249 case 'N': /* count of substructures (word) at end */
250 n += 2;
251 break;
252 case 'D': /* double word (4 byte) */
253 case 'z': /* offset to zero terminated string (4 byte) */
254 case 'l': /* offset to user data (4 byte) */
255 n += 4;
256 break;
257 case 'b': /* offset to data (with counter) (4 byte) */
258 n += 4;
259 get_counter(&p);
260 break;
261 case 'B': /* byte (with optional counter) */
262 n += get_counter(&p);
263 break;
266 return n;
269 static bool init_package(struct pack_desc *p, int count, int subcount)
271 int n = p->buflen;
272 int i;
274 if (!p->format || !p->base) {
275 return False;
278 i = count * getlen(p->format);
279 if (p->subformat) {
280 i += subcount * getlen(p->subformat);
282 p->structbuf = p->base;
283 p->neededlen = 0;
284 p->usedlen = 0;
285 p->subcount = 0;
286 p->curpos = p->format;
287 if (i > n) {
288 p->neededlen = i;
289 i = n = 0;
290 #if 0
292 * This is the old error code we used. Aparently
293 * WinNT/2k systems return ERRbuftoosmall (2123) and
294 * OS/2 needs this. I'm leaving this here so we can revert
295 * if needed. JRA.
297 p->errcode = ERRmoredata;
298 #else
299 p->errcode = ERRbuftoosmall;
300 #endif
301 } else {
302 p->errcode = NERR_Success;
304 p->buflen = i;
305 n -= i;
306 p->stringbuf = p->base + i;
307 p->stringlen = n;
308 return (p->errcode == NERR_Success);
311 static int package(struct pack_desc *p, ...)
313 va_list args;
314 int needed=0, stringneeded;
315 const char *str=NULL;
316 int is_string=0, stringused;
317 int32 temp;
319 va_start(args,p);
321 if (!*p->curpos) {
322 if (!p->subcount) {
323 p->curpos = p->format;
324 } else {
325 p->curpos = p->subformat;
326 p->subcount--;
329 #if CHECK_TYPES
330 str = va_arg(args,char*);
331 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
332 #endif
333 stringneeded = -1;
335 if (!p->curpos) {
336 va_end(args);
337 return 0;
340 switch( *p->curpos++ ) {
341 case 'W': /* word (2 byte) */
342 needed = 2;
343 temp = va_arg(args,int);
344 if (p->buflen >= needed) {
345 SSVAL(p->structbuf,0,temp);
347 break;
348 case 'K': /* status word? (2 byte) */
349 needed = 2;
350 temp = va_arg(args,int);
351 if (p->buflen >= needed) {
352 SSVAL(p->structbuf,0,temp);
354 break;
355 case 'N': /* count of substructures (word) at end */
356 needed = 2;
357 p->subcount = va_arg(args,int);
358 if (p->buflen >= needed) {
359 SSVAL(p->structbuf,0,p->subcount);
361 break;
362 case 'D': /* double word (4 byte) */
363 needed = 4;
364 temp = va_arg(args,int);
365 if (p->buflen >= needed) {
366 SIVAL(p->structbuf,0,temp);
368 break;
369 case 'B': /* byte (with optional counter) */
370 needed = get_counter(&p->curpos);
372 char *s = va_arg(args,char*);
373 if (p->buflen >= needed) {
374 StrnCpy(p->structbuf,s?s:"",needed-1);
377 break;
378 case 'z': /* offset to zero terminated string (4 byte) */
379 str = va_arg(args,char*);
380 stringneeded = (str ? strlen(str)+1 : 0);
381 is_string = 1;
382 break;
383 case 'l': /* offset to user data (4 byte) */
384 str = va_arg(args,char*);
385 stringneeded = va_arg(args,int);
386 is_string = 0;
387 break;
388 case 'b': /* offset to data (with counter) (4 byte) */
389 str = va_arg(args,char*);
390 stringneeded = get_counter(&p->curpos);
391 is_string = 0;
392 break;
395 va_end(args);
396 if (stringneeded >= 0) {
397 needed = 4;
398 if (p->buflen >= needed) {
399 stringused = stringneeded;
400 if (stringused > p->stringlen) {
401 stringused = (is_string ? p->stringlen : 0);
402 if (p->errcode == NERR_Success) {
403 p->errcode = ERRmoredata;
406 if (!stringused) {
407 SIVAL(p->structbuf,0,0);
408 } else {
409 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
410 memcpy(p->stringbuf,str?str:"",stringused);
411 if (is_string) {
412 p->stringbuf[stringused-1] = '\0';
414 p->stringbuf += stringused;
415 p->stringlen -= stringused;
416 p->usedlen += stringused;
419 p->neededlen += stringneeded;
422 p->neededlen += needed;
423 if (p->buflen >= needed) {
424 p->structbuf += needed;
425 p->buflen -= needed;
426 p->usedlen += needed;
427 } else {
428 if (p->errcode == NERR_Success) {
429 p->errcode = ERRmoredata;
432 return 1;
435 #if CHECK_TYPES
436 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
437 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
438 #else
439 #define PACK(desc,t,v) package(desc,v)
440 #define PACKl(desc,t,v,l) package(desc,v,l)
441 #endif
443 static void PACKI(struct pack_desc* desc, const char *t,int v)
445 PACK(desc,t,v);
448 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
450 PACK(desc,t,v);
453 /****************************************************************************
454 Get a print queue.
455 ****************************************************************************/
457 static void PackDriverData(struct pack_desc* desc)
459 char drivdata[4+4+32];
460 SIVAL(drivdata,0,sizeof drivdata); /* cb */
461 SIVAL(drivdata,4,1000); /* lVersion */
462 memset(drivdata+8,0,32); /* szDeviceName */
463 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
464 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
467 static int check_printq_info(struct pack_desc* desc,
468 unsigned int uLevel, char *id1, char *id2)
470 desc->subformat = NULL;
471 switch( uLevel ) {
472 case 0:
473 desc->format = "B13";
474 break;
475 case 1:
476 desc->format = "B13BWWWzzzzzWW";
477 break;
478 case 2:
479 desc->format = "B13BWWWzzzzzWN";
480 desc->subformat = "WB21BB16B10zWWzDDz";
481 break;
482 case 3:
483 desc->format = "zWWWWzzzzWWzzl";
484 break;
485 case 4:
486 desc->format = "zWWWWzzzzWNzzl";
487 desc->subformat = "WWzWWDDzz";
488 break;
489 case 5:
490 desc->format = "z";
491 break;
492 case 51:
493 desc->format = "K";
494 break;
495 case 52:
496 desc->format = "WzzzzzzzzN";
497 desc->subformat = "z";
498 break;
499 default:
500 DEBUG(0,("check_printq_info: invalid level %d\n",
501 uLevel ));
502 return False;
504 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
505 DEBUG(0,("check_printq_info: invalid format %s\n",
506 id1 ? id1 : "<NULL>" ));
507 return False;
509 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
510 DEBUG(0,("check_printq_info: invalid subformat %s\n",
511 id2 ? id2 : "<NULL>" ));
512 return False;
514 return True;
518 #define RAP_JOB_STATUS_QUEUED 0
519 #define RAP_JOB_STATUS_PAUSED 1
520 #define RAP_JOB_STATUS_SPOOLING 2
521 #define RAP_JOB_STATUS_PRINTING 3
522 #define RAP_JOB_STATUS_PRINTED 4
524 #define RAP_QUEUE_STATUS_PAUSED 1
525 #define RAP_QUEUE_STATUS_ERROR 2
527 /* turn a print job status into a on the wire status
529 static int printj_status(int v)
531 switch (v) {
532 case LPQ_QUEUED:
533 return RAP_JOB_STATUS_QUEUED;
534 case LPQ_PAUSED:
535 return RAP_JOB_STATUS_PAUSED;
536 case LPQ_SPOOLING:
537 return RAP_JOB_STATUS_SPOOLING;
538 case LPQ_PRINTING:
539 return RAP_JOB_STATUS_PRINTING;
541 return 0;
544 /* turn a print queue status into a on the wire status
546 static int printq_status(int v)
548 switch (v) {
549 case LPQ_QUEUED:
550 return 0;
551 case LPQ_PAUSED:
552 return RAP_QUEUE_STATUS_PAUSED;
554 return RAP_QUEUE_STATUS_ERROR;
557 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
558 struct pack_desc *desc,
559 print_queue_struct *queue, int n)
561 time_t t = queue->time;
563 /* the client expects localtime */
564 t -= get_time_zone(t);
566 PACKI(desc,"W",pjobid_to_rap(lp_const_servicename(snum),queue->job)); /* uJobId */
567 if (uLevel == 1) {
568 PACKS(desc,"B21",queue->fs_user); /* szUserName */
569 PACKS(desc,"B",""); /* pad */
570 PACKS(desc,"B16",""); /* szNotifyName */
571 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
572 PACKS(desc,"z",""); /* pszParms */
573 PACKI(desc,"W",n+1); /* uPosition */
574 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
575 PACKS(desc,"z",""); /* pszStatus */
576 PACKI(desc,"D",t); /* ulSubmitted */
577 PACKI(desc,"D",queue->size); /* ulSize */
578 PACKS(desc,"z",queue->fs_file); /* pszComment */
580 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
581 PACKI(desc,"W",queue->priority); /* uPriority */
582 PACKS(desc,"z",queue->fs_user); /* pszUserName */
583 PACKI(desc,"W",n+1); /* uPosition */
584 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
585 PACKI(desc,"D",t); /* ulSubmitted */
586 PACKI(desc,"D",queue->size); /* ulSize */
587 PACKS(desc,"z","Samba"); /* pszComment */
588 PACKS(desc,"z",queue->fs_file); /* pszDocument */
589 if (uLevel == 3) {
590 PACKS(desc,"z",""); /* pszNotifyName */
591 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
592 PACKS(desc,"z",""); /* pszParms */
593 PACKS(desc,"z",""); /* pszStatus */
594 PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
595 PACKS(desc,"z","lpd"); /* pszQProcName */
596 PACKS(desc,"z",""); /* pszQProcParms */
597 PACKS(desc,"z","NULL"); /* pszDriverName */
598 PackDriverData(desc); /* pDriverData */
599 PACKS(desc,"z",""); /* pszPrinterName */
600 } else if (uLevel == 4) { /* OS2 */
601 PACKS(desc,"z",""); /* pszSpoolFileName */
602 PACKS(desc,"z",""); /* pszPortName */
603 PACKS(desc,"z",""); /* pszStatus */
604 PACKI(desc,"D",0); /* ulPagesSpooled */
605 PACKI(desc,"D",0); /* ulPagesSent */
606 PACKI(desc,"D",0); /* ulPagesPrinted */
607 PACKI(desc,"D",0); /* ulTimePrinted */
608 PACKI(desc,"D",0); /* ulExtendJobStatus */
609 PACKI(desc,"D",0); /* ulStartPage */
610 PACKI(desc,"D",0); /* ulEndPage */
615 /********************************************************************
616 Return a driver name given an snum.
617 Returns True if from tdb, False otherwise.
618 ********************************************************************/
620 static bool get_driver_name(int snum, char **pp_drivername)
622 NT_PRINTER_INFO_LEVEL *info = NULL;
623 bool in_tdb = false;
625 get_a_printer (NULL, &info, 2, lp_servicename(snum));
626 if (info != NULL) {
627 *pp_drivername = talloc_strdup(talloc_tos(),
628 info->info_2->drivername);
629 in_tdb = true;
630 free_a_printer(&info, 2);
631 if (!*pp_drivername) {
632 return false;
636 return in_tdb;
639 /********************************************************************
640 Respond to the DosPrintQInfo command with a level of 52
641 This is used to get printer driver information for Win9x clients
642 ********************************************************************/
643 static void fill_printq_info_52(connection_struct *conn, int snum,
644 struct pack_desc* desc, int count )
646 int i;
647 fstring location;
648 NT_PRINTER_DRIVER_INFO_LEVEL driver;
649 NT_PRINTER_INFO_LEVEL *printer = NULL;
651 ZERO_STRUCT(driver);
653 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
654 DEBUG(3,("fill_printq_info_52: Failed to lookup printer [%s]\n",
655 lp_servicename(snum)));
656 goto err;
659 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
660 "Windows 4.0", 0)) )
662 DEBUG(3,("fill_printq_info_52: Failed to lookup driver [%s]\n",
663 printer->info_2->drivername));
664 goto err;
667 trim_string(driver.info_3->driverpath, "\\print$\\WIN40\\0\\", 0);
668 trim_string(driver.info_3->datafile, "\\print$\\WIN40\\0\\", 0);
669 trim_string(driver.info_3->helpfile, "\\print$\\WIN40\\0\\", 0);
671 PACKI(desc, "W", 0x0400); /* don't know */
672 PACKS(desc, "z", driver.info_3->name); /* long printer name */
673 PACKS(desc, "z", driver.info_3->driverpath); /* Driverfile Name */
674 PACKS(desc, "z", driver.info_3->datafile); /* Datafile name */
675 PACKS(desc, "z", driver.info_3->monitorname); /* language monitor */
677 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
678 standard_sub_basic( "", "", location, sizeof(location)-1 );
679 PACKS(desc,"z", location); /* share to retrieve files */
681 PACKS(desc,"z", driver.info_3->defaultdatatype); /* default data type */
682 PACKS(desc,"z", driver.info_3->helpfile); /* helpfile name */
683 PACKS(desc,"z", driver.info_3->driverpath); /* driver name */
685 DEBUG(3,("Printer Driver Name: %s:\n",driver.info_3->name));
686 DEBUG(3,("Driver: %s:\n",driver.info_3->driverpath));
687 DEBUG(3,("Data File: %s:\n",driver.info_3->datafile));
688 DEBUG(3,("Language Monitor: %s:\n",driver.info_3->monitorname));
689 DEBUG(3,("Driver Location: %s:\n",location));
690 DEBUG(3,("Data Type: %s:\n",driver.info_3->defaultdatatype));
691 DEBUG(3,("Help File: %s:\n",driver.info_3->helpfile));
692 PACKI(desc,"N",count); /* number of files to copy */
694 for ( i=0; i<count && driver.info_3->dependentfiles && *driver.info_3->dependentfiles[i]; i++)
696 trim_string(driver.info_3->dependentfiles[i], "\\print$\\WIN40\\0\\", 0);
697 PACKS(desc,"z",driver.info_3->dependentfiles[i]); /* driver files to copy */
698 DEBUG(3,("Dependent File: %s:\n",driver.info_3->dependentfiles[i]));
701 /* sanity check */
702 if ( i != count )
703 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
704 count, i));
706 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", SERVICE(snum),i));
708 desc->errcode=NERR_Success;
709 goto done;
711 err:
712 DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
713 desc->errcode=NERR_notsupported;
715 done:
716 if ( printer )
717 free_a_printer( &printer, 2 );
719 if ( driver.info_3 )
720 free_a_printer_driver( driver, 3 );
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 NT_PRINTER_DRIVER_INFO_LEVEL 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(&driver, 3, 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.info_3->dependentfiles && *driver.info_3->dependentfiles[result] )
830 result++;
832 done:
833 if ( printer )
834 free_a_printer( &printer, 2 );
836 if ( driver.info_3 )
837 free_a_printer_driver( driver, 3 );
839 return result;
842 static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
843 char *param, int tpscnt,
844 char *data, int tdscnt,
845 int mdrcnt,int mprcnt,
846 char **rdata,char **rparam,
847 int *rdata_len,int *rparam_len)
849 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
850 char *str2 = skip_string(param,tpscnt,str1);
851 char *p = skip_string(param,tpscnt,str2);
852 char *QueueName = p;
853 unsigned int uLevel;
854 int count=0;
855 int snum;
856 char *str3;
857 struct pack_desc desc;
858 print_queue_struct *queue=NULL;
859 print_status_struct status;
860 char* tmpdata=NULL;
862 if (!str1 || !str2 || !p) {
863 return False;
865 memset((char *)&status,'\0',sizeof(status));
866 memset((char *)&desc,'\0',sizeof(desc));
868 p = skip_string(param,tpscnt,p);
869 if (!p) {
870 return False;
872 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
873 str3 = get_safe_str_ptr(param,tpscnt,p,4);
874 /* str3 may be null here and is checked in check_printq_info(). */
876 /* remove any trailing username */
877 if ((p = strchr_m(QueueName,'%')))
878 *p = 0;
880 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
882 /* check it's a supported varient */
883 if (!prefix_ok(str1,"zWrLh"))
884 return False;
885 if (!check_printq_info(&desc,uLevel,str2,str3)) {
887 * Patch from Scott Moomaw <scott@bridgewater.edu>
888 * to return the 'invalid info level' error if an
889 * unknown level was requested.
891 *rdata_len = 0;
892 *rparam_len = 6;
893 *rparam = smb_realloc_limit(*rparam,*rparam_len);
894 if (!*rparam) {
895 return False;
897 SSVALS(*rparam,0,ERRunknownlevel);
898 SSVAL(*rparam,2,0);
899 SSVAL(*rparam,4,0);
900 return(True);
903 snum = find_service(QueueName);
904 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) )
905 return False;
907 if (uLevel==52) {
908 count = get_printerdrivernumber(snum);
909 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
910 } else {
911 count = print_queue_status(snum, &queue,&status);
914 if (mdrcnt > 0) {
915 *rdata = smb_realloc_limit(*rdata,mdrcnt);
916 if (!*rdata) {
917 SAFE_FREE(queue);
918 return False;
920 desc.base = *rdata;
921 desc.buflen = mdrcnt;
922 } else {
924 * Don't return data but need to get correct length
925 * init_package will return wrong size if buflen=0
927 desc.buflen = getlen(desc.format);
928 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
931 if (init_package(&desc,1,count)) {
932 desc.subcount = count;
933 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
936 *rdata_len = desc.usedlen;
939 * We must set the return code to ERRbuftoosmall
940 * in order to support lanman style printing with Win NT/2k
941 * clients --jerry
943 if (!mdrcnt && lp_disable_spoolss())
944 desc.errcode = ERRbuftoosmall;
946 *rdata_len = desc.usedlen;
947 *rparam_len = 6;
948 *rparam = smb_realloc_limit(*rparam,*rparam_len);
949 if (!*rparam) {
950 SAFE_FREE(queue);
951 SAFE_FREE(tmpdata);
952 return False;
954 SSVALS(*rparam,0,desc.errcode);
955 SSVAL(*rparam,2,0);
956 SSVAL(*rparam,4,desc.neededlen);
958 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
960 SAFE_FREE(queue);
961 SAFE_FREE(tmpdata);
963 return(True);
966 /****************************************************************************
967 View list of all print jobs on all queues.
968 ****************************************************************************/
970 static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
971 char *param, int tpscnt,
972 char *data, int tdscnt,
973 int mdrcnt, int mprcnt,
974 char **rdata, char** rparam,
975 int *rdata_len, int *rparam_len)
977 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
978 char *output_format1 = skip_string(param,tpscnt,param_format);
979 char *p = skip_string(param,tpscnt,output_format1);
980 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
981 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
982 int services = lp_numservices();
983 int i, n;
984 struct pack_desc desc;
985 print_queue_struct **queue = NULL;
986 print_status_struct *status = NULL;
987 int *subcntarr = NULL;
988 int queuecnt = 0, subcnt = 0, succnt = 0;
990 if (!param_format || !output_format1 || !p) {
991 return False;
994 memset((char *)&desc,'\0',sizeof(desc));
996 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
998 if (!prefix_ok(param_format,"WrLeh")) {
999 return False;
1001 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
1003 * Patch from Scott Moomaw <scott@bridgewater.edu>
1004 * to return the 'invalid info level' error if an
1005 * unknown level was requested.
1007 *rdata_len = 0;
1008 *rparam_len = 6;
1009 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1010 if (!*rparam) {
1011 return False;
1013 SSVALS(*rparam,0,ERRunknownlevel);
1014 SSVAL(*rparam,2,0);
1015 SSVAL(*rparam,4,0);
1016 return(True);
1019 for (i = 0; i < services; i++) {
1020 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1021 queuecnt++;
1025 if((queue = SMB_MALLOC_ARRAY(print_queue_struct*, queuecnt)) == NULL) {
1026 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1027 goto err;
1029 memset(queue,0,queuecnt*sizeof(print_queue_struct*));
1030 if((status = SMB_MALLOC_ARRAY(print_status_struct,queuecnt)) == NULL) {
1031 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1032 goto err;
1034 memset(status,0,queuecnt*sizeof(print_status_struct));
1035 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1036 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1037 goto err;
1040 subcnt = 0;
1041 n = 0;
1042 for (i = 0; i < services; i++) {
1043 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1044 subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
1045 subcnt += subcntarr[n];
1046 n++;
1050 if (mdrcnt > 0) {
1051 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1052 if (!*rdata) {
1053 goto err;
1056 desc.base = *rdata;
1057 desc.buflen = mdrcnt;
1059 if (init_package(&desc,queuecnt,subcnt)) {
1060 n = 0;
1061 succnt = 0;
1062 for (i = 0; i < services; i++) {
1063 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1064 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1065 n++;
1066 if (desc.errcode == NERR_Success) {
1067 succnt = n;
1073 SAFE_FREE(subcntarr);
1075 *rdata_len = desc.usedlen;
1076 *rparam_len = 8;
1077 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1078 if (!*rparam) {
1079 goto err;
1081 SSVALS(*rparam,0,desc.errcode);
1082 SSVAL(*rparam,2,0);
1083 SSVAL(*rparam,4,succnt);
1084 SSVAL(*rparam,6,queuecnt);
1086 for (i = 0; i < queuecnt; i++) {
1087 if (queue) {
1088 SAFE_FREE(queue[i]);
1092 SAFE_FREE(queue);
1093 SAFE_FREE(status);
1095 return True;
1097 err:
1099 SAFE_FREE(subcntarr);
1100 for (i = 0; i < queuecnt; i++) {
1101 if (queue) {
1102 SAFE_FREE(queue[i]);
1105 SAFE_FREE(queue);
1106 SAFE_FREE(status);
1108 return False;
1111 /****************************************************************************
1112 Get info level for a server list query.
1113 ****************************************************************************/
1115 static bool check_server_info(int uLevel, char* id)
1117 switch( uLevel ) {
1118 case 0:
1119 if (strcmp(id,"B16") != 0) {
1120 return False;
1122 break;
1123 case 1:
1124 if (strcmp(id,"B16BBDz") != 0) {
1125 return False;
1127 break;
1128 default:
1129 return False;
1131 return True;
1134 struct srv_info_struct {
1135 fstring name;
1136 uint32 type;
1137 fstring comment;
1138 fstring domain;
1139 bool server_added;
1142 /*******************************************************************
1143 Get server info lists from the files saved by nmbd. Return the
1144 number of entries.
1145 ******************************************************************/
1147 static int get_server_info(uint32 servertype,
1148 struct srv_info_struct **servers,
1149 const char *domain)
1151 int count=0;
1152 int alloced=0;
1153 char **lines;
1154 bool local_list_only;
1155 int i;
1157 lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
1158 if (!lines) {
1159 DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
1160 return 0;
1163 /* request for everything is code for request all servers */
1164 if (servertype == SV_TYPE_ALL) {
1165 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1168 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1170 DEBUG(4,("Servertype search: %8x\n",servertype));
1172 for (i=0;lines[i];i++) {
1173 fstring stype;
1174 struct srv_info_struct *s;
1175 const char *ptr = lines[i];
1176 bool ok = True;
1177 TALLOC_CTX *frame = NULL;
1178 char *p;
1180 if (!*ptr) {
1181 continue;
1184 if (count == alloced) {
1185 alloced += 10;
1186 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1187 if (!*servers) {
1188 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1189 TALLOC_FREE(lines);
1190 return 0;
1192 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1194 s = &(*servers)[count];
1196 frame = talloc_stackframe();
1197 s->name[0] = '\0';
1198 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1199 TALLOC_FREE(frame);
1200 continue;
1202 fstrcpy(s->name, p);
1204 stype[0] = '\0';
1205 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1206 TALLOC_FREE(frame);
1207 continue;
1209 fstrcpy(stype, p);
1211 s->comment[0] = '\0';
1212 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1213 TALLOC_FREE(frame);
1214 continue;
1216 fstrcpy(s->comment, p);
1218 s->domain[0] = '\0';
1219 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1220 /* this allows us to cope with an old nmbd */
1221 fstrcpy(s->domain,lp_workgroup());
1222 } else {
1223 fstrcpy(s->domain, p);
1225 TALLOC_FREE(frame);
1227 if (sscanf(stype,"%X",&s->type) != 1) {
1228 DEBUG(4,("r:host file "));
1229 ok = False;
1232 /* Filter the servers/domains we return based on what was asked for. */
1234 /* Check to see if we are being asked for a local list only. */
1235 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1236 DEBUG(4,("r: local list only"));
1237 ok = False;
1240 /* doesn't match up: don't want it */
1241 if (!(servertype & s->type)) {
1242 DEBUG(4,("r:serv type "));
1243 ok = False;
1246 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1247 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1248 DEBUG(4,("s: dom mismatch "));
1249 ok = False;
1252 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1253 ok = False;
1256 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1257 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1259 if (ok) {
1260 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1261 s->name, s->type, s->comment, s->domain));
1262 s->server_added = True;
1263 count++;
1264 } else {
1265 DEBUG(4,("%20s %8x %25s %15s\n",
1266 s->name, s->type, s->comment, s->domain));
1270 TALLOC_FREE(lines);
1271 return count;
1274 /*******************************************************************
1275 Fill in a server info structure.
1276 ******************************************************************/
1278 static int fill_srv_info(struct srv_info_struct *service,
1279 int uLevel, char **buf, int *buflen,
1280 char **stringbuf, int *stringspace, char *baseaddr)
1282 int struct_len;
1283 char* p;
1284 char* p2;
1285 int l2;
1286 int len;
1288 switch (uLevel) {
1289 case 0:
1290 struct_len = 16;
1291 break;
1292 case 1:
1293 struct_len = 26;
1294 break;
1295 default:
1296 return -1;
1299 if (!buf) {
1300 len = 0;
1301 switch (uLevel) {
1302 case 1:
1303 len = strlen(service->comment)+1;
1304 break;
1307 *buflen = struct_len;
1308 *stringspace = len;
1309 return struct_len + len;
1312 len = struct_len;
1313 p = *buf;
1314 if (*buflen < struct_len) {
1315 return -1;
1317 if (stringbuf) {
1318 p2 = *stringbuf;
1319 l2 = *stringspace;
1320 } else {
1321 p2 = p + struct_len;
1322 l2 = *buflen - struct_len;
1324 if (!baseaddr) {
1325 baseaddr = p;
1328 switch (uLevel) {
1329 case 0:
1330 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1331 break;
1333 case 1:
1334 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1335 SIVAL(p,18,service->type);
1336 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1337 len += CopyAndAdvance(&p2,service->comment,&l2);
1338 break;
1341 if (stringbuf) {
1342 *buf = p + struct_len;
1343 *buflen -= struct_len;
1344 *stringbuf = p2;
1345 *stringspace = l2;
1346 } else {
1347 *buf = p2;
1348 *buflen -= len;
1350 return len;
1354 static bool srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1356 return(strcmp(s1->name,s2->name));
1359 /****************************************************************************
1360 View list of servers available (or possibly domains). The info is
1361 extracted from lists saved by nmbd on the local host.
1362 ****************************************************************************/
1364 static bool api_RNetServerEnum(connection_struct *conn, uint16 vuid,
1365 char *param, int tpscnt,
1366 char *data, int tdscnt,
1367 int mdrcnt, int mprcnt, char **rdata,
1368 char **rparam, int *rdata_len, int *rparam_len)
1370 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1371 char *str2 = skip_string(param,tpscnt,str1);
1372 char *p = skip_string(param,tpscnt,str2);
1373 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1374 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1375 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1376 char *p2;
1377 int data_len, fixed_len, string_len;
1378 int f_len = 0, s_len = 0;
1379 struct srv_info_struct *servers=NULL;
1380 int counted=0,total=0;
1381 int i,missed;
1382 fstring domain;
1383 bool domain_request;
1384 bool local_request;
1386 if (!str1 || !str2 || !p) {
1387 return False;
1390 /* If someone sets all the bits they don't really mean to set
1391 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1392 known servers. */
1394 if (servertype == SV_TYPE_ALL) {
1395 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1398 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1399 any other bit (they may just set this bit on its own) they
1400 want all the locally seen servers. However this bit can be
1401 set on its own so set the requested servers to be
1402 ALL - DOMAIN_ENUM. */
1404 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1405 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1408 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1409 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1411 p += 8;
1413 if (!prefix_ok(str1,"WrLehD")) {
1414 return False;
1416 if (!check_server_info(uLevel,str2)) {
1417 return False;
1420 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1421 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1422 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1424 if (strcmp(str1, "WrLehDz") == 0) {
1425 if (skip_string(param,tpscnt,p) == NULL) {
1426 return False;
1428 pull_ascii_fstring(domain, p);
1429 } else {
1430 fstrcpy(domain, lp_workgroup());
1433 if (lp_browse_list()) {
1434 total = get_server_info(servertype,&servers,domain);
1437 data_len = fixed_len = string_len = 0;
1438 missed = 0;
1440 if (total > 0) {
1441 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1445 char *lastname=NULL;
1447 for (i=0;i<total;i++) {
1448 struct srv_info_struct *s = &servers[i];
1450 if (lastname && strequal(lastname,s->name)) {
1451 continue;
1453 lastname = s->name;
1454 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1455 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1456 s->name, s->type, s->comment, s->domain));
1458 if (data_len <= buf_len) {
1459 counted++;
1460 fixed_len += f_len;
1461 string_len += s_len;
1462 } else {
1463 missed++;
1468 *rdata_len = fixed_len + string_len;
1469 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1470 if (!*rdata) {
1471 return False;
1474 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1475 p = *rdata;
1476 f_len = fixed_len;
1477 s_len = string_len;
1480 char *lastname=NULL;
1481 int count2 = counted;
1483 for (i = 0; i < total && count2;i++) {
1484 struct srv_info_struct *s = &servers[i];
1486 if (lastname && strequal(lastname,s->name)) {
1487 continue;
1489 lastname = s->name;
1490 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1491 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1492 s->name, s->type, s->comment, s->domain));
1493 count2--;
1497 *rparam_len = 8;
1498 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1499 if (!*rparam) {
1500 return False;
1502 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1503 SSVAL(*rparam,2,0);
1504 SSVAL(*rparam,4,counted);
1505 SSVAL(*rparam,6,counted+missed);
1507 SAFE_FREE(servers);
1509 DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1510 domain,uLevel,counted,counted+missed));
1512 return True;
1515 /****************************************************************************
1516 command 0x34 - suspected of being a "Lookup Names" stub api
1517 ****************************************************************************/
1519 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1520 char *param, int tpscnt,
1521 char *data, int tdscnt,
1522 int mdrcnt, int mprcnt, char **rdata,
1523 char **rparam, int *rdata_len, int *rparam_len)
1525 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1526 char *str2 = skip_string(param,tpscnt,str1);
1527 char *p = skip_string(param,tpscnt,str2);
1528 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1529 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1530 int counted=0;
1531 int missed=0;
1533 if (!str1 || !str2 || !p) {
1534 return False;
1537 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1538 str1, str2, p, uLevel, buf_len));
1540 if (!prefix_ok(str1,"zWrLeh")) {
1541 return False;
1544 *rdata_len = 0;
1546 *rparam_len = 8;
1547 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1548 if (!*rparam) {
1549 return False;
1552 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1553 SSVAL(*rparam,2,0);
1554 SSVAL(*rparam,4,counted);
1555 SSVAL(*rparam,6,counted+missed);
1557 return True;
1560 /****************************************************************************
1561 get info about a share
1562 ****************************************************************************/
1564 static bool check_share_info(int uLevel, char* id)
1566 switch( uLevel ) {
1567 case 0:
1568 if (strcmp(id,"B13") != 0) {
1569 return False;
1571 break;
1572 case 1:
1573 if (strcmp(id,"B13BWz") != 0) {
1574 return False;
1576 break;
1577 case 2:
1578 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1579 return False;
1581 break;
1582 case 91:
1583 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1584 return False;
1586 break;
1587 default:
1588 return False;
1590 return True;
1593 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1594 char** buf, int* buflen,
1595 char** stringbuf, int* stringspace, char* baseaddr)
1597 int struct_len;
1598 char* p;
1599 char* p2;
1600 int l2;
1601 int len;
1603 switch( uLevel ) {
1604 case 0:
1605 struct_len = 13;
1606 break;
1607 case 1:
1608 struct_len = 20;
1609 break;
1610 case 2:
1611 struct_len = 40;
1612 break;
1613 case 91:
1614 struct_len = 68;
1615 break;
1616 default:
1617 return -1;
1620 if (!buf) {
1621 len = 0;
1623 if (uLevel > 0) {
1624 len += StrlenExpanded(conn,snum,lp_comment(snum));
1626 if (uLevel > 1) {
1627 len += strlen(lp_pathname(snum)) + 1;
1629 if (buflen) {
1630 *buflen = struct_len;
1632 if (stringspace) {
1633 *stringspace = len;
1635 return struct_len + len;
1638 len = struct_len;
1639 p = *buf;
1640 if ((*buflen) < struct_len) {
1641 return -1;
1644 if (stringbuf) {
1645 p2 = *stringbuf;
1646 l2 = *stringspace;
1647 } else {
1648 p2 = p + struct_len;
1649 l2 = (*buflen) - struct_len;
1652 if (!baseaddr) {
1653 baseaddr = p;
1656 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1658 if (uLevel > 0) {
1659 int type;
1661 SCVAL(p,13,0);
1662 type = STYPE_DISKTREE;
1663 if (lp_print_ok(snum)) {
1664 type = STYPE_PRINTQ;
1666 if (strequal("IPC",lp_fstype(snum))) {
1667 type = STYPE_IPC;
1669 SSVAL(p,14,type); /* device type */
1670 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1671 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1674 if (uLevel > 1) {
1675 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1676 SSVALS(p,22,-1); /* max uses */
1677 SSVAL(p,24,1); /* current uses */
1678 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1679 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1680 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1683 if (uLevel > 2) {
1684 memset(p+40,0,SHPWLEN+2);
1685 SSVAL(p,50,0);
1686 SIVAL(p,52,0);
1687 SSVAL(p,56,0);
1688 SSVAL(p,58,0);
1689 SIVAL(p,60,0);
1690 SSVAL(p,64,0);
1691 SSVAL(p,66,0);
1694 if (stringbuf) {
1695 (*buf) = p + struct_len;
1696 (*buflen) -= struct_len;
1697 (*stringbuf) = p2;
1698 (*stringspace) = l2;
1699 } else {
1700 (*buf) = p2;
1701 (*buflen) -= len;
1704 return len;
1707 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1708 char *param, int tpscnt,
1709 char *data, int tdscnt,
1710 int mdrcnt,int mprcnt,
1711 char **rdata,char **rparam,
1712 int *rdata_len,int *rparam_len)
1714 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1715 char *str2 = skip_string(param,tpscnt,str1);
1716 char *netname = skip_string(param,tpscnt,str2);
1717 char *p = skip_string(param,tpscnt,netname);
1718 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1719 int snum;
1721 if (!str1 || !str2 || !netname || !p) {
1722 return False;
1725 snum = find_service(netname);
1726 if (snum < 0) {
1727 return False;
1730 /* check it's a supported varient */
1731 if (!prefix_ok(str1,"zWrLh")) {
1732 return False;
1734 if (!check_share_info(uLevel,str2)) {
1735 return False;
1738 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1739 if (!*rdata) {
1740 return False;
1742 p = *rdata;
1743 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1744 if (*rdata_len < 0) {
1745 return False;
1748 *rparam_len = 6;
1749 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1750 if (!*rparam) {
1751 return False;
1753 SSVAL(*rparam,0,NERR_Success);
1754 SSVAL(*rparam,2,0); /* converter word */
1755 SSVAL(*rparam,4,*rdata_len);
1757 return True;
1760 /****************************************************************************
1761 View the list of available shares.
1763 This function is the server side of the NetShareEnum() RAP call.
1764 It fills the return buffer with share names and share comments.
1765 Note that the return buffer normally (in all known cases) allows only
1766 twelve byte strings for share names (plus one for a nul terminator).
1767 Share names longer than 12 bytes must be skipped.
1768 ****************************************************************************/
1770 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
1771 char *param, int tpscnt,
1772 char *data, int tdscnt,
1773 int mdrcnt,
1774 int mprcnt,
1775 char **rdata,
1776 char **rparam,
1777 int *rdata_len,
1778 int *rparam_len )
1780 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1781 char *str2 = skip_string(param,tpscnt,str1);
1782 char *p = skip_string(param,tpscnt,str2);
1783 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1784 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1785 char *p2;
1786 int count = 0;
1787 int total=0,counted=0;
1788 bool missed = False;
1789 int i;
1790 int data_len, fixed_len, string_len;
1791 int f_len = 0, s_len = 0;
1793 if (!str1 || !str2 || !p) {
1794 return False;
1797 if (!prefix_ok(str1,"WrLeh")) {
1798 return False;
1800 if (!check_share_info(uLevel,str2)) {
1801 return False;
1804 /* Ensure all the usershares are loaded. */
1805 become_root();
1806 load_registry_shares();
1807 count = load_usershare_shares();
1808 unbecome_root();
1810 data_len = fixed_len = string_len = 0;
1811 for (i=0;i<count;i++) {
1812 fstring servicename_dos;
1813 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1814 continue;
1816 push_ascii_fstring(servicename_dos, lp_servicename(i));
1817 /* Maximum name length = 13. */
1818 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
1819 total++;
1820 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1821 if (data_len <= buf_len) {
1822 counted++;
1823 fixed_len += f_len;
1824 string_len += s_len;
1825 } else {
1826 missed = True;
1831 *rdata_len = fixed_len + string_len;
1832 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1833 if (!*rdata) {
1834 return False;
1837 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
1838 p = *rdata;
1839 f_len = fixed_len;
1840 s_len = string_len;
1842 for( i = 0; i < count; i++ ) {
1843 fstring servicename_dos;
1844 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1845 continue;
1848 push_ascii_fstring(servicename_dos, lp_servicename(i));
1849 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
1850 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
1851 break;
1856 *rparam_len = 8;
1857 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1858 if (!*rparam) {
1859 return False;
1861 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1862 SSVAL(*rparam,2,0);
1863 SSVAL(*rparam,4,counted);
1864 SSVAL(*rparam,6,total);
1866 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1867 counted,total,uLevel,
1868 buf_len,*rdata_len,mdrcnt));
1870 return True;
1873 /****************************************************************************
1874 Add a share
1875 ****************************************************************************/
1877 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
1878 char *param, int tpscnt,
1879 char *data, int tdscnt,
1880 int mdrcnt,int mprcnt,
1881 char **rdata,char **rparam,
1882 int *rdata_len,int *rparam_len)
1884 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1885 char *str2 = skip_string(param,tpscnt,str1);
1886 char *p = skip_string(param,tpscnt,str2);
1887 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1888 fstring sharename;
1889 fstring comment;
1890 char *pathname = NULL;
1891 char *command, *cmdname;
1892 unsigned int offset;
1893 int snum;
1894 int res = ERRunsup;
1895 size_t converted_size;
1897 if (!str1 || !str2 || !p) {
1898 return False;
1901 /* check it's a supported varient */
1902 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
1903 return False;
1905 if (!check_share_info(uLevel,str2)) {
1906 return False;
1908 if (uLevel != 2) {
1909 return False;
1912 /* Do we have a string ? */
1913 if (skip_string(data,mdrcnt,data) == NULL) {
1914 return False;
1916 pull_ascii_fstring(sharename,data);
1917 snum = find_service(sharename);
1918 if (snum >= 0) { /* already exists */
1919 res = ERRfilexists;
1920 goto error_exit;
1923 if (mdrcnt < 28) {
1924 return False;
1927 /* only support disk share adds */
1928 if (SVAL(data,14)!=STYPE_DISKTREE) {
1929 return False;
1932 offset = IVAL(data, 16);
1933 if (offset >= mdrcnt) {
1934 res = ERRinvalidparam;
1935 goto error_exit;
1938 /* Do we have a string ? */
1939 if (skip_string(data,mdrcnt,data+offset) == NULL) {
1940 return False;
1942 pull_ascii_fstring(comment, offset? (data+offset) : "");
1944 offset = IVAL(data, 26);
1946 if (offset >= mdrcnt) {
1947 res = ERRinvalidparam;
1948 goto error_exit;
1951 /* Do we have a string ? */
1952 if (skip_string(data,mdrcnt,data+offset) == NULL) {
1953 return False;
1956 if (!pull_ascii_talloc(talloc_tos(), &pathname,
1957 offset ? (data+offset) : "", &converted_size))
1959 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
1960 strerror(errno)));
1963 if (!pathname) {
1964 return false;
1967 string_replace(sharename, '"', ' ');
1968 string_replace(pathname, '"', ' ');
1969 string_replace(comment, '"', ' ');
1971 cmdname = lp_add_share_cmd();
1973 if (!cmdname || *cmdname == '\0') {
1974 return False;
1977 if (asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
1978 lp_add_share_cmd(), get_dyn_CONFIGFILE(), sharename,
1979 pathname, comment) == -1) {
1980 return false;
1983 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
1985 if ((res = smbrun(command, NULL)) != 0) {
1986 DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n",
1987 command, res ));
1988 SAFE_FREE(command);
1989 res = ERRnoaccess;
1990 goto error_exit;
1991 } else {
1992 SAFE_FREE(command);
1993 message_send_all(smbd_messaging_context(),
1994 MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
1997 *rparam_len = 6;
1998 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1999 if (!*rparam) {
2000 return False;
2002 SSVAL(*rparam,0,NERR_Success);
2003 SSVAL(*rparam,2,0); /* converter word */
2004 SSVAL(*rparam,4,*rdata_len);
2005 *rdata_len = 0;
2007 return True;
2009 error_exit:
2011 *rparam_len = 4;
2012 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2013 if (!*rparam) {
2014 return False;
2016 *rdata_len = 0;
2017 SSVAL(*rparam,0,res);
2018 SSVAL(*rparam,2,0);
2019 return True;
2022 /****************************************************************************
2023 view list of groups available
2024 ****************************************************************************/
2026 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
2027 char *param, int tpscnt,
2028 char *data, int tdscnt,
2029 int mdrcnt,int mprcnt,
2030 char **rdata,char **rparam,
2031 int *rdata_len,int *rparam_len)
2033 int i;
2034 int errflags=0;
2035 int resume_context, cli_buf_size;
2036 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2037 char *str2 = skip_string(param,tpscnt,str1);
2038 char *p = skip_string(param,tpscnt,str2);
2040 uint32_t num_groups;
2041 uint32_t resume_handle;
2042 struct rpc_pipe_client *samr_pipe;
2043 struct policy_handle samr_handle, domain_handle;
2044 NTSTATUS status;
2046 if (!str1 || !str2 || !p) {
2047 return False;
2050 if (strcmp(str1,"WrLeh") != 0) {
2051 return False;
2054 /* parameters
2055 * W-> resume context (number of users to skip)
2056 * r -> return parameter pointer to receive buffer
2057 * L -> length of receive buffer
2058 * e -> return parameter number of entries
2059 * h -> return parameter total number of users
2062 if (strcmp("B21",str2) != 0) {
2063 return False;
2066 status = rpc_pipe_open_internal(
2067 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2068 conn->server_info, &samr_pipe);
2069 if (!NT_STATUS_IS_OK(status)) {
2070 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2071 nt_errstr(status)));
2072 return false;
2075 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2076 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2077 if (!NT_STATUS_IS_OK(status)) {
2078 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2079 nt_errstr(status)));
2080 return false;
2083 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2084 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2085 get_global_sam_sid(), &domain_handle);
2086 if (!NT_STATUS_IS_OK(status)) {
2087 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2088 nt_errstr(status)));
2089 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2090 return false;
2093 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2094 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2095 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2096 "%d\n", resume_context, cli_buf_size));
2098 *rdata_len = cli_buf_size;
2099 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2100 if (!*rdata) {
2101 return False;
2104 p = *rdata;
2106 errflags = NERR_Success;
2107 num_groups = 0;
2108 resume_handle = 0;
2110 while (true) {
2111 struct samr_SamArray *sam_entries;
2112 uint32_t num_entries;
2114 status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
2115 &domain_handle,
2116 &resume_handle,
2117 &sam_entries, 1,
2118 &num_entries);
2119 if (!NT_STATUS_IS_OK(status)) {
2120 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2121 "%s\n", nt_errstr(status)));
2122 break;
2125 if (num_entries == 0) {
2126 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2127 "no entries -- done\n"));
2128 break;
2131 for(i=0; i<num_entries; i++) {
2132 const char *name;
2134 name = sam_entries->entries[i].name.string;
2136 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2137 /* set overflow error */
2138 DEBUG(3,("overflow on entry %d group %s\n", i,
2139 name));
2140 errflags=234;
2141 break;
2144 /* truncate the name at 21 chars. */
2145 memset(p, 0, 21);
2146 strlcpy(p, name, 21);
2147 DEBUG(10,("adding entry %d group %s\n", i, p));
2148 p += 21;
2149 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2150 * idea why... */
2151 num_groups += 1;
2154 if (errflags != NERR_Success) {
2155 break;
2158 TALLOC_FREE(sam_entries);
2161 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2162 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2164 *rdata_len = PTR_DIFF(p,*rdata);
2166 *rparam_len = 8;
2167 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2168 if (!*rparam) {
2169 return False;
2171 SSVAL(*rparam, 0, errflags);
2172 SSVAL(*rparam, 2, 0); /* converter word */
2173 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2174 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2176 return(True);
2179 /*******************************************************************
2180 Get groups that a user is a member of.
2181 ******************************************************************/
2183 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2184 char *param, int tpscnt,
2185 char *data, int tdscnt,
2186 int mdrcnt,int mprcnt,
2187 char **rdata,char **rparam,
2188 int *rdata_len,int *rparam_len)
2190 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2191 char *str2 = skip_string(param,tpscnt,str1);
2192 char *UserName = skip_string(param,tpscnt,str2);
2193 char *p = skip_string(param,tpscnt,UserName);
2194 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2195 const char *level_string;
2196 int count=0;
2197 bool ret = False;
2198 uint32_t i;
2199 char *endp = NULL;
2201 struct rpc_pipe_client *samr_pipe;
2202 struct policy_handle samr_handle, domain_handle, user_handle;
2203 struct lsa_String name;
2204 struct lsa_Strings names;
2205 struct samr_Ids type, rid;
2206 struct samr_RidWithAttributeArray *rids;
2207 NTSTATUS status;
2209 if (!str1 || !str2 || !UserName || !p) {
2210 return False;
2213 *rparam_len = 8;
2214 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2215 if (!*rparam) {
2216 return False;
2219 /* check it's a supported varient */
2221 if ( strcmp(str1,"zWrLeh") != 0 )
2222 return False;
2224 switch( uLevel ) {
2225 case 0:
2226 level_string = "B21";
2227 break;
2228 default:
2229 return False;
2232 if (strcmp(level_string,str2) != 0)
2233 return False;
2235 *rdata_len = mdrcnt + 1024;
2236 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2237 if (!*rdata) {
2238 return False;
2241 SSVAL(*rparam,0,NERR_Success);
2242 SSVAL(*rparam,2,0); /* converter word */
2244 p = *rdata;
2245 endp = *rdata + *rdata_len;
2247 status = rpc_pipe_open_internal(
2248 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2249 conn->server_info, &samr_pipe);
2250 if (!NT_STATUS_IS_OK(status)) {
2251 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2252 nt_errstr(status)));
2253 return false;
2256 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2257 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2258 if (!NT_STATUS_IS_OK(status)) {
2259 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2260 nt_errstr(status)));
2261 return false;
2264 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2265 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2266 get_global_sam_sid(), &domain_handle);
2267 if (!NT_STATUS_IS_OK(status)) {
2268 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2269 nt_errstr(status)));
2270 goto close_sam;
2273 name.string = UserName;
2275 status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
2276 &domain_handle, 1, &name,
2277 &rid, &type);
2278 if (!NT_STATUS_IS_OK(status)) {
2279 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2280 nt_errstr(status)));
2281 goto close_domain;
2284 if (type.ids[0] != SID_NAME_USER) {
2285 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2286 sid_type_lookup(type.ids[0])));
2287 goto close_domain;
2290 status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
2291 &domain_handle,
2292 SAMR_USER_ACCESS_GET_GROUPS,
2293 rid.ids[0], &user_handle);
2294 if (!NT_STATUS_IS_OK(status)) {
2295 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2296 nt_errstr(status)));
2297 goto close_domain;
2300 status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
2301 &user_handle, &rids);
2302 if (!NT_STATUS_IS_OK(status)) {
2303 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2304 nt_errstr(status)));
2305 goto close_user;
2308 for (i=0; i<rids->count; i++) {
2310 status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
2311 &domain_handle,
2312 1, &rids->rids[i].rid,
2313 &names, &type);
2314 if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
2315 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2316 p += 21;
2317 count++;
2321 *rdata_len = PTR_DIFF(p,*rdata);
2323 SSVAL(*rparam,4,count); /* is this right?? */
2324 SSVAL(*rparam,6,count); /* is this right?? */
2326 ret = True;
2328 close_user:
2329 rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
2330 close_domain:
2331 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2332 close_sam:
2333 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2335 return ret;
2338 /*******************************************************************
2339 Get all users.
2340 ******************************************************************/
2342 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2343 char *param, int tpscnt,
2344 char *data, int tdscnt,
2345 int mdrcnt,int mprcnt,
2346 char **rdata,char **rparam,
2347 int *rdata_len,int *rparam_len)
2349 int count_sent=0;
2350 int num_users=0;
2351 int errflags=0;
2352 int i, resume_context, cli_buf_size;
2353 uint32_t resume_handle;
2355 struct rpc_pipe_client *samr_pipe;
2356 struct policy_handle samr_handle, domain_handle;
2357 NTSTATUS status;
2359 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2360 char *str2 = skip_string(param,tpscnt,str1);
2361 char *p = skip_string(param,tpscnt,str2);
2362 char *endp = NULL;
2364 if (!str1 || !str2 || !p) {
2365 return False;
2368 if (strcmp(str1,"WrLeh") != 0)
2369 return False;
2370 /* parameters
2371 * W-> resume context (number of users to skip)
2372 * r -> return parameter pointer to receive buffer
2373 * L -> length of receive buffer
2374 * e -> return parameter number of entries
2375 * h -> return parameter total number of users
2378 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2379 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2380 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2381 resume_context, cli_buf_size));
2383 *rparam_len = 8;
2384 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2385 if (!*rparam) {
2386 return False;
2389 /* check it's a supported varient */
2390 if (strcmp("B21",str2) != 0)
2391 return False;
2393 *rdata_len = cli_buf_size;
2394 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2395 if (!*rdata) {
2396 return False;
2399 p = *rdata;
2400 endp = *rdata + *rdata_len;
2402 status = rpc_pipe_open_internal(
2403 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2404 conn->server_info, &samr_pipe);
2405 if (!NT_STATUS_IS_OK(status)) {
2406 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2407 nt_errstr(status)));
2408 return false;
2411 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2412 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2413 if (!NT_STATUS_IS_OK(status)) {
2414 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2415 nt_errstr(status)));
2416 return false;
2419 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2420 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2421 get_global_sam_sid(), &domain_handle);
2422 if (!NT_STATUS_IS_OK(status)) {
2423 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2424 nt_errstr(status)));
2425 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2426 return false;
2429 errflags=NERR_Success;
2431 resume_handle = 0;
2433 while (true) {
2434 struct samr_SamArray *sam_entries;
2435 uint32_t num_entries;
2437 status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
2438 &domain_handle,
2439 &resume_handle,
2440 0, &sam_entries, 1,
2441 &num_entries);
2443 if (!NT_STATUS_IS_OK(status)) {
2444 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2445 "%s\n", nt_errstr(status)));
2446 break;
2449 if (num_entries == 0) {
2450 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2451 "no entries -- done\n"));
2452 break;
2455 for (i=0; i<num_entries; i++) {
2456 const char *name;
2458 name = sam_entries->entries[i].name.string;
2460 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2461 &&(strlen(name)<=21)) {
2462 strlcpy(p,name,PTR_DIFF(endp,p));
2463 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2464 "username %s\n",count_sent,p));
2465 p += 21;
2466 count_sent++;
2467 } else {
2468 /* set overflow error */
2469 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2470 "username %s\n",count_sent,name));
2471 errflags=234;
2472 break;
2476 if (errflags != NERR_Success) {
2477 break;
2480 TALLOC_FREE(sam_entries);
2483 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2484 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2486 *rdata_len = PTR_DIFF(p,*rdata);
2488 SSVAL(*rparam,0,errflags);
2489 SSVAL(*rparam,2,0); /* converter word */
2490 SSVAL(*rparam,4,count_sent); /* is this right?? */
2491 SSVAL(*rparam,6,num_users); /* is this right?? */
2493 return True;
2496 /****************************************************************************
2497 Get the time of day info.
2498 ****************************************************************************/
2500 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2501 char *param, int tpscnt,
2502 char *data, int tdscnt,
2503 int mdrcnt,int mprcnt,
2504 char **rdata,char **rparam,
2505 int *rdata_len,int *rparam_len)
2507 struct tm *t;
2508 time_t unixdate = time(NULL);
2509 char *p;
2511 *rparam_len = 4;
2512 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2513 if (!*rparam) {
2514 return False;
2517 *rdata_len = 21;
2518 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2519 if (!*rdata) {
2520 return False;
2523 SSVAL(*rparam,0,NERR_Success);
2524 SSVAL(*rparam,2,0); /* converter word */
2526 p = *rdata;
2528 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2529 by NT in a "net time" operation,
2530 it seems to ignore the one below */
2532 /* the client expects to get localtime, not GMT, in this bit
2533 (I think, this needs testing) */
2534 t = localtime(&unixdate);
2535 if (!t) {
2536 return False;
2539 SIVAL(p,4,0); /* msecs ? */
2540 SCVAL(p,8,t->tm_hour);
2541 SCVAL(p,9,t->tm_min);
2542 SCVAL(p,10,t->tm_sec);
2543 SCVAL(p,11,0); /* hundredths of seconds */
2544 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2545 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2546 SCVAL(p,16,t->tm_mday);
2547 SCVAL(p,17,t->tm_mon + 1);
2548 SSVAL(p,18,1900+t->tm_year);
2549 SCVAL(p,20,t->tm_wday);
2551 return True;
2554 /****************************************************************************
2555 Set the user password.
2556 *****************************************************************************/
2558 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2559 char *param, int tpscnt,
2560 char *data, int tdscnt,
2561 int mdrcnt,int mprcnt,
2562 char **rdata,char **rparam,
2563 int *rdata_len,int *rparam_len)
2565 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2566 char *p = NULL;
2567 fstring user;
2568 fstring pass1,pass2;
2570 /* Skip 2 strings. */
2571 p = skip_string(param,tpscnt,np);
2572 p = skip_string(param,tpscnt,p);
2574 if (!np || !p) {
2575 return False;
2578 /* Do we have a string ? */
2579 if (skip_string(param,tpscnt,p) == NULL) {
2580 return False;
2582 pull_ascii_fstring(user,p);
2584 p = skip_string(param,tpscnt,p);
2585 if (!p) {
2586 return False;
2589 memset(pass1,'\0',sizeof(pass1));
2590 memset(pass2,'\0',sizeof(pass2));
2592 * We use 31 here not 32 as we're checking
2593 * the last byte we want to access is safe.
2595 if (!is_offset_safe(param,tpscnt,p,31)) {
2596 return False;
2598 memcpy(pass1,p,16);
2599 memcpy(pass2,p+16,16);
2601 *rparam_len = 4;
2602 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2603 if (!*rparam) {
2604 return False;
2607 *rdata_len = 0;
2609 SSVAL(*rparam,0,NERR_badpass);
2610 SSVAL(*rparam,2,0); /* converter word */
2612 DEBUG(3,("Set password for <%s>\n",user));
2615 * Attempt to verify the old password against smbpasswd entries
2616 * Win98 clients send old and new password in plaintext for this call.
2620 auth_serversupplied_info *server_info = NULL;
2621 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2623 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2625 become_root();
2626 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2627 SSVAL(*rparam,0,NERR_Success);
2629 unbecome_root();
2631 TALLOC_FREE(server_info);
2633 data_blob_clear_free(&password);
2637 * If the plaintext change failed, attempt
2638 * the old encrypted method. NT will generate this
2639 * after trying the samr method. Note that this
2640 * method is done as a last resort as this
2641 * password change method loses the NT password hash
2642 * and cannot change the UNIX password as no plaintext
2643 * is received.
2646 if(SVAL(*rparam,0) != NERR_Success) {
2647 struct samu *hnd = NULL;
2649 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2650 become_root();
2651 if (change_lanman_password(hnd,(uchar *)pass2)) {
2652 SSVAL(*rparam,0,NERR_Success);
2654 unbecome_root();
2655 TALLOC_FREE(hnd);
2659 memset((char *)pass1,'\0',sizeof(fstring));
2660 memset((char *)pass2,'\0',sizeof(fstring));
2662 return(True);
2665 /****************************************************************************
2666 Set the user password (SamOEM version - gets plaintext).
2667 ****************************************************************************/
2669 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2670 char *param, int tpscnt,
2671 char *data, int tdscnt,
2672 int mdrcnt,int mprcnt,
2673 char **rdata,char **rparam,
2674 int *rdata_len,int *rparam_len)
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(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 if (print_queue_pause(conn->server_info, snum, &werr)) {
2873 errcode = NERR_Success;
2875 break;
2876 case 75: /* Resume queue */
2877 if (print_queue_resume(conn->server_info, snum, &werr)) {
2878 errcode = NERR_Success;
2880 break;
2881 case 103: /* Purge */
2882 if (print_queue_purge(conn->server_info, snum, &werr)) {
2883 errcode = NERR_Success;
2885 break;
2888 if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr);
2890 out:
2891 SSVAL(*rparam,0,errcode);
2892 SSVAL(*rparam,2,0); /* converter word */
2894 return(True);
2897 /****************************************************************************
2898 set the property of a print job (undocumented?)
2899 ? function = 0xb -> set name of print job
2900 ? function = 0x6 -> move print job up/down
2901 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
2902 or <WWsTP> <WB21BB16B10zWWzDDz>
2903 ****************************************************************************/
2905 static int check_printjob_info(struct pack_desc* desc,
2906 int uLevel, char* id)
2908 desc->subformat = NULL;
2909 switch( uLevel ) {
2910 case 0: desc->format = "W"; break;
2911 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2912 case 2: desc->format = "WWzWWDDzz"; break;
2913 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2914 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2915 default:
2916 DEBUG(0,("check_printjob_info: invalid level %d\n",
2917 uLevel ));
2918 return False;
2920 if (id == NULL || strcmp(desc->format,id) != 0) {
2921 DEBUG(0,("check_printjob_info: invalid format %s\n",
2922 id ? id : "<NULL>" ));
2923 return False;
2925 return True;
2928 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
2929 char *param, int tpscnt,
2930 char *data, int tdscnt,
2931 int mdrcnt,int mprcnt,
2932 char **rdata,char **rparam,
2933 int *rdata_len,int *rparam_len)
2935 struct pack_desc desc;
2936 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2937 char *str2 = skip_string(param,tpscnt,str1);
2938 char *p = skip_string(param,tpscnt,str2);
2939 uint32 jobid;
2940 fstring sharename;
2941 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
2942 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
2943 int place, errcode;
2945 if (!str1 || !str2 || !p) {
2946 return False;
2949 * We use 1 here not 2 as we're checking
2950 * the last byte we want to access is safe.
2952 if (!is_offset_safe(param,tpscnt,p,1)) {
2953 return False;
2955 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2956 return False;
2957 *rparam_len = 4;
2958 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2959 if (!*rparam) {
2960 return False;
2963 if (!share_defined(sharename)) {
2964 DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
2965 sharename));
2966 return False;
2969 *rdata_len = 0;
2971 /* check it's a supported varient */
2972 if ((strcmp(str1,"WWsTP")) ||
2973 (!check_printjob_info(&desc,uLevel,str2)))
2974 return(False);
2976 if (!print_job_exists(sharename, jobid)) {
2977 errcode=NERR_JobNotFound;
2978 goto out;
2981 errcode = NERR_notsupported;
2983 switch (function) {
2984 case 0x6:
2985 /* change job place in the queue,
2986 data gives the new place */
2987 place = SVAL(data,0);
2988 if (print_job_set_place(sharename, jobid, place)) {
2989 errcode=NERR_Success;
2991 break;
2993 case 0xb:
2994 /* change print job name, data gives the name */
2995 if (print_job_set_name(sharename, jobid, data)) {
2996 errcode=NERR_Success;
2998 break;
3000 default:
3001 return False;
3004 out:
3005 SSVALS(*rparam,0,errcode);
3006 SSVAL(*rparam,2,0); /* converter word */
3008 return(True);
3012 /****************************************************************************
3013 Get info about the server.
3014 ****************************************************************************/
3016 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
3017 char *param, int tpscnt,
3018 char *data, int tdscnt,
3019 int mdrcnt,int mprcnt,
3020 char **rdata,char **rparam,
3021 int *rdata_len,int *rparam_len)
3023 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3024 char *str2 = skip_string(param,tpscnt,str1);
3025 char *p = skip_string(param,tpscnt,str2);
3026 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3027 char *p2;
3028 int struct_len;
3030 if (!str1 || !str2 || !p) {
3031 return False;
3034 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3036 /* check it's a supported varient */
3037 if (!prefix_ok(str1,"WrLh")) {
3038 return False;
3041 switch( uLevel ) {
3042 case 0:
3043 if (strcmp(str2,"B16") != 0) {
3044 return False;
3046 struct_len = 16;
3047 break;
3048 case 1:
3049 if (strcmp(str2,"B16BBDz") != 0) {
3050 return False;
3052 struct_len = 26;
3053 break;
3054 case 2:
3055 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3056 return False;
3058 struct_len = 134;
3059 break;
3060 case 3:
3061 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3062 return False;
3064 struct_len = 144;
3065 break;
3066 case 20:
3067 if (strcmp(str2,"DN") != 0) {
3068 return False;
3070 struct_len = 6;
3071 break;
3072 case 50:
3073 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3074 return False;
3076 struct_len = 42;
3077 break;
3078 default:
3079 return False;
3082 *rdata_len = mdrcnt;
3083 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3084 if (!*rdata) {
3085 return False;
3088 p = *rdata;
3089 p2 = p + struct_len;
3090 if (uLevel != 20) {
3091 srvstr_push(NULL, 0, p,global_myname(),16,
3092 STR_ASCII|STR_UPPER|STR_TERMINATE);
3094 p += 16;
3095 if (uLevel > 0) {
3096 struct srv_info_struct *servers=NULL;
3097 int i,count;
3098 char *comment = NULL;
3099 TALLOC_CTX *ctx = talloc_tos();
3100 uint32 servertype= lp_default_server_announce();
3102 comment = talloc_strdup(ctx,lp_serverstring());
3103 if (!comment) {
3104 return false;
3107 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
3108 for (i=0;i<count;i++) {
3109 if (strequal(servers[i].name,global_myname())) {
3110 servertype = servers[i].type;
3111 TALLOC_FREE(comment);
3112 comment = talloc_strdup(ctx,
3113 servers[i].comment);
3114 if (comment) {
3115 return false;
3121 SAFE_FREE(servers);
3123 SCVAL(p,0,lp_major_announce_version());
3124 SCVAL(p,1,lp_minor_announce_version());
3125 SIVAL(p,2,servertype);
3127 if (mdrcnt == struct_len) {
3128 SIVAL(p,6,0);
3129 } else {
3130 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3131 comment = talloc_sub_advanced(
3132 ctx,
3133 lp_servicename(SNUM(conn)),
3134 conn->server_info->unix_name,
3135 conn->connectpath,
3136 conn->server_info->utok.gid,
3137 conn->server_info->sanitized_username,
3138 pdb_get_domain(conn->server_info->sam_account),
3139 comment);
3140 if (comment) {
3141 return false;
3143 if (mdrcnt - struct_len <= 0) {
3144 return false;
3146 push_ascii(p2,
3147 comment,
3148 MIN(mdrcnt - struct_len,
3149 MAX_SERVER_STRING_LENGTH),
3150 STR_TERMINATE);
3151 p2 = skip_string(*rdata,*rdata_len,p2);
3152 if (!p2) {
3153 return False;
3158 if (uLevel > 1) {
3159 return False; /* not yet implemented */
3162 *rdata_len = PTR_DIFF(p2,*rdata);
3164 *rparam_len = 6;
3165 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3166 if (!*rparam) {
3167 return False;
3169 SSVAL(*rparam,0,NERR_Success);
3170 SSVAL(*rparam,2,0); /* converter word */
3171 SSVAL(*rparam,4,*rdata_len);
3173 return True;
3176 /****************************************************************************
3177 Get info about the server.
3178 ****************************************************************************/
3180 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3181 char *param, int tpscnt,
3182 char *data, int tdscnt,
3183 int mdrcnt,int mprcnt,
3184 char **rdata,char **rparam,
3185 int *rdata_len,int *rparam_len)
3187 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3188 char *str2 = skip_string(param,tpscnt,str1);
3189 char *p = skip_string(param,tpscnt,str2);
3190 char *p2;
3191 char *endp;
3192 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3194 if (!str1 || !str2 || !p) {
3195 return False;
3198 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3200 *rparam_len = 6;
3201 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3202 if (!*rparam) {
3203 return False;
3206 /* check it's a supported varient */
3207 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3208 return False;
3211 *rdata_len = mdrcnt + 1024;
3212 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3213 if (!*rdata) {
3214 return False;
3217 SSVAL(*rparam,0,NERR_Success);
3218 SSVAL(*rparam,2,0); /* converter word */
3220 p = *rdata;
3221 endp = *rdata + *rdata_len;
3223 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3224 if (!p2) {
3225 return False;
3228 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3229 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3230 strupper_m(p2);
3231 p2 = skip_string(*rdata,*rdata_len,p2);
3232 if (!p2) {
3233 return False;
3235 p += 4;
3237 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3238 strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3239 p2 = skip_string(*rdata,*rdata_len,p2);
3240 if (!p2) {
3241 return False;
3243 p += 4;
3245 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3246 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3247 strupper_m(p2);
3248 p2 = skip_string(*rdata,*rdata_len,p2);
3249 if (!p2) {
3250 return False;
3252 p += 4;
3254 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3255 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3256 p += 2;
3258 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3259 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3260 p2 = skip_string(*rdata,*rdata_len,p2);
3261 if (!p2) {
3262 return False;
3264 p += 4;
3266 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3267 strlcpy(p2,"",PTR_DIFF(endp,p2));
3268 p2 = skip_string(*rdata,*rdata_len,p2);
3269 if (!p2) {
3270 return False;
3272 p += 4;
3274 *rdata_len = PTR_DIFF(p2,*rdata);
3276 SSVAL(*rparam,4,*rdata_len);
3278 return True;
3281 /****************************************************************************
3282 get info about a user
3284 struct user_info_11 {
3285 char usri11_name[21]; 0-20
3286 char usri11_pad; 21
3287 char *usri11_comment; 22-25
3288 char *usri11_usr_comment; 26-29
3289 unsigned short usri11_priv; 30-31
3290 unsigned long usri11_auth_flags; 32-35
3291 long usri11_password_age; 36-39
3292 char *usri11_homedir; 40-43
3293 char *usri11_parms; 44-47
3294 long usri11_last_logon; 48-51
3295 long usri11_last_logoff; 52-55
3296 unsigned short usri11_bad_pw_count; 56-57
3297 unsigned short usri11_num_logons; 58-59
3298 char *usri11_logon_server; 60-63
3299 unsigned short usri11_country_code; 64-65
3300 char *usri11_workstations; 66-69
3301 unsigned long usri11_max_storage; 70-73
3302 unsigned short usri11_units_per_week; 74-75
3303 unsigned char *usri11_logon_hours; 76-79
3304 unsigned short usri11_code_page; 80-81
3307 where:
3309 usri11_name specifies the user name for which information is retrieved
3311 usri11_pad aligns the next data structure element to a word boundary
3313 usri11_comment is a null terminated ASCII comment
3315 usri11_user_comment is a null terminated ASCII comment about the user
3317 usri11_priv specifies the level of the privilege assigned to the user.
3318 The possible values are:
3320 Name Value Description
3321 USER_PRIV_GUEST 0 Guest privilege
3322 USER_PRIV_USER 1 User privilege
3323 USER_PRV_ADMIN 2 Administrator privilege
3325 usri11_auth_flags specifies the account operator privileges. The
3326 possible values are:
3328 Name Value Description
3329 AF_OP_PRINT 0 Print operator
3332 Leach, Naik [Page 28]
3336 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3339 AF_OP_COMM 1 Communications operator
3340 AF_OP_SERVER 2 Server operator
3341 AF_OP_ACCOUNTS 3 Accounts operator
3344 usri11_password_age specifies how many seconds have elapsed since the
3345 password was last changed.
3347 usri11_home_dir points to a null terminated ASCII string that contains
3348 the path name of the user's home directory.
3350 usri11_parms points to a null terminated ASCII string that is set
3351 aside for use by applications.
3353 usri11_last_logon specifies the time when the user last logged on.
3354 This value is stored as the number of seconds elapsed since
3355 00:00:00, January 1, 1970.
3357 usri11_last_logoff specifies the time when the user last logged off.
3358 This value is stored as the number of seconds elapsed since
3359 00:00:00, January 1, 1970. A value of 0 means the last logoff
3360 time is unknown.
3362 usri11_bad_pw_count specifies the number of incorrect passwords
3363 entered since the last successful logon.
3365 usri11_log1_num_logons specifies the number of times this user has
3366 logged on. A value of -1 means the number of logons is unknown.
3368 usri11_logon_server points to a null terminated ASCII string that
3369 contains the name of the server to which logon requests are sent.
3370 A null string indicates logon requests should be sent to the
3371 domain controller.
3373 usri11_country_code specifies the country code for the user's language
3374 of choice.
3376 usri11_workstations points to a null terminated ASCII string that
3377 contains the names of workstations the user may log on from.
3378 There may be up to 8 workstations, with the names separated by
3379 commas. A null strings indicates there are no restrictions.
3381 usri11_max_storage specifies the maximum amount of disk space the user
3382 can occupy. A value of 0xffffffff indicates there are no
3383 restrictions.
3385 usri11_units_per_week specifies the equal number of time units into
3386 which a week is divided. This value must be equal to 168.
3388 usri11_logon_hours points to a 21 byte (168 bits) string that
3389 specifies the time during which the user can log on. Each bit
3390 represents one unique hour in a week. The first bit (bit 0, word
3391 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3395 Leach, Naik [Page 29]
3399 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3402 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3403 are no restrictions.
3405 usri11_code_page specifies the code page for the user's language of
3406 choice
3408 All of the pointers in this data structure need to be treated
3409 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3410 to be ignored. The converter word returned in the parameters section
3411 needs to be subtracted from the lower 16 bits to calculate an offset
3412 into the return buffer where this ASCII string resides.
3414 There is no auxiliary data in the response.
3416 ****************************************************************************/
3418 #define usri11_name 0
3419 #define usri11_pad 21
3420 #define usri11_comment 22
3421 #define usri11_usr_comment 26
3422 #define usri11_full_name 30
3423 #define usri11_priv 34
3424 #define usri11_auth_flags 36
3425 #define usri11_password_age 40
3426 #define usri11_homedir 44
3427 #define usri11_parms 48
3428 #define usri11_last_logon 52
3429 #define usri11_last_logoff 56
3430 #define usri11_bad_pw_count 60
3431 #define usri11_num_logons 62
3432 #define usri11_logon_server 64
3433 #define usri11_country_code 68
3434 #define usri11_workstations 70
3435 #define usri11_max_storage 74
3436 #define usri11_units_per_week 78
3437 #define usri11_logon_hours 80
3438 #define usri11_code_page 84
3439 #define usri11_end 86
3441 #define USER_PRIV_GUEST 0
3442 #define USER_PRIV_USER 1
3443 #define USER_PRIV_ADMIN 2
3445 #define AF_OP_PRINT 0
3446 #define AF_OP_COMM 1
3447 #define AF_OP_SERVER 2
3448 #define AF_OP_ACCOUNTS 3
3451 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3452 char *param, int tpscnt,
3453 char *data, int tdscnt,
3454 int mdrcnt,int mprcnt,
3455 char **rdata,char **rparam,
3456 int *rdata_len,int *rparam_len)
3458 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3459 char *str2 = skip_string(param,tpscnt,str1);
3460 char *UserName = skip_string(param,tpscnt,str2);
3461 char *p = skip_string(param,tpscnt,UserName);
3462 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3463 char *p2;
3464 char *endp;
3465 const char *level_string;
3467 /* get NIS home of a previously validated user - simeon */
3468 /* With share level security vuid will always be zero.
3469 Don't depend on vuser being non-null !!. JRA */
3470 user_struct *vuser = get_valid_user_struct(vuid);
3471 if(vuser != NULL) {
3472 DEBUG(3,(" Username of UID %d is %s\n",
3473 (int)vuser->server_info->utok.uid,
3474 vuser->server_info->unix_name));
3477 if (!str1 || !str2 || !UserName || !p) {
3478 return False;
3481 *rparam_len = 6;
3482 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3483 if (!*rparam) {
3484 return False;
3487 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3489 /* check it's a supported variant */
3490 if (strcmp(str1,"zWrLh") != 0) {
3491 return False;
3493 switch( uLevel ) {
3494 case 0: level_string = "B21"; break;
3495 case 1: level_string = "B21BB16DWzzWz"; break;
3496 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3497 case 10: level_string = "B21Bzzz"; break;
3498 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3499 default: return False;
3502 if (strcmp(level_string,str2) != 0) {
3503 return False;
3506 *rdata_len = mdrcnt + 1024;
3507 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3508 if (!*rdata) {
3509 return False;
3512 SSVAL(*rparam,0,NERR_Success);
3513 SSVAL(*rparam,2,0); /* converter word */
3515 p = *rdata;
3516 endp = *rdata + *rdata_len;
3517 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3518 if (!p2) {
3519 return False;
3522 memset(p,0,21);
3523 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3525 if (uLevel > 0) {
3526 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3527 *p2 = 0;
3530 if (uLevel >= 10) {
3531 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3532 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
3533 p2 = skip_string(*rdata,*rdata_len,p2);
3534 if (!p2) {
3535 return False;
3538 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3539 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
3540 p2 = skip_string(*rdata,*rdata_len,p2);
3541 if (!p2) {
3542 return False;
3545 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3546 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3547 strlcpy(p2,((vuser != NULL)
3548 ? pdb_get_fullname(vuser->server_info->sam_account)
3549 : UserName),PTR_DIFF(endp,p2));
3550 p2 = skip_string(*rdata,*rdata_len,p2);
3551 if (!p2) {
3552 return False;
3556 if (uLevel == 11) {
3557 const char *homedir = "";
3558 if (vuser != NULL) {
3559 homedir = pdb_get_homedir(
3560 vuser->server_info->sam_account);
3562 /* modelled after NTAS 3.51 reply */
3563 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3564 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
3565 SIVALS(p,usri11_password_age,-1); /* password age */
3566 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3567 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
3568 p2 = skip_string(*rdata,*rdata_len,p2);
3569 if (!p2) {
3570 return False;
3572 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3573 strlcpy(p2,"",PTR_DIFF(endp,p2));
3574 p2 = skip_string(*rdata,*rdata_len,p2);
3575 if (!p2) {
3576 return False;
3578 SIVAL(p,usri11_last_logon,0); /* last logon */
3579 SIVAL(p,usri11_last_logoff,0); /* last logoff */
3580 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
3581 SSVALS(p,usri11_num_logons,-1); /* num logons */
3582 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3583 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
3584 p2 = skip_string(*rdata,*rdata_len,p2);
3585 if (!p2) {
3586 return False;
3588 SSVAL(p,usri11_country_code,0); /* country code */
3590 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3591 strlcpy(p2,"",PTR_DIFF(endp,p2));
3592 p2 = skip_string(*rdata,*rdata_len,p2);
3593 if (!p2) {
3594 return False;
3597 SIVALS(p,usri11_max_storage,-1); /* max storage */
3598 SSVAL(p,usri11_units_per_week,168); /* units per week */
3599 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
3601 /* a simple way to get logon hours at all times. */
3602 memset(p2,0xff,21);
3603 SCVAL(p2,21,0); /* fix zero termination */
3604 p2 = skip_string(*rdata,*rdata_len,p2);
3605 if (!p2) {
3606 return False;
3609 SSVAL(p,usri11_code_page,0); /* code page */
3612 if (uLevel == 1 || uLevel == 2) {
3613 memset(p+22,' ',16); /* password */
3614 SIVALS(p,38,-1); /* password age */
3615 SSVAL(p,42,
3616 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3617 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
3618 strlcpy(p2, vuser ? pdb_get_homedir(
3619 vuser->server_info->sam_account) : "",
3620 PTR_DIFF(endp,p2));
3621 p2 = skip_string(*rdata,*rdata_len,p2);
3622 if (!p2) {
3623 return False;
3625 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
3626 *p2++ = 0;
3627 SSVAL(p,52,0); /* flags */
3628 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
3629 strlcpy(p2, vuser ? pdb_get_logon_script(
3630 vuser->server_info->sam_account) : "",
3631 PTR_DIFF(endp,p2));
3632 p2 = skip_string(*rdata,*rdata_len,p2);
3633 if (!p2) {
3634 return False;
3636 if (uLevel == 2) {
3637 SIVAL(p,60,0); /* auth_flags */
3638 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
3639 strlcpy(p2,((vuser != NULL)
3640 ? pdb_get_fullname(vuser->server_info->sam_account)
3641 : UserName),PTR_DIFF(endp,p2));
3642 p2 = skip_string(*rdata,*rdata_len,p2);
3643 if (!p2) {
3644 return False;
3646 SIVAL(p,68,0); /* urs_comment */
3647 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
3648 strlcpy(p2,"",PTR_DIFF(endp,p2));
3649 p2 = skip_string(*rdata,*rdata_len,p2);
3650 if (!p2) {
3651 return False;
3653 SIVAL(p,76,0); /* workstations */
3654 SIVAL(p,80,0); /* last_logon */
3655 SIVAL(p,84,0); /* last_logoff */
3656 SIVALS(p,88,-1); /* acct_expires */
3657 SIVALS(p,92,-1); /* max_storage */
3658 SSVAL(p,96,168); /* units_per_week */
3659 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
3660 memset(p2,-1,21);
3661 p2 += 21;
3662 SSVALS(p,102,-1); /* bad_pw_count */
3663 SSVALS(p,104,-1); /* num_logons */
3664 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
3666 TALLOC_CTX *ctx = talloc_tos();
3667 int space_rem = *rdata_len - (p2 - *rdata);
3668 char *tmp;
3670 if (space_rem <= 0) {
3671 return false;
3673 tmp = talloc_strdup(ctx, "\\\\%L");
3674 if (!tmp) {
3675 return false;
3677 tmp = talloc_sub_basic(ctx,
3680 tmp);
3681 if (!tmp) {
3682 return false;
3685 push_ascii(p2,
3686 tmp,
3687 space_rem,
3688 STR_TERMINATE);
3690 p2 = skip_string(*rdata,*rdata_len,p2);
3691 if (!p2) {
3692 return False;
3694 SSVAL(p,110,49); /* country_code */
3695 SSVAL(p,112,860); /* code page */
3699 *rdata_len = PTR_DIFF(p2,*rdata);
3701 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
3703 return(True);
3706 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
3707 char *param, int tpscnt,
3708 char *data, int tdscnt,
3709 int mdrcnt,int mprcnt,
3710 char **rdata,char **rparam,
3711 int *rdata_len,int *rparam_len)
3713 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3714 char *str2 = skip_string(param,tpscnt,str1);
3715 char *p = skip_string(param,tpscnt,str2);
3716 int uLevel;
3717 struct pack_desc desc;
3718 char* name;
3719 /* With share level security vuid will always be zero.
3720 Don't depend on vuser being non-null !!. JRA */
3721 user_struct *vuser = get_valid_user_struct(vuid);
3723 if (!str1 || !str2 || !p) {
3724 return False;
3727 if(vuser != NULL) {
3728 DEBUG(3,(" Username of UID %d is %s\n",
3729 (int)vuser->server_info->utok.uid,
3730 vuser->server_info->unix_name));
3733 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3734 name = get_safe_str_ptr(param,tpscnt,p,2);
3735 if (!name) {
3736 return False;
3739 memset((char *)&desc,'\0',sizeof(desc));
3741 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
3743 /* check it's a supported varient */
3744 if (strcmp(str1,"OOWb54WrLh") != 0) {
3745 return False;
3747 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
3748 return False;
3750 if (mdrcnt > 0) {
3751 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3752 if (!*rdata) {
3753 return False;
3757 desc.base = *rdata;
3758 desc.buflen = mdrcnt;
3759 desc.subformat = NULL;
3760 desc.format = str2;
3762 if (init_package(&desc,1,0)) {
3763 PACKI(&desc,"W",0); /* code */
3764 PACKS(&desc,"B21",name); /* eff. name */
3765 PACKS(&desc,"B",""); /* pad */
3766 PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3767 PACKI(&desc,"D",0); /* auth flags XXX */
3768 PACKI(&desc,"W",0); /* num logons */
3769 PACKI(&desc,"W",0); /* bad pw count */
3770 PACKI(&desc,"D",0); /* last logon */
3771 PACKI(&desc,"D",-1); /* last logoff */
3772 PACKI(&desc,"D",-1); /* logoff time */
3773 PACKI(&desc,"D",-1); /* kickoff time */
3774 PACKI(&desc,"D",0); /* password age */
3775 PACKI(&desc,"D",0); /* password can change */
3776 PACKI(&desc,"D",-1); /* password must change */
3779 fstring mypath;
3780 fstrcpy(mypath,"\\\\");
3781 fstrcat(mypath,get_local_machine_name());
3782 strupper_m(mypath);
3783 PACKS(&desc,"z",mypath); /* computer */
3786 PACKS(&desc,"z",lp_workgroup());/* domain */
3787 PACKS(&desc,"z", vuser ? pdb_get_logon_script(
3788 vuser->server_info->sam_account) : ""); /* script path */
3789 PACKI(&desc,"D",0x00000000); /* reserved */
3792 *rdata_len = desc.usedlen;
3793 *rparam_len = 6;
3794 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3795 if (!*rparam) {
3796 return False;
3798 SSVALS(*rparam,0,desc.errcode);
3799 SSVAL(*rparam,2,0);
3800 SSVAL(*rparam,4,desc.neededlen);
3802 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
3804 return True;
3807 /****************************************************************************
3808 api_WAccessGetUserPerms
3809 ****************************************************************************/
3811 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
3812 char *param, int tpscnt,
3813 char *data, int tdscnt,
3814 int mdrcnt,int mprcnt,
3815 char **rdata,char **rparam,
3816 int *rdata_len,int *rparam_len)
3818 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3819 char *str2 = skip_string(param,tpscnt,str1);
3820 char *user = skip_string(param,tpscnt,str2);
3821 char *resource = skip_string(param,tpscnt,user);
3823 if (!str1 || !str2 || !user || !resource) {
3824 return False;
3827 if (skip_string(param,tpscnt,resource) == NULL) {
3828 return False;
3830 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
3832 /* check it's a supported varient */
3833 if (strcmp(str1,"zzh") != 0) {
3834 return False;
3836 if (strcmp(str2,"") != 0) {
3837 return False;
3840 *rparam_len = 6;
3841 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3842 if (!*rparam) {
3843 return False;
3845 SSVALS(*rparam,0,0); /* errorcode */
3846 SSVAL(*rparam,2,0); /* converter word */
3847 SSVAL(*rparam,4,0x7f); /* permission flags */
3849 return True;
3852 /****************************************************************************
3853 api_WPrintJobEnumerate
3854 ****************************************************************************/
3856 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
3857 char *param, int tpscnt,
3858 char *data, int tdscnt,
3859 int mdrcnt,int mprcnt,
3860 char **rdata,char **rparam,
3861 int *rdata_len,int *rparam_len)
3863 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3864 char *str2 = skip_string(param,tpscnt,str1);
3865 char *p = skip_string(param,tpscnt,str2);
3866 int uLevel;
3867 int count;
3868 int i;
3869 int snum;
3870 fstring sharename;
3871 uint32 jobid;
3872 struct pack_desc desc;
3873 print_queue_struct *queue=NULL;
3874 print_status_struct status;
3875 char *tmpdata=NULL;
3877 if (!str1 || !str2 || !p) {
3878 return False;
3881 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3883 memset((char *)&desc,'\0',sizeof(desc));
3884 memset((char *)&status,'\0',sizeof(status));
3886 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
3888 /* check it's a supported varient */
3889 if (strcmp(str1,"WWrLh") != 0) {
3890 return False;
3892 if (!check_printjob_info(&desc,uLevel,str2)) {
3893 return False;
3896 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
3897 return False;
3900 snum = lp_servicenumber( sharename);
3901 if (snum < 0 || !VALID_SNUM(snum)) {
3902 return(False);
3905 count = print_queue_status(snum,&queue,&status);
3906 for (i = 0; i < count; i++) {
3907 if (queue[i].job == jobid) {
3908 break;
3912 if (mdrcnt > 0) {
3913 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3914 if (!*rdata) {
3915 return False;
3917 desc.base = *rdata;
3918 desc.buflen = mdrcnt;
3919 } else {
3921 * Don't return data but need to get correct length
3922 * init_package will return wrong size if buflen=0
3924 desc.buflen = getlen(desc.format);
3925 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3928 if (init_package(&desc,1,0)) {
3929 if (i < count) {
3930 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3931 *rdata_len = desc.usedlen;
3932 } else {
3933 desc.errcode = NERR_JobNotFound;
3934 *rdata_len = 0;
3938 *rparam_len = 6;
3939 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3940 if (!*rparam) {
3941 return False;
3943 SSVALS(*rparam,0,desc.errcode);
3944 SSVAL(*rparam,2,0);
3945 SSVAL(*rparam,4,desc.neededlen);
3947 SAFE_FREE(queue);
3948 SAFE_FREE(tmpdata);
3950 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
3952 return True;
3955 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
3956 char *param, int tpscnt,
3957 char *data, int tdscnt,
3958 int mdrcnt,int mprcnt,
3959 char **rdata,char **rparam,
3960 int *rdata_len,int *rparam_len)
3962 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3963 char *str2 = skip_string(param,tpscnt,str1);
3964 char *p = skip_string(param,tpscnt,str2);
3965 char *name = p;
3966 int uLevel;
3967 int count;
3968 int i, succnt=0;
3969 int snum;
3970 struct pack_desc desc;
3971 print_queue_struct *queue=NULL;
3972 print_status_struct status;
3974 if (!str1 || !str2 || !p) {
3975 return False;
3978 memset((char *)&desc,'\0',sizeof(desc));
3979 memset((char *)&status,'\0',sizeof(status));
3981 p = skip_string(param,tpscnt,p);
3982 if (!p) {
3983 return False;
3985 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3987 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
3989 /* check it's a supported variant */
3990 if (strcmp(str1,"zWrLeh") != 0) {
3991 return False;
3994 if (uLevel > 2) {
3995 return False; /* defined only for uLevel 0,1,2 */
3998 if (!check_printjob_info(&desc,uLevel,str2)) {
3999 return False;
4002 snum = find_service(name);
4003 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
4004 return False;
4007 count = print_queue_status(snum,&queue,&status);
4008 if (mdrcnt > 0) {
4009 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4010 if (!*rdata) {
4011 return False;
4014 desc.base = *rdata;
4015 desc.buflen = mdrcnt;
4017 if (init_package(&desc,count,0)) {
4018 succnt = 0;
4019 for (i = 0; i < count; i++) {
4020 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
4021 if (desc.errcode == NERR_Success) {
4022 succnt = i+1;
4027 *rdata_len = desc.usedlen;
4029 *rparam_len = 8;
4030 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4031 if (!*rparam) {
4032 return False;
4034 SSVALS(*rparam,0,desc.errcode);
4035 SSVAL(*rparam,2,0);
4036 SSVAL(*rparam,4,succnt);
4037 SSVAL(*rparam,6,count);
4039 SAFE_FREE(queue);
4041 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4043 return True;
4046 static int check_printdest_info(struct pack_desc* desc,
4047 int uLevel, char* id)
4049 desc->subformat = NULL;
4050 switch( uLevel ) {
4051 case 0:
4052 desc->format = "B9";
4053 break;
4054 case 1:
4055 desc->format = "B9B21WWzW";
4056 break;
4057 case 2:
4058 desc->format = "z";
4059 break;
4060 case 3:
4061 desc->format = "zzzWWzzzWW";
4062 break;
4063 default:
4064 DEBUG(0,("check_printdest_info: invalid level %d\n",
4065 uLevel));
4066 return False;
4068 if (id == NULL || strcmp(desc->format,id) != 0) {
4069 DEBUG(0,("check_printdest_info: invalid string %s\n",
4070 id ? id : "<NULL>" ));
4071 return False;
4073 return True;
4076 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
4077 struct pack_desc* desc)
4079 char buf[100];
4081 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
4082 buf[sizeof(buf)-1] = 0;
4083 strupper_m(buf);
4085 if (uLevel <= 1) {
4086 PACKS(desc,"B9",buf); /* szName */
4087 if (uLevel == 1) {
4088 PACKS(desc,"B21",""); /* szUserName */
4089 PACKI(desc,"W",0); /* uJobId */
4090 PACKI(desc,"W",0); /* fsStatus */
4091 PACKS(desc,"z",""); /* pszStatus */
4092 PACKI(desc,"W",0); /* time */
4096 if (uLevel == 2 || uLevel == 3) {
4097 PACKS(desc,"z",buf); /* pszPrinterName */
4098 if (uLevel == 3) {
4099 PACKS(desc,"z",""); /* pszUserName */
4100 PACKS(desc,"z",""); /* pszLogAddr */
4101 PACKI(desc,"W",0); /* uJobId */
4102 PACKI(desc,"W",0); /* fsStatus */
4103 PACKS(desc,"z",""); /* pszStatus */
4104 PACKS(desc,"z",""); /* pszComment */
4105 PACKS(desc,"z","NULL"); /* pszDrivers */
4106 PACKI(desc,"W",0); /* time */
4107 PACKI(desc,"W",0); /* pad1 */
4112 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
4113 char *param, int tpscnt,
4114 char *data, int tdscnt,
4115 int mdrcnt,int mprcnt,
4116 char **rdata,char **rparam,
4117 int *rdata_len,int *rparam_len)
4119 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4120 char *str2 = skip_string(param,tpscnt,str1);
4121 char *p = skip_string(param,tpscnt,str2);
4122 char* PrinterName = p;
4123 int uLevel;
4124 struct pack_desc desc;
4125 int snum;
4126 char *tmpdata=NULL;
4128 if (!str1 || !str2 || !p) {
4129 return False;
4132 memset((char *)&desc,'\0',sizeof(desc));
4134 p = skip_string(param,tpscnt,p);
4135 if (!p) {
4136 return False;
4138 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4140 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4142 /* check it's a supported varient */
4143 if (strcmp(str1,"zWrLh") != 0) {
4144 return False;
4146 if (!check_printdest_info(&desc,uLevel,str2)) {
4147 return False;
4150 snum = find_service(PrinterName);
4151 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
4152 *rdata_len = 0;
4153 desc.errcode = NERR_DestNotFound;
4154 desc.neededlen = 0;
4155 } else {
4156 if (mdrcnt > 0) {
4157 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4158 if (!*rdata) {
4159 return False;
4161 desc.base = *rdata;
4162 desc.buflen = mdrcnt;
4163 } else {
4165 * Don't return data but need to get correct length
4166 * init_package will return wrong size if buflen=0
4168 desc.buflen = getlen(desc.format);
4169 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4171 if (init_package(&desc,1,0)) {
4172 fill_printdest_info(conn,snum,uLevel,&desc);
4174 *rdata_len = desc.usedlen;
4177 *rparam_len = 6;
4178 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4179 if (!*rparam) {
4180 return False;
4182 SSVALS(*rparam,0,desc.errcode);
4183 SSVAL(*rparam,2,0);
4184 SSVAL(*rparam,4,desc.neededlen);
4186 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4187 SAFE_FREE(tmpdata);
4189 return True;
4192 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4193 char *param, int tpscnt,
4194 char *data, int tdscnt,
4195 int mdrcnt,int mprcnt,
4196 char **rdata,char **rparam,
4197 int *rdata_len,int *rparam_len)
4199 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4200 char *str2 = skip_string(param,tpscnt,str1);
4201 char *p = skip_string(param,tpscnt,str2);
4202 int uLevel;
4203 int queuecnt;
4204 int i, n, succnt=0;
4205 struct pack_desc desc;
4206 int services = lp_numservices();
4208 if (!str1 || !str2 || !p) {
4209 return False;
4212 memset((char *)&desc,'\0',sizeof(desc));
4214 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4216 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4218 /* check it's a supported varient */
4219 if (strcmp(str1,"WrLeh") != 0) {
4220 return False;
4222 if (!check_printdest_info(&desc,uLevel,str2)) {
4223 return False;
4226 queuecnt = 0;
4227 for (i = 0; i < services; i++) {
4228 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4229 queuecnt++;
4233 if (mdrcnt > 0) {
4234 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4235 if (!*rdata) {
4236 return False;
4240 desc.base = *rdata;
4241 desc.buflen = mdrcnt;
4242 if (init_package(&desc,queuecnt,0)) {
4243 succnt = 0;
4244 n = 0;
4245 for (i = 0; i < services; i++) {
4246 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4247 fill_printdest_info(conn,i,uLevel,&desc);
4248 n++;
4249 if (desc.errcode == NERR_Success) {
4250 succnt = n;
4256 *rdata_len = desc.usedlen;
4258 *rparam_len = 8;
4259 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4260 if (!*rparam) {
4261 return False;
4263 SSVALS(*rparam,0,desc.errcode);
4264 SSVAL(*rparam,2,0);
4265 SSVAL(*rparam,4,succnt);
4266 SSVAL(*rparam,6,queuecnt);
4268 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4270 return True;
4273 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4274 char *param, int tpscnt,
4275 char *data, int tdscnt,
4276 int mdrcnt,int mprcnt,
4277 char **rdata,char **rparam,
4278 int *rdata_len,int *rparam_len)
4280 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4281 char *str2 = skip_string(param,tpscnt,str1);
4282 char *p = skip_string(param,tpscnt,str2);
4283 int uLevel;
4284 int succnt;
4285 struct pack_desc desc;
4287 if (!str1 || !str2 || !p) {
4288 return False;
4291 memset((char *)&desc,'\0',sizeof(desc));
4293 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4295 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4297 /* check it's a supported varient */
4298 if (strcmp(str1,"WrLeh") != 0) {
4299 return False;
4301 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4302 return False;
4305 if (mdrcnt > 0) {
4306 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4307 if (!*rdata) {
4308 return False;
4311 desc.base = *rdata;
4312 desc.buflen = mdrcnt;
4313 if (init_package(&desc,1,0)) {
4314 PACKS(&desc,"B41","NULL");
4317 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4319 *rdata_len = desc.usedlen;
4321 *rparam_len = 8;
4322 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4323 if (!*rparam) {
4324 return False;
4326 SSVALS(*rparam,0,desc.errcode);
4327 SSVAL(*rparam,2,0);
4328 SSVAL(*rparam,4,succnt);
4329 SSVAL(*rparam,6,1);
4331 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4333 return True;
4336 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4337 char *param, int tpscnt,
4338 char *data, int tdscnt,
4339 int mdrcnt,int mprcnt,
4340 char **rdata,char **rparam,
4341 int *rdata_len,int *rparam_len)
4343 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4344 char *str2 = skip_string(param,tpscnt,str1);
4345 char *p = skip_string(param,tpscnt,str2);
4346 int uLevel;
4347 int succnt;
4348 struct pack_desc desc;
4350 if (!str1 || !str2 || !p) {
4351 return False;
4353 memset((char *)&desc,'\0',sizeof(desc));
4355 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4357 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4359 /* check it's a supported varient */
4360 if (strcmp(str1,"WrLeh") != 0) {
4361 return False;
4363 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4364 return False;
4367 if (mdrcnt > 0) {
4368 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4369 if (!*rdata) {
4370 return False;
4373 desc.base = *rdata;
4374 desc.buflen = mdrcnt;
4375 desc.format = str2;
4376 if (init_package(&desc,1,0)) {
4377 PACKS(&desc,"B13","lpd");
4380 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4382 *rdata_len = desc.usedlen;
4384 *rparam_len = 8;
4385 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4386 if (!*rparam) {
4387 return False;
4389 SSVALS(*rparam,0,desc.errcode);
4390 SSVAL(*rparam,2,0);
4391 SSVAL(*rparam,4,succnt);
4392 SSVAL(*rparam,6,1);
4394 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4396 return True;
4399 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4400 char *param, int tpscnt,
4401 char *data, int tdscnt,
4402 int mdrcnt,int mprcnt,
4403 char **rdata,char **rparam,
4404 int *rdata_len,int *rparam_len)
4406 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4407 char *str2 = skip_string(param,tpscnt,str1);
4408 char *p = skip_string(param,tpscnt,str2);
4409 int uLevel;
4410 int succnt;
4411 struct pack_desc desc;
4413 if (!str1 || !str2 || !p) {
4414 return False;
4417 memset((char *)&desc,'\0',sizeof(desc));
4419 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4421 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4423 /* check it's a supported varient */
4424 if (strcmp(str1,"WrLeh") != 0) {
4425 return False;
4427 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
4428 return False;
4431 if (mdrcnt > 0) {
4432 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4433 if (!*rdata) {
4434 return False;
4437 memset((char *)&desc,'\0',sizeof(desc));
4438 desc.base = *rdata;
4439 desc.buflen = mdrcnt;
4440 desc.format = str2;
4441 if (init_package(&desc,1,0)) {
4442 PACKS(&desc,"B13","lp0");
4445 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4447 *rdata_len = desc.usedlen;
4449 *rparam_len = 8;
4450 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4451 if (!*rparam) {
4452 return False;
4454 SSVALS(*rparam,0,desc.errcode);
4455 SSVAL(*rparam,2,0);
4456 SSVAL(*rparam,4,succnt);
4457 SSVAL(*rparam,6,1);
4459 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
4461 return True;
4464 /****************************************************************************
4465 List open sessions
4466 ****************************************************************************/
4468 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
4469 char *param, int tpscnt,
4470 char *data, int tdscnt,
4471 int mdrcnt,int mprcnt,
4472 char **rdata,char **rparam,
4473 int *rdata_len,int *rparam_len)
4476 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4477 char *str2 = skip_string(param,tpscnt,str1);
4478 char *p = skip_string(param,tpscnt,str2);
4479 int uLevel;
4480 struct pack_desc desc;
4481 struct sessionid *session_list;
4482 int i, num_sessions;
4484 if (!str1 || !str2 || !p) {
4485 return False;
4488 memset((char *)&desc,'\0',sizeof(desc));
4490 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4492 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
4493 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
4494 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
4496 /* check it's a supported varient */
4497 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
4498 return False;
4500 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
4501 return False;
4504 num_sessions = list_sessions(talloc_tos(), &session_list);
4506 if (mdrcnt > 0) {
4507 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4508 if (!*rdata) {
4509 return False;
4512 memset((char *)&desc,'\0',sizeof(desc));
4513 desc.base = *rdata;
4514 desc.buflen = mdrcnt;
4515 desc.format = str2;
4516 if (!init_package(&desc,num_sessions,0)) {
4517 return False;
4520 for(i=0; i<num_sessions; i++) {
4521 PACKS(&desc, "z", session_list[i].remote_machine);
4522 PACKS(&desc, "z", session_list[i].username);
4523 PACKI(&desc, "W", 1); /* num conns */
4524 PACKI(&desc, "W", 0); /* num opens */
4525 PACKI(&desc, "W", 1); /* num users */
4526 PACKI(&desc, "D", 0); /* session time */
4527 PACKI(&desc, "D", 0); /* idle time */
4528 PACKI(&desc, "D", 0); /* flags */
4529 PACKS(&desc, "z", "Unknown Client"); /* client type string */
4532 *rdata_len = desc.usedlen;
4534 *rparam_len = 8;
4535 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4536 if (!*rparam) {
4537 return False;
4539 SSVALS(*rparam,0,desc.errcode);
4540 SSVAL(*rparam,2,0); /* converter */
4541 SSVAL(*rparam,4,num_sessions); /* count */
4543 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
4545 return True;
4549 /****************************************************************************
4550 The buffer was too small.
4551 ****************************************************************************/
4553 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
4554 int mdrcnt, int mprcnt,
4555 char **rdata, char **rparam,
4556 int *rdata_len, int *rparam_len)
4558 *rparam_len = MIN(*rparam_len,mprcnt);
4559 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4560 if (!*rparam) {
4561 return False;
4564 *rdata_len = 0;
4566 SSVAL(*rparam,0,NERR_BufTooSmall);
4568 DEBUG(3,("Supplied buffer too small in API command\n"));
4570 return True;
4573 /****************************************************************************
4574 The request is not supported.
4575 ****************************************************************************/
4577 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
4578 char *param, int tpscnt,
4579 char *data, int tdscnt,
4580 int mdrcnt, int mprcnt,
4581 char **rdata, char **rparam,
4582 int *rdata_len, int *rparam_len)
4584 *rparam_len = 4;
4585 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4586 if (!*rparam) {
4587 return False;
4590 *rdata_len = 0;
4592 SSVAL(*rparam,0,NERR_notsupported);
4593 SSVAL(*rparam,2,0); /* converter word */
4595 DEBUG(3,("Unsupported API command\n"));
4597 return True;
4600 static const struct {
4601 const char *name;
4602 int id;
4603 bool (*fn)(connection_struct *, uint16,
4604 char *, int,
4605 char *, int,
4606 int,int,char **,char **,int *,int *);
4607 bool auth_user; /* Deny anonymous access? */
4608 } api_commands[] = {
4609 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
4610 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
4611 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
4612 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
4613 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
4614 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
4615 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
4616 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
4617 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
4618 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
4619 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
4620 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
4621 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
4622 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
4623 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
4624 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
4625 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
4626 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
4627 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
4628 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
4629 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
4630 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
4631 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
4632 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
4633 {"NetServerEnum", RAP_NetServerEnum2, api_RNetServerEnum}, /* anon OK */
4634 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
4635 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
4636 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
4637 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
4638 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
4639 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
4640 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
4641 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
4642 {NULL, -1, api_Unsupported}
4643 /* The following RAP calls are not implemented by Samba:
4645 RAP_WFileEnum2 - anon not OK
4650 /****************************************************************************
4651 Handle remote api calls.
4652 ****************************************************************************/
4654 void api_reply(connection_struct *conn, uint16 vuid,
4655 struct smb_request *req,
4656 char *data, char *params,
4657 int tdscnt, int tpscnt,
4658 int mdrcnt, int mprcnt)
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(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;