Group the access checks together in check_user_ok()
[Samba/gbeck.git] / source / smbd / lanman.c
blob31d4a398421b0e3221aa909b2a83bc9534fdd6a2
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 extern struct current_user current_user;
32 #ifdef CHECK_TYPES
33 #undef CHECK_TYPES
34 #endif
35 #define CHECK_TYPES 0
37 #define NERR_Success 0
38 #define NERR_badpass 86
39 #define NERR_notsupported 50
41 #define NERR_BASE (2100)
42 #define NERR_BufTooSmall (NERR_BASE+23)
43 #define NERR_JobNotFound (NERR_BASE+51)
44 #define NERR_DestNotFound (NERR_BASE+52)
46 #define ACCESS_READ 0x01
47 #define ACCESS_WRITE 0x02
48 #define ACCESS_CREATE 0x04
50 #define SHPWLEN 8 /* share password length */
52 /* Limit size of ipc replies */
54 static char *smb_realloc_limit(void *ptr, size_t size)
56 char *val;
58 size = MAX((size),4*1024);
59 val = (char *)SMB_REALLOC(ptr,size);
60 if (val) {
61 memset(val,'\0',size);
63 return val;
66 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
67 char *param, int tpscnt,
68 char *data, int tdscnt,
69 int mdrcnt, int mprcnt,
70 char **rdata, char **rparam,
71 int *rdata_len, int *rparam_len);
73 static bool api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
74 int mdrcnt, int mprcnt,
75 char **rdata, char **rparam,
76 int *rdata_len, int *rparam_len);
79 static int CopyExpanded(connection_struct *conn,
80 int snum, char **dst, char *src, int *p_space_remaining)
82 TALLOC_CTX *ctx = talloc_tos();
83 char *buf = NULL;
84 int l;
86 if (!src || !dst || !p_space_remaining || !(*dst) ||
87 *p_space_remaining <= 0) {
88 return 0;
91 buf = talloc_strdup(ctx, src);
92 if (!buf) {
93 *p_space_remaining = 0;
94 return 0;
96 buf = talloc_string_sub(ctx, buf,"%S",lp_servicename(snum));
97 if (!buf) {
98 *p_space_remaining = 0;
99 return 0;
101 buf = talloc_sub_advanced(ctx,
102 lp_servicename(SNUM(conn)),
103 conn->server_info->unix_name,
104 conn->connectpath,
105 conn->server_info->gid,
106 conn->server_info->sanitized_username,
107 pdb_get_domain(conn->server_info->sam_account),
108 buf);
109 if (!buf) {
110 *p_space_remaining = 0;
111 return 0;
113 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
114 if (l == -1) {
115 return 0;
117 (*dst) += l;
118 (*p_space_remaining) -= l;
119 return l;
122 static int CopyAndAdvance(char **dst, char *src, int *n)
124 int l;
125 if (!src || !dst || !n || !(*dst)) {
126 return 0;
128 l = push_ascii(*dst,src,*n, STR_TERMINATE);
129 if (l == -1) {
130 return 0;
132 (*dst) += l;
133 (*n) -= l;
134 return l;
137 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
139 TALLOC_CTX *ctx = talloc_tos();
140 char *buf = NULL;
141 if (!s) {
142 return 0;
144 buf = talloc_strdup(ctx,s);
145 if (!buf) {
146 return 0;
148 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
149 if (!buf) {
150 return 0;
152 buf = talloc_sub_advanced(ctx,
153 lp_servicename(SNUM(conn)),
154 conn->server_info->unix_name,
155 conn->connectpath,
156 conn->server_info->gid,
157 conn->server_info->sanitized_username,
158 pdb_get_domain(conn->server_info->sam_account),
159 buf);
160 if (!buf) {
161 return 0;
163 return strlen(buf) + 1;
166 static char *Expand(connection_struct *conn, int snum, char *s)
168 TALLOC_CTX *ctx = talloc_tos();
169 char *buf = NULL;
171 if (!s) {
172 return NULL;
174 buf = talloc_strdup(ctx,s);
175 if (!buf) {
176 return 0;
178 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
179 if (!buf) {
180 return 0;
182 return talloc_sub_advanced(ctx,
183 lp_servicename(SNUM(conn)),
184 conn->server_info->unix_name,
185 conn->connectpath,
186 conn->server_info->gid,
187 conn->server_info->sanitized_username,
188 pdb_get_domain(conn->server_info->sam_account),
189 buf);
192 /*******************************************************************
193 Check a API string for validity when we only need to check the prefix.
194 ******************************************************************/
196 static bool prefix_ok(const char *str, const char *prefix)
198 return(strncmp(str,prefix,strlen(prefix)) == 0);
201 struct pack_desc {
202 const char *format; /* formatstring for structure */
203 const char *subformat; /* subformat for structure */
204 char *base; /* baseaddress of buffer */
205 int buflen; /* remaining size for fixed part; on init: length of base */
206 int subcount; /* count of substructures */
207 char *structbuf; /* pointer into buffer for remaining fixed part */
208 int stringlen; /* remaining size for variable part */
209 char *stringbuf; /* pointer into buffer for remaining variable part */
210 int neededlen; /* total needed size */
211 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
212 const char *curpos; /* current position; pointer into format or subformat */
213 int errcode;
216 static int get_counter(const char **p)
218 int i, n;
219 if (!p || !(*p)) {
220 return 1;
222 if (!isdigit((int)**p)) {
223 return 1;
225 for (n = 0;;) {
226 i = **p;
227 if (isdigit(i)) {
228 n = 10 * n + (i - '0');
229 } else {
230 return n;
232 (*p)++;
236 static int getlen(const char *p)
238 int n = 0;
239 if (!p) {
240 return 0;
243 while (*p) {
244 switch( *p++ ) {
245 case 'W': /* word (2 byte) */
246 n += 2;
247 break;
248 case 'K': /* status word? (2 byte) */
249 n += 2;
250 break;
251 case 'N': /* count of substructures (word) at end */
252 n += 2;
253 break;
254 case 'D': /* double word (4 byte) */
255 case 'z': /* offset to zero terminated string (4 byte) */
256 case 'l': /* offset to user data (4 byte) */
257 n += 4;
258 break;
259 case 'b': /* offset to data (with counter) (4 byte) */
260 n += 4;
261 get_counter(&p);
262 break;
263 case 'B': /* byte (with optional counter) */
264 n += get_counter(&p);
265 break;
268 return n;
271 static bool init_package(struct pack_desc *p, int count, int subcount)
273 int n = p->buflen;
274 int i;
276 if (!p->format || !p->base) {
277 return False;
280 i = count * getlen(p->format);
281 if (p->subformat) {
282 i += subcount * getlen(p->subformat);
284 p->structbuf = p->base;
285 p->neededlen = 0;
286 p->usedlen = 0;
287 p->subcount = 0;
288 p->curpos = p->format;
289 if (i > n) {
290 p->neededlen = i;
291 i = n = 0;
292 #if 0
294 * This is the old error code we used. Aparently
295 * WinNT/2k systems return ERRbuftoosmall (2123) and
296 * OS/2 needs this. I'm leaving this here so we can revert
297 * if needed. JRA.
299 p->errcode = ERRmoredata;
300 #else
301 p->errcode = ERRbuftoosmall;
302 #endif
303 } else {
304 p->errcode = NERR_Success;
306 p->buflen = i;
307 n -= i;
308 p->stringbuf = p->base + i;
309 p->stringlen = n;
310 return (p->errcode == NERR_Success);
313 static int package(struct pack_desc *p, ...)
315 va_list args;
316 int needed=0, stringneeded;
317 const char *str=NULL;
318 int is_string=0, stringused;
319 int32 temp;
321 va_start(args,p);
323 if (!*p->curpos) {
324 if (!p->subcount) {
325 p->curpos = p->format;
326 } else {
327 p->curpos = p->subformat;
328 p->subcount--;
331 #if CHECK_TYPES
332 str = va_arg(args,char*);
333 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
334 #endif
335 stringneeded = -1;
337 if (!p->curpos) {
338 va_end(args);
339 return 0;
342 switch( *p->curpos++ ) {
343 case 'W': /* word (2 byte) */
344 needed = 2;
345 temp = va_arg(args,int);
346 if (p->buflen >= needed) {
347 SSVAL(p->structbuf,0,temp);
349 break;
350 case 'K': /* status word? (2 byte) */
351 needed = 2;
352 temp = va_arg(args,int);
353 if (p->buflen >= needed) {
354 SSVAL(p->structbuf,0,temp);
356 break;
357 case 'N': /* count of substructures (word) at end */
358 needed = 2;
359 p->subcount = va_arg(args,int);
360 if (p->buflen >= needed) {
361 SSVAL(p->structbuf,0,p->subcount);
363 break;
364 case 'D': /* double word (4 byte) */
365 needed = 4;
366 temp = va_arg(args,int);
367 if (p->buflen >= needed) {
368 SIVAL(p->structbuf,0,temp);
370 break;
371 case 'B': /* byte (with optional counter) */
372 needed = get_counter(&p->curpos);
374 char *s = va_arg(args,char*);
375 if (p->buflen >= needed) {
376 StrnCpy(p->structbuf,s?s:"",needed-1);
379 break;
380 case 'z': /* offset to zero terminated string (4 byte) */
381 str = va_arg(args,char*);
382 stringneeded = (str ? strlen(str)+1 : 0);
383 is_string = 1;
384 break;
385 case 'l': /* offset to user data (4 byte) */
386 str = va_arg(args,char*);
387 stringneeded = va_arg(args,int);
388 is_string = 0;
389 break;
390 case 'b': /* offset to data (with counter) (4 byte) */
391 str = va_arg(args,char*);
392 stringneeded = get_counter(&p->curpos);
393 is_string = 0;
394 break;
397 va_end(args);
398 if (stringneeded >= 0) {
399 needed = 4;
400 if (p->buflen >= needed) {
401 stringused = stringneeded;
402 if (stringused > p->stringlen) {
403 stringused = (is_string ? p->stringlen : 0);
404 if (p->errcode == NERR_Success) {
405 p->errcode = ERRmoredata;
408 if (!stringused) {
409 SIVAL(p->structbuf,0,0);
410 } else {
411 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
412 memcpy(p->stringbuf,str?str:"",stringused);
413 if (is_string) {
414 p->stringbuf[stringused-1] = '\0';
416 p->stringbuf += stringused;
417 p->stringlen -= stringused;
418 p->usedlen += stringused;
421 p->neededlen += stringneeded;
424 p->neededlen += needed;
425 if (p->buflen >= needed) {
426 p->structbuf += needed;
427 p->buflen -= needed;
428 p->usedlen += needed;
429 } else {
430 if (p->errcode == NERR_Success) {
431 p->errcode = ERRmoredata;
434 return 1;
437 #if CHECK_TYPES
438 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
439 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
440 #else
441 #define PACK(desc,t,v) package(desc,v)
442 #define PACKl(desc,t,v,l) package(desc,v,l)
443 #endif
445 static void PACKI(struct pack_desc* desc, const char *t,int v)
447 PACK(desc,t,v);
450 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
452 PACK(desc,t,v);
455 /****************************************************************************
456 Get a print queue.
457 ****************************************************************************/
459 static void PackDriverData(struct pack_desc* desc)
461 char drivdata[4+4+32];
462 SIVAL(drivdata,0,sizeof drivdata); /* cb */
463 SIVAL(drivdata,4,1000); /* lVersion */
464 memset(drivdata+8,0,32); /* szDeviceName */
465 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
466 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
469 static int check_printq_info(struct pack_desc* desc,
470 unsigned int uLevel, char *id1, char *id2)
472 desc->subformat = NULL;
473 switch( uLevel ) {
474 case 0:
475 desc->format = "B13";
476 break;
477 case 1:
478 desc->format = "B13BWWWzzzzzWW";
479 break;
480 case 2:
481 desc->format = "B13BWWWzzzzzWN";
482 desc->subformat = "WB21BB16B10zWWzDDz";
483 break;
484 case 3:
485 desc->format = "zWWWWzzzzWWzzl";
486 break;
487 case 4:
488 desc->format = "zWWWWzzzzWNzzl";
489 desc->subformat = "WWzWWDDzz";
490 break;
491 case 5:
492 desc->format = "z";
493 break;
494 case 51:
495 desc->format = "K";
496 break;
497 case 52:
498 desc->format = "WzzzzzzzzN";
499 desc->subformat = "z";
500 break;
501 default:
502 DEBUG(0,("check_printq_info: invalid level %d\n",
503 uLevel ));
504 return False;
506 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
507 DEBUG(0,("check_printq_info: invalid format %s\n",
508 id1 ? id1 : "<NULL>" ));
509 return False;
511 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
512 DEBUG(0,("check_printq_info: invalid subformat %s\n",
513 id2 ? id2 : "<NULL>" ));
514 return False;
516 return True;
520 #define RAP_JOB_STATUS_QUEUED 0
521 #define RAP_JOB_STATUS_PAUSED 1
522 #define RAP_JOB_STATUS_SPOOLING 2
523 #define RAP_JOB_STATUS_PRINTING 3
524 #define RAP_JOB_STATUS_PRINTED 4
526 #define RAP_QUEUE_STATUS_PAUSED 1
527 #define RAP_QUEUE_STATUS_ERROR 2
529 /* turn a print job status into a on the wire status
531 static int printj_status(int v)
533 switch (v) {
534 case LPQ_QUEUED:
535 return RAP_JOB_STATUS_QUEUED;
536 case LPQ_PAUSED:
537 return RAP_JOB_STATUS_PAUSED;
538 case LPQ_SPOOLING:
539 return RAP_JOB_STATUS_SPOOLING;
540 case LPQ_PRINTING:
541 return RAP_JOB_STATUS_PRINTING;
543 return 0;
546 /* turn a print queue status into a on the wire status
548 static int printq_status(int v)
550 switch (v) {
551 case LPQ_QUEUED:
552 return 0;
553 case LPQ_PAUSED:
554 return RAP_QUEUE_STATUS_PAUSED;
556 return RAP_QUEUE_STATUS_ERROR;
559 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
560 struct pack_desc *desc,
561 print_queue_struct *queue, int n)
563 time_t t = queue->time;
565 /* the client expects localtime */
566 t -= get_time_zone(t);
568 PACKI(desc,"W",pjobid_to_rap(lp_const_servicename(snum),queue->job)); /* uJobId */
569 if (uLevel == 1) {
570 PACKS(desc,"B21",queue->fs_user); /* szUserName */
571 PACKS(desc,"B",""); /* pad */
572 PACKS(desc,"B16",""); /* szNotifyName */
573 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
574 PACKS(desc,"z",""); /* pszParms */
575 PACKI(desc,"W",n+1); /* uPosition */
576 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
577 PACKS(desc,"z",""); /* pszStatus */
578 PACKI(desc,"D",t); /* ulSubmitted */
579 PACKI(desc,"D",queue->size); /* ulSize */
580 PACKS(desc,"z",queue->fs_file); /* pszComment */
582 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
583 PACKI(desc,"W",queue->priority); /* uPriority */
584 PACKS(desc,"z",queue->fs_user); /* pszUserName */
585 PACKI(desc,"W",n+1); /* uPosition */
586 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
587 PACKI(desc,"D",t); /* ulSubmitted */
588 PACKI(desc,"D",queue->size); /* ulSize */
589 PACKS(desc,"z","Samba"); /* pszComment */
590 PACKS(desc,"z",queue->fs_file); /* pszDocument */
591 if (uLevel == 3) {
592 PACKS(desc,"z",""); /* pszNotifyName */
593 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
594 PACKS(desc,"z",""); /* pszParms */
595 PACKS(desc,"z",""); /* pszStatus */
596 PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
597 PACKS(desc,"z","lpd"); /* pszQProcName */
598 PACKS(desc,"z",""); /* pszQProcParms */
599 PACKS(desc,"z","NULL"); /* pszDriverName */
600 PackDriverData(desc); /* pDriverData */
601 PACKS(desc,"z",""); /* pszPrinterName */
602 } else if (uLevel == 4) { /* OS2 */
603 PACKS(desc,"z",""); /* pszSpoolFileName */
604 PACKS(desc,"z",""); /* pszPortName */
605 PACKS(desc,"z",""); /* pszStatus */
606 PACKI(desc,"D",0); /* ulPagesSpooled */
607 PACKI(desc,"D",0); /* ulPagesSent */
608 PACKI(desc,"D",0); /* ulPagesPrinted */
609 PACKI(desc,"D",0); /* ulTimePrinted */
610 PACKI(desc,"D",0); /* ulExtendJobStatus */
611 PACKI(desc,"D",0); /* ulStartPage */
612 PACKI(desc,"D",0); /* ulEndPage */
617 /********************************************************************
618 Return a driver name given an snum.
619 Returns True if from tdb, False otherwise.
620 ********************************************************************/
622 static bool get_driver_name(int snum, char **pp_drivername)
624 NT_PRINTER_INFO_LEVEL *info = NULL;
625 bool in_tdb = false;
627 get_a_printer (NULL, &info, 2, lp_servicename(snum));
628 if (info != NULL) {
629 *pp_drivername = talloc_strdup(talloc_tos(),
630 info->info_2->drivername);
631 in_tdb = true;
632 free_a_printer(&info, 2);
633 if (!*pp_drivername) {
634 return false;
638 return in_tdb;
641 /********************************************************************
642 Respond to the DosPrintQInfo command with a level of 52
643 This is used to get printer driver information for Win9x clients
644 ********************************************************************/
645 static void fill_printq_info_52(connection_struct *conn, int snum,
646 struct pack_desc* desc, int count )
648 int i;
649 fstring location;
650 NT_PRINTER_DRIVER_INFO_LEVEL driver;
651 NT_PRINTER_INFO_LEVEL *printer = NULL;
653 ZERO_STRUCT(driver);
655 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
656 DEBUG(3,("fill_printq_info_52: Failed to lookup printer [%s]\n",
657 lp_servicename(snum)));
658 goto err;
661 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
662 "Windows 4.0", 0)) )
664 DEBUG(3,("fill_printq_info_52: Failed to lookup driver [%s]\n",
665 printer->info_2->drivername));
666 goto err;
669 trim_string(driver.info_3->driverpath, "\\print$\\WIN40\\0\\", 0);
670 trim_string(driver.info_3->datafile, "\\print$\\WIN40\\0\\", 0);
671 trim_string(driver.info_3->helpfile, "\\print$\\WIN40\\0\\", 0);
673 PACKI(desc, "W", 0x0400); /* don't know */
674 PACKS(desc, "z", driver.info_3->name); /* long printer name */
675 PACKS(desc, "z", driver.info_3->driverpath); /* Driverfile Name */
676 PACKS(desc, "z", driver.info_3->datafile); /* Datafile name */
677 PACKS(desc, "z", driver.info_3->monitorname); /* language monitor */
679 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
680 standard_sub_basic( "", "", location, sizeof(location)-1 );
681 PACKS(desc,"z", location); /* share to retrieve files */
683 PACKS(desc,"z", driver.info_3->defaultdatatype); /* default data type */
684 PACKS(desc,"z", driver.info_3->helpfile); /* helpfile name */
685 PACKS(desc,"z", driver.info_3->driverpath); /* driver name */
687 DEBUG(3,("Printer Driver Name: %s:\n",driver.info_3->name));
688 DEBUG(3,("Driver: %s:\n",driver.info_3->driverpath));
689 DEBUG(3,("Data File: %s:\n",driver.info_3->datafile));
690 DEBUG(3,("Language Monitor: %s:\n",driver.info_3->monitorname));
691 DEBUG(3,("Driver Location: %s:\n",location));
692 DEBUG(3,("Data Type: %s:\n",driver.info_3->defaultdatatype));
693 DEBUG(3,("Help File: %s:\n",driver.info_3->helpfile));
694 PACKI(desc,"N",count); /* number of files to copy */
696 for ( i=0; i<count && driver.info_3->dependentfiles && *driver.info_3->dependentfiles[i]; i++)
698 trim_string(driver.info_3->dependentfiles[i], "\\print$\\WIN40\\0\\", 0);
699 PACKS(desc,"z",driver.info_3->dependentfiles[i]); /* driver files to copy */
700 DEBUG(3,("Dependent File: %s:\n",driver.info_3->dependentfiles[i]));
703 /* sanity check */
704 if ( i != count )
705 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
706 count, i));
708 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", SERVICE(snum),i));
710 desc->errcode=NERR_Success;
711 goto done;
713 err:
714 DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
715 desc->errcode=NERR_notsupported;
717 done:
718 if ( printer )
719 free_a_printer( &printer, 2 );
721 if ( driver.info_3 )
722 free_a_printer_driver( driver, 3 );
726 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
727 struct pack_desc* desc,
728 int count, print_queue_struct* queue,
729 print_status_struct* status)
731 switch (uLevel) {
732 case 1:
733 case 2:
734 PACKS(desc,"B13",SERVICE(snum));
735 break;
736 case 3:
737 case 4:
738 case 5:
739 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
740 break;
741 case 51:
742 PACKI(desc,"K",printq_status(status->status));
743 break;
746 if (uLevel == 1 || uLevel == 2) {
747 PACKS(desc,"B",""); /* alignment */
748 PACKI(desc,"W",5); /* priority */
749 PACKI(desc,"W",0); /* start time */
750 PACKI(desc,"W",0); /* until time */
751 PACKS(desc,"z",""); /* pSepFile */
752 PACKS(desc,"z","lpd"); /* pPrProc */
753 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
754 PACKS(desc,"z",""); /* pParms */
755 if (snum < 0) {
756 PACKS(desc,"z","UNKNOWN PRINTER");
757 PACKI(desc,"W",LPSTAT_ERROR);
759 else if (!status || !status->message[0]) {
760 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
761 PACKI(desc,"W",LPSTAT_OK); /* status */
762 } else {
763 PACKS(desc,"z",status->message);
764 PACKI(desc,"W",printq_status(status->status)); /* status */
766 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
769 if (uLevel == 3 || uLevel == 4) {
770 char *drivername = NULL;
772 PACKI(desc,"W",5); /* uPriority */
773 PACKI(desc,"W",0); /* uStarttime */
774 PACKI(desc,"W",0); /* uUntiltime */
775 PACKI(desc,"W",5); /* pad1 */
776 PACKS(desc,"z",""); /* pszSepFile */
777 PACKS(desc,"z","WinPrint"); /* pszPrProc */
778 PACKS(desc,"z",NULL); /* pszParms */
779 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
780 /* "don't ask" that it's done this way to fix corrupted
781 Win9X/ME printer comments. */
782 if (!status) {
783 PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
784 } else {
785 PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
787 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
788 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
789 get_driver_name(snum,&drivername);
790 if (!drivername) {
791 return;
793 PACKS(desc,"z",drivername); /* pszDriverName */
794 PackDriverData(desc); /* pDriverData */
797 if (uLevel == 2 || uLevel == 4) {
798 int i;
799 for (i=0;i<count;i++)
800 fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
803 if (uLevel==52)
804 fill_printq_info_52( conn, snum, desc, count );
807 /* This function returns the number of files for a given driver */
808 static int get_printerdrivernumber(int snum)
810 int result = 0;
811 NT_PRINTER_DRIVER_INFO_LEVEL driver;
812 NT_PRINTER_INFO_LEVEL *printer = NULL;
814 ZERO_STRUCT(driver);
816 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
817 DEBUG(3,("get_printerdrivernumber: Failed to lookup printer [%s]\n",
818 lp_servicename(snum)));
819 goto done;
822 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
823 "Windows 4.0", 0)) )
825 DEBUG(3,("get_printerdrivernumber: Failed to lookup driver [%s]\n",
826 printer->info_2->drivername));
827 goto done;
830 /* count the number of files */
831 while ( driver.info_3->dependentfiles && *driver.info_3->dependentfiles[result] )
832 result++;
834 done:
835 if ( printer )
836 free_a_printer( &printer, 2 );
838 if ( driver.info_3 )
839 free_a_printer_driver( driver, 3 );
841 return result;
844 static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
845 char *param, int tpscnt,
846 char *data, int tdscnt,
847 int mdrcnt,int mprcnt,
848 char **rdata,char **rparam,
849 int *rdata_len,int *rparam_len)
851 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
852 char *str2 = skip_string(param,tpscnt,str1);
853 char *p = skip_string(param,tpscnt,str2);
854 char *QueueName = p;
855 unsigned int uLevel;
856 int count=0;
857 int snum;
858 char *str3;
859 struct pack_desc desc;
860 print_queue_struct *queue=NULL;
861 print_status_struct status;
862 char* tmpdata=NULL;
864 if (!str1 || !str2 || !p) {
865 return False;
867 memset((char *)&status,'\0',sizeof(status));
868 memset((char *)&desc,'\0',sizeof(desc));
870 p = skip_string(param,tpscnt,p);
871 if (!p) {
872 return False;
874 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
875 str3 = get_safe_str_ptr(param,tpscnt,p,4);
876 /* str3 may be null here and is checked in check_printq_info(). */
878 /* remove any trailing username */
879 if ((p = strchr_m(QueueName,'%')))
880 *p = 0;
882 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
884 /* check it's a supported varient */
885 if (!prefix_ok(str1,"zWrLh"))
886 return False;
887 if (!check_printq_info(&desc,uLevel,str2,str3)) {
889 * Patch from Scott Moomaw <scott@bridgewater.edu>
890 * to return the 'invalid info level' error if an
891 * unknown level was requested.
893 *rdata_len = 0;
894 *rparam_len = 6;
895 *rparam = smb_realloc_limit(*rparam,*rparam_len);
896 if (!*rparam) {
897 return False;
899 SSVALS(*rparam,0,ERRunknownlevel);
900 SSVAL(*rparam,2,0);
901 SSVAL(*rparam,4,0);
902 return(True);
905 snum = find_service(QueueName);
906 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) )
907 return False;
909 if (uLevel==52) {
910 count = get_printerdrivernumber(snum);
911 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
912 } else {
913 count = print_queue_status(snum, &queue,&status);
916 if (mdrcnt > 0) {
917 *rdata = smb_realloc_limit(*rdata,mdrcnt);
918 if (!*rdata) {
919 SAFE_FREE(queue);
920 return False;
922 desc.base = *rdata;
923 desc.buflen = mdrcnt;
924 } else {
926 * Don't return data but need to get correct length
927 * init_package will return wrong size if buflen=0
929 desc.buflen = getlen(desc.format);
930 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
933 if (init_package(&desc,1,count)) {
934 desc.subcount = count;
935 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
938 *rdata_len = desc.usedlen;
941 * We must set the return code to ERRbuftoosmall
942 * in order to support lanman style printing with Win NT/2k
943 * clients --jerry
945 if (!mdrcnt && lp_disable_spoolss())
946 desc.errcode = ERRbuftoosmall;
948 *rdata_len = desc.usedlen;
949 *rparam_len = 6;
950 *rparam = smb_realloc_limit(*rparam,*rparam_len);
951 if (!*rparam) {
952 SAFE_FREE(queue);
953 SAFE_FREE(tmpdata);
954 return False;
956 SSVALS(*rparam,0,desc.errcode);
957 SSVAL(*rparam,2,0);
958 SSVAL(*rparam,4,desc.neededlen);
960 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
962 SAFE_FREE(queue);
963 SAFE_FREE(tmpdata);
965 return(True);
968 /****************************************************************************
969 View list of all print jobs on all queues.
970 ****************************************************************************/
972 static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
973 char *param, int tpscnt,
974 char *data, int tdscnt,
975 int mdrcnt, int mprcnt,
976 char **rdata, char** rparam,
977 int *rdata_len, int *rparam_len)
979 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
980 char *output_format1 = skip_string(param,tpscnt,param_format);
981 char *p = skip_string(param,tpscnt,output_format1);
982 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
983 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
984 int services = lp_numservices();
985 int i, n;
986 struct pack_desc desc;
987 print_queue_struct **queue = NULL;
988 print_status_struct *status = NULL;
989 int *subcntarr = NULL;
990 int queuecnt = 0, subcnt = 0, succnt = 0;
992 if (!param_format || !output_format1 || !p) {
993 return False;
996 memset((char *)&desc,'\0',sizeof(desc));
998 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
1000 if (!prefix_ok(param_format,"WrLeh")) {
1001 return False;
1003 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
1005 * Patch from Scott Moomaw <scott@bridgewater.edu>
1006 * to return the 'invalid info level' error if an
1007 * unknown level was requested.
1009 *rdata_len = 0;
1010 *rparam_len = 6;
1011 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1012 if (!*rparam) {
1013 return False;
1015 SSVALS(*rparam,0,ERRunknownlevel);
1016 SSVAL(*rparam,2,0);
1017 SSVAL(*rparam,4,0);
1018 return(True);
1021 for (i = 0; i < services; i++) {
1022 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1023 queuecnt++;
1027 if((queue = SMB_MALLOC_ARRAY(print_queue_struct*, queuecnt)) == NULL) {
1028 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1029 goto err;
1031 memset(queue,0,queuecnt*sizeof(print_queue_struct*));
1032 if((status = SMB_MALLOC_ARRAY(print_status_struct,queuecnt)) == NULL) {
1033 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1034 goto err;
1036 memset(status,0,queuecnt*sizeof(print_status_struct));
1037 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1038 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1039 goto err;
1042 subcnt = 0;
1043 n = 0;
1044 for (i = 0; i < services; i++) {
1045 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1046 subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
1047 subcnt += subcntarr[n];
1048 n++;
1052 if (mdrcnt > 0) {
1053 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1054 if (!*rdata) {
1055 goto err;
1058 desc.base = *rdata;
1059 desc.buflen = mdrcnt;
1061 if (init_package(&desc,queuecnt,subcnt)) {
1062 n = 0;
1063 succnt = 0;
1064 for (i = 0; i < services; i++) {
1065 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1066 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1067 n++;
1068 if (desc.errcode == NERR_Success) {
1069 succnt = n;
1075 SAFE_FREE(subcntarr);
1077 *rdata_len = desc.usedlen;
1078 *rparam_len = 8;
1079 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1080 if (!*rparam) {
1081 goto err;
1083 SSVALS(*rparam,0,desc.errcode);
1084 SSVAL(*rparam,2,0);
1085 SSVAL(*rparam,4,succnt);
1086 SSVAL(*rparam,6,queuecnt);
1088 for (i = 0; i < queuecnt; i++) {
1089 if (queue) {
1090 SAFE_FREE(queue[i]);
1094 SAFE_FREE(queue);
1095 SAFE_FREE(status);
1097 return True;
1099 err:
1101 SAFE_FREE(subcntarr);
1102 for (i = 0; i < queuecnt; i++) {
1103 if (queue) {
1104 SAFE_FREE(queue[i]);
1107 SAFE_FREE(queue);
1108 SAFE_FREE(status);
1110 return False;
1113 /****************************************************************************
1114 Get info level for a server list query.
1115 ****************************************************************************/
1117 static bool check_server_info(int uLevel, char* id)
1119 switch( uLevel ) {
1120 case 0:
1121 if (strcmp(id,"B16") != 0) {
1122 return False;
1124 break;
1125 case 1:
1126 if (strcmp(id,"B16BBDz") != 0) {
1127 return False;
1129 break;
1130 default:
1131 return False;
1133 return True;
1136 struct srv_info_struct {
1137 fstring name;
1138 uint32 type;
1139 fstring comment;
1140 fstring domain;
1141 bool server_added;
1144 /*******************************************************************
1145 Get server info lists from the files saved by nmbd. Return the
1146 number of entries.
1147 ******************************************************************/
1149 static int get_server_info(uint32 servertype,
1150 struct srv_info_struct **servers,
1151 const char *domain)
1153 int count=0;
1154 int alloced=0;
1155 char **lines;
1156 bool local_list_only;
1157 int i;
1159 lines = file_lines_load(lock_path(SERVER_LIST), NULL, 0);
1160 if (!lines) {
1161 DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
1162 return 0;
1165 /* request for everything is code for request all servers */
1166 if (servertype == SV_TYPE_ALL) {
1167 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1170 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1172 DEBUG(4,("Servertype search: %8x\n",servertype));
1174 for (i=0;lines[i];i++) {
1175 fstring stype;
1176 struct srv_info_struct *s;
1177 const char *ptr = lines[i];
1178 bool ok = True;
1179 TALLOC_CTX *frame = NULL;
1180 char *p;
1182 if (!*ptr) {
1183 continue;
1186 if (count == alloced) {
1187 alloced += 10;
1188 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1189 if (!*servers) {
1190 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1191 file_lines_free(lines);
1192 return 0;
1194 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1196 s = &(*servers)[count];
1198 frame = talloc_stackframe();
1199 s->name[0] = '\0';
1200 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1201 TALLOC_FREE(frame);
1202 continue;
1204 fstrcpy(s->name, p);
1206 stype[0] = '\0';
1207 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1208 TALLOC_FREE(frame);
1209 continue;
1211 fstrcpy(stype, p);
1213 s->comment[0] = '\0';
1214 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1215 TALLOC_FREE(frame);
1216 continue;
1218 fstrcpy(s->comment, p);
1220 s->domain[0] = '\0';
1221 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1222 /* this allows us to cope with an old nmbd */
1223 fstrcpy(s->domain,lp_workgroup());
1224 } else {
1225 fstrcpy(s->domain, p);
1227 TALLOC_FREE(frame);
1229 if (sscanf(stype,"%X",&s->type) != 1) {
1230 DEBUG(4,("r:host file "));
1231 ok = False;
1234 /* Filter the servers/domains we return based on what was asked for. */
1236 /* Check to see if we are being asked for a local list only. */
1237 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1238 DEBUG(4,("r: local list only"));
1239 ok = False;
1242 /* doesn't match up: don't want it */
1243 if (!(servertype & s->type)) {
1244 DEBUG(4,("r:serv type "));
1245 ok = False;
1248 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1249 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1250 DEBUG(4,("s: dom mismatch "));
1251 ok = False;
1254 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1255 ok = False;
1258 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1259 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1261 if (ok) {
1262 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1263 s->name, s->type, s->comment, s->domain));
1264 s->server_added = True;
1265 count++;
1266 } else {
1267 DEBUG(4,("%20s %8x %25s %15s\n",
1268 s->name, s->type, s->comment, s->domain));
1272 file_lines_free(lines);
1273 return count;
1276 /*******************************************************************
1277 Fill in a server info structure.
1278 ******************************************************************/
1280 static int fill_srv_info(struct srv_info_struct *service,
1281 int uLevel, char **buf, int *buflen,
1282 char **stringbuf, int *stringspace, char *baseaddr)
1284 int struct_len;
1285 char* p;
1286 char* p2;
1287 int l2;
1288 int len;
1290 switch (uLevel) {
1291 case 0:
1292 struct_len = 16;
1293 break;
1294 case 1:
1295 struct_len = 26;
1296 break;
1297 default:
1298 return -1;
1301 if (!buf) {
1302 len = 0;
1303 switch (uLevel) {
1304 case 1:
1305 len = strlen(service->comment)+1;
1306 break;
1309 *buflen = struct_len;
1310 *stringspace = len;
1311 return struct_len + len;
1314 len = struct_len;
1315 p = *buf;
1316 if (*buflen < struct_len) {
1317 return -1;
1319 if (stringbuf) {
1320 p2 = *stringbuf;
1321 l2 = *stringspace;
1322 } else {
1323 p2 = p + struct_len;
1324 l2 = *buflen - struct_len;
1326 if (!baseaddr) {
1327 baseaddr = p;
1330 switch (uLevel) {
1331 case 0:
1332 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1333 break;
1335 case 1:
1336 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1337 SIVAL(p,18,service->type);
1338 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1339 len += CopyAndAdvance(&p2,service->comment,&l2);
1340 break;
1343 if (stringbuf) {
1344 *buf = p + struct_len;
1345 *buflen -= struct_len;
1346 *stringbuf = p2;
1347 *stringspace = l2;
1348 } else {
1349 *buf = p2;
1350 *buflen -= len;
1352 return len;
1356 static bool srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1358 return(strcmp(s1->name,s2->name));
1361 /****************************************************************************
1362 View list of servers available (or possibly domains). The info is
1363 extracted from lists saved by nmbd on the local host.
1364 ****************************************************************************/
1366 static bool api_RNetServerEnum(connection_struct *conn, uint16 vuid,
1367 char *param, int tpscnt,
1368 char *data, int tdscnt,
1369 int mdrcnt, int mprcnt, char **rdata,
1370 char **rparam, int *rdata_len, int *rparam_len)
1372 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1373 char *str2 = skip_string(param,tpscnt,str1);
1374 char *p = skip_string(param,tpscnt,str2);
1375 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1376 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1377 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1378 char *p2;
1379 int data_len, fixed_len, string_len;
1380 int f_len = 0, s_len = 0;
1381 struct srv_info_struct *servers=NULL;
1382 int counted=0,total=0;
1383 int i,missed;
1384 fstring domain;
1385 bool domain_request;
1386 bool local_request;
1388 if (!str1 || !str2 || !p) {
1389 return False;
1392 /* If someone sets all the bits they don't really mean to set
1393 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1394 known servers. */
1396 if (servertype == SV_TYPE_ALL) {
1397 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1400 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1401 any other bit (they may just set this bit on its own) they
1402 want all the locally seen servers. However this bit can be
1403 set on its own so set the requested servers to be
1404 ALL - DOMAIN_ENUM. */
1406 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1407 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1410 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1411 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1413 p += 8;
1415 if (!prefix_ok(str1,"WrLehD")) {
1416 return False;
1418 if (!check_server_info(uLevel,str2)) {
1419 return False;
1422 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1423 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1424 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1426 if (strcmp(str1, "WrLehDz") == 0) {
1427 if (skip_string(param,tpscnt,p) == NULL) {
1428 return False;
1430 pull_ascii_fstring(domain, p);
1431 } else {
1432 fstrcpy(domain, lp_workgroup());
1435 if (lp_browse_list()) {
1436 total = get_server_info(servertype,&servers,domain);
1439 data_len = fixed_len = string_len = 0;
1440 missed = 0;
1442 if (total > 0) {
1443 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1447 char *lastname=NULL;
1449 for (i=0;i<total;i++) {
1450 struct srv_info_struct *s = &servers[i];
1452 if (lastname && strequal(lastname,s->name)) {
1453 continue;
1455 lastname = s->name;
1456 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1457 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1458 s->name, s->type, s->comment, s->domain));
1460 if (data_len <= buf_len) {
1461 counted++;
1462 fixed_len += f_len;
1463 string_len += s_len;
1464 } else {
1465 missed++;
1470 *rdata_len = fixed_len + string_len;
1471 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1472 if (!*rdata) {
1473 return False;
1476 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1477 p = *rdata;
1478 f_len = fixed_len;
1479 s_len = string_len;
1482 char *lastname=NULL;
1483 int count2 = counted;
1485 for (i = 0; i < total && count2;i++) {
1486 struct srv_info_struct *s = &servers[i];
1488 if (lastname && strequal(lastname,s->name)) {
1489 continue;
1491 lastname = s->name;
1492 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1493 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1494 s->name, s->type, s->comment, s->domain));
1495 count2--;
1499 *rparam_len = 8;
1500 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1501 if (!*rparam) {
1502 return False;
1504 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1505 SSVAL(*rparam,2,0);
1506 SSVAL(*rparam,4,counted);
1507 SSVAL(*rparam,6,counted+missed);
1509 SAFE_FREE(servers);
1511 DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1512 domain,uLevel,counted,counted+missed));
1514 return True;
1517 /****************************************************************************
1518 command 0x34 - suspected of being a "Lookup Names" stub api
1519 ****************************************************************************/
1521 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1522 char *param, int tpscnt,
1523 char *data, int tdscnt,
1524 int mdrcnt, int mprcnt, char **rdata,
1525 char **rparam, int *rdata_len, int *rparam_len)
1527 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1528 char *str2 = skip_string(param,tpscnt,str1);
1529 char *p = skip_string(param,tpscnt,str2);
1530 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1531 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1532 int counted=0;
1533 int missed=0;
1535 if (!str1 || !str2 || !p) {
1536 return False;
1539 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1540 str1, str2, p, uLevel, buf_len));
1542 if (!prefix_ok(str1,"zWrLeh")) {
1543 return False;
1546 *rdata_len = 0;
1548 *rparam_len = 8;
1549 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1550 if (!*rparam) {
1551 return False;
1554 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1555 SSVAL(*rparam,2,0);
1556 SSVAL(*rparam,4,counted);
1557 SSVAL(*rparam,6,counted+missed);
1559 return True;
1562 /****************************************************************************
1563 get info about a share
1564 ****************************************************************************/
1566 static bool check_share_info(int uLevel, char* id)
1568 switch( uLevel ) {
1569 case 0:
1570 if (strcmp(id,"B13") != 0) {
1571 return False;
1573 break;
1574 case 1:
1575 if (strcmp(id,"B13BWz") != 0) {
1576 return False;
1578 break;
1579 case 2:
1580 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1581 return False;
1583 break;
1584 case 91:
1585 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1586 return False;
1588 break;
1589 default:
1590 return False;
1592 return True;
1595 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1596 char** buf, int* buflen,
1597 char** stringbuf, int* stringspace, char* baseaddr)
1599 int struct_len;
1600 char* p;
1601 char* p2;
1602 int l2;
1603 int len;
1605 switch( uLevel ) {
1606 case 0:
1607 struct_len = 13;
1608 break;
1609 case 1:
1610 struct_len = 20;
1611 break;
1612 case 2:
1613 struct_len = 40;
1614 break;
1615 case 91:
1616 struct_len = 68;
1617 break;
1618 default:
1619 return -1;
1623 if (!buf) {
1624 len = 0;
1626 if (uLevel > 0) {
1627 len += StrlenExpanded(conn,snum,lp_comment(snum));
1629 if (uLevel > 1) {
1630 len += strlen(lp_pathname(snum)) + 1;
1632 if (buflen) {
1633 *buflen = struct_len;
1635 if (stringspace) {
1636 *stringspace = len;
1638 return struct_len + len;
1641 len = struct_len;
1642 p = *buf;
1643 if ((*buflen) < struct_len) {
1644 return -1;
1647 if (stringbuf) {
1648 p2 = *stringbuf;
1649 l2 = *stringspace;
1650 } else {
1651 p2 = p + struct_len;
1652 l2 = (*buflen) - struct_len;
1655 if (!baseaddr) {
1656 baseaddr = p;
1659 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1661 if (uLevel > 0) {
1662 int type;
1664 SCVAL(p,13,0);
1665 type = STYPE_DISKTREE;
1666 if (lp_print_ok(snum)) {
1667 type = STYPE_PRINTQ;
1669 if (strequal("IPC",lp_fstype(snum))) {
1670 type = STYPE_IPC;
1672 SSVAL(p,14,type); /* device type */
1673 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1674 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1677 if (uLevel > 1) {
1678 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1679 SSVALS(p,22,-1); /* max uses */
1680 SSVAL(p,24,1); /* current uses */
1681 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1682 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1683 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1686 if (uLevel > 2) {
1687 memset(p+40,0,SHPWLEN+2);
1688 SSVAL(p,50,0);
1689 SIVAL(p,52,0);
1690 SSVAL(p,56,0);
1691 SSVAL(p,58,0);
1692 SIVAL(p,60,0);
1693 SSVAL(p,64,0);
1694 SSVAL(p,66,0);
1697 if (stringbuf) {
1698 (*buf) = p + struct_len;
1699 (*buflen) -= struct_len;
1700 (*stringbuf) = p2;
1701 (*stringspace) = l2;
1702 } else {
1703 (*buf) = p2;
1704 (*buflen) -= len;
1707 return len;
1710 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1711 char *param, int tpscnt,
1712 char *data, int tdscnt,
1713 int mdrcnt,int mprcnt,
1714 char **rdata,char **rparam,
1715 int *rdata_len,int *rparam_len)
1717 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1718 char *str2 = skip_string(param,tpscnt,str1);
1719 char *netname = skip_string(param,tpscnt,str2);
1720 char *p = skip_string(param,tpscnt,netname);
1721 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1722 int snum;
1724 if (!str1 || !str2 || !netname || !p) {
1725 return False;
1728 snum = find_service(netname);
1729 if (snum < 0) {
1730 return False;
1733 /* check it's a supported varient */
1734 if (!prefix_ok(str1,"zWrLh")) {
1735 return False;
1737 if (!check_share_info(uLevel,str2)) {
1738 return False;
1741 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1742 if (!*rdata) {
1743 return False;
1745 p = *rdata;
1746 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1747 if (*rdata_len < 0) {
1748 return False;
1751 *rparam_len = 6;
1752 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1753 if (!*rparam) {
1754 return False;
1756 SSVAL(*rparam,0,NERR_Success);
1757 SSVAL(*rparam,2,0); /* converter word */
1758 SSVAL(*rparam,4,*rdata_len);
1760 return True;
1763 /****************************************************************************
1764 View the list of available shares.
1766 This function is the server side of the NetShareEnum() RAP call.
1767 It fills the return buffer with share names and share comments.
1768 Note that the return buffer normally (in all known cases) allows only
1769 twelve byte strings for share names (plus one for a nul terminator).
1770 Share names longer than 12 bytes must be skipped.
1771 ****************************************************************************/
1773 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
1774 char *param, int tpscnt,
1775 char *data, int tdscnt,
1776 int mdrcnt,
1777 int mprcnt,
1778 char **rdata,
1779 char **rparam,
1780 int *rdata_len,
1781 int *rparam_len )
1783 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1784 char *str2 = skip_string(param,tpscnt,str1);
1785 char *p = skip_string(param,tpscnt,str2);
1786 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1787 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1788 char *p2;
1789 int count = 0;
1790 int total=0,counted=0;
1791 bool missed = False;
1792 int i;
1793 int data_len, fixed_len, string_len;
1794 int f_len = 0, s_len = 0;
1796 if (!str1 || !str2 || !p) {
1797 return False;
1800 if (!prefix_ok(str1,"WrLeh")) {
1801 return False;
1803 if (!check_share_info(uLevel,str2)) {
1804 return False;
1807 /* Ensure all the usershares are loaded. */
1808 become_root();
1809 load_registry_shares();
1810 count = load_usershare_shares();
1811 unbecome_root();
1813 data_len = fixed_len = string_len = 0;
1814 for (i=0;i<count;i++) {
1815 fstring servicename_dos;
1816 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1817 continue;
1819 push_ascii_fstring(servicename_dos, lp_servicename(i));
1820 /* Maximum name length = 13. */
1821 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
1822 total++;
1823 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1824 if (data_len <= buf_len) {
1825 counted++;
1826 fixed_len += f_len;
1827 string_len += s_len;
1828 } else {
1829 missed = True;
1834 *rdata_len = fixed_len + string_len;
1835 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1836 if (!*rdata) {
1837 return False;
1840 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
1841 p = *rdata;
1842 f_len = fixed_len;
1843 s_len = string_len;
1845 for( i = 0; i < count; i++ ) {
1846 fstring servicename_dos;
1847 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1848 continue;
1851 push_ascii_fstring(servicename_dos, lp_servicename(i));
1852 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
1853 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
1854 break;
1859 *rparam_len = 8;
1860 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1861 if (!*rparam) {
1862 return False;
1864 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1865 SSVAL(*rparam,2,0);
1866 SSVAL(*rparam,4,counted);
1867 SSVAL(*rparam,6,total);
1869 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1870 counted,total,uLevel,
1871 buf_len,*rdata_len,mdrcnt));
1873 return True;
1876 /****************************************************************************
1877 Add a share
1878 ****************************************************************************/
1880 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
1881 char *param, int tpscnt,
1882 char *data, int tdscnt,
1883 int mdrcnt,int mprcnt,
1884 char **rdata,char **rparam,
1885 int *rdata_len,int *rparam_len)
1887 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1888 char *str2 = skip_string(param,tpscnt,str1);
1889 char *p = skip_string(param,tpscnt,str2);
1890 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1891 fstring sharename;
1892 fstring comment;
1893 char *pathname = NULL;
1894 char *command, *cmdname;
1895 unsigned int offset;
1896 int snum;
1897 int res = ERRunsup;
1898 size_t converted_size;
1900 if (!str1 || !str2 || !p) {
1901 return False;
1904 /* check it's a supported varient */
1905 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
1906 return False;
1908 if (!check_share_info(uLevel,str2)) {
1909 return False;
1911 if (uLevel != 2) {
1912 return False;
1915 /* Do we have a string ? */
1916 if (skip_string(data,mdrcnt,data) == NULL) {
1917 return False;
1919 pull_ascii_fstring(sharename,data);
1920 snum = find_service(sharename);
1921 if (snum >= 0) { /* already exists */
1922 res = ERRfilexists;
1923 goto error_exit;
1926 if (mdrcnt < 28) {
1927 return False;
1930 /* only support disk share adds */
1931 if (SVAL(data,14)!=STYPE_DISKTREE) {
1932 return False;
1935 offset = IVAL(data, 16);
1936 if (offset >= mdrcnt) {
1937 res = ERRinvalidparam;
1938 goto error_exit;
1941 /* Do we have a string ? */
1942 if (skip_string(data,mdrcnt,data+offset) == NULL) {
1943 return False;
1945 pull_ascii_fstring(comment, offset? (data+offset) : "");
1947 offset = IVAL(data, 26);
1949 if (offset >= mdrcnt) {
1950 res = ERRinvalidparam;
1951 goto error_exit;
1954 /* Do we have a string ? */
1955 if (skip_string(data,mdrcnt,data+offset) == NULL) {
1956 return False;
1959 if (!pull_ascii_talloc(talloc_tos(), &pathname,
1960 offset ? (data+offset) : "", &converted_size))
1962 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
1963 strerror(errno)));
1966 if (!pathname) {
1967 return false;
1970 string_replace(sharename, '"', ' ');
1971 string_replace(pathname, '"', ' ');
1972 string_replace(comment, '"', ' ');
1974 cmdname = lp_add_share_cmd();
1976 if (!cmdname || *cmdname == '\0') {
1977 return False;
1980 if (asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
1981 lp_add_share_cmd(), get_dyn_CONFIGFILE(), sharename,
1982 pathname, comment) == -1) {
1983 return false;
1986 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
1988 if ((res = smbrun(command, NULL)) != 0) {
1989 DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n",
1990 command, res ));
1991 SAFE_FREE(command);
1992 res = ERRnoaccess;
1993 goto error_exit;
1994 } else {
1995 SAFE_FREE(command);
1996 message_send_all(smbd_messaging_context(),
1997 MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
2000 *rparam_len = 6;
2001 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2002 if (!*rparam) {
2003 return False;
2005 SSVAL(*rparam,0,NERR_Success);
2006 SSVAL(*rparam,2,0); /* converter word */
2007 SSVAL(*rparam,4,*rdata_len);
2008 *rdata_len = 0;
2010 return True;
2012 error_exit:
2014 *rparam_len = 4;
2015 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2016 if (!*rparam) {
2017 return False;
2019 *rdata_len = 0;
2020 SSVAL(*rparam,0,res);
2021 SSVAL(*rparam,2,0);
2022 return True;
2025 /****************************************************************************
2026 view list of groups available
2027 ****************************************************************************/
2029 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
2030 char *param, int tpscnt,
2031 char *data, int tdscnt,
2032 int mdrcnt,int mprcnt,
2033 char **rdata,char **rparam,
2034 int *rdata_len,int *rparam_len)
2036 int i;
2037 int errflags=0;
2038 int resume_context, cli_buf_size;
2039 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2040 char *str2 = skip_string(param,tpscnt,str1);
2041 char *p = skip_string(param,tpscnt,str2);
2043 struct pdb_search *search;
2044 struct samr_displayentry *entries;
2046 int num_entries;
2048 if (!str1 || !str2 || !p) {
2049 return False;
2052 if (strcmp(str1,"WrLeh") != 0) {
2053 return False;
2056 /* parameters
2057 * W-> resume context (number of users to skip)
2058 * r -> return parameter pointer to receive buffer
2059 * L -> length of receive buffer
2060 * e -> return parameter number of entries
2061 * h -> return parameter total number of users
2064 if (strcmp("B21",str2) != 0) {
2065 return False;
2068 /* get list of domain groups SID_DOMAIN_GRP=2 */
2069 become_root();
2070 search = pdb_search_groups();
2071 unbecome_root();
2073 if (search == NULL) {
2074 DEBUG(3,("api_RNetGroupEnum:failed to get group list"));
2075 return False;
2078 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2079 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2080 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2081 "%d\n", resume_context, cli_buf_size));
2083 become_root();
2084 num_entries = pdb_search_entries(search, resume_context, 0xffffffff,
2085 &entries);
2086 unbecome_root();
2088 *rdata_len = cli_buf_size;
2089 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2090 if (!*rdata) {
2091 return False;
2094 p = *rdata;
2096 for(i=0; i<num_entries; i++) {
2097 fstring name;
2098 fstrcpy(name, entries[i].account_name);
2099 if( ((PTR_DIFF(p,*rdata)+21) <= *rdata_len) ) {
2100 /* truncate the name at 21 chars. */
2101 memcpy(p, name, 21);
2102 DEBUG(10,("adding entry %d group %s\n", i, p));
2103 p += 21;
2104 p += 5; /* Both NT4 and W2k3SP1 do padding here.
2105 No idea why... */
2106 } else {
2107 /* set overflow error */
2108 DEBUG(3,("overflow on entry %d group %s\n", i, name));
2109 errflags=234;
2110 break;
2114 pdb_search_destroy(search);
2116 *rdata_len = PTR_DIFF(p,*rdata);
2118 *rparam_len = 8;
2119 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2120 if (!*rparam) {
2121 return False;
2123 SSVAL(*rparam, 0, errflags);
2124 SSVAL(*rparam, 2, 0); /* converter word */
2125 SSVAL(*rparam, 4, i); /* is this right?? */
2126 SSVAL(*rparam, 6, resume_context+num_entries); /* is this right?? */
2128 return(True);
2131 /*******************************************************************
2132 Get groups that a user is a member of.
2133 ******************************************************************/
2135 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2136 char *param, int tpscnt,
2137 char *data, int tdscnt,
2138 int mdrcnt,int mprcnt,
2139 char **rdata,char **rparam,
2140 int *rdata_len,int *rparam_len)
2142 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2143 char *str2 = skip_string(param,tpscnt,str1);
2144 char *UserName = skip_string(param,tpscnt,str2);
2145 char *p = skip_string(param,tpscnt,UserName);
2146 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2147 const char *level_string;
2148 int count=0;
2149 struct samu *sampw = NULL;
2150 bool ret = False;
2151 DOM_SID *sids;
2152 gid_t *gids;
2153 size_t num_groups;
2154 size_t i;
2155 NTSTATUS result;
2156 DOM_SID user_sid;
2157 enum lsa_SidType type;
2158 char *endp = NULL;
2159 TALLOC_CTX *mem_ctx;
2161 if (!str1 || !str2 || !UserName || !p) {
2162 return False;
2165 *rparam_len = 8;
2166 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2167 if (!*rparam) {
2168 return False;
2171 /* check it's a supported varient */
2173 if ( strcmp(str1,"zWrLeh") != 0 )
2174 return False;
2176 switch( uLevel ) {
2177 case 0:
2178 level_string = "B21";
2179 break;
2180 default:
2181 return False;
2184 if (strcmp(level_string,str2) != 0)
2185 return False;
2187 *rdata_len = mdrcnt + 1024;
2188 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2189 if (!*rdata) {
2190 return False;
2193 SSVAL(*rparam,0,NERR_Success);
2194 SSVAL(*rparam,2,0); /* converter word */
2196 p = *rdata;
2197 endp = *rdata + *rdata_len;
2199 mem_ctx = talloc_new(NULL);
2200 if (mem_ctx == NULL) {
2201 DEBUG(0, ("talloc_new failed\n"));
2202 return False;
2205 if ( !(sampw = samu_new(mem_ctx)) ) {
2206 DEBUG(0, ("samu_new() failed!\n"));
2207 TALLOC_FREE(mem_ctx);
2208 return False;
2211 /* Lookup the user information; This should only be one of
2212 our accounts (not remote domains) */
2214 become_root(); /* ROOT BLOCK */
2216 if (!lookup_name(mem_ctx, UserName, LOOKUP_NAME_ALL,
2217 NULL, NULL, &user_sid, &type)) {
2218 DEBUG(10, ("lookup_name(%s) failed\n", UserName));
2219 goto done;
2222 if (type != SID_NAME_USER) {
2223 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2224 sid_type_lookup(type)));
2225 goto done;
2228 if ( !pdb_getsampwsid(sampw, &user_sid) ) {
2229 DEBUG(10, ("pdb_getsampwsid(%s) failed for user %s\n",
2230 sid_string_dbg(&user_sid), UserName));
2231 goto done;
2234 gids = NULL;
2235 sids = NULL;
2236 num_groups = 0;
2238 result = pdb_enum_group_memberships(mem_ctx, sampw,
2239 &sids, &gids, &num_groups);
2241 if (!NT_STATUS_IS_OK(result)) {
2242 DEBUG(10, ("pdb_enum_group_memberships failed for %s\n",
2243 UserName));
2244 goto done;
2247 for (i=0; i<num_groups; i++) {
2248 const char *grp_name;
2250 if ( lookup_sid(mem_ctx, &sids[i], NULL, &grp_name, NULL) ) {
2251 strlcpy(p, grp_name, PTR_DIFF(endp,p));
2252 p += 21;
2253 count++;
2257 *rdata_len = PTR_DIFF(p,*rdata);
2259 SSVAL(*rparam,4,count); /* is this right?? */
2260 SSVAL(*rparam,6,count); /* is this right?? */
2262 ret = True;
2264 done:
2265 unbecome_root(); /* END ROOT BLOCK */
2267 TALLOC_FREE(mem_ctx);
2269 return ret;
2272 /*******************************************************************
2273 Get all users.
2274 ******************************************************************/
2276 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2277 char *param, int tpscnt,
2278 char *data, int tdscnt,
2279 int mdrcnt,int mprcnt,
2280 char **rdata,char **rparam,
2281 int *rdata_len,int *rparam_len)
2283 int count_sent=0;
2284 int num_users=0;
2285 int errflags=0;
2286 int i, resume_context, cli_buf_size;
2287 struct pdb_search *search;
2288 struct samr_displayentry *users;
2290 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2291 char *str2 = skip_string(param,tpscnt,str1);
2292 char *p = skip_string(param,tpscnt,str2);
2293 char *endp = NULL;
2295 if (!str1 || !str2 || !p) {
2296 return False;
2299 if (strcmp(str1,"WrLeh") != 0)
2300 return False;
2301 /* parameters
2302 * W-> resume context (number of users to skip)
2303 * r -> return parameter pointer to receive buffer
2304 * L -> length of receive buffer
2305 * e -> return parameter number of entries
2306 * h -> return parameter total number of users
2309 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2310 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2311 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2312 resume_context, cli_buf_size));
2314 *rparam_len = 8;
2315 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2316 if (!*rparam) {
2317 return False;
2320 /* check it's a supported varient */
2321 if (strcmp("B21",str2) != 0)
2322 return False;
2324 *rdata_len = cli_buf_size;
2325 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2326 if (!*rdata) {
2327 return False;
2330 p = *rdata;
2331 endp = *rdata + *rdata_len;
2333 become_root();
2334 search = pdb_search_users(ACB_NORMAL);
2335 unbecome_root();
2336 if (search == NULL) {
2337 DEBUG(0, ("api_RNetUserEnum:unable to open sam database.\n"));
2338 return False;
2341 become_root();
2342 num_users = pdb_search_entries(search, resume_context, 0xffffffff,
2343 &users);
2344 unbecome_root();
2346 errflags=NERR_Success;
2348 for (i=0; i<num_users; i++) {
2349 const char *name = users[i].account_name;
2351 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)&&(strlen(name)<=21)) {
2352 strlcpy(p,name,PTR_DIFF(endp,p));
2353 DEBUG(10,("api_RNetUserEnum:adding entry %d username "
2354 "%s\n",count_sent,p));
2355 p += 21;
2356 count_sent++;
2357 } else {
2358 /* set overflow error */
2359 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2360 "username %s\n",count_sent,name));
2361 errflags=234;
2362 break;
2366 pdb_search_destroy(search);
2368 *rdata_len = PTR_DIFF(p,*rdata);
2370 SSVAL(*rparam,0,errflags);
2371 SSVAL(*rparam,2,0); /* converter word */
2372 SSVAL(*rparam,4,count_sent); /* is this right?? */
2373 SSVAL(*rparam,6,num_users); /* is this right?? */
2375 return True;
2378 /****************************************************************************
2379 Get the time of day info.
2380 ****************************************************************************/
2382 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2383 char *param, int tpscnt,
2384 char *data, int tdscnt,
2385 int mdrcnt,int mprcnt,
2386 char **rdata,char **rparam,
2387 int *rdata_len,int *rparam_len)
2389 struct tm *t;
2390 time_t unixdate = time(NULL);
2391 char *p;
2393 *rparam_len = 4;
2394 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2395 if (!*rparam) {
2396 return False;
2399 *rdata_len = 21;
2400 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2401 if (!*rdata) {
2402 return False;
2405 SSVAL(*rparam,0,NERR_Success);
2406 SSVAL(*rparam,2,0); /* converter word */
2408 p = *rdata;
2410 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2411 by NT in a "net time" operation,
2412 it seems to ignore the one below */
2414 /* the client expects to get localtime, not GMT, in this bit
2415 (I think, this needs testing) */
2416 t = localtime(&unixdate);
2417 if (!t) {
2418 return False;
2421 SIVAL(p,4,0); /* msecs ? */
2422 SCVAL(p,8,t->tm_hour);
2423 SCVAL(p,9,t->tm_min);
2424 SCVAL(p,10,t->tm_sec);
2425 SCVAL(p,11,0); /* hundredths of seconds */
2426 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2427 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2428 SCVAL(p,16,t->tm_mday);
2429 SCVAL(p,17,t->tm_mon + 1);
2430 SSVAL(p,18,1900+t->tm_year);
2431 SCVAL(p,20,t->tm_wday);
2433 return True;
2436 /****************************************************************************
2437 Set the user password.
2438 *****************************************************************************/
2440 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2441 char *param, int tpscnt,
2442 char *data, int tdscnt,
2443 int mdrcnt,int mprcnt,
2444 char **rdata,char **rparam,
2445 int *rdata_len,int *rparam_len)
2447 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2448 char *p = NULL;
2449 fstring user;
2450 fstring pass1,pass2;
2452 /* Skip 2 strings. */
2453 p = skip_string(param,tpscnt,np);
2454 p = skip_string(param,tpscnt,p);
2456 if (!np || !p) {
2457 return False;
2460 /* Do we have a string ? */
2461 if (skip_string(param,tpscnt,p) == NULL) {
2462 return False;
2464 pull_ascii_fstring(user,p);
2466 p = skip_string(param,tpscnt,p);
2467 if (!p) {
2468 return False;
2471 memset(pass1,'\0',sizeof(pass1));
2472 memset(pass2,'\0',sizeof(pass2));
2474 * We use 31 here not 32 as we're checking
2475 * the last byte we want to access is safe.
2477 if (!is_offset_safe(param,tpscnt,p,31)) {
2478 return False;
2480 memcpy(pass1,p,16);
2481 memcpy(pass2,p+16,16);
2483 *rparam_len = 4;
2484 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2485 if (!*rparam) {
2486 return False;
2489 *rdata_len = 0;
2491 SSVAL(*rparam,0,NERR_badpass);
2492 SSVAL(*rparam,2,0); /* converter word */
2494 DEBUG(3,("Set password for <%s>\n",user));
2497 * Attempt to verify the old password against smbpasswd entries
2498 * Win98 clients send old and new password in plaintext for this call.
2502 auth_serversupplied_info *server_info = NULL;
2503 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2505 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2507 become_root();
2508 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2509 SSVAL(*rparam,0,NERR_Success);
2511 unbecome_root();
2513 TALLOC_FREE(server_info);
2515 data_blob_clear_free(&password);
2519 * If the plaintext change failed, attempt
2520 * the old encrypted method. NT will generate this
2521 * after trying the samr method. Note that this
2522 * method is done as a last resort as this
2523 * password change method loses the NT password hash
2524 * and cannot change the UNIX password as no plaintext
2525 * is received.
2528 if(SVAL(*rparam,0) != NERR_Success) {
2529 struct samu *hnd = NULL;
2531 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2532 become_root();
2533 if (change_lanman_password(hnd,(uchar *)pass2)) {
2534 SSVAL(*rparam,0,NERR_Success);
2536 unbecome_root();
2537 TALLOC_FREE(hnd);
2541 memset((char *)pass1,'\0',sizeof(fstring));
2542 memset((char *)pass2,'\0',sizeof(fstring));
2544 return(True);
2547 /****************************************************************************
2548 Set the user password (SamOEM version - gets plaintext).
2549 ****************************************************************************/
2551 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2552 char *param, int tpscnt,
2553 char *data, int tdscnt,
2554 int mdrcnt,int mprcnt,
2555 char **rdata,char **rparam,
2556 int *rdata_len,int *rparam_len)
2558 fstring user;
2559 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2560 *rparam_len = 2;
2561 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2562 if (!*rparam) {
2563 return False;
2566 if (!p) {
2567 return False;
2569 *rdata_len = 0;
2571 SSVAL(*rparam,0,NERR_badpass);
2574 * Check the parameter definition is correct.
2577 /* Do we have a string ? */
2578 if (skip_string(param,tpscnt,p) == 0) {
2579 return False;
2581 if(!strequal(p, "zsT")) {
2582 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2583 return False;
2585 p = skip_string(param, tpscnt, p);
2586 if (!p) {
2587 return False;
2590 /* Do we have a string ? */
2591 if (skip_string(param,tpscnt,p) == 0) {
2592 return False;
2594 if(!strequal(p, "B516B16")) {
2595 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2596 return False;
2598 p = skip_string(param,tpscnt,p);
2599 if (!p) {
2600 return False;
2602 /* Do we have a string ? */
2603 if (skip_string(param,tpscnt,p) == 0) {
2604 return False;
2606 p += pull_ascii_fstring(user,p);
2608 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2611 * Pass the user through the NT -> unix user mapping
2612 * function.
2615 (void)map_username(user);
2617 if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2618 SSVAL(*rparam,0,NERR_Success);
2621 return(True);
2624 /****************************************************************************
2625 delete a print job
2626 Form: <W> <>
2627 ****************************************************************************/
2629 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
2630 char *param, int tpscnt,
2631 char *data, int tdscnt,
2632 int mdrcnt,int mprcnt,
2633 char **rdata,char **rparam,
2634 int *rdata_len,int *rparam_len)
2636 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2637 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2638 char *str2 = skip_string(param,tpscnt,str1);
2639 char *p = skip_string(param,tpscnt,str2);
2640 uint32 jobid;
2641 int snum;
2642 fstring sharename;
2643 int errcode;
2644 WERROR werr = WERR_OK;
2646 if (!str1 || !str2 || !p) {
2647 return False;
2650 * We use 1 here not 2 as we're checking
2651 * the last byte we want to access is safe.
2653 if (!is_offset_safe(param,tpscnt,p,1)) {
2654 return False;
2656 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2657 return False;
2659 /* check it's a supported varient */
2660 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2661 return(False);
2663 *rparam_len = 4;
2664 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2665 if (!*rparam) {
2666 return False;
2668 *rdata_len = 0;
2670 if (!print_job_exists(sharename, jobid)) {
2671 errcode = NERR_JobNotFound;
2672 goto out;
2675 snum = lp_servicenumber( sharename);
2676 if (snum == -1) {
2677 errcode = NERR_DestNotFound;
2678 goto out;
2681 errcode = NERR_notsupported;
2683 switch (function) {
2684 case 81: /* delete */
2685 if (print_job_delete(&current_user, snum, jobid, &werr))
2686 errcode = NERR_Success;
2687 break;
2688 case 82: /* pause */
2689 if (print_job_pause(&current_user, snum, jobid, &werr))
2690 errcode = NERR_Success;
2691 break;
2692 case 83: /* resume */
2693 if (print_job_resume(&current_user, snum, jobid, &werr))
2694 errcode = NERR_Success;
2695 break;
2698 if (!W_ERROR_IS_OK(werr))
2699 errcode = W_ERROR_V(werr);
2701 out:
2702 SSVAL(*rparam,0,errcode);
2703 SSVAL(*rparam,2,0); /* converter word */
2705 return(True);
2708 /****************************************************************************
2709 Purge a print queue - or pause or resume it.
2710 ****************************************************************************/
2712 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
2713 char *param, int tpscnt,
2714 char *data, int tdscnt,
2715 int mdrcnt,int mprcnt,
2716 char **rdata,char **rparam,
2717 int *rdata_len,int *rparam_len)
2719 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2720 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2721 char *str2 = skip_string(param,tpscnt,str1);
2722 char *QueueName = skip_string(param,tpscnt,str2);
2723 int errcode = NERR_notsupported;
2724 int snum;
2725 WERROR werr = WERR_OK;
2727 if (!str1 || !str2 || !QueueName) {
2728 return False;
2731 /* check it's a supported varient */
2732 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
2733 return(False);
2735 *rparam_len = 4;
2736 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2737 if (!*rparam) {
2738 return False;
2740 *rdata_len = 0;
2742 if (skip_string(param,tpscnt,QueueName) == NULL) {
2743 return False;
2745 snum = print_queue_snum(QueueName);
2747 if (snum == -1) {
2748 errcode = NERR_JobNotFound;
2749 goto out;
2752 switch (function) {
2753 case 74: /* Pause queue */
2754 if (print_queue_pause(&current_user, snum, &werr)) errcode = NERR_Success;
2755 break;
2756 case 75: /* Resume queue */
2757 if (print_queue_resume(&current_user, snum, &werr)) errcode = NERR_Success;
2758 break;
2759 case 103: /* Purge */
2760 if (print_queue_purge(&current_user, snum, &werr)) errcode = NERR_Success;
2761 break;
2764 if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr);
2766 out:
2767 SSVAL(*rparam,0,errcode);
2768 SSVAL(*rparam,2,0); /* converter word */
2770 return(True);
2773 /****************************************************************************
2774 set the property of a print job (undocumented?)
2775 ? function = 0xb -> set name of print job
2776 ? function = 0x6 -> move print job up/down
2777 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
2778 or <WWsTP> <WB21BB16B10zWWzDDz>
2779 ****************************************************************************/
2781 static int check_printjob_info(struct pack_desc* desc,
2782 int uLevel, char* id)
2784 desc->subformat = NULL;
2785 switch( uLevel ) {
2786 case 0: desc->format = "W"; break;
2787 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2788 case 2: desc->format = "WWzWWDDzz"; break;
2789 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2790 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2791 default:
2792 DEBUG(0,("check_printjob_info: invalid level %d\n",
2793 uLevel ));
2794 return False;
2796 if (id == NULL || strcmp(desc->format,id) != 0) {
2797 DEBUG(0,("check_printjob_info: invalid format %s\n",
2798 id ? id : "<NULL>" ));
2799 return False;
2801 return True;
2804 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
2805 char *param, int tpscnt,
2806 char *data, int tdscnt,
2807 int mdrcnt,int mprcnt,
2808 char **rdata,char **rparam,
2809 int *rdata_len,int *rparam_len)
2811 struct pack_desc desc;
2812 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2813 char *str2 = skip_string(param,tpscnt,str1);
2814 char *p = skip_string(param,tpscnt,str2);
2815 uint32 jobid;
2816 fstring sharename;
2817 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
2818 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
2819 int place, errcode;
2821 if (!str1 || !str2 || !p) {
2822 return False;
2825 * We use 1 here not 2 as we're checking
2826 * the last byte we want to access is safe.
2828 if (!is_offset_safe(param,tpscnt,p,1)) {
2829 return False;
2831 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2832 return False;
2833 *rparam_len = 4;
2834 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2835 if (!*rparam) {
2836 return False;
2839 if (!share_defined(sharename)) {
2840 DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
2841 sharename));
2842 return False;
2845 *rdata_len = 0;
2847 /* check it's a supported varient */
2848 if ((strcmp(str1,"WWsTP")) ||
2849 (!check_printjob_info(&desc,uLevel,str2)))
2850 return(False);
2852 if (!print_job_exists(sharename, jobid)) {
2853 errcode=NERR_JobNotFound;
2854 goto out;
2857 errcode = NERR_notsupported;
2859 switch (function) {
2860 case 0x6:
2861 /* change job place in the queue,
2862 data gives the new place */
2863 place = SVAL(data,0);
2864 if (print_job_set_place(sharename, jobid, place)) {
2865 errcode=NERR_Success;
2867 break;
2869 case 0xb:
2870 /* change print job name, data gives the name */
2871 if (print_job_set_name(sharename, jobid, data)) {
2872 errcode=NERR_Success;
2874 break;
2876 default:
2877 return False;
2880 out:
2881 SSVALS(*rparam,0,errcode);
2882 SSVAL(*rparam,2,0); /* converter word */
2884 return(True);
2888 /****************************************************************************
2889 Get info about the server.
2890 ****************************************************************************/
2892 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
2893 char *param, int tpscnt,
2894 char *data, int tdscnt,
2895 int mdrcnt,int mprcnt,
2896 char **rdata,char **rparam,
2897 int *rdata_len,int *rparam_len)
2899 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2900 char *str2 = skip_string(param,tpscnt,str1);
2901 char *p = skip_string(param,tpscnt,str2);
2902 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2903 char *p2;
2904 int struct_len;
2906 if (!str1 || !str2 || !p) {
2907 return False;
2910 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2912 /* check it's a supported varient */
2913 if (!prefix_ok(str1,"WrLh")) {
2914 return False;
2917 switch( uLevel ) {
2918 case 0:
2919 if (strcmp(str2,"B16") != 0) {
2920 return False;
2922 struct_len = 16;
2923 break;
2924 case 1:
2925 if (strcmp(str2,"B16BBDz") != 0) {
2926 return False;
2928 struct_len = 26;
2929 break;
2930 case 2:
2931 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
2932 return False;
2934 struct_len = 134;
2935 break;
2936 case 3:
2937 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
2938 return False;
2940 struct_len = 144;
2941 break;
2942 case 20:
2943 if (strcmp(str2,"DN") != 0) {
2944 return False;
2946 struct_len = 6;
2947 break;
2948 case 50:
2949 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
2950 return False;
2952 struct_len = 42;
2953 break;
2954 default:
2955 return False;
2958 *rdata_len = mdrcnt;
2959 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2960 if (!*rdata) {
2961 return False;
2964 p = *rdata;
2965 p2 = p + struct_len;
2966 if (uLevel != 20) {
2967 srvstr_push(NULL, 0, p,global_myname(),16,
2968 STR_ASCII|STR_UPPER|STR_TERMINATE);
2970 p += 16;
2971 if (uLevel > 0) {
2972 struct srv_info_struct *servers=NULL;
2973 int i,count;
2974 char *comment = NULL;
2975 TALLOC_CTX *ctx = talloc_tos();
2976 uint32 servertype= lp_default_server_announce();
2978 comment = talloc_strdup(ctx,lp_serverstring());
2979 if (!comment) {
2980 return false;
2983 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
2984 for (i=0;i<count;i++) {
2985 if (strequal(servers[i].name,global_myname())) {
2986 servertype = servers[i].type;
2987 TALLOC_FREE(comment);
2988 comment = talloc_strdup(ctx,
2989 servers[i].comment);
2990 if (comment) {
2991 return false;
2997 SAFE_FREE(servers);
2999 SCVAL(p,0,lp_major_announce_version());
3000 SCVAL(p,1,lp_minor_announce_version());
3001 SIVAL(p,2,servertype);
3003 if (mdrcnt == struct_len) {
3004 SIVAL(p,6,0);
3005 } else {
3006 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3007 comment = talloc_sub_advanced(
3008 ctx,
3009 lp_servicename(SNUM(conn)),
3010 conn->server_info->unix_name,
3011 conn->connectpath,
3012 conn->server_info->gid,
3013 conn->server_info->sanitized_username,
3014 pdb_get_domain(conn->server_info->sam_account),
3015 comment);
3016 if (comment) {
3017 return false;
3019 if (mdrcnt - struct_len <= 0) {
3020 return false;
3022 push_ascii(p2,
3023 comment,
3024 MIN(mdrcnt - struct_len,
3025 MAX_SERVER_STRING_LENGTH),
3026 STR_TERMINATE);
3027 p2 = skip_string(*rdata,*rdata_len,p2);
3028 if (!p2) {
3029 return False;
3034 if (uLevel > 1) {
3035 return False; /* not yet implemented */
3038 *rdata_len = PTR_DIFF(p2,*rdata);
3040 *rparam_len = 6;
3041 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3042 if (!*rparam) {
3043 return False;
3045 SSVAL(*rparam,0,NERR_Success);
3046 SSVAL(*rparam,2,0); /* converter word */
3047 SSVAL(*rparam,4,*rdata_len);
3049 return True;
3052 /****************************************************************************
3053 Get info about the server.
3054 ****************************************************************************/
3056 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3057 char *param, int tpscnt,
3058 char *data, int tdscnt,
3059 int mdrcnt,int mprcnt,
3060 char **rdata,char **rparam,
3061 int *rdata_len,int *rparam_len)
3063 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3064 char *str2 = skip_string(param,tpscnt,str1);
3065 char *p = skip_string(param,tpscnt,str2);
3066 char *p2;
3067 char *endp;
3068 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3070 if (!str1 || !str2 || !p) {
3071 return False;
3074 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3076 *rparam_len = 6;
3077 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3078 if (!*rparam) {
3079 return False;
3082 /* check it's a supported varient */
3083 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3084 return False;
3087 *rdata_len = mdrcnt + 1024;
3088 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3089 if (!*rdata) {
3090 return False;
3093 SSVAL(*rparam,0,NERR_Success);
3094 SSVAL(*rparam,2,0); /* converter word */
3096 p = *rdata;
3097 endp = *rdata + *rdata_len;
3099 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3100 if (!p2) {
3101 return False;
3104 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3105 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3106 strupper_m(p2);
3107 p2 = skip_string(*rdata,*rdata_len,p2);
3108 if (!p2) {
3109 return False;
3111 p += 4;
3113 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3114 strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3115 p2 = skip_string(*rdata,*rdata_len,p2);
3116 if (!p2) {
3117 return False;
3119 p += 4;
3121 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3122 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3123 strupper_m(p2);
3124 p2 = skip_string(*rdata,*rdata_len,p2);
3125 if (!p2) {
3126 return False;
3128 p += 4;
3130 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3131 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3132 p += 2;
3134 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3135 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3136 p2 = skip_string(*rdata,*rdata_len,p2);
3137 if (!p2) {
3138 return False;
3140 p += 4;
3142 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3143 strlcpy(p2,"",PTR_DIFF(endp,p2));
3144 p2 = skip_string(*rdata,*rdata_len,p2);
3145 if (!p2) {
3146 return False;
3148 p += 4;
3150 *rdata_len = PTR_DIFF(p2,*rdata);
3152 SSVAL(*rparam,4,*rdata_len);
3154 return True;
3157 /****************************************************************************
3158 get info about a user
3160 struct user_info_11 {
3161 char usri11_name[21]; 0-20
3162 char usri11_pad; 21
3163 char *usri11_comment; 22-25
3164 char *usri11_usr_comment; 26-29
3165 unsigned short usri11_priv; 30-31
3166 unsigned long usri11_auth_flags; 32-35
3167 long usri11_password_age; 36-39
3168 char *usri11_homedir; 40-43
3169 char *usri11_parms; 44-47
3170 long usri11_last_logon; 48-51
3171 long usri11_last_logoff; 52-55
3172 unsigned short usri11_bad_pw_count; 56-57
3173 unsigned short usri11_num_logons; 58-59
3174 char *usri11_logon_server; 60-63
3175 unsigned short usri11_country_code; 64-65
3176 char *usri11_workstations; 66-69
3177 unsigned long usri11_max_storage; 70-73
3178 unsigned short usri11_units_per_week; 74-75
3179 unsigned char *usri11_logon_hours; 76-79
3180 unsigned short usri11_code_page; 80-81
3183 where:
3185 usri11_name specifies the user name for which information is retrieved
3187 usri11_pad aligns the next data structure element to a word boundary
3189 usri11_comment is a null terminated ASCII comment
3191 usri11_user_comment is a null terminated ASCII comment about the user
3193 usri11_priv specifies the level of the privilege assigned to the user.
3194 The possible values are:
3196 Name Value Description
3197 USER_PRIV_GUEST 0 Guest privilege
3198 USER_PRIV_USER 1 User privilege
3199 USER_PRV_ADMIN 2 Administrator privilege
3201 usri11_auth_flags specifies the account operator privileges. The
3202 possible values are:
3204 Name Value Description
3205 AF_OP_PRINT 0 Print operator
3208 Leach, Naik [Page 28]
3212 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3215 AF_OP_COMM 1 Communications operator
3216 AF_OP_SERVER 2 Server operator
3217 AF_OP_ACCOUNTS 3 Accounts operator
3220 usri11_password_age specifies how many seconds have elapsed since the
3221 password was last changed.
3223 usri11_home_dir points to a null terminated ASCII string that contains
3224 the path name of the user's home directory.
3226 usri11_parms points to a null terminated ASCII string that is set
3227 aside for use by applications.
3229 usri11_last_logon specifies the time when the user last logged on.
3230 This value is stored as the number of seconds elapsed since
3231 00:00:00, January 1, 1970.
3233 usri11_last_logoff specifies the time when the user last logged off.
3234 This value is stored as the number of seconds elapsed since
3235 00:00:00, January 1, 1970. A value of 0 means the last logoff
3236 time is unknown.
3238 usri11_bad_pw_count specifies the number of incorrect passwords
3239 entered since the last successful logon.
3241 usri11_log1_num_logons specifies the number of times this user has
3242 logged on. A value of -1 means the number of logons is unknown.
3244 usri11_logon_server points to a null terminated ASCII string that
3245 contains the name of the server to which logon requests are sent.
3246 A null string indicates logon requests should be sent to the
3247 domain controller.
3249 usri11_country_code specifies the country code for the user's language
3250 of choice.
3252 usri11_workstations points to a null terminated ASCII string that
3253 contains the names of workstations the user may log on from.
3254 There may be up to 8 workstations, with the names separated by
3255 commas. A null strings indicates there are no restrictions.
3257 usri11_max_storage specifies the maximum amount of disk space the user
3258 can occupy. A value of 0xffffffff indicates there are no
3259 restrictions.
3261 usri11_units_per_week specifies the equal number of time units into
3262 which a week is divided. This value must be equal to 168.
3264 usri11_logon_hours points to a 21 byte (168 bits) string that
3265 specifies the time during which the user can log on. Each bit
3266 represents one unique hour in a week. The first bit (bit 0, word
3267 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3271 Leach, Naik [Page 29]
3275 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3278 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3279 are no restrictions.
3281 usri11_code_page specifies the code page for the user's language of
3282 choice
3284 All of the pointers in this data structure need to be treated
3285 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3286 to be ignored. The converter word returned in the parameters section
3287 needs to be subtracted from the lower 16 bits to calculate an offset
3288 into the return buffer where this ASCII string resides.
3290 There is no auxiliary data in the response.
3292 ****************************************************************************/
3294 #define usri11_name 0
3295 #define usri11_pad 21
3296 #define usri11_comment 22
3297 #define usri11_usr_comment 26
3298 #define usri11_full_name 30
3299 #define usri11_priv 34
3300 #define usri11_auth_flags 36
3301 #define usri11_password_age 40
3302 #define usri11_homedir 44
3303 #define usri11_parms 48
3304 #define usri11_last_logon 52
3305 #define usri11_last_logoff 56
3306 #define usri11_bad_pw_count 60
3307 #define usri11_num_logons 62
3308 #define usri11_logon_server 64
3309 #define usri11_country_code 68
3310 #define usri11_workstations 70
3311 #define usri11_max_storage 74
3312 #define usri11_units_per_week 78
3313 #define usri11_logon_hours 80
3314 #define usri11_code_page 84
3315 #define usri11_end 86
3317 #define USER_PRIV_GUEST 0
3318 #define USER_PRIV_USER 1
3319 #define USER_PRIV_ADMIN 2
3321 #define AF_OP_PRINT 0
3322 #define AF_OP_COMM 1
3323 #define AF_OP_SERVER 2
3324 #define AF_OP_ACCOUNTS 3
3327 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3328 char *param, int tpscnt,
3329 char *data, int tdscnt,
3330 int mdrcnt,int mprcnt,
3331 char **rdata,char **rparam,
3332 int *rdata_len,int *rparam_len)
3334 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3335 char *str2 = skip_string(param,tpscnt,str1);
3336 char *UserName = skip_string(param,tpscnt,str2);
3337 char *p = skip_string(param,tpscnt,UserName);
3338 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3339 char *p2;
3340 char *endp;
3341 const char *level_string;
3343 /* get NIS home of a previously validated user - simeon */
3344 /* With share level security vuid will always be zero.
3345 Don't depend on vuser being non-null !!. JRA */
3346 user_struct *vuser = get_valid_user_struct(vuid);
3347 if(vuser != NULL) {
3348 DEBUG(3,(" Username of UID %d is %s\n",
3349 (int)vuser->server_info->uid,
3350 vuser->server_info->unix_name));
3353 if (!str1 || !str2 || !UserName || !p) {
3354 return False;
3357 *rparam_len = 6;
3358 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3359 if (!*rparam) {
3360 return False;
3363 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3365 /* check it's a supported variant */
3366 if (strcmp(str1,"zWrLh") != 0) {
3367 return False;
3369 switch( uLevel ) {
3370 case 0: level_string = "B21"; break;
3371 case 1: level_string = "B21BB16DWzzWz"; break;
3372 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3373 case 10: level_string = "B21Bzzz"; break;
3374 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3375 default: return False;
3378 if (strcmp(level_string,str2) != 0) {
3379 return False;
3382 *rdata_len = mdrcnt + 1024;
3383 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3384 if (!*rdata) {
3385 return False;
3388 SSVAL(*rparam,0,NERR_Success);
3389 SSVAL(*rparam,2,0); /* converter word */
3391 p = *rdata;
3392 endp = *rdata + *rdata_len;
3393 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3394 if (!p2) {
3395 return False;
3398 memset(p,0,21);
3399 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3401 if (uLevel > 0) {
3402 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3403 *p2 = 0;
3406 if (uLevel >= 10) {
3407 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3408 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
3409 p2 = skip_string(*rdata,*rdata_len,p2);
3410 if (!p2) {
3411 return False;
3414 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3415 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
3416 p2 = skip_string(*rdata,*rdata_len,p2);
3417 if (!p2) {
3418 return False;
3421 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3422 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3423 strlcpy(p2,((vuser != NULL)
3424 ? pdb_get_fullname(vuser->server_info->sam_account)
3425 : UserName),PTR_DIFF(endp,p2));
3426 p2 = skip_string(*rdata,*rdata_len,p2);
3427 if (!p2) {
3428 return False;
3432 if (uLevel == 11) {
3433 const char *homedir = "";
3434 if (vuser != NULL) {
3435 homedir = pdb_get_homedir(
3436 vuser->server_info->sam_account);
3438 /* modelled after NTAS 3.51 reply */
3439 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3440 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
3441 SIVALS(p,usri11_password_age,-1); /* password age */
3442 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3443 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
3444 p2 = skip_string(*rdata,*rdata_len,p2);
3445 if (!p2) {
3446 return False;
3448 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3449 strlcpy(p2,"",PTR_DIFF(endp,p2));
3450 p2 = skip_string(*rdata,*rdata_len,p2);
3451 if (!p2) {
3452 return False;
3454 SIVAL(p,usri11_last_logon,0); /* last logon */
3455 SIVAL(p,usri11_last_logoff,0); /* last logoff */
3456 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
3457 SSVALS(p,usri11_num_logons,-1); /* num logons */
3458 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3459 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
3460 p2 = skip_string(*rdata,*rdata_len,p2);
3461 if (!p2) {
3462 return False;
3464 SSVAL(p,usri11_country_code,0); /* country code */
3466 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3467 strlcpy(p2,"",PTR_DIFF(endp,p2));
3468 p2 = skip_string(*rdata,*rdata_len,p2);
3469 if (!p2) {
3470 return False;
3473 SIVALS(p,usri11_max_storage,-1); /* max storage */
3474 SSVAL(p,usri11_units_per_week,168); /* units per week */
3475 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
3477 /* a simple way to get logon hours at all times. */
3478 memset(p2,0xff,21);
3479 SCVAL(p2,21,0); /* fix zero termination */
3480 p2 = skip_string(*rdata,*rdata_len,p2);
3481 if (!p2) {
3482 return False;
3485 SSVAL(p,usri11_code_page,0); /* code page */
3488 if (uLevel == 1 || uLevel == 2) {
3489 memset(p+22,' ',16); /* password */
3490 SIVALS(p,38,-1); /* password age */
3491 SSVAL(p,42,
3492 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3493 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
3494 strlcpy(p2, vuser ? pdb_get_homedir(
3495 vuser->server_info->sam_account) : "",
3496 PTR_DIFF(endp,p2));
3497 p2 = skip_string(*rdata,*rdata_len,p2);
3498 if (!p2) {
3499 return False;
3501 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
3502 *p2++ = 0;
3503 SSVAL(p,52,0); /* flags */
3504 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
3505 strlcpy(p2, vuser ? pdb_get_logon_script(
3506 vuser->server_info->sam_account) : "",
3507 PTR_DIFF(endp,p2));
3508 p2 = skip_string(*rdata,*rdata_len,p2);
3509 if (!p2) {
3510 return False;
3512 if (uLevel == 2) {
3513 SIVAL(p,60,0); /* auth_flags */
3514 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
3515 strlcpy(p2,((vuser != NULL)
3516 ? pdb_get_fullname(vuser->server_info->sam_account)
3517 : UserName),PTR_DIFF(endp,p2));
3518 p2 = skip_string(*rdata,*rdata_len,p2);
3519 if (!p2) {
3520 return False;
3522 SIVAL(p,68,0); /* urs_comment */
3523 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
3524 strlcpy(p2,"",PTR_DIFF(endp,p2));
3525 p2 = skip_string(*rdata,*rdata_len,p2);
3526 if (!p2) {
3527 return False;
3529 SIVAL(p,76,0); /* workstations */
3530 SIVAL(p,80,0); /* last_logon */
3531 SIVAL(p,84,0); /* last_logoff */
3532 SIVALS(p,88,-1); /* acct_expires */
3533 SIVALS(p,92,-1); /* max_storage */
3534 SSVAL(p,96,168); /* units_per_week */
3535 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
3536 memset(p2,-1,21);
3537 p2 += 21;
3538 SSVALS(p,102,-1); /* bad_pw_count */
3539 SSVALS(p,104,-1); /* num_logons */
3540 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
3542 TALLOC_CTX *ctx = talloc_tos();
3543 int space_rem = *rdata_len - (p2 - *rdata);
3544 char *tmp;
3546 if (space_rem <= 0) {
3547 return false;
3549 tmp = talloc_strdup(ctx, "\\\\%L");
3550 if (!tmp) {
3551 return false;
3553 tmp = talloc_sub_basic(ctx,
3556 tmp);
3557 if (!tmp) {
3558 return false;
3561 push_ascii(p2,
3562 tmp,
3563 space_rem,
3564 STR_TERMINATE);
3566 p2 = skip_string(*rdata,*rdata_len,p2);
3567 if (!p2) {
3568 return False;
3570 SSVAL(p,110,49); /* country_code */
3571 SSVAL(p,112,860); /* code page */
3575 *rdata_len = PTR_DIFF(p2,*rdata);
3577 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
3579 return(True);
3582 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
3583 char *param, int tpscnt,
3584 char *data, int tdscnt,
3585 int mdrcnt,int mprcnt,
3586 char **rdata,char **rparam,
3587 int *rdata_len,int *rparam_len)
3589 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3590 char *str2 = skip_string(param,tpscnt,str1);
3591 char *p = skip_string(param,tpscnt,str2);
3592 int uLevel;
3593 struct pack_desc desc;
3594 char* name;
3595 /* With share level security vuid will always be zero.
3596 Don't depend on vuser being non-null !!. JRA */
3597 user_struct *vuser = get_valid_user_struct(vuid);
3599 if (!str1 || !str2 || !p) {
3600 return False;
3603 if(vuser != NULL) {
3604 DEBUG(3,(" Username of UID %d is %s\n",
3605 (int)vuser->server_info->uid,
3606 vuser->server_info->unix_name));
3609 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3610 name = get_safe_str_ptr(param,tpscnt,p,2);
3611 if (!name) {
3612 return False;
3615 memset((char *)&desc,'\0',sizeof(desc));
3617 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
3619 /* check it's a supported varient */
3620 if (strcmp(str1,"OOWb54WrLh") != 0) {
3621 return False;
3623 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
3624 return False;
3626 if (mdrcnt > 0) {
3627 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3628 if (!*rdata) {
3629 return False;
3633 desc.base = *rdata;
3634 desc.buflen = mdrcnt;
3635 desc.subformat = NULL;
3636 desc.format = str2;
3638 if (init_package(&desc,1,0)) {
3639 PACKI(&desc,"W",0); /* code */
3640 PACKS(&desc,"B21",name); /* eff. name */
3641 PACKS(&desc,"B",""); /* pad */
3642 PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3643 PACKI(&desc,"D",0); /* auth flags XXX */
3644 PACKI(&desc,"W",0); /* num logons */
3645 PACKI(&desc,"W",0); /* bad pw count */
3646 PACKI(&desc,"D",0); /* last logon */
3647 PACKI(&desc,"D",-1); /* last logoff */
3648 PACKI(&desc,"D",-1); /* logoff time */
3649 PACKI(&desc,"D",-1); /* kickoff time */
3650 PACKI(&desc,"D",0); /* password age */
3651 PACKI(&desc,"D",0); /* password can change */
3652 PACKI(&desc,"D",-1); /* password must change */
3655 fstring mypath;
3656 fstrcpy(mypath,"\\\\");
3657 fstrcat(mypath,get_local_machine_name());
3658 strupper_m(mypath);
3659 PACKS(&desc,"z",mypath); /* computer */
3662 PACKS(&desc,"z",lp_workgroup());/* domain */
3663 PACKS(&desc,"z", vuser ? pdb_get_logon_script(
3664 vuser->server_info->sam_account) : ""); /* script path */
3665 PACKI(&desc,"D",0x00000000); /* reserved */
3668 *rdata_len = desc.usedlen;
3669 *rparam_len = 6;
3670 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3671 if (!*rparam) {
3672 return False;
3674 SSVALS(*rparam,0,desc.errcode);
3675 SSVAL(*rparam,2,0);
3676 SSVAL(*rparam,4,desc.neededlen);
3678 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
3680 return True;
3683 /****************************************************************************
3684 api_WAccessGetUserPerms
3685 ****************************************************************************/
3687 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
3688 char *param, int tpscnt,
3689 char *data, int tdscnt,
3690 int mdrcnt,int mprcnt,
3691 char **rdata,char **rparam,
3692 int *rdata_len,int *rparam_len)
3694 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3695 char *str2 = skip_string(param,tpscnt,str1);
3696 char *user = skip_string(param,tpscnt,str2);
3697 char *resource = skip_string(param,tpscnt,user);
3699 if (!str1 || !str2 || !user || !resource) {
3700 return False;
3703 if (skip_string(param,tpscnt,resource) == NULL) {
3704 return False;
3706 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
3708 /* check it's a supported varient */
3709 if (strcmp(str1,"zzh") != 0) {
3710 return False;
3712 if (strcmp(str2,"") != 0) {
3713 return False;
3716 *rparam_len = 6;
3717 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3718 if (!*rparam) {
3719 return False;
3721 SSVALS(*rparam,0,0); /* errorcode */
3722 SSVAL(*rparam,2,0); /* converter word */
3723 SSVAL(*rparam,4,0x7f); /* permission flags */
3725 return True;
3728 /****************************************************************************
3729 api_WPrintJobEnumerate
3730 ****************************************************************************/
3732 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
3733 char *param, int tpscnt,
3734 char *data, int tdscnt,
3735 int mdrcnt,int mprcnt,
3736 char **rdata,char **rparam,
3737 int *rdata_len,int *rparam_len)
3739 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3740 char *str2 = skip_string(param,tpscnt,str1);
3741 char *p = skip_string(param,tpscnt,str2);
3742 int uLevel;
3743 int count;
3744 int i;
3745 int snum;
3746 fstring sharename;
3747 uint32 jobid;
3748 struct pack_desc desc;
3749 print_queue_struct *queue=NULL;
3750 print_status_struct status;
3751 char *tmpdata=NULL;
3753 if (!str1 || !str2 || !p) {
3754 return False;
3757 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3759 memset((char *)&desc,'\0',sizeof(desc));
3760 memset((char *)&status,'\0',sizeof(status));
3762 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
3764 /* check it's a supported varient */
3765 if (strcmp(str1,"WWrLh") != 0) {
3766 return False;
3768 if (!check_printjob_info(&desc,uLevel,str2)) {
3769 return False;
3772 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
3773 return False;
3776 snum = lp_servicenumber( sharename);
3777 if (snum < 0 || !VALID_SNUM(snum)) {
3778 return(False);
3781 count = print_queue_status(snum,&queue,&status);
3782 for (i = 0; i < count; i++) {
3783 if (queue[i].job == jobid) {
3784 break;
3788 if (mdrcnt > 0) {
3789 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3790 if (!*rdata) {
3791 return False;
3793 desc.base = *rdata;
3794 desc.buflen = mdrcnt;
3795 } else {
3797 * Don't return data but need to get correct length
3798 * init_package will return wrong size if buflen=0
3800 desc.buflen = getlen(desc.format);
3801 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3804 if (init_package(&desc,1,0)) {
3805 if (i < count) {
3806 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3807 *rdata_len = desc.usedlen;
3808 } else {
3809 desc.errcode = NERR_JobNotFound;
3810 *rdata_len = 0;
3814 *rparam_len = 6;
3815 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3816 if (!*rparam) {
3817 return False;
3819 SSVALS(*rparam,0,desc.errcode);
3820 SSVAL(*rparam,2,0);
3821 SSVAL(*rparam,4,desc.neededlen);
3823 SAFE_FREE(queue);
3824 SAFE_FREE(tmpdata);
3826 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
3828 return True;
3831 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
3832 char *param, int tpscnt,
3833 char *data, int tdscnt,
3834 int mdrcnt,int mprcnt,
3835 char **rdata,char **rparam,
3836 int *rdata_len,int *rparam_len)
3838 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3839 char *str2 = skip_string(param,tpscnt,str1);
3840 char *p = skip_string(param,tpscnt,str2);
3841 char *name = p;
3842 int uLevel;
3843 int count;
3844 int i, succnt=0;
3845 int snum;
3846 struct pack_desc desc;
3847 print_queue_struct *queue=NULL;
3848 print_status_struct status;
3850 if (!str1 || !str2 || !p) {
3851 return False;
3854 memset((char *)&desc,'\0',sizeof(desc));
3855 memset((char *)&status,'\0',sizeof(status));
3857 p = skip_string(param,tpscnt,p);
3858 if (!p) {
3859 return False;
3861 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3863 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
3865 /* check it's a supported variant */
3866 if (strcmp(str1,"zWrLeh") != 0) {
3867 return False;
3870 if (uLevel > 2) {
3871 return False; /* defined only for uLevel 0,1,2 */
3874 if (!check_printjob_info(&desc,uLevel,str2)) {
3875 return False;
3878 snum = find_service(name);
3879 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3880 return False;
3883 count = print_queue_status(snum,&queue,&status);
3884 if (mdrcnt > 0) {
3885 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3886 if (!*rdata) {
3887 return False;
3890 desc.base = *rdata;
3891 desc.buflen = mdrcnt;
3893 if (init_package(&desc,count,0)) {
3894 succnt = 0;
3895 for (i = 0; i < count; i++) {
3896 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3897 if (desc.errcode == NERR_Success) {
3898 succnt = i+1;
3903 *rdata_len = desc.usedlen;
3905 *rparam_len = 8;
3906 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3907 if (!*rparam) {
3908 return False;
3910 SSVALS(*rparam,0,desc.errcode);
3911 SSVAL(*rparam,2,0);
3912 SSVAL(*rparam,4,succnt);
3913 SSVAL(*rparam,6,count);
3915 SAFE_FREE(queue);
3917 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
3919 return True;
3922 static int check_printdest_info(struct pack_desc* desc,
3923 int uLevel, char* id)
3925 desc->subformat = NULL;
3926 switch( uLevel ) {
3927 case 0:
3928 desc->format = "B9";
3929 break;
3930 case 1:
3931 desc->format = "B9B21WWzW";
3932 break;
3933 case 2:
3934 desc->format = "z";
3935 break;
3936 case 3:
3937 desc->format = "zzzWWzzzWW";
3938 break;
3939 default:
3940 DEBUG(0,("check_printdest_info: invalid level %d\n",
3941 uLevel));
3942 return False;
3944 if (id == NULL || strcmp(desc->format,id) != 0) {
3945 DEBUG(0,("check_printdest_info: invalid string %s\n",
3946 id ? id : "<NULL>" ));
3947 return False;
3949 return True;
3952 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
3953 struct pack_desc* desc)
3955 char buf[100];
3957 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
3958 buf[sizeof(buf)-1] = 0;
3959 strupper_m(buf);
3961 if (uLevel <= 1) {
3962 PACKS(desc,"B9",buf); /* szName */
3963 if (uLevel == 1) {
3964 PACKS(desc,"B21",""); /* szUserName */
3965 PACKI(desc,"W",0); /* uJobId */
3966 PACKI(desc,"W",0); /* fsStatus */
3967 PACKS(desc,"z",""); /* pszStatus */
3968 PACKI(desc,"W",0); /* time */
3972 if (uLevel == 2 || uLevel == 3) {
3973 PACKS(desc,"z",buf); /* pszPrinterName */
3974 if (uLevel == 3) {
3975 PACKS(desc,"z",""); /* pszUserName */
3976 PACKS(desc,"z",""); /* pszLogAddr */
3977 PACKI(desc,"W",0); /* uJobId */
3978 PACKI(desc,"W",0); /* fsStatus */
3979 PACKS(desc,"z",""); /* pszStatus */
3980 PACKS(desc,"z",""); /* pszComment */
3981 PACKS(desc,"z","NULL"); /* pszDrivers */
3982 PACKI(desc,"W",0); /* time */
3983 PACKI(desc,"W",0); /* pad1 */
3988 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
3989 char *param, int tpscnt,
3990 char *data, int tdscnt,
3991 int mdrcnt,int mprcnt,
3992 char **rdata,char **rparam,
3993 int *rdata_len,int *rparam_len)
3995 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3996 char *str2 = skip_string(param,tpscnt,str1);
3997 char *p = skip_string(param,tpscnt,str2);
3998 char* PrinterName = p;
3999 int uLevel;
4000 struct pack_desc desc;
4001 int snum;
4002 char *tmpdata=NULL;
4004 if (!str1 || !str2 || !p) {
4005 return False;
4008 memset((char *)&desc,'\0',sizeof(desc));
4010 p = skip_string(param,tpscnt,p);
4011 if (!p) {
4012 return False;
4014 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4016 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4018 /* check it's a supported varient */
4019 if (strcmp(str1,"zWrLh") != 0) {
4020 return False;
4022 if (!check_printdest_info(&desc,uLevel,str2)) {
4023 return False;
4026 snum = find_service(PrinterName);
4027 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
4028 *rdata_len = 0;
4029 desc.errcode = NERR_DestNotFound;
4030 desc.neededlen = 0;
4031 } else {
4032 if (mdrcnt > 0) {
4033 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4034 if (!*rdata) {
4035 return False;
4037 desc.base = *rdata;
4038 desc.buflen = mdrcnt;
4039 } else {
4041 * Don't return data but need to get correct length
4042 * init_package will return wrong size if buflen=0
4044 desc.buflen = getlen(desc.format);
4045 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4047 if (init_package(&desc,1,0)) {
4048 fill_printdest_info(conn,snum,uLevel,&desc);
4050 *rdata_len = desc.usedlen;
4053 *rparam_len = 6;
4054 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4055 if (!*rparam) {
4056 return False;
4058 SSVALS(*rparam,0,desc.errcode);
4059 SSVAL(*rparam,2,0);
4060 SSVAL(*rparam,4,desc.neededlen);
4062 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4063 SAFE_FREE(tmpdata);
4065 return True;
4068 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4069 char *param, int tpscnt,
4070 char *data, int tdscnt,
4071 int mdrcnt,int mprcnt,
4072 char **rdata,char **rparam,
4073 int *rdata_len,int *rparam_len)
4075 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4076 char *str2 = skip_string(param,tpscnt,str1);
4077 char *p = skip_string(param,tpscnt,str2);
4078 int uLevel;
4079 int queuecnt;
4080 int i, n, succnt=0;
4081 struct pack_desc desc;
4082 int services = lp_numservices();
4084 if (!str1 || !str2 || !p) {
4085 return False;
4088 memset((char *)&desc,'\0',sizeof(desc));
4090 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4092 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4094 /* check it's a supported varient */
4095 if (strcmp(str1,"WrLeh") != 0) {
4096 return False;
4098 if (!check_printdest_info(&desc,uLevel,str2)) {
4099 return False;
4102 queuecnt = 0;
4103 for (i = 0; i < services; i++) {
4104 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4105 queuecnt++;
4109 if (mdrcnt > 0) {
4110 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4111 if (!*rdata) {
4112 return False;
4116 desc.base = *rdata;
4117 desc.buflen = mdrcnt;
4118 if (init_package(&desc,queuecnt,0)) {
4119 succnt = 0;
4120 n = 0;
4121 for (i = 0; i < services; i++) {
4122 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4123 fill_printdest_info(conn,i,uLevel,&desc);
4124 n++;
4125 if (desc.errcode == NERR_Success) {
4126 succnt = n;
4132 *rdata_len = desc.usedlen;
4134 *rparam_len = 8;
4135 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4136 if (!*rparam) {
4137 return False;
4139 SSVALS(*rparam,0,desc.errcode);
4140 SSVAL(*rparam,2,0);
4141 SSVAL(*rparam,4,succnt);
4142 SSVAL(*rparam,6,queuecnt);
4144 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4146 return True;
4149 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4150 char *param, int tpscnt,
4151 char *data, int tdscnt,
4152 int mdrcnt,int mprcnt,
4153 char **rdata,char **rparam,
4154 int *rdata_len,int *rparam_len)
4156 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4157 char *str2 = skip_string(param,tpscnt,str1);
4158 char *p = skip_string(param,tpscnt,str2);
4159 int uLevel;
4160 int succnt;
4161 struct pack_desc desc;
4163 if (!str1 || !str2 || !p) {
4164 return False;
4167 memset((char *)&desc,'\0',sizeof(desc));
4169 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4171 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4173 /* check it's a supported varient */
4174 if (strcmp(str1,"WrLeh") != 0) {
4175 return False;
4177 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4178 return False;
4181 if (mdrcnt > 0) {
4182 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4183 if (!*rdata) {
4184 return False;
4187 desc.base = *rdata;
4188 desc.buflen = mdrcnt;
4189 if (init_package(&desc,1,0)) {
4190 PACKS(&desc,"B41","NULL");
4193 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4195 *rdata_len = desc.usedlen;
4197 *rparam_len = 8;
4198 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4199 if (!*rparam) {
4200 return False;
4202 SSVALS(*rparam,0,desc.errcode);
4203 SSVAL(*rparam,2,0);
4204 SSVAL(*rparam,4,succnt);
4205 SSVAL(*rparam,6,1);
4207 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4209 return True;
4212 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4213 char *param, int tpscnt,
4214 char *data, int tdscnt,
4215 int mdrcnt,int mprcnt,
4216 char **rdata,char **rparam,
4217 int *rdata_len,int *rparam_len)
4219 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4220 char *str2 = skip_string(param,tpscnt,str1);
4221 char *p = skip_string(param,tpscnt,str2);
4222 int uLevel;
4223 int succnt;
4224 struct pack_desc desc;
4226 if (!str1 || !str2 || !p) {
4227 return False;
4229 memset((char *)&desc,'\0',sizeof(desc));
4231 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4233 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4235 /* check it's a supported varient */
4236 if (strcmp(str1,"WrLeh") != 0) {
4237 return False;
4239 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4240 return False;
4243 if (mdrcnt > 0) {
4244 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4245 if (!*rdata) {
4246 return False;
4249 desc.base = *rdata;
4250 desc.buflen = mdrcnt;
4251 desc.format = str2;
4252 if (init_package(&desc,1,0)) {
4253 PACKS(&desc,"B13","lpd");
4256 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4258 *rdata_len = desc.usedlen;
4260 *rparam_len = 8;
4261 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4262 if (!*rparam) {
4263 return False;
4265 SSVALS(*rparam,0,desc.errcode);
4266 SSVAL(*rparam,2,0);
4267 SSVAL(*rparam,4,succnt);
4268 SSVAL(*rparam,6,1);
4270 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4272 return True;
4275 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4276 char *param, int tpscnt,
4277 char *data, int tdscnt,
4278 int mdrcnt,int mprcnt,
4279 char **rdata,char **rparam,
4280 int *rdata_len,int *rparam_len)
4282 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4283 char *str2 = skip_string(param,tpscnt,str1);
4284 char *p = skip_string(param,tpscnt,str2);
4285 int uLevel;
4286 int succnt;
4287 struct pack_desc desc;
4289 if (!str1 || !str2 || !p) {
4290 return False;
4293 memset((char *)&desc,'\0',sizeof(desc));
4295 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4297 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4299 /* check it's a supported varient */
4300 if (strcmp(str1,"WrLeh") != 0) {
4301 return False;
4303 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
4304 return False;
4307 if (mdrcnt > 0) {
4308 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4309 if (!*rdata) {
4310 return False;
4313 memset((char *)&desc,'\0',sizeof(desc));
4314 desc.base = *rdata;
4315 desc.buflen = mdrcnt;
4316 desc.format = str2;
4317 if (init_package(&desc,1,0)) {
4318 PACKS(&desc,"B13","lp0");
4321 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4323 *rdata_len = desc.usedlen;
4325 *rparam_len = 8;
4326 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4327 if (!*rparam) {
4328 return False;
4330 SSVALS(*rparam,0,desc.errcode);
4331 SSVAL(*rparam,2,0);
4332 SSVAL(*rparam,4,succnt);
4333 SSVAL(*rparam,6,1);
4335 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
4337 return True;
4340 /****************************************************************************
4341 List open sessions
4342 ****************************************************************************/
4344 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
4345 char *param, int tpscnt,
4346 char *data, int tdscnt,
4347 int mdrcnt,int mprcnt,
4348 char **rdata,char **rparam,
4349 int *rdata_len,int *rparam_len)
4352 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4353 char *str2 = skip_string(param,tpscnt,str1);
4354 char *p = skip_string(param,tpscnt,str2);
4355 int uLevel;
4356 struct pack_desc desc;
4357 struct sessionid *session_list;
4358 int i, num_sessions;
4360 if (!str1 || !str2 || !p) {
4361 return False;
4364 memset((char *)&desc,'\0',sizeof(desc));
4366 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4368 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
4369 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
4370 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
4372 /* check it's a supported varient */
4373 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
4374 return False;
4376 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
4377 return False;
4380 num_sessions = list_sessions(talloc_tos(), &session_list);
4382 if (mdrcnt > 0) {
4383 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4384 if (!*rdata) {
4385 return False;
4388 memset((char *)&desc,'\0',sizeof(desc));
4389 desc.base = *rdata;
4390 desc.buflen = mdrcnt;
4391 desc.format = str2;
4392 if (!init_package(&desc,num_sessions,0)) {
4393 return False;
4396 for(i=0; i<num_sessions; i++) {
4397 PACKS(&desc, "z", session_list[i].remote_machine);
4398 PACKS(&desc, "z", session_list[i].username);
4399 PACKI(&desc, "W", 1); /* num conns */
4400 PACKI(&desc, "W", 0); /* num opens */
4401 PACKI(&desc, "W", 1); /* num users */
4402 PACKI(&desc, "D", 0); /* session time */
4403 PACKI(&desc, "D", 0); /* idle time */
4404 PACKI(&desc, "D", 0); /* flags */
4405 PACKS(&desc, "z", "Unknown Client"); /* client type string */
4408 *rdata_len = desc.usedlen;
4410 *rparam_len = 8;
4411 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4412 if (!*rparam) {
4413 return False;
4415 SSVALS(*rparam,0,desc.errcode);
4416 SSVAL(*rparam,2,0); /* converter */
4417 SSVAL(*rparam,4,num_sessions); /* count */
4419 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
4421 return True;
4425 /****************************************************************************
4426 The buffer was too small.
4427 ****************************************************************************/
4429 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
4430 int mdrcnt, int mprcnt,
4431 char **rdata, char **rparam,
4432 int *rdata_len, int *rparam_len)
4434 *rparam_len = MIN(*rparam_len,mprcnt);
4435 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4436 if (!*rparam) {
4437 return False;
4440 *rdata_len = 0;
4442 SSVAL(*rparam,0,NERR_BufTooSmall);
4444 DEBUG(3,("Supplied buffer too small in API command\n"));
4446 return True;
4449 /****************************************************************************
4450 The request is not supported.
4451 ****************************************************************************/
4453 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
4454 char *param, int tpscnt,
4455 char *data, int tdscnt,
4456 int mdrcnt, int mprcnt,
4457 char **rdata, char **rparam,
4458 int *rdata_len, int *rparam_len)
4460 *rparam_len = 4;
4461 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4462 if (!*rparam) {
4463 return False;
4466 *rdata_len = 0;
4468 SSVAL(*rparam,0,NERR_notsupported);
4469 SSVAL(*rparam,2,0); /* converter word */
4471 DEBUG(3,("Unsupported API command\n"));
4473 return True;
4476 static const struct {
4477 const char *name;
4478 int id;
4479 bool (*fn)(connection_struct *, uint16,
4480 char *, int,
4481 char *, int,
4482 int,int,char **,char **,int *,int *);
4483 bool auth_user; /* Deny anonymous access? */
4484 } api_commands[] = {
4485 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
4486 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
4487 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
4488 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
4489 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
4490 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
4491 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
4492 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
4493 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
4494 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
4495 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
4496 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
4497 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
4498 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
4499 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
4500 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
4501 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
4502 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
4503 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
4504 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
4505 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
4506 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
4507 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
4508 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
4509 {"NetServerEnum", RAP_NetServerEnum2, api_RNetServerEnum}, /* anon OK */
4510 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
4511 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
4512 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
4513 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
4514 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
4515 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
4516 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
4517 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
4518 {NULL, -1, api_Unsupported}
4519 /* The following RAP calls are not implemented by Samba:
4521 RAP_WFileEnum2 - anon not OK
4526 /****************************************************************************
4527 Handle remote api calls.
4528 ****************************************************************************/
4530 void api_reply(connection_struct *conn, uint16 vuid,
4531 struct smb_request *req,
4532 char *data, char *params,
4533 int tdscnt, int tpscnt,
4534 int mdrcnt, int mprcnt)
4536 int api_command;
4537 char *rdata = NULL;
4538 char *rparam = NULL;
4539 const char *name1 = NULL;
4540 const char *name2 = NULL;
4541 int rdata_len = 0;
4542 int rparam_len = 0;
4543 bool reply=False;
4544 int i;
4546 if (!params) {
4547 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
4548 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4549 return;
4552 if (tpscnt < 2) {
4553 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4554 return;
4556 api_command = SVAL(params,0);
4557 /* Is there a string at position params+2 ? */
4558 if (skip_string(params,tpscnt,params+2)) {
4559 name1 = params + 2;
4560 } else {
4561 name1 = "";
4563 name2 = skip_string(params,tpscnt,params+2);
4564 if (!name2) {
4565 name2 = "";
4568 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
4569 api_command,
4570 name1,
4571 name2,
4572 tdscnt,tpscnt,mdrcnt,mprcnt));
4574 for (i=0;api_commands[i].name;i++) {
4575 if (api_commands[i].id == api_command && api_commands[i].fn) {
4576 DEBUG(3,("Doing %s\n",api_commands[i].name));
4577 break;
4581 /* Check whether this api call can be done anonymously */
4583 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
4584 user_struct *user = get_valid_user_struct(vuid);
4586 if (!user || user->server_info->guest) {
4587 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4588 return;
4592 rdata = (char *)SMB_MALLOC(1024);
4593 if (rdata) {
4594 memset(rdata,'\0',1024);
4597 rparam = (char *)SMB_MALLOC(1024);
4598 if (rparam) {
4599 memset(rparam,'\0',1024);
4602 if(!rdata || !rparam) {
4603 DEBUG(0,("api_reply: malloc fail !\n"));
4604 SAFE_FREE(rdata);
4605 SAFE_FREE(rparam);
4606 reply_nterror(req, NT_STATUS_NO_MEMORY);
4607 return;
4610 reply = api_commands[i].fn(conn,
4611 vuid,
4612 params,tpscnt, /* params + length */
4613 data,tdscnt, /* data + length */
4614 mdrcnt,mprcnt,
4615 &rdata,&rparam,&rdata_len,&rparam_len);
4618 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
4619 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
4620 &rdata,&rparam,&rdata_len,&rparam_len);
4623 /* if we get False back then it's actually unsupported */
4624 if (!reply) {
4625 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
4626 &rdata,&rparam,&rdata_len,&rparam_len);
4629 /* If api_Unsupported returns false we can't return anything. */
4630 if (reply) {
4631 send_trans_reply(conn, req, rparam, rparam_len,
4632 rdata, rdata_len, False);
4635 SAFE_FREE(rdata);
4636 SAFE_FREE(rparam);
4637 return;