Fairly large change to printing code.
[Samba.git] / source / smbd / lanman.c
blob8bfad4ab334854b938677f973ee5308283da36ac
1 /*
2 Unix SMB/CIFS implementation.
3 Inter-process communication and named pipe handling
4 Copyright (C) Andrew Tridgell 1992-1998
6 SMB Version handling
7 Copyright (C) John H Terpstra 1995-1998
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 This file handles the named pipe and mailslot calls
25 in the SMBtrans protocol
28 #include "includes.h"
30 #ifdef CHECK_TYPES
31 #undef CHECK_TYPES
32 #endif
33 #define CHECK_TYPES 0
35 extern fstring local_machine;
36 extern pstring global_myname;
37 extern fstring global_myworkgroup;
39 #define NERR_Success 0
40 #define NERR_badpass 86
41 #define NERR_notsupported 50
43 #define NERR_BASE (2100)
44 #define NERR_BufTooSmall (NERR_BASE+23)
45 #define NERR_JobNotFound (NERR_BASE+51)
46 #define NERR_DestNotFound (NERR_BASE+52)
48 #define ACCESS_READ 0x01
49 #define ACCESS_WRITE 0x02
50 #define ACCESS_CREATE 0x04
52 #define SHPWLEN 8 /* share password length */
54 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
55 int mdrcnt,int mprcnt,
56 char **rdata,char **rparam,
57 int *rdata_len,int *rparam_len);
58 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
59 int mdrcnt,int mprcnt,
60 char **rdata,char **rparam,
61 int *rdata_len,int *rparam_len);
64 static int CopyExpanded(connection_struct *conn,
65 int snum, char** dst, char* src, int* n)
67 pstring buf;
68 int l;
70 if (!src || !dst || !n || !(*dst)) return(0);
72 StrnCpy(buf,src,sizeof(buf)/2);
73 pstring_sub(buf,"%S",lp_servicename(snum));
74 standard_sub_conn(conn,buf,sizeof(buf));
75 l = push_ascii(*dst,buf,*n-1, STR_TERMINATE);
76 (*dst) += l;
77 (*n) -= l;
78 return l;
81 static int CopyAndAdvance(char** dst, char* src, int* n)
83 int l;
84 if (!src || !dst || !n || !(*dst)) return(0);
85 l = push_ascii(*dst,src,*n, STR_TERMINATE);
86 (*dst) += l;
87 (*n) -= l;
88 return l;
91 static int StrlenExpanded(connection_struct *conn, int snum, char* s)
93 pstring buf;
94 if (!s) return(0);
95 StrnCpy(buf,s,sizeof(buf)/2);
96 pstring_sub(buf,"%S",lp_servicename(snum));
97 standard_sub_conn(conn,buf,sizeof(buf));
98 return strlen(buf) + 1;
101 static char* Expand(connection_struct *conn, int snum, char* s)
103 static pstring buf;
104 if (!s) return(NULL);
105 StrnCpy(buf,s,sizeof(buf)/2);
106 pstring_sub(buf,"%S",lp_servicename(snum));
107 standard_sub_conn(conn,buf,sizeof(buf));
108 return &buf[0];
111 /*******************************************************************
112 check a API string for validity when we only need to check the prefix
113 ******************************************************************/
114 static BOOL prefix_ok(char *str,char *prefix)
116 return(strncmp(str,prefix,strlen(prefix)) == 0);
119 struct pack_desc {
120 char* format; /* formatstring for structure */
121 char* subformat; /* subformat for structure */
122 char* base; /* baseaddress of buffer */
123 int buflen; /* remaining size for fixed part; on init: length of base */
124 int subcount; /* count of substructures */
125 char* structbuf; /* pointer into buffer for remaining fixed part */
126 int stringlen; /* remaining size for variable part */
127 char* stringbuf; /* pointer into buffer for remaining variable part */
128 int neededlen; /* total needed size */
129 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
130 char* curpos; /* current position; pointer into format or subformat */
131 int errcode;
134 static int get_counter(char** p)
136 int i, n;
137 if (!p || !(*p)) return(1);
138 if (!isdigit((int)**p)) return 1;
139 for (n = 0;;) {
140 i = **p;
141 if (isdigit(i))
142 n = 10 * n + (i - '0');
143 else
144 return n;
145 (*p)++;
149 static int getlen(char* p)
151 int n = 0;
152 if (!p) return(0);
153 while (*p) {
154 switch( *p++ ) {
155 case 'W': /* word (2 byte) */
156 n += 2;
157 break;
158 case 'K': /* status word? (2 byte) */
159 n += 2;
160 break;
161 case 'N': /* count of substructures (word) at end */
162 n += 2;
163 break;
164 case 'D': /* double word (4 byte) */
165 case 'z': /* offset to zero terminated string (4 byte) */
166 case 'l': /* offset to user data (4 byte) */
167 n += 4;
168 break;
169 case 'b': /* offset to data (with counter) (4 byte) */
170 n += 4;
171 get_counter(&p);
172 break;
173 case 'B': /* byte (with optional counter) */
174 n += get_counter(&p);
175 break;
178 return n;
181 static BOOL init_package(struct pack_desc* p, int count, int subcount)
183 int n = p->buflen;
184 int i;
186 if (!p->format || !p->base) return(False);
188 i = count * getlen(p->format);
189 if (p->subformat) i += subcount * getlen(p->subformat);
190 p->structbuf = p->base;
191 p->neededlen = 0;
192 p->usedlen = 0;
193 p->subcount = 0;
194 p->curpos = p->format;
195 if (i > n) {
196 p->neededlen = i;
197 i = n = 0;
198 #if 0
200 * This is the old error code we used. Aparently
201 * WinNT/2k systems return ERRbuftoosmall (2123) and
202 * OS/2 needs this. I'm leaving this here so we can revert
203 * if needed. JRA.
205 p->errcode = ERRmoredata;
206 #else
207 p->errcode = ERRbuftoosmall;
208 #endif
210 else
211 p->errcode = NERR_Success;
212 p->buflen = i;
213 n -= i;
214 p->stringbuf = p->base + i;
215 p->stringlen = n;
216 return(p->errcode == NERR_Success);
219 static int package(struct pack_desc* p, ...)
221 va_list args;
222 int needed=0, stringneeded;
223 char* str=NULL;
224 int is_string=0, stringused;
225 int32 temp;
227 va_start(args,p);
229 if (!*p->curpos) {
230 if (!p->subcount)
231 p->curpos = p->format;
232 else {
233 p->curpos = p->subformat;
234 p->subcount--;
237 #if CHECK_TYPES
238 str = va_arg(args,char*);
239 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
240 #endif
241 stringneeded = -1;
243 if (!p->curpos) {
244 va_end(args);
245 return(0);
248 switch( *p->curpos++ ) {
249 case 'W': /* word (2 byte) */
250 needed = 2;
251 temp = va_arg(args,int);
252 if (p->buflen >= needed) SSVAL(p->structbuf,0,temp);
253 break;
254 case 'K': /* status word? (2 byte) */
255 needed = 2;
256 temp = va_arg(args,int);
257 if (p->buflen >= needed) SSVAL(p->structbuf,0,temp);
258 break;
259 case 'N': /* count of substructures (word) at end */
260 needed = 2;
261 p->subcount = va_arg(args,int);
262 if (p->buflen >= needed) SSVAL(p->structbuf,0,p->subcount);
263 break;
264 case 'D': /* double word (4 byte) */
265 needed = 4;
266 temp = va_arg(args,int);
267 if (p->buflen >= needed) SIVAL(p->structbuf,0,temp);
268 break;
269 case 'B': /* byte (with optional counter) */
270 needed = get_counter(&p->curpos);
272 char *s = va_arg(args,char*);
273 if (p->buflen >= needed) StrnCpy(p->structbuf,s?s:"",needed-1);
275 break;
276 case 'z': /* offset to zero terminated string (4 byte) */
277 str = va_arg(args,char*);
278 stringneeded = (str ? strlen(str)+1 : 0);
279 is_string = 1;
280 break;
281 case 'l': /* offset to user data (4 byte) */
282 str = va_arg(args,char*);
283 stringneeded = va_arg(args,int);
284 is_string = 0;
285 break;
286 case 'b': /* offset to data (with counter) (4 byte) */
287 str = va_arg(args,char*);
288 stringneeded = get_counter(&p->curpos);
289 is_string = 0;
290 break;
292 va_end(args);
293 if (stringneeded >= 0) {
294 needed = 4;
295 if (p->buflen >= needed) {
296 stringused = stringneeded;
297 if (stringused > p->stringlen) {
298 stringused = (is_string ? p->stringlen : 0);
299 if (p->errcode == NERR_Success) p->errcode = ERRmoredata;
301 if (!stringused)
302 SIVAL(p->structbuf,0,0);
303 else {
304 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
305 memcpy(p->stringbuf,str?str:"",stringused);
306 if (is_string) p->stringbuf[stringused-1] = '\0';
307 p->stringbuf += stringused;
308 p->stringlen -= stringused;
309 p->usedlen += stringused;
312 p->neededlen += stringneeded;
314 p->neededlen += needed;
315 if (p->buflen >= needed) {
316 p->structbuf += needed;
317 p->buflen -= needed;
318 p->usedlen += needed;
320 else {
321 if (p->errcode == NERR_Success) p->errcode = ERRmoredata;
323 return 1;
326 #if CHECK_TYPES
327 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
328 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
329 #else
330 #define PACK(desc,t,v) package(desc,v)
331 #define PACKl(desc,t,v,l) package(desc,v,l)
332 #endif
334 static void PACKI(struct pack_desc* desc,char *t,int v)
336 PACK(desc,t,v);
339 static void PACKS(struct pack_desc* desc,char *t,char *v)
341 PACK(desc,t,v);
345 /****************************************************************************
346 get a print queue
347 ****************************************************************************/
348 static void PackDriverData(struct pack_desc* desc)
350 char drivdata[4+4+32];
351 SIVAL(drivdata,0,sizeof drivdata); /* cb */
352 SIVAL(drivdata,4,1000); /* lVersion */
353 memset(drivdata+8,0,32); /* szDeviceName */
354 push_ascii(drivdata+8,"NULL",-1, STR_TERMINATE);
355 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
358 static int check_printq_info(struct pack_desc* desc,
359 int uLevel, char *id1, char *id2)
361 desc->subformat = NULL;
362 switch( uLevel ) {
363 case 0:
364 desc->format = "B13";
365 break;
366 case 1:
367 desc->format = "B13BWWWzzzzzWW";
368 break;
369 case 2:
370 desc->format = "B13BWWWzzzzzWN";
371 desc->subformat = "WB21BB16B10zWWzDDz";
372 break;
373 case 3:
374 desc->format = "zWWWWzzzzWWzzl";
375 break;
376 case 4:
377 desc->format = "zWWWWzzzzWNzzl";
378 desc->subformat = "WWzWWDDzz";
379 break;
380 case 5:
381 desc->format = "z";
382 break;
383 case 51:
384 desc->format = "K";
385 break;
386 case 52:
387 desc->format = "WzzzzzzzzN";
388 desc->subformat = "z";
389 break;
390 default: return False;
392 if (strcmp(desc->format,id1) != 0) return False;
393 if (desc->subformat && strcmp(desc->subformat,id2) != 0) return False;
394 return True;
398 #define RAP_JOB_STATUS_QUEUED 0
399 #define RAP_JOB_STATUS_PAUSED 1
400 #define RAP_JOB_STATUS_SPOOLING 2
401 #define RAP_JOB_STATUS_PRINTING 3
402 #define RAP_JOB_STATUS_PRINTED 4
404 #define RAP_QUEUE_STATUS_PAUSED 1
405 #define RAP_QUEUE_STATUS_ERROR 2
407 /* turn a print job status into a on the wire status
409 static int printj_status(int v)
411 switch (v) {
412 case LPQ_QUEUED:
413 return RAP_JOB_STATUS_QUEUED;
414 case LPQ_PAUSED:
415 return RAP_JOB_STATUS_PAUSED;
416 case LPQ_SPOOLING:
417 return RAP_JOB_STATUS_SPOOLING;
418 case LPQ_PRINTING:
419 return RAP_JOB_STATUS_PRINTING;
421 return 0;
424 /* turn a print queue status into a on the wire status
426 static int printq_status(int v)
428 switch (v) {
429 case LPQ_QUEUED:
430 return 0;
431 case LPQ_PAUSED:
432 return RAP_QUEUE_STATUS_PAUSED;
434 return RAP_QUEUE_STATUS_ERROR;
437 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
438 struct pack_desc* desc,
439 print_queue_struct* queue, int n)
441 time_t t = queue->time;
443 /* the client expects localtime */
444 t -= TimeDiff(t);
446 PACKI(desc,"W",pjobid_to_rap(snum,queue->job)); /* uJobId */
447 if (uLevel == 1) {
448 PACKS(desc,"B21",queue->fs_user); /* szUserName */
449 PACKS(desc,"B",""); /* pad */
450 PACKS(desc,"B16",""); /* szNotifyName */
451 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
452 PACKS(desc,"z",""); /* pszParms */
453 PACKI(desc,"W",n+1); /* uPosition */
454 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
455 PACKS(desc,"z",""); /* pszStatus */
456 PACKI(desc,"D",t); /* ulSubmitted */
457 PACKI(desc,"D",queue->size); /* ulSize */
458 PACKS(desc,"z",queue->fs_file); /* pszComment */
460 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
461 PACKI(desc,"W",queue->priority); /* uPriority */
462 PACKS(desc,"z",queue->fs_user); /* pszUserName */
463 PACKI(desc,"W",n+1); /* uPosition */
464 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
465 PACKI(desc,"D",t); /* ulSubmitted */
466 PACKI(desc,"D",queue->size); /* ulSize */
467 PACKS(desc,"z","Samba"); /* pszComment */
468 PACKS(desc,"z",queue->fs_file); /* pszDocument */
469 if (uLevel == 3) {
470 PACKS(desc,"z",""); /* pszNotifyName */
471 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
472 PACKS(desc,"z",""); /* pszParms */
473 PACKS(desc,"z",""); /* pszStatus */
474 PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
475 PACKS(desc,"z","lpd"); /* pszQProcName */
476 PACKS(desc,"z",""); /* pszQProcParms */
477 PACKS(desc,"z","NULL"); /* pszDriverName */
478 PackDriverData(desc); /* pDriverData */
479 PACKS(desc,"z",""); /* pszPrinterName */
480 } else if (uLevel == 4) { /* OS2 */
481 PACKS(desc,"z",""); /* pszSpoolFileName */
482 PACKS(desc,"z",""); /* pszPortName */
483 PACKS(desc,"z",""); /* pszStatus */
484 PACKI(desc,"D",0); /* ulPagesSpooled */
485 PACKI(desc,"D",0); /* ulPagesSent */
486 PACKI(desc,"D",0); /* ulPagesPrinted */
487 PACKI(desc,"D",0); /* ulTimePrinted */
488 PACKI(desc,"D",0); /* ulExtendJobStatus */
489 PACKI(desc,"D",0); /* ulStartPage */
490 PACKI(desc,"D",0); /* ulEndPage */
495 /********************************************************************
496 Return a driver name given an snum.
497 Looks in a tdb first. Returns True if from tdb, False otherwise.
498 ********************************************************************/
500 static BOOL get_driver_name(int snum, pstring drivername)
502 NT_PRINTER_INFO_LEVEL *info = NULL;
503 BOOL in_tdb = False;
505 get_a_printer (&info, 2, lp_servicename(snum));
506 if (info != NULL) {
507 pstrcpy( drivername, info->info_2->drivername);
508 in_tdb = True;
509 free_a_printer(&info, 2);
510 } else {
511 pstrcpy( drivername, lp_printerdriver(snum));
514 return in_tdb;
517 /********************************************************************
518 Respond to the DosPrintQInfo command with a level of 52
519 This is used to get printer driver information for Win9x clients
520 ********************************************************************/
521 static void fill_printq_info_52(connection_struct *conn, int snum, int uLevel,
522 struct pack_desc* desc,
523 int count, print_queue_struct* queue,
524 print_status_struct* status)
526 int i;
527 BOOL ok = False;
528 pstring tok,driver,datafile,langmon,helpfile,datatype;
529 char *p;
530 char **lines = NULL;
531 pstring gen_line;
532 BOOL in_tdb = False;
533 fstring location;
534 pstring drivername;
537 * Check in the tdb *first* before checking the legacy
538 * files. This allows an NT upload to take precedence over
539 * the existing fileset. JRA.
541 * we need to lookup the driver name prior to making the call
542 * to get_a_printer_driver_9x_compatible() and not rely on the
543 * 'print driver' parameter --jerry
547 if ((get_driver_name(snum,drivername)) &&
548 ((ok = get_a_printer_driver_9x_compatible(gen_line, drivername)) == True))
550 in_tdb = True;
551 p = gen_line;
552 DEBUG(10,("9x compatable driver line for [%s]: [%s]\n", drivername, gen_line));
554 else
556 /* didn't find driver in tdb */
558 DEBUG(10,("snum: %d\nprinterdriver: [%s]\nlp_driverfile: [%s]\n",
559 snum, drivername, lp_driverfile(snum)));
561 lines = file_lines_load(lp_driverfile(snum),NULL);
562 if (!lines)
564 DEBUG(3,("Can't open %s - %s\n", lp_driverfile(snum),
565 strerror(errno)));
566 desc->errcode=NERR_notsupported;
567 goto done;
570 /* lookup the long printer driver name in the file description */
571 for (i=0;lines[i] && !ok;i++)
573 p = lines[i];
574 if (next_token(&p,tok,":",sizeof(tok)) &&
575 (strlen(drivername) == strlen(tok)) &&
576 (!strncmp(tok,drivername,strlen(drivername))))
578 ok = True;
583 if (ok)
585 /* driver file name */
586 if (!next_token(&p,driver,":",sizeof(driver)))
587 goto err;
589 /* data file name */
590 if (!next_token(&p,datafile,":",sizeof(datafile)))
591 goto err;
594 * for the next tokens - which may be empty - I have
595 * to check for empty tokens first because the
596 * next_token function will skip all empty token
597 * fields */
599 /* help file */
600 if (*p == ':')
602 *helpfile = '\0';
603 p++;
605 else if (!next_token(&p,helpfile,":",sizeof(helpfile)))
606 goto err;
608 /* language monitor */
609 if (*p == ':')
611 *langmon = '\0';
612 p++;
614 else if (!next_token(&p,langmon,":",sizeof(langmon)))
615 goto err;
617 /* default data type */
618 if (!next_token(&p,datatype,":",sizeof(datatype)))
619 goto err;
621 PACKI(desc,"W",0x0400); /* don't know */
622 PACKS(desc,"z",drivername); /* long printer name */
623 PACKS(desc,"z",driver); /* Driverfile Name */
624 PACKS(desc,"z",datafile); /* Datafile name */
625 PACKS(desc,"z",langmon); /* language monitor */
626 if (in_tdb)
628 fstrcpy(location, "\\\\");
629 fstrcat(location, global_myname);
630 fstrcat(location, "\\print$\\WIN40\\0");
631 PACKS(desc,"z",location); /* share to retrieve files */
633 else
635 PACKS(desc,"z",lp_driverlocation(snum)); /* share to retrieve files */
637 PACKS(desc,"z",datatype); /* default data type */
638 PACKS(desc,"z",helpfile); /* helpfile name */
639 PACKS(desc,"z",driver); /* driver name */
641 DEBUG(3,("printerdriver:%s:\n",drivername));
642 DEBUG(3,("Driver:%s:\n",driver));
643 DEBUG(3,("Data File:%s:\n",datafile));
644 DEBUG(3,("Language Monitor:%s:\n",langmon));
645 if (in_tdb)
646 DEBUG(3,("lp_driverlocation:%s:\n",location));
647 else
648 DEBUG(3,("lp_driverlocation:%s:\n",lp_driverlocation(snum)));
649 DEBUG(3,("Data Type:%s:\n",datatype));
650 DEBUG(3,("Help File:%s:\n",helpfile));
651 PACKI(desc,"N",count); /* number of files to copy */
653 for (i=0;i<count;i++)
655 /* no need to check return value here
656 * - it was already tested in
657 * get_printerdrivernumber */
658 next_token(&p,tok,",",sizeof(tok));
659 PACKS(desc,"z",tok); /* driver files to copy */
660 DEBUG(3,("file:%s:\n",tok));
663 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n",
664 SERVICE(snum),count));
666 desc->errcode=NERR_Success;
667 goto done;
670 err:
672 DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
673 desc->errcode=NERR_notsupported;
675 done:
676 file_lines_free(lines);
680 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
681 struct pack_desc* desc,
682 int count, print_queue_struct* queue,
683 print_status_struct* status)
685 switch (uLevel) {
686 case 1:
687 case 2:
688 PACKS(desc,"B13",SERVICE(snum));
689 break;
690 case 3:
691 case 4:
692 case 5:
693 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
694 break;
695 case 51:
696 PACKI(desc,"K",printq_status(status->status));
697 break;
700 if (uLevel == 1 || uLevel == 2) {
701 PACKS(desc,"B",""); /* alignment */
702 PACKI(desc,"W",5); /* priority */
703 PACKI(desc,"W",0); /* start time */
704 PACKI(desc,"W",0); /* until time */
705 PACKS(desc,"z",""); /* pSepFile */
706 PACKS(desc,"z","lpd"); /* pPrProc */
707 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
708 PACKS(desc,"z",""); /* pParms */
709 if (snum < 0) {
710 PACKS(desc,"z","UNKNOWN PRINTER");
711 PACKI(desc,"W",LPSTAT_ERROR);
713 else if (!status || !status->message[0]) {
714 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
715 PACKI(desc,"W",LPSTAT_OK); /* status */
716 } else {
717 PACKS(desc,"z",status->message);
718 PACKI(desc,"W",printq_status(status->status)); /* status */
720 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
723 if (uLevel == 3 || uLevel == 4) {
724 pstring drivername;
726 PACKI(desc,"W",5); /* uPriority */
727 PACKI(desc,"W",0); /* uStarttime */
728 PACKI(desc,"W",0); /* uUntiltime */
729 PACKI(desc,"W",5); /* pad1 */
730 PACKS(desc,"z",""); /* pszSepFile */
731 PACKS(desc,"z","WinPrint"); /* pszPrProc */
732 PACKS(desc,"z",NULL); /* pszParms */
733 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
734 /* "don't ask" that it's done this way to fix corrupted
735 Win9X/ME printer comments. */
736 if (!status) {
737 PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
738 } else {
739 PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
741 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
742 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
743 get_driver_name(snum,drivername);
744 PACKS(desc,"z",drivername); /* pszDriverName */
745 PackDriverData(desc); /* pDriverData */
748 if (uLevel == 2 || uLevel == 4) {
749 int i;
750 for (i=0;i<count;i++)
751 fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
754 if (uLevel==52) {
755 fill_printq_info_52(conn, snum, uLevel, desc, count, queue, status);
759 /* This function returns the number of files for a given driver */
760 static int get_printerdrivernumber(int snum)
762 int i, result = 0;
763 BOOL ok = False;
764 pstring tok;
765 char *p;
766 char **lines = NULL;
767 pstring gen_line;
768 pstring drivername;
771 * Check in the tdb *first* before checking the legacy
772 * files. This allows an NT upload to take precedence over
773 * the existing fileset. JRA.
775 * we need to lookup the driver name prior to making the call
776 * to get_a_printer_driver_9x_compatible() and not rely on the
777 * 'print driver' parameter --jerry
780 if ((get_driver_name(snum,drivername)) &&
781 (ok = get_a_printer_driver_9x_compatible(gen_line, drivername) == True))
783 p = gen_line;
784 DEBUG(10,("9x compatable driver line for [%s]: [%s]\n", drivername, gen_line));
786 else
788 /* didn't find driver in tdb */
790 DEBUG(10,("snum: %d\nprinterdriver: [%s]\nlp_driverfile: [%s]\n",
791 snum, drivername, lp_driverfile(snum)));
793 lines = file_lines_load(lp_driverfile(snum), NULL);
794 if (!lines)
796 DEBUG(3,("Can't open %s - %s\n", lp_driverfile(snum),strerror(errno)));
797 goto done;
800 /* lookup the long printer driver name in the file description */
801 for (i=0;lines[i] && !ok;i++)
803 p = lines[i];
804 if (next_token(&p,tok,":",sizeof(tok)) &&
805 (strlen(drivername) == strlen(tok)) &&
806 (!strncmp(tok,drivername,strlen(drivername))))
808 ok = True;
813 if( ok )
815 /* skip 5 fields */
816 i = 5;
817 while (*p && i) {
818 if (*p++ == ':') i--;
820 if (!*p || i) {
821 DEBUG(3,("Can't determine number of printer driver files\n"));
822 goto done;
825 /* count the number of files */
826 while (next_token(&p,tok,",",sizeof(tok)))
827 i++;
829 result = i;
832 done:
834 file_lines_free(lines);
836 return result;
839 static BOOL api_DosPrintQGetInfo(connection_struct *conn,
840 uint16 vuid, char *param,char *data,
841 int mdrcnt,int mprcnt,
842 char **rdata,char **rparam,
843 int *rdata_len,int *rparam_len)
845 char *str1 = param+2;
846 char *str2 = skip_string(str1,1);
847 char *p = skip_string(str2,1);
848 char *QueueName = p;
849 int uLevel;
850 int count=0;
851 int snum;
852 char* str3;
853 struct pack_desc desc;
854 print_queue_struct *queue=NULL;
855 print_status_struct status;
856 char* tmpdata=NULL;
858 memset((char *)&status,'\0',sizeof(status));
859 memset((char *)&desc,'\0',sizeof(desc));
861 p = skip_string(p,1);
862 uLevel = SVAL(p,0);
863 str3 = p + 4;
865 /* remove any trailing username */
866 if ((p = strchr_m(QueueName,'%')))
867 *p = 0;
869 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
871 /* check it's a supported varient */
872 if (!prefix_ok(str1,"zWrLh"))
873 return False;
874 if (!check_printq_info(&desc,uLevel,str2,str3)) {
876 * Patch from Scott Moomaw <scott@bridgewater.edu>
877 * to return the 'invalid info level' error if an
878 * unknown level was requested.
880 *rdata_len = 0;
881 *rparam_len = 6;
882 *rparam = REALLOC(*rparam,*rparam_len);
883 SSVALS(*rparam,0,ERRunknownlevel);
884 SSVAL(*rparam,2,0);
885 SSVAL(*rparam,4,0);
886 return(True);
889 snum = lp_servicenumber(QueueName);
890 if (snum < 0 && pcap_printername_ok(QueueName,NULL)) {
891 int pnum = lp_servicenumber(PRINTERS_NAME);
892 if (pnum >= 0) {
893 lp_add_printer(QueueName,pnum);
894 snum = lp_servicenumber(QueueName);
898 if (snum < 0 || !VALID_SNUM(snum))
899 return(False);
901 if (uLevel==52) {
902 count = get_printerdrivernumber(snum);
903 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
904 } else {
905 count = print_queue_status(snum, &queue,&status);
908 if (mdrcnt > 0) {
909 *rdata = REALLOC(*rdata,mdrcnt);
910 desc.base = *rdata;
911 desc.buflen = mdrcnt;
912 } else {
914 * Don't return data but need to get correct length
915 * init_package will return wrong size if buflen=0
917 desc.buflen = getlen(desc.format);
918 desc.base = tmpdata = (char *) malloc (desc.buflen);
921 if (init_package(&desc,1,count)) {
922 desc.subcount = count;
923 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
926 *rdata_len = desc.usedlen;
929 * We must set the return code to ERRbuftoosmall
930 * in order to support lanman style printing with Win NT/2k
931 * clients --jerry
933 if (!mdrcnt && lp_disable_spoolss())
934 desc.errcode = ERRbuftoosmall;
936 *rdata_len = desc.usedlen;
937 *rparam_len = 6;
938 *rparam = REALLOC(*rparam,*rparam_len);
939 SSVALS(*rparam,0,desc.errcode);
940 SSVAL(*rparam,2,0);
941 SSVAL(*rparam,4,desc.neededlen);
943 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
945 SAFE_FREE(queue);
946 SAFE_FREE(tmpdata);
948 return(True);
951 /****************************************************************************
952 View list of all print jobs on all queues.
953 ****************************************************************************/
955 static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param, char* data,
956 int mdrcnt, int mprcnt,
957 char **rdata, char** rparam,
958 int *rdata_len, int *rparam_len)
960 char *param_format = param+2;
961 char *output_format1 = skip_string(param_format,1);
962 char *p = skip_string(output_format1,1);
963 int uLevel = SVAL(p,0);
964 char *output_format2 = p + 4;
965 int services = lp_numservices();
966 int i, n;
967 struct pack_desc desc;
968 print_queue_struct **queue = NULL;
969 print_status_struct *status = NULL;
970 int* subcntarr = NULL;
971 int queuecnt, subcnt=0, succnt=0;
973 memset((char *)&desc,'\0',sizeof(desc));
975 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
977 if (!prefix_ok(param_format,"WrLeh")) return False;
978 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
980 * Patch from Scott Moomaw <scott@bridgewater.edu>
981 * to return the 'invalid info level' error if an
982 * unknown level was requested.
984 *rdata_len = 0;
985 *rparam_len = 6;
986 *rparam = REALLOC(*rparam,*rparam_len);
987 SSVALS(*rparam,0,ERRunknownlevel);
988 SSVAL(*rparam,2,0);
989 SSVAL(*rparam,4,0);
990 return(True);
993 queuecnt = 0;
994 for (i = 0; i < services; i++)
995 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
996 queuecnt++;
997 if (uLevel > 0) {
998 if((queue = (print_queue_struct**)malloc(queuecnt*sizeof(print_queue_struct*))) == NULL) {
999 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1000 return False;
1002 memset(queue,0,queuecnt*sizeof(print_queue_struct*));
1003 if((status = (print_status_struct*)malloc(queuecnt*sizeof(print_status_struct))) == NULL) {
1004 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1005 return False;
1007 memset(status,0,queuecnt*sizeof(print_status_struct));
1008 if((subcntarr = (int*)malloc(queuecnt*sizeof(int))) == NULL) {
1009 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1010 return False;
1012 subcnt = 0;
1013 n = 0;
1014 for (i = 0; i < services; i++)
1015 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1016 subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
1017 subcnt += subcntarr[n];
1018 n++;
1021 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
1022 desc.base = *rdata;
1023 desc.buflen = mdrcnt;
1025 if (init_package(&desc,queuecnt,subcnt)) {
1026 n = 0;
1027 succnt = 0;
1028 for (i = 0; i < services; i++)
1029 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1030 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1031 n++;
1032 if (desc.errcode == NERR_Success) succnt = n;
1036 SAFE_FREE(subcntarr);
1038 *rdata_len = desc.usedlen;
1039 *rparam_len = 8;
1040 *rparam = REALLOC(*rparam,*rparam_len);
1041 SSVALS(*rparam,0,desc.errcode);
1042 SSVAL(*rparam,2,0);
1043 SSVAL(*rparam,4,succnt);
1044 SSVAL(*rparam,6,queuecnt);
1046 for (i = 0; i < queuecnt; i++) {
1047 if (queue) SAFE_FREE(queue[i]);
1050 SAFE_FREE(queue);
1051 SAFE_FREE(status);
1053 return True;
1056 /****************************************************************************
1057 get info level for a server list query
1058 ****************************************************************************/
1059 static BOOL check_server_info(int uLevel, char* id)
1061 switch( uLevel ) {
1062 case 0:
1063 if (strcmp(id,"B16") != 0) return False;
1064 break;
1065 case 1:
1066 if (strcmp(id,"B16BBDz") != 0) return False;
1067 break;
1068 default:
1069 return False;
1071 return True;
1074 struct srv_info_struct
1076 fstring name;
1077 uint32 type;
1078 fstring comment;
1079 fstring domain;
1080 BOOL server_added;
1084 /*******************************************************************
1085 get server info lists from the files saved by nmbd. Return the
1086 number of entries
1087 ******************************************************************/
1088 static int get_server_info(uint32 servertype,
1089 struct srv_info_struct **servers,
1090 char *domain)
1092 int count=0;
1093 int alloced=0;
1094 char **lines;
1095 BOOL local_list_only;
1096 int i;
1098 lines = file_lines_load(lock_path(SERVER_LIST), NULL);
1099 if (!lines) {
1100 DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
1101 return(0);
1104 /* request for everything is code for request all servers */
1105 if (servertype == SV_TYPE_ALL)
1106 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1108 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1110 DEBUG(4,("Servertype search: %8x\n",servertype));
1112 for (i=0;lines[i];i++) {
1113 fstring stype;
1114 struct srv_info_struct *s;
1115 char *ptr = lines[i];
1116 BOOL ok = True;
1118 if (!*ptr) continue;
1120 if (count == alloced) {
1121 struct srv_info_struct *ts;
1123 alloced += 10;
1124 ts = (struct srv_info_struct *)
1125 Realloc(*servers,sizeof(**servers)*alloced);
1126 if (!ts) {
1127 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1128 return(0);
1130 else *servers = ts;
1131 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1133 s = &(*servers)[count];
1135 if (!next_token(&ptr,s->name , NULL, sizeof(s->name))) continue;
1136 if (!next_token(&ptr,stype , NULL, sizeof(stype))) continue;
1137 if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) continue;
1138 if (!next_token(&ptr,s->domain , NULL, sizeof(s->domain))) {
1139 /* this allows us to cope with an old nmbd */
1140 pstrcpy(s->domain,global_myworkgroup);
1143 if (sscanf(stype,"%X",&s->type) != 1) {
1144 DEBUG(4,("r:host file "));
1145 ok = False;
1148 /* Filter the servers/domains we return based on what was asked for. */
1150 /* Check to see if we are being asked for a local list only. */
1151 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1152 DEBUG(4,("r: local list only"));
1153 ok = False;
1156 /* doesn't match up: don't want it */
1157 if (!(servertype & s->type)) {
1158 DEBUG(4,("r:serv type "));
1159 ok = False;
1162 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1163 (s->type & SV_TYPE_DOMAIN_ENUM))
1165 DEBUG(4,("s: dom mismatch "));
1166 ok = False;
1169 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM))
1171 ok = False;
1174 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1175 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1177 if (ok)
1179 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1180 s->name, s->type, s->comment, s->domain));
1182 s->server_added = True;
1183 count++;
1185 else
1187 DEBUG(4,("%20s %8x %25s %15s\n",
1188 s->name, s->type, s->comment, s->domain));
1192 file_lines_free(lines);
1193 return(count);
1197 /*******************************************************************
1198 fill in a server info structure
1199 ******************************************************************/
1200 static int fill_srv_info(struct srv_info_struct *service,
1201 int uLevel, char **buf, int *buflen,
1202 char **stringbuf, int *stringspace, char *baseaddr)
1204 int struct_len;
1205 char* p;
1206 char* p2;
1207 int l2;
1208 int len;
1210 switch (uLevel) {
1211 case 0: struct_len = 16; break;
1212 case 1: struct_len = 26; break;
1213 default: return -1;
1216 if (!buf)
1218 len = 0;
1219 switch (uLevel)
1221 case 1:
1222 len = strlen(service->comment)+1;
1223 break;
1226 if (buflen) *buflen = struct_len;
1227 if (stringspace) *stringspace = len;
1228 return struct_len + len;
1231 len = struct_len;
1232 p = *buf;
1233 if (*buflen < struct_len) return -1;
1234 if (stringbuf)
1236 p2 = *stringbuf;
1237 l2 = *stringspace;
1239 else
1241 p2 = p + struct_len;
1242 l2 = *buflen - struct_len;
1244 if (!baseaddr) baseaddr = p;
1246 switch (uLevel)
1248 case 0:
1249 push_ascii(p,service->name, 15, STR_TERMINATE);
1250 break;
1252 case 1:
1253 push_ascii(p,service->name,15, STR_TERMINATE);
1254 SIVAL(p,18,service->type);
1255 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1256 len += CopyAndAdvance(&p2,service->comment,&l2);
1257 break;
1260 if (stringbuf)
1262 *buf = p + struct_len;
1263 *buflen -= struct_len;
1264 *stringbuf = p2;
1265 *stringspace = l2;
1267 else
1269 *buf = p2;
1270 *buflen -= len;
1272 return len;
1276 static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1278 return(strcmp(s1->name,s2->name));
1281 /****************************************************************************
1282 view list of servers available (or possibly domains). The info is
1283 extracted from lists saved by nmbd on the local host
1284 ****************************************************************************/
1285 static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param, char *data,
1286 int mdrcnt, int mprcnt, char **rdata,
1287 char **rparam, int *rdata_len, int *rparam_len)
1289 char *str1 = param+2;
1290 char *str2 = skip_string(str1,1);
1291 char *p = skip_string(str2,1);
1292 int uLevel = SVAL(p,0);
1293 int buf_len = SVAL(p,2);
1294 uint32 servertype = IVAL(p,4);
1295 char *p2;
1296 int data_len, fixed_len, string_len;
1297 int f_len = 0, s_len = 0;
1298 struct srv_info_struct *servers=NULL;
1299 int counted=0,total=0;
1300 int i,missed;
1301 fstring domain;
1302 BOOL domain_request;
1303 BOOL local_request;
1305 /* If someone sets all the bits they don't really mean to set
1306 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1307 known servers. */
1309 if (servertype == SV_TYPE_ALL)
1310 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1312 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1313 any other bit (they may just set this bit on it's own) they
1314 want all the locally seen servers. However this bit can be
1315 set on its own so set the requested servers to be
1316 ALL - DOMAIN_ENUM. */
1318 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM))
1319 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1321 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1322 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1324 p += 8;
1326 if (!prefix_ok(str1,"WrLehD")) return False;
1327 if (!check_server_info(uLevel,str2)) return False;
1329 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1330 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1331 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1333 if (strcmp(str1, "WrLehDz") == 0) {
1334 pull_ascii_fstring(domain, p);
1335 } else {
1336 fstrcpy(domain, global_myworkgroup);
1339 if (lp_browse_list())
1340 total = get_server_info(servertype,&servers,domain);
1342 data_len = fixed_len = string_len = 0;
1343 missed = 0;
1345 if (total > 0)
1346 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1349 char *lastname=NULL;
1351 for (i=0;i<total;i++)
1353 struct srv_info_struct *s = &servers[i];
1354 if (lastname && strequal(lastname,s->name)) continue;
1355 lastname = s->name;
1356 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1357 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1358 s->name, s->type, s->comment, s->domain));
1360 if (data_len <= buf_len) {
1361 counted++;
1362 fixed_len += f_len;
1363 string_len += s_len;
1364 } else {
1365 missed++;
1370 *rdata_len = fixed_len + string_len;
1371 *rdata = REALLOC(*rdata,*rdata_len);
1372 memset(*rdata,'\0',*rdata_len);
1374 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1375 p = *rdata;
1376 f_len = fixed_len;
1377 s_len = string_len;
1380 char *lastname=NULL;
1381 int count2 = counted;
1382 for (i = 0; i < total && count2;i++)
1384 struct srv_info_struct *s = &servers[i];
1385 if (lastname && strequal(lastname,s->name)) continue;
1386 lastname = s->name;
1387 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1388 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1389 s->name, s->type, s->comment, s->domain));
1390 count2--;
1394 *rparam_len = 8;
1395 *rparam = REALLOC(*rparam,*rparam_len);
1396 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1397 SSVAL(*rparam,2,0);
1398 SSVAL(*rparam,4,counted);
1399 SSVAL(*rparam,6,counted+missed);
1401 SAFE_FREE(servers);
1403 DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1404 domain,uLevel,counted,counted+missed));
1406 return(True);
1409 /****************************************************************************
1410 command 0x34 - suspected of being a "Lookup Names" stub api
1411 ****************************************************************************/
1412 static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid, char *param, char *data,
1413 int mdrcnt, int mprcnt, char **rdata,
1414 char **rparam, int *rdata_len, int *rparam_len)
1416 char *str1 = param+2;
1417 char *str2 = skip_string(str1,1);
1418 char *p = skip_string(str2,1);
1419 int uLevel = SVAL(p,0);
1420 int buf_len = SVAL(p,2);
1421 int counted=0;
1422 int missed=0;
1424 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1425 str1, str2, p, uLevel, buf_len));
1427 if (!prefix_ok(str1,"zWrLeh")) return False;
1429 *rdata_len = 0;
1431 *rparam_len = 8;
1432 *rparam = REALLOC(*rparam,*rparam_len);
1434 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1435 SSVAL(*rparam,2,0);
1436 SSVAL(*rparam,4,counted);
1437 SSVAL(*rparam,6,counted+missed);
1439 return(True);
1442 /****************************************************************************
1443 get info about a share
1444 ****************************************************************************/
1445 static BOOL check_share_info(int uLevel, char* id)
1447 switch( uLevel ) {
1448 case 0:
1449 if (strcmp(id,"B13") != 0) return False;
1450 break;
1451 case 1:
1452 if (strcmp(id,"B13BWz") != 0) return False;
1453 break;
1454 case 2:
1455 if (strcmp(id,"B13BWzWWWzB9B") != 0) return False;
1456 break;
1457 case 91:
1458 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) return False;
1459 break;
1460 default: return False;
1462 return True;
1465 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1466 char** buf, int* buflen,
1467 char** stringbuf, int* stringspace, char* baseaddr)
1469 int struct_len;
1470 char* p;
1471 char* p2;
1472 int l2;
1473 int len;
1475 switch( uLevel ) {
1476 case 0: struct_len = 13; break;
1477 case 1: struct_len = 20; break;
1478 case 2: struct_len = 40; break;
1479 case 91: struct_len = 68; break;
1480 default: return -1;
1484 if (!buf)
1486 len = 0;
1487 if (uLevel > 0) len += StrlenExpanded(conn,snum,lp_comment(snum));
1488 if (uLevel > 1) len += strlen(lp_pathname(snum)) + 1;
1489 if (buflen) *buflen = struct_len;
1490 if (stringspace) *stringspace = len;
1491 return struct_len + len;
1494 len = struct_len;
1495 p = *buf;
1496 if ((*buflen) < struct_len) return -1;
1497 if (stringbuf)
1499 p2 = *stringbuf;
1500 l2 = *stringspace;
1502 else
1504 p2 = p + struct_len;
1505 l2 = (*buflen) - struct_len;
1507 if (!baseaddr) baseaddr = p;
1509 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1511 if (uLevel > 0)
1513 int type;
1514 SCVAL(p,13,0);
1515 type = STYPE_DISKTREE;
1516 if (lp_print_ok(snum)) type = STYPE_PRINTQ;
1517 if (strequal("IPC",lp_fstype(snum))) type = STYPE_IPC;
1518 SSVAL(p,14,type); /* device type */
1519 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1520 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1523 if (uLevel > 1)
1525 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1526 SSVALS(p,22,-1); /* max uses */
1527 SSVAL(p,24,1); /* current uses */
1528 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1529 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1530 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1533 if (uLevel > 2)
1535 memset(p+40,0,SHPWLEN+2);
1536 SSVAL(p,50,0);
1537 SIVAL(p,52,0);
1538 SSVAL(p,56,0);
1539 SSVAL(p,58,0);
1540 SIVAL(p,60,0);
1541 SSVAL(p,64,0);
1542 SSVAL(p,66,0);
1545 if (stringbuf)
1547 (*buf) = p + struct_len;
1548 (*buflen) -= struct_len;
1549 (*stringbuf) = p2;
1550 (*stringspace) = l2;
1552 else
1554 (*buf) = p2;
1555 (*buflen) -= len;
1557 return len;
1560 static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
1561 int mdrcnt,int mprcnt,
1562 char **rdata,char **rparam,
1563 int *rdata_len,int *rparam_len)
1565 char *str1 = param+2;
1566 char *str2 = skip_string(str1,1);
1567 char *netname = skip_string(str2,1);
1568 char *p = skip_string(netname,1);
1569 int uLevel = SVAL(p,0);
1570 int snum = find_service(netname);
1572 if (snum < 0) return False;
1574 /* check it's a supported varient */
1575 if (!prefix_ok(str1,"zWrLh")) return False;
1576 if (!check_share_info(uLevel,str2)) return False;
1578 *rdata = REALLOC(*rdata,mdrcnt);
1579 p = *rdata;
1580 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1581 if (*rdata_len < 0) return False;
1583 *rparam_len = 6;
1584 *rparam = REALLOC(*rparam,*rparam_len);
1585 SSVAL(*rparam,0,NERR_Success);
1586 SSVAL(*rparam,2,0); /* converter word */
1587 SSVAL(*rparam,4,*rdata_len);
1589 return(True);
1592 /****************************************************************************
1593 view list of shares available
1594 ****************************************************************************/
1595 static BOOL api_RNetShareEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
1596 int mdrcnt,int mprcnt,
1597 char **rdata,char **rparam,
1598 int *rdata_len,int *rparam_len)
1600 char *str1 = param+2;
1601 char *str2 = skip_string(str1,1);
1602 char *p = skip_string(str2,1);
1603 int uLevel = SVAL(p,0);
1604 int buf_len = SVAL(p,2);
1605 char *p2;
1606 int count=lp_numservices();
1607 int total=0,counted=0;
1608 BOOL missed = False;
1609 int i;
1610 int data_len, fixed_len, string_len;
1611 int f_len = 0, s_len = 0;
1613 if (!prefix_ok(str1,"WrLeh")) return False;
1614 if (!check_share_info(uLevel,str2)) return False;
1616 data_len = fixed_len = string_len = 0;
1617 for (i=0;i<count;i++)
1618 if (lp_browseable(i) && lp_snum_ok(i))
1620 total++;
1621 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1622 if (data_len <= buf_len)
1624 counted++;
1625 fixed_len += f_len;
1626 string_len += s_len;
1628 else
1629 missed = True;
1631 *rdata_len = fixed_len + string_len;
1632 *rdata = REALLOC(*rdata,*rdata_len);
1633 memset(*rdata,0,*rdata_len);
1635 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
1636 p = *rdata;
1637 f_len = fixed_len;
1638 s_len = string_len;
1639 for (i = 0; i < count;i++)
1640 if (lp_browseable(i) && lp_snum_ok(i))
1641 if (fill_share_info(conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata) < 0)
1642 break;
1644 *rparam_len = 8;
1645 *rparam = REALLOC(*rparam,*rparam_len);
1646 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1647 SSVAL(*rparam,2,0);
1648 SSVAL(*rparam,4,counted);
1649 SSVAL(*rparam,6,total);
1651 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1652 counted,total,uLevel,
1653 buf_len,*rdata_len,mdrcnt));
1654 return(True);
1657 /****************************************************************************
1658 Add a share
1659 ****************************************************************************/
1660 static BOOL api_RNetShareAdd(connection_struct *conn,uint16 vuid, char *param,char *data,
1661 int mdrcnt,int mprcnt,
1662 char **rdata,char **rparam,
1663 int *rdata_len,int *rparam_len)
1665 char *str1 = param+2;
1666 char *str2 = skip_string(str1,1);
1667 char *p = skip_string(str2,1);
1668 int uLevel = SVAL(p,0);
1669 fstring sharename;
1670 fstring comment;
1671 pstring pathname;
1672 char *command, *cmdname;
1673 unsigned int offset;
1674 int snum;
1675 int res = ERRunsup;
1677 /* check it's a supported varient */
1678 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) return False;
1679 if (!check_share_info(uLevel,str2)) return False;
1680 if (uLevel != 2) return False;
1682 pull_ascii_fstring(sharename,data);
1683 snum = find_service(sharename);
1684 if (snum >= 0) { /* already exists */
1685 res = ERRfilexists;
1686 goto error_exit;
1689 /* only support disk share adds */
1690 if (SVAL(data,14)!=STYPE_DISKTREE) return False;
1692 offset = IVAL(data, 16);
1693 if (offset >= mdrcnt) {
1694 res = ERRinvalidparam;
1695 goto error_exit;
1697 pull_ascii_fstring(comment, offset? (data+offset) : "");
1699 offset = IVAL(data, 26);
1700 if (offset >= mdrcnt) {
1701 res = ERRinvalidparam;
1702 goto error_exit;
1704 pull_ascii_pstring(pathname, offset? (data+offset) : "");
1706 string_replace(sharename, '"', ' ');
1707 string_replace(pathname, '"', ' ');
1708 string_replace(comment, '"', ' ');
1710 cmdname = lp_add_share_cmd();
1712 if (!cmdname || *cmdname == '\0') return False;
1714 asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
1715 lp_add_share_cmd(), dyn_CONFIGFILE, sharename, pathname, comment);
1717 if (command) {
1718 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
1719 if ((res = smbrun(command, NULL)) != 0) {
1720 DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n", command, res ));
1721 SAFE_FREE(command);
1722 res = ERRnoaccess;
1723 goto error_exit;
1724 } else {
1725 SAFE_FREE(command);
1726 message_send_all(conn_tdb_ctx(), MSG_SMB_CONF_UPDATED, NULL, 0, False, NULL);
1728 } else return False;
1730 *rparam_len = 6;
1731 *rparam = REALLOC(*rparam,*rparam_len);
1732 SSVAL(*rparam,0,NERR_Success);
1733 SSVAL(*rparam,2,0); /* converter word */
1734 SSVAL(*rparam,4,*rdata_len);
1735 *rdata_len = 0;
1737 return True;
1739 error_exit:
1740 *rparam_len = 4;
1741 *rparam = REALLOC(*rparam,*rparam_len);
1742 *rdata_len = 0;
1743 SSVAL(*rparam,0,res);
1744 SSVAL(*rparam,2,0);
1745 return True;
1749 /****************************************************************************
1750 view list of groups available
1751 ****************************************************************************/
1752 static BOOL api_RNetGroupEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
1753 int mdrcnt,int mprcnt,
1754 char **rdata,char **rparam,
1755 int *rdata_len,int *rparam_len)
1757 int i;
1758 int errflags=0;
1759 int resume_context, cli_buf_size;
1760 char *str1 = param+2;
1761 char *str2 = skip_string(str1,1);
1762 char *p = skip_string(str2,1);
1764 GROUP_MAP *group_list;
1765 int num_entries;
1767 if (strcmp(str1,"WrLeh") != 0)
1768 return False;
1770 /* parameters
1771 * W-> resume context (number of users to skip)
1772 * r -> return parameter pointer to receive buffer
1773 * L -> length of receive buffer
1774 * e -> return parameter number of entries
1775 * h -> return parameter total number of users
1777 if (strcmp("B21",str2) != 0)
1778 return False;
1780 /* get list of domain groups SID_DOMAIN_GRP=2 */
1781 if(!enum_group_mapping(SID_NAME_DOM_GRP , &group_list, &num_entries, False, False)) {
1782 DEBUG(3,("api_RNetGroupEnum:failed to get group list"));
1783 return False;
1786 resume_context = SVAL(p,0);
1787 cli_buf_size=SVAL(p+2,0);
1788 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: %d\n", resume_context, cli_buf_size));
1790 *rdata_len = cli_buf_size;
1791 *rdata = REALLOC(*rdata,*rdata_len);
1793 p = *rdata;
1795 for(i=resume_context; i<num_entries; i++) {
1796 char* name=group_list[i].nt_name;
1797 if( ((PTR_DIFF(p,*rdata)+21) <= *rdata_len) ) {
1798 /* truncate the name at 21 chars. */
1799 memcpy(p, name, 21);
1800 DEBUG(10,("adding entry %d group %s\n", i, p));
1801 p += 21;
1802 } else {
1803 /* set overflow error */
1804 DEBUG(3,("overflow on entry %d group %s\n", i, name));
1805 errflags=234;
1806 break;
1810 *rdata_len = PTR_DIFF(p,*rdata);
1812 *rparam_len = 8;
1813 *rparam = REALLOC(*rparam,*rparam_len);
1815 SSVAL(*rparam, 0, errflags);
1816 SSVAL(*rparam, 2, 0); /* converter word */
1817 SSVAL(*rparam, 4, i-resume_context); /* is this right?? */
1818 SSVAL(*rparam, 6, num_entries); /* is this right?? */
1820 return(True);
1823 /*******************************************************************
1824 get groups that a user is a member of
1825 ******************************************************************/
1826 static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *param,char *data,
1827 int mdrcnt,int mprcnt,
1828 char **rdata,char **rparam,
1829 int *rdata_len,int *rparam_len)
1831 char *str1 = param+2;
1832 char *str2 = skip_string(str1,1);
1833 char *UserName = skip_string(str2,1);
1834 char *p = skip_string(UserName,1);
1835 int uLevel = SVAL(p,0);
1836 char *p2;
1837 int count=0;
1839 *rparam_len = 8;
1840 *rparam = REALLOC(*rparam,*rparam_len);
1842 /* check it's a supported varient */
1843 if (!strcmp(str1,"zWrLeh"))
1844 return False;
1845 switch( uLevel ) {
1846 case 0:
1847 p2 = "B21";
1848 break;
1849 default:
1850 return False;
1853 if (strcmp(p2,str2) != 0)
1854 return False;
1856 *rdata_len = mdrcnt + 1024;
1857 *rdata = REALLOC(*rdata,*rdata_len);
1859 SSVAL(*rparam,0,NERR_Success);
1860 SSVAL(*rparam,2,0); /* converter word */
1862 p = *rdata;
1864 /* XXXX we need a real SAM database some day */
1865 pstrcpy(p,"Users"); p += 21; count++;
1866 pstrcpy(p,"Domain Users"); p += 21; count++;
1867 pstrcpy(p,"Guests"); p += 21; count++;
1868 pstrcpy(p,"Domain Guests"); p += 21; count++;
1870 *rdata_len = PTR_DIFF(p,*rdata);
1872 SSVAL(*rparam,4,count); /* is this right?? */
1873 SSVAL(*rparam,6,count); /* is this right?? */
1875 return(True);
1878 /*******************************************************************
1879 get all users
1880 ******************************************************************/
1881 static BOOL api_RNetUserEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
1882 int mdrcnt,int mprcnt,
1883 char **rdata,char **rparam,
1884 int *rdata_len,int *rparam_len)
1886 SAM_ACCOUNT *pwd=NULL;
1887 int count_sent=0;
1888 int count_total=0;
1889 int errflags=0;
1890 int resume_context, cli_buf_size;
1892 char *str1 = param+2;
1893 char *str2 = skip_string(str1,1);
1894 char *p = skip_string(str2,1);
1896 if (strcmp(str1,"WrLeh") != 0)
1897 return False;
1898 /* parameters
1899 * W-> resume context (number of users to skip)
1900 * r -> return parameter pointer to receive buffer
1901 * L -> length of receive buffer
1902 * e -> return parameter number of entries
1903 * h -> return parameter total number of users
1906 resume_context = SVAL(p,0);
1907 cli_buf_size=SVAL(p+2,0);
1908 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n", resume_context, cli_buf_size));
1910 *rparam_len = 8;
1911 *rparam = REALLOC(*rparam,*rparam_len);
1913 /* check it's a supported varient */
1914 if (strcmp("B21",str2) != 0)
1915 return False;
1917 *rdata_len = cli_buf_size;
1918 *rdata = REALLOC(*rdata,*rdata_len);
1920 p = *rdata;
1922 /* to get user list enumerations for NetUserEnum in B21 format */
1923 pdb_init_sam(&pwd);
1925 /* Open the passgrp file - not for update. */
1926 become_root();
1927 if(!pdb_setsampwent(False)) {
1928 DEBUG(0, ("api_RNetUserEnum:unable to open sam database.\n"));
1929 unbecome_root();
1930 return False;
1932 errflags=NERR_Success;
1934 while ( pdb_getsampwent(pwd) ) {
1935 const char *name=pdb_get_username(pwd);
1936 if ((name) && (*(name+strlen(name)-1)!='$')) {
1937 count_total++;
1938 if(count_total>=resume_context) {
1939 if( ((PTR_DIFF(p,*rdata)+21)<=*rdata_len)&&(strlen(name)<=21) ) {
1940 pstrcpy(p,name);
1941 DEBUG(10,("api_RNetUserEnum:adding entry %d username %s\n",count_sent,p));
1942 p += 21;
1943 count_sent++;
1944 } else {
1945 /* set overflow error */
1946 DEBUG(10,("api_RNetUserEnum:overflow on entry %d username %s\n",count_sent,name));
1947 errflags=234;
1948 break;
1954 pdb_endsampwent();
1955 unbecome_root();
1957 pdb_free_sam(&pwd);
1959 *rdata_len = PTR_DIFF(p,*rdata);
1961 SSVAL(*rparam,0,errflags);
1962 SSVAL(*rparam,2,0); /* converter word */
1963 SSVAL(*rparam,4,count_sent); /* is this right?? */
1964 SSVAL(*rparam,6,count_total); /* is this right?? */
1966 return True;
1971 /****************************************************************************
1972 get the time of day info
1973 ****************************************************************************/
1974 static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid, char *param,char *data,
1975 int mdrcnt,int mprcnt,
1976 char **rdata,char **rparam,
1977 int *rdata_len,int *rparam_len)
1979 char *p;
1980 *rparam_len = 4;
1981 *rparam = REALLOC(*rparam,*rparam_len);
1983 *rdata_len = 21;
1984 *rdata = REALLOC(*rdata,*rdata_len);
1986 SSVAL(*rparam,0,NERR_Success);
1987 SSVAL(*rparam,2,0); /* converter word */
1989 p = *rdata;
1992 struct tm *t;
1993 time_t unixdate = time(NULL);
1995 put_dos_date3(p,0,unixdate); /* this is the time that is looked at
1996 by NT in a "net time" operation,
1997 it seems to ignore the one below */
1999 /* the client expects to get localtime, not GMT, in this bit
2000 (I think, this needs testing) */
2001 t = LocalTime(&unixdate);
2003 SIVAL(p,4,0); /* msecs ? */
2004 SCVAL(p,8,t->tm_hour);
2005 SCVAL(p,9,t->tm_min);
2006 SCVAL(p,10,t->tm_sec);
2007 SCVAL(p,11,0); /* hundredths of seconds */
2008 SSVALS(p,12,TimeDiff(unixdate)/60); /* timezone in minutes from GMT */
2009 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2010 SCVAL(p,16,t->tm_mday);
2011 SCVAL(p,17,t->tm_mon + 1);
2012 SSVAL(p,18,1900+t->tm_year);
2013 SCVAL(p,20,t->tm_wday);
2017 return(True);
2020 /****************************************************************************
2021 Set the user password.
2022 *****************************************************************************/
2024 static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param,char *data,
2025 int mdrcnt,int mprcnt,
2026 char **rdata,char **rparam,
2027 int *rdata_len,int *rparam_len)
2029 char *p = skip_string(param+2,2);
2030 fstring user;
2031 fstring pass1,pass2;
2033 pull_ascii_fstring(user,p);
2035 p = skip_string(p,1);
2037 memset(pass1,'\0',sizeof(pass1));
2038 memset(pass2,'\0',sizeof(pass2));
2039 memcpy(pass1,p,16);
2040 memcpy(pass2,p+16,16);
2042 *rparam_len = 4;
2043 *rparam = REALLOC(*rparam,*rparam_len);
2045 *rdata_len = 0;
2047 SSVAL(*rparam,0,NERR_badpass);
2048 SSVAL(*rparam,2,0); /* converter word */
2050 DEBUG(3,("Set password for <%s>\n",user));
2053 * Attempt to verify the old password against smbpasswd entries
2054 * Win98 clients send old and new password in plaintext for this call.
2058 auth_serversupplied_info *server_info = NULL;
2059 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2060 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2063 * If unix password sync was requested, attempt to change
2064 * the /etc/passwd database first. Return failure if this cannot
2065 * be done.
2067 * This occurs before the oem change, becouse we don't want to
2068 * update it if chgpasswd failed.
2070 * Conditional on lp_unix_password_sync() becouse we don't want
2071 * to touch the unix db unless we have admin permission.
2074 if(lp_unix_password_sync() && IS_SAM_UNIX_USER(server_info->sam_account)
2075 && !chgpasswd(pdb_get_username(server_info->sam_account),
2076 pass1,pass2,False)) {
2077 SSVAL(*rparam,0,NERR_badpass);
2080 if (change_oem_password(server_info->sam_account,pass2))
2082 SSVAL(*rparam,0,NERR_Success);
2085 free_server_info(&server_info);
2087 data_blob_clear_free(&password);
2091 * If the plaintext change failed, attempt
2092 * the old encrypted method. NT will generate this
2093 * after trying the samr method. Note that this
2094 * method is done as a last resort as this
2095 * password change method loses the NT password hash
2096 * and cannot change the UNIX password as no plaintext
2097 * is received.
2100 if(SVAL(*rparam,0) != NERR_Success)
2102 SAM_ACCOUNT *hnd = NULL;
2104 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd) &&
2105 change_lanman_password(hnd,(unsigned char *)pass1,(unsigned char *)pass2))
2107 SSVAL(*rparam,0,NERR_Success);
2109 pdb_free_sam(&hnd);
2113 memset((char *)pass1,'\0',sizeof(fstring));
2114 memset((char *)pass2,'\0',sizeof(fstring));
2116 return(True);
2119 /****************************************************************************
2120 Set the user password (SamOEM version - gets plaintext).
2121 ****************************************************************************/
2123 static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char *param,char *data,
2124 int mdrcnt,int mprcnt,
2125 char **rdata,char **rparam,
2126 int *rdata_len,int *rparam_len)
2128 fstring user;
2129 char *p = param + 2;
2130 *rparam_len = 2;
2131 *rparam = REALLOC(*rparam,*rparam_len);
2133 *rdata_len = 0;
2135 SSVAL(*rparam,0,NERR_badpass);
2138 * Check the parameter definition is correct.
2140 if(!strequal(param + 2, "zsT")) {
2141 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", param + 2));
2142 return False;
2144 p = skip_string(p, 1);
2146 if(!strequal(p, "B516B16")) {
2147 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2148 return False;
2150 p = skip_string(p,1);
2152 p += pull_ascii_fstring(user,p);
2154 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2157 * Pass the user through the NT -> unix user mapping
2158 * function.
2161 (void)map_username(user);
2163 if (pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL))
2165 SSVAL(*rparam,0,NERR_Success);
2168 return(True);
2171 /****************************************************************************
2172 delete a print job
2173 Form: <W> <>
2174 ****************************************************************************/
2175 static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param,char *data,
2176 int mdrcnt,int mprcnt,
2177 char **rdata,char **rparam,
2178 int *rdata_len,int *rparam_len)
2180 int function = SVAL(param,0);
2181 char *str1 = param+2;
2182 char *str2 = skip_string(str1,1);
2183 char *p = skip_string(str2,1);
2184 uint32 jobid;
2185 int snum;
2186 int errcode;
2187 extern struct current_user current_user;
2188 WERROR werr = WERR_OK;
2190 if(!rap_to_pjobid(SVAL(p,0),&snum,&jobid))
2191 return False;
2193 /* check it's a supported varient */
2194 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2195 return(False);
2197 *rparam_len = 4;
2198 *rparam = REALLOC(*rparam,*rparam_len);
2199 *rdata_len = 0;
2201 if (!print_job_exists(snum, jobid)) {
2202 errcode = NERR_JobNotFound;
2203 goto out;
2206 errcode = NERR_notsupported;
2208 switch (function) {
2209 case 81: /* delete */
2210 if (print_job_delete(&current_user, snum, jobid, &werr))
2211 errcode = NERR_Success;
2212 break;
2213 case 82: /* pause */
2214 if (print_job_pause(&current_user, snum, jobid, &werr))
2215 errcode = NERR_Success;
2216 break;
2217 case 83: /* resume */
2218 if (print_job_resume(&current_user, snum, jobid, &werr))
2219 errcode = NERR_Success;
2220 break;
2223 if (!W_ERROR_IS_OK(werr))
2224 errcode = W_ERROR_V(werr);
2226 out:
2227 SSVAL(*rparam,0,errcode);
2228 SSVAL(*rparam,2,0); /* converter word */
2230 return(True);
2233 /****************************************************************************
2234 Purge a print queue - or pause or resume it.
2235 ****************************************************************************/
2236 static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid, char *param,char *data,
2237 int mdrcnt,int mprcnt,
2238 char **rdata,char **rparam,
2239 int *rdata_len,int *rparam_len)
2241 int function = SVAL(param,0);
2242 char *str1 = param+2;
2243 char *str2 = skip_string(str1,1);
2244 char *QueueName = skip_string(str2,1);
2245 int errcode = NERR_notsupported;
2246 int snum;
2247 WERROR werr = WERR_OK;
2248 extern struct current_user current_user;
2250 /* check it's a supported varient */
2251 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
2252 return(False);
2254 *rparam_len = 4;
2255 *rparam = REALLOC(*rparam,*rparam_len);
2256 *rdata_len = 0;
2258 snum = print_queue_snum(QueueName);
2260 if (snum == -1) {
2261 errcode = NERR_JobNotFound;
2262 goto out;
2265 switch (function) {
2266 case 74: /* Pause queue */
2267 if (print_queue_pause(&current_user, snum, &werr)) errcode = NERR_Success;
2268 break;
2269 case 75: /* Resume queue */
2270 if (print_queue_resume(&current_user, snum, &werr)) errcode = NERR_Success;
2271 break;
2272 case 103: /* Purge */
2273 if (print_queue_purge(&current_user, snum, &werr)) errcode = NERR_Success;
2274 break;
2277 if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr);
2279 out:
2280 SSVAL(*rparam,0,errcode);
2281 SSVAL(*rparam,2,0); /* converter word */
2283 return(True);
2287 /****************************************************************************
2288 set the property of a print job (undocumented?)
2289 ? function = 0xb -> set name of print job
2290 ? function = 0x6 -> move print job up/down
2291 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
2292 or <WWsTP> <WB21BB16B10zWWzDDz>
2293 ****************************************************************************/
2294 static int check_printjob_info(struct pack_desc* desc,
2295 int uLevel, char* id)
2297 desc->subformat = NULL;
2298 switch( uLevel ) {
2299 case 0: desc->format = "W"; break;
2300 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2301 case 2: desc->format = "WWzWWDDzz"; break;
2302 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2303 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2304 default: return False;
2306 if (strcmp(desc->format,id) != 0) return False;
2307 return True;
2310 static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,char *data,
2311 int mdrcnt,int mprcnt,
2312 char **rdata,char **rparam,
2313 int *rdata_len,int *rparam_len)
2315 struct pack_desc desc;
2316 char *str1 = param+2;
2317 char *str2 = skip_string(str1,1);
2318 char *p = skip_string(str2,1);
2319 uint32 jobid;
2320 int snum;
2321 int uLevel = SVAL(p,2);
2322 int function = SVAL(p,4);
2323 int place, errcode;
2325 if(!rap_to_pjobid(SVAL(p,0),&snum,&jobid))
2326 return False;
2327 *rparam_len = 4;
2328 *rparam = REALLOC(*rparam,*rparam_len);
2330 *rdata_len = 0;
2332 /* check it's a supported varient */
2333 if ((strcmp(str1,"WWsTP")) ||
2334 (!check_printjob_info(&desc,uLevel,str2)))
2335 return(False);
2337 if (!print_job_exists(snum, jobid)) {
2338 errcode=NERR_JobNotFound;
2339 goto out;
2342 errcode = NERR_notsupported;
2344 switch (function) {
2345 case 0x6:
2346 /* change job place in the queue,
2347 data gives the new place */
2348 place = SVAL(data,0);
2349 if (print_job_set_place(snum, jobid, place)) {
2350 errcode=NERR_Success;
2352 break;
2354 case 0xb:
2355 /* change print job name, data gives the name */
2356 if (print_job_set_name(snum, jobid, data)) {
2357 errcode=NERR_Success;
2359 break;
2361 default:
2362 return False;
2365 out:
2366 SSVALS(*rparam,0,errcode);
2367 SSVAL(*rparam,2,0); /* converter word */
2369 return(True);
2373 /****************************************************************************
2374 get info about the server
2375 ****************************************************************************/
2376 static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2377 int mdrcnt,int mprcnt,
2378 char **rdata,char **rparam,
2379 int *rdata_len,int *rparam_len)
2381 char *str1 = param+2;
2382 char *str2 = skip_string(str1,1);
2383 char *p = skip_string(str2,1);
2384 int uLevel = SVAL(p,0);
2385 char *p2;
2386 int struct_len;
2388 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2390 /* check it's a supported varient */
2391 if (!prefix_ok(str1,"WrLh")) return False;
2392 switch( uLevel ) {
2393 case 0:
2394 if (strcmp(str2,"B16") != 0) return False;
2395 struct_len = 16;
2396 break;
2397 case 1:
2398 if (strcmp(str2,"B16BBDz") != 0) return False;
2399 struct_len = 26;
2400 break;
2401 case 2:
2402 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")
2403 != 0) return False;
2404 struct_len = 134;
2405 break;
2406 case 3:
2407 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz")
2408 != 0) return False;
2409 struct_len = 144;
2410 break;
2411 case 20:
2412 if (strcmp(str2,"DN") != 0) return False;
2413 struct_len = 6;
2414 break;
2415 case 50:
2416 if (strcmp(str2,"B16BBDzWWzzz") != 0) return False;
2417 struct_len = 42;
2418 break;
2419 default: return False;
2422 *rdata_len = mdrcnt;
2423 *rdata = REALLOC(*rdata,*rdata_len);
2425 p = *rdata;
2426 p2 = p + struct_len;
2427 if (uLevel != 20) {
2428 srvstr_push(NULL, p,local_machine,16,
2429 STR_ASCII|STR_UPPER|STR_TERMINATE);
2431 p += 16;
2432 if (uLevel > 0)
2434 struct srv_info_struct *servers=NULL;
2435 int i,count;
2436 pstring comment;
2437 uint32 servertype= lp_default_server_announce();
2439 pstrcpy(comment,string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH));
2441 if ((count=get_server_info(SV_TYPE_ALL,&servers,global_myworkgroup))>0) {
2442 for (i=0;i<count;i++)
2443 if (strequal(servers[i].name,local_machine))
2445 servertype = servers[i].type;
2446 pstrcpy(comment,servers[i].comment);
2449 SAFE_FREE(servers);
2451 SCVAL(p,0,lp_major_announce_version());
2452 SCVAL(p,1,lp_minor_announce_version());
2453 SIVAL(p,2,servertype);
2455 if (mdrcnt == struct_len) {
2456 SIVAL(p,6,0);
2457 } else {
2458 SIVAL(p,6,PTR_DIFF(p2,*rdata));
2459 standard_sub_conn(conn,comment,sizeof(comment));
2460 StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2461 p2 = skip_string(p2,1);
2464 if (uLevel > 1)
2466 return False; /* not yet implemented */
2469 *rdata_len = PTR_DIFF(p2,*rdata);
2471 *rparam_len = 6;
2472 *rparam = REALLOC(*rparam,*rparam_len);
2473 SSVAL(*rparam,0,NERR_Success);
2474 SSVAL(*rparam,2,0); /* converter word */
2475 SSVAL(*rparam,4,*rdata_len);
2477 return(True);
2481 /****************************************************************************
2482 get info about the server
2483 ****************************************************************************/
2484 static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2485 int mdrcnt,int mprcnt,
2486 char **rdata,char **rparam,
2487 int *rdata_len,int *rparam_len)
2489 char *str1 = param+2;
2490 char *str2 = skip_string(str1,1);
2491 char *p = skip_string(str2,1);
2492 char *p2;
2493 extern userdom_struct current_user_info;
2494 int level = SVAL(p,0);
2496 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2498 *rparam_len = 6;
2499 *rparam = REALLOC(*rparam,*rparam_len);
2501 /* check it's a supported varient */
2502 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz")))
2503 return(False);
2505 *rdata_len = mdrcnt + 1024;
2506 *rdata = REALLOC(*rdata,*rdata_len);
2508 SSVAL(*rparam,0,NERR_Success);
2509 SSVAL(*rparam,2,0); /* converter word */
2511 p = *rdata;
2512 p2 = p + 22;
2515 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2516 pstrcpy(p2,local_machine);
2517 strupper(p2);
2518 p2 = skip_string(p2,1);
2519 p += 4;
2521 SIVAL(p,0,PTR_DIFF(p2,*rdata));
2522 pstrcpy(p2,current_user_info.smb_name);
2523 p2 = skip_string(p2,1);
2524 p += 4;
2526 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
2527 pstrcpy(p2,global_myworkgroup);
2528 strupper(p2);
2529 p2 = skip_string(p2,1);
2530 p += 4;
2532 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
2533 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
2534 p += 2;
2536 SIVAL(p,0,PTR_DIFF(p2,*rdata));
2537 pstrcpy(p2,global_myworkgroup); /* don't know. login domain?? */
2538 p2 = skip_string(p2,1);
2539 p += 4;
2541 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
2542 pstrcpy(p2,"");
2543 p2 = skip_string(p2,1);
2544 p += 4;
2546 *rdata_len = PTR_DIFF(p2,*rdata);
2548 SSVAL(*rparam,4,*rdata_len);
2550 return(True);
2553 /****************************************************************************
2554 get info about a user
2556 struct user_info_11 {
2557 char usri11_name[21]; 0-20
2558 char usri11_pad; 21
2559 char *usri11_comment; 22-25
2560 char *usri11_usr_comment; 26-29
2561 unsigned short usri11_priv; 30-31
2562 unsigned long usri11_auth_flags; 32-35
2563 long usri11_password_age; 36-39
2564 char *usri11_homedir; 40-43
2565 char *usri11_parms; 44-47
2566 long usri11_last_logon; 48-51
2567 long usri11_last_logoff; 52-55
2568 unsigned short usri11_bad_pw_count; 56-57
2569 unsigned short usri11_num_logons; 58-59
2570 char *usri11_logon_server; 60-63
2571 unsigned short usri11_country_code; 64-65
2572 char *usri11_workstations; 66-69
2573 unsigned long usri11_max_storage; 70-73
2574 unsigned short usri11_units_per_week; 74-75
2575 unsigned char *usri11_logon_hours; 76-79
2576 unsigned short usri11_code_page; 80-81
2579 where:
2581 usri11_name specifies the user name for which information is retireved
2583 usri11_pad aligns the next data structure element to a word boundary
2585 usri11_comment is a null terminated ASCII comment
2587 usri11_user_comment is a null terminated ASCII comment about the user
2589 usri11_priv specifies the level of the privilege assigned to the user.
2590 The possible values are:
2592 Name Value Description
2593 USER_PRIV_GUEST 0 Guest privilege
2594 USER_PRIV_USER 1 User privilege
2595 USER_PRV_ADMIN 2 Administrator privilege
2597 usri11_auth_flags specifies the account operator privileges. The
2598 possible values are:
2600 Name Value Description
2601 AF_OP_PRINT 0 Print operator
2604 Leach, Naik [Page 28]
2608 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
2611 AF_OP_COMM 1 Communications operator
2612 AF_OP_SERVER 2 Server operator
2613 AF_OP_ACCOUNTS 3 Accounts operator
2616 usri11_password_age specifies how many seconds have elapsed since the
2617 password was last changed.
2619 usri11_home_dir points to a null terminated ASCII string that contains
2620 the path name of the user's home directory.
2622 usri11_parms points to a null terminated ASCII string that is set
2623 aside for use by applications.
2625 usri11_last_logon specifies the time when the user last logged on.
2626 This value is stored as the number of seconds elapsed since
2627 00:00:00, January 1, 1970.
2629 usri11_last_logoff specifies the time when the user last logged off.
2630 This value is stored as the number of seconds elapsed since
2631 00:00:00, January 1, 1970. A value of 0 means the last logoff
2632 time is unknown.
2634 usri11_bad_pw_count specifies the number of incorrect passwords
2635 entered since the last successful logon.
2637 usri11_log1_num_logons specifies the number of times this user has
2638 logged on. A value of -1 means the number of logons is unknown.
2640 usri11_logon_server points to a null terminated ASCII string that
2641 contains the name of the server to which logon requests are sent.
2642 A null string indicates logon requests should be sent to the
2643 domain controller.
2645 usri11_country_code specifies the country code for the user's language
2646 of choice.
2648 usri11_workstations points to a null terminated ASCII string that
2649 contains the names of workstations the user may log on from.
2650 There may be up to 8 workstations, with the names separated by
2651 commas. A null strings indicates there are no restrictions.
2653 usri11_max_storage specifies the maximum amount of disk space the user
2654 can occupy. A value of 0xffffffff indicates there are no
2655 restrictions.
2657 usri11_units_per_week specifies the equal number of time units into
2658 which a week is divided. This value must be equal to 168.
2660 usri11_logon_hours points to a 21 byte (168 bits) string that
2661 specifies the time during which the user can log on. Each bit
2662 represents one unique hour in a week. The first bit (bit 0, word
2663 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
2667 Leach, Naik [Page 29]
2671 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
2674 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
2675 are no restrictions.
2677 usri11_code_page specifies the code page for the user's language of
2678 choice
2680 All of the pointers in this data structure need to be treated
2681 specially. The pointer is a 32 bit pointer. The higher 16 bits need
2682 to be ignored. The converter word returned in the parameters section
2683 needs to be subtracted from the lower 16 bits to calculate an offset
2684 into the return buffer where this ASCII string resides.
2686 There is no auxiliary data in the response.
2688 ****************************************************************************/
2690 #define usri11_name 0
2691 #define usri11_pad 21
2692 #define usri11_comment 22
2693 #define usri11_usr_comment 26
2694 #define usri11_full_name 30
2695 #define usri11_priv 34
2696 #define usri11_auth_flags 36
2697 #define usri11_password_age 40
2698 #define usri11_homedir 44
2699 #define usri11_parms 48
2700 #define usri11_last_logon 52
2701 #define usri11_last_logoff 56
2702 #define usri11_bad_pw_count 60
2703 #define usri11_num_logons 62
2704 #define usri11_logon_server 64
2705 #define usri11_country_code 68
2706 #define usri11_workstations 70
2707 #define usri11_max_storage 74
2708 #define usri11_units_per_week 78
2709 #define usri11_logon_hours 80
2710 #define usri11_code_page 84
2711 #define usri11_end 86
2713 #define USER_PRIV_GUEST 0
2714 #define USER_PRIV_USER 1
2715 #define USER_PRIV_ADMIN 2
2717 #define AF_OP_PRINT 0
2718 #define AF_OP_COMM 1
2719 #define AF_OP_SERVER 2
2720 #define AF_OP_ACCOUNTS 3
2723 static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2724 int mdrcnt,int mprcnt,
2725 char **rdata,char **rparam,
2726 int *rdata_len,int *rparam_len)
2728 char *str1 = param+2;
2729 char *str2 = skip_string(str1,1);
2730 char *UserName = skip_string(str2,1);
2731 char *p = skip_string(UserName,1);
2732 int uLevel = SVAL(p,0);
2733 char *p2;
2735 /* get NIS home of a previously validated user - simeon */
2736 /* With share level security vuid will always be zero.
2737 Don't depend on vuser being non-null !!. JRA */
2738 user_struct *vuser = get_valid_user_struct(vuid);
2739 if(vuser != NULL)
2740 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
2741 vuser->user.unix_name));
2743 *rparam_len = 6;
2744 *rparam = REALLOC(*rparam,*rparam_len);
2746 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
2748 /* check it's a supported variant */
2749 if (strcmp(str1,"zWrLh") != 0) return False;
2750 switch( uLevel )
2752 case 0: p2 = "B21"; break;
2753 case 1: p2 = "B21BB16DWzzWz"; break;
2754 case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
2755 case 10: p2 = "B21Bzzz"; break;
2756 case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
2757 default: return False;
2760 if (strcmp(p2,str2) != 0) return False;
2762 *rdata_len = mdrcnt + 1024;
2763 *rdata = REALLOC(*rdata,*rdata_len);
2765 SSVAL(*rparam,0,NERR_Success);
2766 SSVAL(*rparam,2,0); /* converter word */
2768 p = *rdata;
2769 p2 = p + usri11_end;
2771 memset(p,0,21);
2772 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
2774 if (uLevel > 0)
2776 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
2777 *p2 = 0;
2779 if (uLevel >= 10)
2781 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
2782 pstrcpy(p2,"Comment");
2783 p2 = skip_string(p2,1);
2785 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
2786 pstrcpy(p2,"UserComment");
2787 p2 = skip_string(p2,1);
2789 /* EEK! the cifsrap.txt doesn't have this in!!!! */
2790 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
2791 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2792 p2 = skip_string(p2,1);
2795 if (uLevel == 11) /* modelled after NTAS 3.51 reply */
2797 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2798 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
2799 SIVALS(p,usri11_password_age,-1); /* password age */
2800 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
2801 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
2802 p2 = skip_string(p2,1);
2803 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
2804 pstrcpy(p2,"");
2805 p2 = skip_string(p2,1);
2806 SIVAL(p,usri11_last_logon,0); /* last logon */
2807 SIVAL(p,usri11_last_logoff,0); /* last logoff */
2808 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
2809 SSVALS(p,usri11_num_logons,-1); /* num logons */
2810 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
2811 pstrcpy(p2,"\\\\*");
2812 p2 = skip_string(p2,1);
2813 SSVAL(p,usri11_country_code,0); /* country code */
2815 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
2816 pstrcpy(p2,"");
2817 p2 = skip_string(p2,1);
2819 SIVALS(p,usri11_max_storage,-1); /* max storage */
2820 SSVAL(p,usri11_units_per_week,168); /* units per week */
2821 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
2823 /* a simple way to get logon hours at all times. */
2824 memset(p2,0xff,21);
2825 SCVAL(p2,21,0); /* fix zero termination */
2826 p2 = skip_string(p2,1);
2828 SSVAL(p,usri11_code_page,0); /* code page */
2830 if (uLevel == 1 || uLevel == 2)
2832 memset(p+22,' ',16); /* password */
2833 SIVALS(p,38,-1); /* password age */
2834 SSVAL(p,42,
2835 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2836 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
2837 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
2838 p2 = skip_string(p2,1);
2839 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
2840 *p2++ = 0;
2841 SSVAL(p,52,0); /* flags */
2842 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
2843 pstrcpy(p2,vuser && vuser->logon_script ? vuser->logon_script : "");
2844 p2 = skip_string(p2,1);
2845 if (uLevel == 2)
2847 SIVAL(p,60,0); /* auth_flags */
2848 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
2849 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2850 p2 = skip_string(p2,1);
2851 SIVAL(p,68,0); /* urs_comment */
2852 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
2853 pstrcpy(p2,"");
2854 p2 = skip_string(p2,1);
2855 SIVAL(p,76,0); /* workstations */
2856 SIVAL(p,80,0); /* last_logon */
2857 SIVAL(p,84,0); /* last_logoff */
2858 SIVALS(p,88,-1); /* acct_expires */
2859 SIVALS(p,92,-1); /* max_storage */
2860 SSVAL(p,96,168); /* units_per_week */
2861 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
2862 memset(p2,-1,21);
2863 p2 += 21;
2864 SSVALS(p,102,-1); /* bad_pw_count */
2865 SSVALS(p,104,-1); /* num_logons */
2866 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
2867 pstrcpy(p2,"\\\\%L");
2868 standard_sub_conn(conn, p2,0);
2869 p2 = skip_string(p2,1);
2870 SSVAL(p,110,49); /* country_code */
2871 SSVAL(p,112,860); /* code page */
2875 *rdata_len = PTR_DIFF(p2,*rdata);
2877 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
2879 return(True);
2882 static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param,char *data,
2883 int mdrcnt,int mprcnt,
2884 char **rdata,char **rparam,
2885 int *rdata_len,int *rparam_len)
2887 char *str1 = param+2;
2888 char *str2 = skip_string(str1,1);
2889 char *p = skip_string(str2,1);
2890 int uLevel;
2891 struct pack_desc desc;
2892 char* name;
2893 /* With share level security vuid will always be zero.
2894 Don't depend on vuser being non-null !!. JRA */
2895 user_struct *vuser = get_valid_user_struct(vuid);
2896 if(vuser != NULL)
2897 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
2898 vuser->user.unix_name));
2900 uLevel = SVAL(p,0);
2901 name = p + 2;
2903 memset((char *)&desc,'\0',sizeof(desc));
2905 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
2907 /* check it's a supported varient */
2908 if (strcmp(str1,"OOWb54WrLh") != 0) return False;
2909 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) return False;
2910 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2911 desc.base = *rdata;
2912 desc.buflen = mdrcnt;
2913 desc.subformat = NULL;
2914 desc.format = str2;
2916 if (init_package(&desc,1,0))
2918 PACKI(&desc,"W",0); /* code */
2919 PACKS(&desc,"B21",name); /* eff. name */
2920 PACKS(&desc,"B",""); /* pad */
2921 PACKI(&desc,"W",
2922 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2923 PACKI(&desc,"D",0); /* auth flags XXX */
2924 PACKI(&desc,"W",0); /* num logons */
2925 PACKI(&desc,"W",0); /* bad pw count */
2926 PACKI(&desc,"D",0); /* last logon */
2927 PACKI(&desc,"D",-1); /* last logoff */
2928 PACKI(&desc,"D",-1); /* logoff time */
2929 PACKI(&desc,"D",-1); /* kickoff time */
2930 PACKI(&desc,"D",0); /* password age */
2931 PACKI(&desc,"D",0); /* password can change */
2932 PACKI(&desc,"D",-1); /* password must change */
2934 fstring mypath;
2935 fstrcpy(mypath,"\\\\");
2936 fstrcat(mypath,local_machine);
2937 strupper(mypath);
2938 PACKS(&desc,"z",mypath); /* computer */
2940 PACKS(&desc,"z",global_myworkgroup);/* domain */
2942 PACKS(&desc,"z", vuser && vuser->logon_script ? vuser->logon_script :""); /* script path */
2944 PACKI(&desc,"D",0x00000000); /* reserved */
2947 *rdata_len = desc.usedlen;
2948 *rparam_len = 6;
2949 *rparam = REALLOC(*rparam,*rparam_len);
2950 SSVALS(*rparam,0,desc.errcode);
2951 SSVAL(*rparam,2,0);
2952 SSVAL(*rparam,4,desc.neededlen);
2954 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
2955 return(True);
2959 /****************************************************************************
2960 api_WAccessGetUserPerms
2961 ****************************************************************************/
2962 static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid, char *param,char *data,
2963 int mdrcnt,int mprcnt,
2964 char **rdata,char **rparam,
2965 int *rdata_len,int *rparam_len)
2967 char *str1 = param+2;
2968 char *str2 = skip_string(str1,1);
2969 char *user = skip_string(str2,1);
2970 char *resource = skip_string(user,1);
2972 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
2974 /* check it's a supported varient */
2975 if (strcmp(str1,"zzh") != 0) return False;
2976 if (strcmp(str2,"") != 0) return False;
2978 *rparam_len = 6;
2979 *rparam = REALLOC(*rparam,*rparam_len);
2980 SSVALS(*rparam,0,0); /* errorcode */
2981 SSVAL(*rparam,2,0); /* converter word */
2982 SSVAL(*rparam,4,0x7f); /* permission flags */
2984 return(True);
2987 /****************************************************************************
2988 api_WPrintJobEnumerate
2989 ****************************************************************************/
2990 static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2991 int mdrcnt,int mprcnt,
2992 char **rdata,char **rparam,
2993 int *rdata_len,int *rparam_len)
2995 char *str1 = param+2;
2996 char *str2 = skip_string(str1,1);
2997 char *p = skip_string(str2,1);
2998 int uLevel;
2999 int count;
3000 int i;
3001 int snum;
3002 uint32 jobid;
3003 struct pack_desc desc;
3004 print_queue_struct *queue=NULL;
3005 print_status_struct status;
3006 char *tmpdata=NULL;
3008 uLevel = SVAL(p,2);
3010 memset((char *)&desc,'\0',sizeof(desc));
3011 memset((char *)&status,'\0',sizeof(status));
3013 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
3015 /* check it's a supported varient */
3016 if (strcmp(str1,"WWrLh") != 0) return False;
3017 if (!check_printjob_info(&desc,uLevel,str2)) return False;
3019 if(!rap_to_pjobid(SVAL(p,0),&snum,&jobid))
3020 return False;
3022 if (snum < 0 || !VALID_SNUM(snum)) return(False);
3024 count = print_queue_status(snum,&queue,&status);
3025 for (i = 0; i < count; i++) {
3026 if (queue[i].job == jobid) break;
3029 if (mdrcnt > 0) {
3030 *rdata = REALLOC(*rdata,mdrcnt);
3031 desc.base = *rdata;
3032 desc.buflen = mdrcnt;
3033 } else {
3035 * Don't return data but need to get correct length
3036 * init_package will return wrong size if buflen=0
3038 desc.buflen = getlen(desc.format);
3039 desc.base = tmpdata = (char *)malloc ( desc.buflen );
3042 if (init_package(&desc,1,0)) {
3043 if (i < count) {
3044 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3045 *rdata_len = desc.usedlen;
3047 else {
3048 desc.errcode = NERR_JobNotFound;
3049 *rdata_len = 0;
3053 *rparam_len = 6;
3054 *rparam = REALLOC(*rparam,*rparam_len);
3055 SSVALS(*rparam,0,desc.errcode);
3056 SSVAL(*rparam,2,0);
3057 SSVAL(*rparam,4,desc.neededlen);
3059 SAFE_FREE(queue);
3060 SAFE_FREE(tmpdata);
3062 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
3063 return(True);
3066 static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *param,char *data,
3067 int mdrcnt,int mprcnt,
3068 char **rdata,char **rparam,
3069 int *rdata_len,int *rparam_len)
3071 char *str1 = param+2;
3072 char *str2 = skip_string(str1,1);
3073 char *p = skip_string(str2,1);
3074 char* name = p;
3075 int uLevel;
3076 int count;
3077 int i, succnt=0;
3078 int snum;
3079 struct pack_desc desc;
3080 print_queue_struct *queue=NULL;
3081 print_status_struct status;
3083 memset((char *)&desc,'\0',sizeof(desc));
3084 memset((char *)&status,'\0',sizeof(status));
3086 p = skip_string(p,1);
3087 uLevel = SVAL(p,0);
3089 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
3091 /* check it's a supported variant */
3092 if (strcmp(str1,"zWrLeh") != 0) return False;
3093 if (uLevel > 2) return False; /* defined only for uLevel 0,1,2 */
3094 if (!check_printjob_info(&desc,uLevel,str2)) return False;
3096 snum = lp_servicenumber(name);
3097 if (snum < 0 && pcap_printername_ok(name,NULL)) {
3098 int pnum = lp_servicenumber(PRINTERS_NAME);
3099 if (pnum >= 0) {
3100 lp_add_printer(name,pnum);
3101 snum = lp_servicenumber(name);
3105 if (snum < 0 || !VALID_SNUM(snum)) return(False);
3107 count = print_queue_status(snum,&queue,&status);
3108 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3109 desc.base = *rdata;
3110 desc.buflen = mdrcnt;
3112 if (init_package(&desc,count,0)) {
3113 succnt = 0;
3114 for (i = 0; i < count; i++) {
3115 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3116 if (desc.errcode == NERR_Success) succnt = i+1;
3120 *rdata_len = desc.usedlen;
3122 *rparam_len = 8;
3123 *rparam = REALLOC(*rparam,*rparam_len);
3124 SSVALS(*rparam,0,desc.errcode);
3125 SSVAL(*rparam,2,0);
3126 SSVAL(*rparam,4,succnt);
3127 SSVAL(*rparam,6,count);
3129 SAFE_FREE(queue);
3131 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
3132 return(True);
3135 static int check_printdest_info(struct pack_desc* desc,
3136 int uLevel, char* id)
3138 desc->subformat = NULL;
3139 switch( uLevel ) {
3140 case 0: desc->format = "B9"; break;
3141 case 1: desc->format = "B9B21WWzW"; break;
3142 case 2: desc->format = "z"; break;
3143 case 3: desc->format = "zzzWWzzzWW"; break;
3144 default: return False;
3146 if (strcmp(desc->format,id) != 0) return False;
3147 return True;
3150 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
3151 struct pack_desc* desc)
3153 char buf[100];
3154 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
3155 buf[sizeof(buf)-1] = 0;
3156 strupper(buf);
3157 if (uLevel <= 1) {
3158 PACKS(desc,"B9",buf); /* szName */
3159 if (uLevel == 1) {
3160 PACKS(desc,"B21",""); /* szUserName */
3161 PACKI(desc,"W",0); /* uJobId */
3162 PACKI(desc,"W",0); /* fsStatus */
3163 PACKS(desc,"z",""); /* pszStatus */
3164 PACKI(desc,"W",0); /* time */
3167 if (uLevel == 2 || uLevel == 3) {
3168 PACKS(desc,"z",buf); /* pszPrinterName */
3169 if (uLevel == 3) {
3170 PACKS(desc,"z",""); /* pszUserName */
3171 PACKS(desc,"z",""); /* pszLogAddr */
3172 PACKI(desc,"W",0); /* uJobId */
3173 PACKI(desc,"W",0); /* fsStatus */
3174 PACKS(desc,"z",""); /* pszStatus */
3175 PACKS(desc,"z",""); /* pszComment */
3176 PACKS(desc,"z","NULL"); /* pszDrivers */
3177 PACKI(desc,"W",0); /* time */
3178 PACKI(desc,"W",0); /* pad1 */
3183 static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
3184 int mdrcnt,int mprcnt,
3185 char **rdata,char **rparam,
3186 int *rdata_len,int *rparam_len)
3188 char *str1 = param+2;
3189 char *str2 = skip_string(str1,1);
3190 char *p = skip_string(str2,1);
3191 char* PrinterName = p;
3192 int uLevel;
3193 struct pack_desc desc;
3194 int snum;
3195 char *tmpdata=NULL;
3197 memset((char *)&desc,'\0',sizeof(desc));
3199 p = skip_string(p,1);
3200 uLevel = SVAL(p,0);
3202 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
3204 /* check it's a supported varient */
3205 if (strcmp(str1,"zWrLh") != 0) return False;
3206 if (!check_printdest_info(&desc,uLevel,str2)) return False;
3208 snum = lp_servicenumber(PrinterName);
3209 if (snum < 0 && pcap_printername_ok(PrinterName,NULL)) {
3210 int pnum = lp_servicenumber(PRINTERS_NAME);
3211 if (pnum >= 0) {
3212 lp_add_printer(PrinterName,pnum);
3213 snum = lp_servicenumber(PrinterName);
3217 if (snum < 0) {
3218 *rdata_len = 0;
3219 desc.errcode = NERR_DestNotFound;
3220 desc.neededlen = 0;
3222 else {
3223 if (mdrcnt > 0) {
3224 *rdata = REALLOC(*rdata,mdrcnt);
3225 desc.base = *rdata;
3226 desc.buflen = mdrcnt;
3227 } else {
3229 * Don't return data but need to get correct length
3230 * init_package will return wrong size if buflen=0
3232 desc.buflen = getlen(desc.format);
3233 desc.base = tmpdata = (char *)malloc ( desc.buflen );
3235 if (init_package(&desc,1,0)) {
3236 fill_printdest_info(conn,snum,uLevel,&desc);
3238 *rdata_len = desc.usedlen;
3241 *rparam_len = 6;
3242 *rparam = REALLOC(*rparam,*rparam_len);
3243 SSVALS(*rparam,0,desc.errcode);
3244 SSVAL(*rparam,2,0);
3245 SSVAL(*rparam,4,desc.neededlen);
3247 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
3248 SAFE_FREE(tmpdata);
3249 return(True);
3252 static BOOL api_WPrintDestEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3253 int mdrcnt,int mprcnt,
3254 char **rdata,char **rparam,
3255 int *rdata_len,int *rparam_len)
3257 char *str1 = param+2;
3258 char *str2 = skip_string(str1,1);
3259 char *p = skip_string(str2,1);
3260 int uLevel;
3261 int queuecnt;
3262 int i, n, succnt=0;
3263 struct pack_desc desc;
3264 int services = lp_numservices();
3266 memset((char *)&desc,'\0',sizeof(desc));
3268 uLevel = SVAL(p,0);
3270 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
3272 /* check it's a supported varient */
3273 if (strcmp(str1,"WrLeh") != 0) return False;
3274 if (!check_printdest_info(&desc,uLevel,str2)) return False;
3276 queuecnt = 0;
3277 for (i = 0; i < services; i++)
3278 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
3279 queuecnt++;
3281 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3282 desc.base = *rdata;
3283 desc.buflen = mdrcnt;
3284 if (init_package(&desc,queuecnt,0)) {
3285 succnt = 0;
3286 n = 0;
3287 for (i = 0; i < services; i++) {
3288 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3289 fill_printdest_info(conn,i,uLevel,&desc);
3290 n++;
3291 if (desc.errcode == NERR_Success) succnt = n;
3296 *rdata_len = desc.usedlen;
3298 *rparam_len = 8;
3299 *rparam = REALLOC(*rparam,*rparam_len);
3300 SSVALS(*rparam,0,desc.errcode);
3301 SSVAL(*rparam,2,0);
3302 SSVAL(*rparam,4,succnt);
3303 SSVAL(*rparam,6,queuecnt);
3305 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
3306 return(True);
3309 static BOOL api_WPrintDriverEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3310 int mdrcnt,int mprcnt,
3311 char **rdata,char **rparam,
3312 int *rdata_len,int *rparam_len)
3314 char *str1 = param+2;
3315 char *str2 = skip_string(str1,1);
3316 char *p = skip_string(str2,1);
3317 int uLevel;
3318 int succnt;
3319 struct pack_desc desc;
3321 memset((char *)&desc,'\0',sizeof(desc));
3323 uLevel = SVAL(p,0);
3325 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
3327 /* check it's a supported varient */
3328 if (strcmp(str1,"WrLeh") != 0) return False;
3329 if (uLevel != 0 || strcmp(str2,"B41") != 0) return False;
3331 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3332 desc.base = *rdata;
3333 desc.buflen = mdrcnt;
3334 if (init_package(&desc,1,0)) {
3335 PACKS(&desc,"B41","NULL");
3338 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3340 *rdata_len = desc.usedlen;
3342 *rparam_len = 8;
3343 *rparam = REALLOC(*rparam,*rparam_len);
3344 SSVALS(*rparam,0,desc.errcode);
3345 SSVAL(*rparam,2,0);
3346 SSVAL(*rparam,4,succnt);
3347 SSVAL(*rparam,6,1);
3349 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
3350 return(True);
3353 static BOOL api_WPrintQProcEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3354 int mdrcnt,int mprcnt,
3355 char **rdata,char **rparam,
3356 int *rdata_len,int *rparam_len)
3358 char *str1 = param+2;
3359 char *str2 = skip_string(str1,1);
3360 char *p = skip_string(str2,1);
3361 int uLevel;
3362 int succnt;
3363 struct pack_desc desc;
3365 memset((char *)&desc,'\0',sizeof(desc));
3367 uLevel = SVAL(p,0);
3369 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
3371 /* check it's a supported varient */
3372 if (strcmp(str1,"WrLeh") != 0) return False;
3373 if (uLevel != 0 || strcmp(str2,"B13") != 0) return False;
3375 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3376 desc.base = *rdata;
3377 desc.buflen = mdrcnt;
3378 desc.format = str2;
3379 if (init_package(&desc,1,0)) {
3380 PACKS(&desc,"B13","lpd");
3383 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3385 *rdata_len = desc.usedlen;
3387 *rparam_len = 8;
3388 *rparam = REALLOC(*rparam,*rparam_len);
3389 SSVALS(*rparam,0,desc.errcode);
3390 SSVAL(*rparam,2,0);
3391 SSVAL(*rparam,4,succnt);
3392 SSVAL(*rparam,6,1);
3394 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
3395 return(True);
3398 static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3399 int mdrcnt,int mprcnt,
3400 char **rdata,char **rparam,
3401 int *rdata_len,int *rparam_len)
3403 char *str1 = param+2;
3404 char *str2 = skip_string(str1,1);
3405 char *p = skip_string(str2,1);
3406 int uLevel;
3407 int succnt;
3408 struct pack_desc desc;
3410 memset((char *)&desc,'\0',sizeof(desc));
3412 uLevel = SVAL(p,0);
3414 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
3416 /* check it's a supported varient */
3417 if (strcmp(str1,"WrLeh") != 0) return False;
3418 if (uLevel != 0 || strcmp(str2,"B9") != 0) return False;
3420 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3421 memset((char *)&desc,'\0',sizeof(desc));
3422 desc.base = *rdata;
3423 desc.buflen = mdrcnt;
3424 desc.format = str2;
3425 if (init_package(&desc,1,0)) {
3426 PACKS(&desc,"B13","lp0");
3429 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3431 *rdata_len = desc.usedlen;
3433 *rparam_len = 8;
3434 *rparam = REALLOC(*rparam,*rparam_len);
3435 SSVALS(*rparam,0,desc.errcode);
3436 SSVAL(*rparam,2,0);
3437 SSVAL(*rparam,4,succnt);
3438 SSVAL(*rparam,6,1);
3440 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
3441 return(True);
3445 /****************************************************************************
3446 List open sessions
3447 ****************************************************************************/
3448 static BOOL api_RNetSessionEnum(connection_struct *conn,uint16 vuid, char *param, char *data,
3449 int mdrcnt,int mprcnt,
3450 char **rdata,char **rparam,
3451 int *rdata_len,int *rparam_len)
3454 char *str1 = param+2;
3455 char *str2 = skip_string(str1,1);
3456 char *p = skip_string(str2,1);
3457 int uLevel;
3458 struct pack_desc desc;
3459 struct sessionid *session_list;
3460 int i, num_sessions;
3462 memset((char *)&desc,'\0',sizeof(desc));
3464 uLevel = SVAL(p,0);
3466 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
3467 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
3468 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
3470 /* check it's a supported varient */
3471 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) return False;
3472 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) return False;
3474 num_sessions = list_sessions(&session_list);
3476 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3477 memset((char *)&desc,'\0',sizeof(desc));
3478 desc.base = *rdata;
3479 desc.buflen = mdrcnt;
3480 desc.format = str2;
3481 if (!init_package(&desc,num_sessions,0)) {
3482 return False;
3485 for(i=0; i<num_sessions; i++) {
3486 PACKS(&desc, "z", session_list[i].remote_machine);
3487 PACKS(&desc, "z", session_list[i].username);
3488 PACKI(&desc, "W", 1); /* num conns */
3489 PACKI(&desc, "W", 0); /* num opens */
3490 PACKI(&desc, "W", 1); /* num users */
3491 PACKI(&desc, "D", 0); /* session time */
3492 PACKI(&desc, "D", 0); /* idle time */
3493 PACKI(&desc, "D", 0); /* flags */
3494 PACKS(&desc, "z", "Unknown Client"); /* client type string */
3497 *rdata_len = desc.usedlen;
3499 *rparam_len = 8;
3500 *rparam = REALLOC(*rparam,*rparam_len);
3501 SSVALS(*rparam,0,desc.errcode);
3502 SSVAL(*rparam,2,0); /* converter */
3503 SSVAL(*rparam,4,num_sessions); /* count */
3505 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
3506 return True;
3510 /****************************************************************************
3511 The buffer was too small
3512 ****************************************************************************/
3514 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
3515 int mdrcnt,int mprcnt,
3516 char **rdata,char **rparam,
3517 int *rdata_len,int *rparam_len)
3519 *rparam_len = MIN(*rparam_len,mprcnt);
3520 *rparam = REALLOC(*rparam,*rparam_len);
3522 *rdata_len = 0;
3524 SSVAL(*rparam,0,NERR_BufTooSmall);
3526 DEBUG(3,("Supplied buffer too small in API command\n"));
3528 return(True);
3532 /****************************************************************************
3533 The request is not supported
3534 ****************************************************************************/
3536 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
3537 int mdrcnt,int mprcnt,
3538 char **rdata,char **rparam,
3539 int *rdata_len,int *rparam_len)
3541 *rparam_len = 4;
3542 *rparam = REALLOC(*rparam,*rparam_len);
3544 *rdata_len = 0;
3546 SSVAL(*rparam,0,NERR_notsupported);
3547 SSVAL(*rparam,2,0); /* converter word */
3549 DEBUG(3,("Unsupported API command\n"));
3551 return(True);
3557 const static struct
3559 char *name;
3560 int id;
3561 BOOL (*fn)(connection_struct *,uint16,char *,char *,
3562 int,int,char **,char **,int *,int *);
3563 BOOL auth_user; /* Deny anonymous access? */
3564 } api_commands[] = {
3565 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
3566 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
3567 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
3568 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
3569 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
3570 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
3571 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
3572 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
3573 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
3574 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
3575 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
3576 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
3577 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
3578 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
3579 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
3580 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
3581 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
3582 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
3583 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
3584 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
3585 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
3586 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
3587 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
3588 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
3589 {"NetServerEnum", RAP_NetServerEnum2, api_RNetServerEnum}, /* anon OK */
3590 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
3591 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
3592 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
3593 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
3594 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
3595 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
3596 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
3597 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
3598 {NULL, -1, api_Unsupported}};
3600 /* The following RAP calls are not implemented by Samba:
3602 RAP_WFileEnum2 - anon not OK
3605 /****************************************************************************
3606 Handle remote api calls
3607 ****************************************************************************/
3609 int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *params,
3610 int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
3612 int api_command;
3613 char *rdata = NULL;
3614 char *rparam = NULL;
3615 int rdata_len = 0;
3616 int rparam_len = 0;
3617 BOOL reply=False;
3618 int i;
3620 if (!params) {
3621 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
3622 return 0;
3625 api_command = SVAL(params,0);
3627 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
3628 api_command,
3629 params+2,
3630 skip_string(params+2,1),
3631 tdscnt,tpscnt,mdrcnt,mprcnt));
3633 for (i=0;api_commands[i].name;i++) {
3634 if (api_commands[i].id == api_command && api_commands[i].fn) {
3635 DEBUG(3,("Doing %s\n",api_commands[i].name));
3636 break;
3640 /* Check whether this api call can be done anonymously */
3642 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
3643 user_struct *user = get_valid_user_struct(vuid);
3645 if (!user || user->guest)
3646 return ERROR_NT(NT_STATUS_ACCESS_DENIED);
3649 rdata = (char *)malloc(1024);
3650 if (rdata)
3651 memset(rdata,'\0',1024);
3653 rparam = (char *)malloc(1024);
3654 if (rparam)
3655 memset(rparam,'\0',1024);
3657 if(!rdata || !rparam) {
3658 DEBUG(0,("api_reply: malloc fail !\n"));
3659 return -1;
3662 reply = api_commands[i].fn(conn,vuid,params,data,mdrcnt,mprcnt,
3663 &rdata,&rparam,&rdata_len,&rparam_len);
3666 if (rdata_len > mdrcnt ||
3667 rparam_len > mprcnt) {
3668 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
3669 &rdata,&rparam,&rdata_len,&rparam_len);
3672 /* if we get False back then it's actually unsupported */
3673 if (!reply)
3674 api_Unsupported(conn,vuid,params,data,mdrcnt,mprcnt,
3675 &rdata,&rparam,&rdata_len,&rparam_len);
3677 send_trans_reply(outbuf, rparam, rparam_len, rdata, rdata_len, False);
3679 SAFE_FREE(rdata);
3680 SAFE_FREE(rparam);
3682 return -1;