add WITH_SENDFILE profiling data (from Pierre Belanger)
[Samba.git] / source / smbd / lanman.c
blobc0de7c9f9c41fa55c4a3632d5ab38a06c3953349
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 Inter-process communication and named pipe handling
5 Copyright (C) Andrew Tridgell 1992-1998
7 SMB Version handling
8 Copyright (C) John H Terpstra 1995-1998
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 This file handles the named pipe and mailslot calls
26 in the SMBtrans protocol
29 #include "includes.h"
31 #ifdef CHECK_TYPES
32 #undef CHECK_TYPES
33 #endif
34 #define CHECK_TYPES 0
36 extern fstring local_machine;
37 extern pstring global_myname;
38 extern fstring global_myworkgroup;
40 #define NERR_Success 0
41 #define NERR_badpass 86
42 #define NERR_notsupported 50
44 #define NERR_BASE (2100)
45 #define NERR_BufTooSmall (NERR_BASE+23)
46 #define NERR_JobNotFound (NERR_BASE+51)
47 #define NERR_DestNotFound (NERR_BASE+52)
49 #define ACCESS_READ 0x01
50 #define ACCESS_WRITE 0x02
51 #define ACCESS_CREATE 0x04
53 #define SHPWLEN 8 /* share password length */
55 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
56 int mdrcnt,int mprcnt,
57 char **rdata,char **rparam,
58 int *rdata_len,int *rparam_len);
59 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
60 int mdrcnt,int mprcnt,
61 char **rdata,char **rparam,
62 int *rdata_len,int *rparam_len);
65 static int CopyExpanded(connection_struct *conn,
66 int snum, char** dst, char* src, int* n)
68 pstring buf;
69 int l;
71 if (!src || !dst || !n || !(*dst)) return(0);
73 StrnCpy(buf,src,sizeof(buf)/2);
74 pstring_sub(buf,"%S",lp_servicename(snum));
75 standard_sub_conn(conn,buf,sizeof(buf));
76 StrnCpy(*dst,buf,*n-1);
77 l = strlen(*dst) + 1;
78 (*dst) += l;
79 (*n) -= l;
80 return l;
83 static int CopyAndAdvance(char** dst, char* src, int* n)
85 int l;
86 if (!src || !dst || !n || !(*dst)) return(0);
87 StrnCpy(*dst,src,*n-1);
88 l = strlen(*dst) + 1;
89 (*dst) += l;
90 (*n) -= l;
91 return l;
94 static int StrlenExpanded(connection_struct *conn, int snum, char* s)
96 pstring buf;
97 if (!s) return(0);
98 StrnCpy(buf,s,sizeof(buf)/2);
99 pstring_sub(buf,"%S",lp_servicename(snum));
100 standard_sub_conn(conn,buf,sizeof(buf));
101 return strlen(buf) + 1;
104 static char* Expand(connection_struct *conn, int snum, char* s)
106 static pstring buf;
107 if (!s) return(NULL);
108 StrnCpy(buf,s,sizeof(buf)/2);
109 pstring_sub(buf,"%S",lp_servicename(snum));
110 standard_sub_conn(conn,buf,sizeof(buf));
111 return &buf[0];
114 /*******************************************************************
115 check a API string for validity when we only need to check the prefix
116 ******************************************************************/
117 static BOOL prefix_ok(char *str,char *prefix)
119 return(strncmp(str,prefix,strlen(prefix)) == 0);
122 struct pack_desc {
123 char* format; /* formatstring for structure */
124 char* subformat; /* subformat for structure */
125 char* base; /* baseaddress of buffer */
126 int buflen; /* remaining size for fixed part; on init: length of base */
127 int subcount; /* count of substructures */
128 char* structbuf; /* pointer into buffer for remaining fixed part */
129 int stringlen; /* remaining size for variable part */
130 char* stringbuf; /* pointer into buffer for remaining variable part */
131 int neededlen; /* total needed size */
132 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
133 char* curpos; /* current position; pointer into format or subformat */
134 int errcode;
137 static int get_counter(char** p)
139 int i, n;
140 if (!p || !(*p)) return(1);
141 if (!isdigit((int)**p)) return 1;
142 for (n = 0;;) {
143 i = **p;
144 if (isdigit(i))
145 n = 10 * n + (i - '0');
146 else
147 return n;
148 (*p)++;
152 static int getlen(char* p)
154 int n = 0;
155 if (!p) return(0);
156 while (*p) {
157 switch( *p++ ) {
158 case 'W': /* word (2 byte) */
159 n += 2;
160 break;
161 case 'K': /* status word? (2 byte) */
162 n += 2;
163 break;
164 case 'N': /* count of substructures (word) at end */
165 n += 2;
166 break;
167 case 'D': /* double word (4 byte) */
168 case 'z': /* offset to zero terminated string (4 byte) */
169 case 'l': /* offset to user data (4 byte) */
170 n += 4;
171 break;
172 case 'b': /* offset to data (with counter) (4 byte) */
173 n += 4;
174 get_counter(&p);
175 break;
176 case 'B': /* byte (with optional counter) */
177 n += get_counter(&p);
178 break;
181 return n;
184 static BOOL init_package(struct pack_desc* p, int count, int subcount)
186 int n = p->buflen;
187 int i;
189 if (!p->format || !p->base) return(False);
191 i = count * getlen(p->format);
192 if (p->subformat) i += subcount * getlen(p->subformat);
193 p->structbuf = p->base;
194 p->neededlen = 0;
195 p->usedlen = 0;
196 p->subcount = 0;
197 p->curpos = p->format;
198 if (i > n) {
199 p->neededlen = i;
200 i = n = 0;
201 #if 0
203 * This is the old error code we used. Aparently
204 * WinNT/2k systems return ERRbuftoosmall (2123) and
205 * OS/2 needs this. I'm leaving this here so we can revert
206 * if needed. JRA.
208 p->errcode = ERRmoredata;
209 #else
210 p->errcode = ERRbuftoosmall;
211 #endif
213 else
214 p->errcode = NERR_Success;
215 p->buflen = i;
216 n -= i;
217 p->stringbuf = p->base + i;
218 p->stringlen = n;
219 return(p->errcode == NERR_Success);
222 #ifdef HAVE_STDARG_H
223 static int package(struct pack_desc* p, ...)
225 #else
226 static int package(va_alist)
227 va_dcl
229 struct pack_desc* p;
230 #endif
231 va_list args;
232 int needed=0, stringneeded;
233 char* str=NULL;
234 int is_string=0, stringused;
235 int32 temp;
237 #ifdef HAVE_STDARG_H
238 va_start(args,p);
239 #else
240 va_start(args);
241 p = va_arg(args,struct pack_desc *);
242 #endif
244 if (!*p->curpos) {
245 if (!p->subcount)
246 p->curpos = p->format;
247 else {
248 p->curpos = p->subformat;
249 p->subcount--;
252 #if CHECK_TYPES
253 str = va_arg(args,char*);
254 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
255 #endif
256 stringneeded = -1;
258 if (!p->curpos) {
259 va_end(args);
260 return(0);
263 switch( *p->curpos++ ) {
264 case 'W': /* word (2 byte) */
265 needed = 2;
266 temp = va_arg(args,int);
267 if (p->buflen >= needed) SSVAL(p->structbuf,0,temp);
268 break;
269 case 'K': /* status word? (2 byte) */
270 needed = 2;
271 temp = va_arg(args,int);
272 if (p->buflen >= needed) SSVAL(p->structbuf,0,temp);
273 break;
274 case 'N': /* count of substructures (word) at end */
275 needed = 2;
276 p->subcount = va_arg(args,int);
277 if (p->buflen >= needed) SSVAL(p->structbuf,0,p->subcount);
278 break;
279 case 'D': /* double word (4 byte) */
280 needed = 4;
281 temp = va_arg(args,int);
282 if (p->buflen >= needed) SIVAL(p->structbuf,0,temp);
283 break;
284 case 'B': /* byte (with optional counter) */
285 needed = get_counter(&p->curpos);
287 char *s = va_arg(args,char*);
288 if (p->buflen >= needed) StrnCpy(p->structbuf,s?s:"",needed-1);
290 break;
291 case 'z': /* offset to zero terminated string (4 byte) */
292 str = va_arg(args,char*);
293 stringneeded = (str ? strlen(str)+1 : 0);
294 is_string = 1;
295 break;
296 case 'l': /* offset to user data (4 byte) */
297 str = va_arg(args,char*);
298 stringneeded = va_arg(args,int);
299 is_string = 0;
300 break;
301 case 'b': /* offset to data (with counter) (4 byte) */
302 str = va_arg(args,char*);
303 stringneeded = get_counter(&p->curpos);
304 is_string = 0;
305 break;
307 va_end(args);
308 if (stringneeded >= 0) {
309 needed = 4;
310 if (p->buflen >= needed) {
311 stringused = stringneeded;
312 if (stringused > p->stringlen) {
313 stringused = (is_string ? p->stringlen : 0);
314 if (p->errcode == NERR_Success) p->errcode = ERRmoredata;
316 if (!stringused)
317 SIVAL(p->structbuf,0,0);
318 else {
319 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
320 memcpy(p->stringbuf,str?str:"",stringused);
321 if (is_string) p->stringbuf[stringused-1] = '\0';
322 p->stringbuf += stringused;
323 p->stringlen -= stringused;
324 p->usedlen += stringused;
327 p->neededlen += stringneeded;
329 p->neededlen += needed;
330 if (p->buflen >= needed) {
331 p->structbuf += needed;
332 p->buflen -= needed;
333 p->usedlen += needed;
335 else {
336 if (p->errcode == NERR_Success) p->errcode = ERRmoredata;
338 return 1;
341 #if CHECK_TYPES
342 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
343 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
344 #else
345 #define PACK(desc,t,v) package(desc,v)
346 #define PACKl(desc,t,v,l) package(desc,v,l)
347 #endif
349 static void PACKI(struct pack_desc* desc,char *t,int v)
351 PACK(desc,t,v);
354 static void PACKS(struct pack_desc* desc,char *t,char *v)
356 PACK(desc,t,v);
360 /****************************************************************************
361 get a print queue
362 ****************************************************************************/
363 static void PackDriverData(struct pack_desc* desc)
365 char drivdata[4+4+32];
366 SIVAL(drivdata,0,sizeof drivdata); /* cb */
367 SIVAL(drivdata,4,1000); /* lVersion */
368 memset(drivdata+8,0,32); /* szDeviceName */
369 pstrcpy(drivdata+8,"NULL");
370 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
373 static int check_printq_info(struct pack_desc* desc,
374 int uLevel, char *id1, char *id2)
376 desc->subformat = NULL;
377 switch( uLevel ) {
378 case 0:
379 desc->format = "B13";
380 break;
381 case 1:
382 desc->format = "B13BWWWzzzzzWW";
383 break;
384 case 2:
385 desc->format = "B13BWWWzzzzzWN";
386 desc->subformat = "WB21BB16B10zWWzDDz";
387 break;
388 case 3:
389 desc->format = "zWWWWzzzzWWzzl";
390 break;
391 case 4:
392 desc->format = "zWWWWzzzzWNzzl";
393 desc->subformat = "WWzWWDDzz";
394 break;
395 case 5:
396 desc->format = "z";
397 break;
398 case 51:
399 desc->format = "K";
400 break;
401 case 52:
402 desc->format = "WzzzzzzzzN";
403 desc->subformat = "z";
404 break;
405 default: return False;
407 if (strcmp(desc->format,id1) != 0) return False;
408 if (desc->subformat && strcmp(desc->subformat,id2) != 0) return False;
409 return True;
413 #define RAP_JOB_STATUS_QUEUED 0
414 #define RAP_JOB_STATUS_PAUSED 1
415 #define RAP_JOB_STATUS_SPOOLING 2
416 #define RAP_JOB_STATUS_PRINTING 3
417 #define RAP_JOB_STATUS_PRINTED 4
419 #define RAP_QUEUE_STATUS_PAUSED 1
420 #define RAP_QUEUE_STATUS_ERROR 2
422 /* turn a print job status into a on the wire status
424 static int printj_status(int v)
426 switch (v) {
427 case LPQ_QUEUED:
428 return RAP_JOB_STATUS_QUEUED;
429 case LPQ_PAUSED:
430 return RAP_JOB_STATUS_PAUSED;
431 case LPQ_SPOOLING:
432 return RAP_JOB_STATUS_SPOOLING;
433 case LPQ_PRINTING:
434 return RAP_JOB_STATUS_PRINTING;
436 return 0;
439 /* turn a print queue status into a on the wire status
441 static int printq_status(int v)
443 switch (v) {
444 case LPQ_QUEUED:
445 return 0;
446 case LPQ_PAUSED:
447 return RAP_QUEUE_STATUS_PAUSED;
449 return RAP_QUEUE_STATUS_ERROR;
452 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
453 struct pack_desc* desc,
454 print_queue_struct* queue, int n)
456 time_t t = queue->time;
458 /* the client expects localtime */
459 t -= TimeDiff(t);
461 PACKI(desc,"W",queue->job); /* uJobId */
462 if (uLevel == 1) {
463 PACKS(desc,"B21",dos_to_unix_static(queue->fs_user)); /* szUserName */
464 PACKS(desc,"B",""); /* pad */
465 PACKS(desc,"B16",""); /* szNotifyName */
466 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
467 PACKS(desc,"z",""); /* pszParms */
468 PACKI(desc,"W",n+1); /* uPosition */
469 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
470 PACKS(desc,"z",""); /* pszStatus */
471 PACKI(desc,"D",t); /* ulSubmitted */
472 PACKI(desc,"D",queue->size); /* ulSize */
473 PACKS(desc,"z",dos_to_unix_static(queue->fs_file)); /* pszComment */
475 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
476 PACKI(desc,"W",queue->priority); /* uPriority */
477 PACKS(desc,"z",dos_to_unix_static(queue->fs_user)); /* pszUserName */
478 PACKI(desc,"W",n+1); /* uPosition */
479 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
480 PACKI(desc,"D",t); /* ulSubmitted */
481 PACKI(desc,"D",queue->size); /* ulSize */
482 PACKS(desc,"z","Samba"); /* pszComment */
483 PACKS(desc,"z",dos_to_unix_static(queue->fs_file)); /* pszDocument */
484 if (uLevel == 3) {
485 PACKS(desc,"z",""); /* pszNotifyName */
486 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
487 PACKS(desc,"z",""); /* pszParms */
488 PACKS(desc,"z",""); /* pszStatus */
489 PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
490 PACKS(desc,"z","lpd"); /* pszQProcName */
491 PACKS(desc,"z",""); /* pszQProcParms */
492 PACKS(desc,"z","NULL"); /* pszDriverName */
493 PackDriverData(desc); /* pDriverData */
494 PACKS(desc,"z",""); /* pszPrinterName */
495 } else if (uLevel == 4) { /* OS2 */
496 PACKS(desc,"z",""); /* pszSpoolFileName */
497 PACKS(desc,"z",""); /* pszPortName */
498 PACKS(desc,"z",""); /* pszStatus */
499 PACKI(desc,"D",0); /* ulPagesSpooled */
500 PACKI(desc,"D",0); /* ulPagesSent */
501 PACKI(desc,"D",0); /* ulPagesPrinted */
502 PACKI(desc,"D",0); /* ulTimePrinted */
503 PACKI(desc,"D",0); /* ulExtendJobStatus */
504 PACKI(desc,"D",0); /* ulStartPage */
505 PACKI(desc,"D",0); /* ulEndPage */
510 /********************************************************************
511 Return a driver name given an snum.
512 Looks in a tdb first. Returns True if from tdb, False otherwise.
513 ********************************************************************/
515 static BOOL get_driver_name(int snum, pstring drivername)
517 NT_PRINTER_INFO_LEVEL *info = NULL;
518 BOOL in_tdb = False;
520 get_a_printer (&info, 2, lp_servicename(snum));
521 if (info != NULL) {
522 pstrcpy( drivername, info->info_2->drivername);
523 in_tdb = True;
524 free_a_printer(&info, 2);
525 } else {
526 pstrcpy( drivername, lp_printerdriver(snum));
529 return in_tdb;
532 /********************************************************************
533 Respond to the DosPrintQInfo command with a level of 52
534 This is used to get printer driver information for Win9x clients
535 ********************************************************************/
536 static void fill_printq_info_52(connection_struct *conn, int snum, int uLevel,
537 struct pack_desc* desc,
538 int count, print_queue_struct* queue,
539 print_status_struct* status)
541 int i;
542 BOOL ok = False;
543 pstring tok,driver,datafile,langmon,helpfile,datatype;
544 char *p;
545 char **lines = NULL;
546 pstring gen_line;
547 BOOL in_tdb = False;
548 fstring location;
549 pstring drivername;
552 * Check in the tdb *first* before checking the legacy
553 * files. This allows an NT upload to take precedence over
554 * the existing fileset. JRA.
556 * we need to lookup the driver name prior to making the call
557 * to get_a_printer_driver_9x_compatible() and not rely on the
558 * 'print driver' parameter --jerry
562 if ((get_driver_name(snum,drivername)) &&
563 ((ok = get_a_printer_driver_9x_compatible(gen_line, drivername)) == True))
565 in_tdb = True;
566 p = gen_line;
567 DEBUG(10,("9x compatable driver line for [%s]: [%s]\n", drivername, gen_line));
569 else
571 /* didn't find driver in tdb */
573 DEBUG(10,("snum: %d\nprinterdriver: [%s]\nlp_driverfile: [%s]\n",
574 snum, drivername, lp_driverfile(snum)));
576 lines = file_lines_load(lp_driverfile(snum),NULL, False);
577 if (!lines)
579 DEBUG(3,("Can't open %s - %s\n", lp_driverfile(snum),
580 strerror(errno)));
581 desc->errcode=NERR_notsupported;
582 goto done;
585 /* lookup the long printer driver name in the file description */
586 for (i=0;lines[i] && !ok;i++)
588 p = lines[i];
589 if (next_token(&p,tok,":",sizeof(tok)) &&
590 (strlen(drivername) == strlen(tok)) &&
591 (!strncmp(tok,drivername,strlen(drivername))))
593 ok = True;
598 if (ok)
600 /* driver file name */
601 if (!next_token(&p,driver,":",sizeof(driver)))
602 goto err;
604 /* data file name */
605 if (!next_token(&p,datafile,":",sizeof(datafile)))
606 goto err;
609 * for the next tokens - which may be empty - I have
610 * to check for empty tokens first because the
611 * next_token function will skip all empty token
612 * fields */
614 /* help file */
615 if (*p == ':')
617 *helpfile = '\0';
618 p++;
620 else if (!next_token(&p,helpfile,":",sizeof(helpfile)))
621 goto err;
623 /* language monitor */
624 if (*p == ':')
626 *langmon = '\0';
627 p++;
629 else if (!next_token(&p,langmon,":",sizeof(langmon)))
630 goto err;
632 /* default data type */
633 if (!next_token(&p,datatype,":",sizeof(datatype)))
634 goto err;
636 PACKI(desc,"W",0x0400); /* don't know */
637 PACKS(desc,"z",drivername); /* long printer name */
638 PACKS(desc,"z",driver); /* Driverfile Name */
639 PACKS(desc,"z",datafile); /* Datafile name */
640 PACKS(desc,"z",langmon); /* language monitor */
641 if (in_tdb)
643 fstrcpy(location, "\\\\");
644 fstrcat(location, global_myname);
645 fstrcat(location, "\\print$\\WIN40\\0");
646 PACKS(desc,"z",location); /* share to retrieve files */
648 else
650 PACKS(desc,"z",lp_driverlocation(snum)); /* share to retrieve files */
652 PACKS(desc,"z",datatype); /* default data type */
653 PACKS(desc,"z",helpfile); /* helpfile name */
654 PACKS(desc,"z",driver); /* driver name */
656 DEBUG(3,("printerdriver:%s:\n",drivername));
657 DEBUG(3,("Driver:%s:\n",driver));
658 DEBUG(3,("Data File:%s:\n",datafile));
659 DEBUG(3,("Language Monitor:%s:\n",langmon));
660 if (in_tdb)
661 DEBUG(3,("lp_driverlocation:%s:\n",location));
662 else
663 DEBUG(3,("lp_driverlocation:%s:\n",lp_driverlocation(snum)));
664 DEBUG(3,("Data Type:%s:\n",datatype));
665 DEBUG(3,("Help File:%s:\n",helpfile));
666 PACKI(desc,"N",count); /* number of files to copy */
668 for (i=0;i<count;i++)
670 /* no need to check return value here
671 * - it was already tested in
672 * get_printerdrivernumber */
673 next_token(&p,tok,",",sizeof(tok));
674 PACKS(desc,"z",tok); /* driver files to copy */
675 DEBUG(3,("file:%s:\n",tok));
678 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n",
679 SERVICE(snum),count));
681 desc->errcode=NERR_Success;
682 goto done;
685 err:
687 DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
688 desc->errcode=NERR_notsupported;
690 done:
691 file_lines_free(lines);
695 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
696 struct pack_desc* desc,
697 int count, print_queue_struct* queue,
698 print_status_struct* status)
700 switch (uLevel) {
701 case 1:
702 case 2:
703 PACKS(desc,"B13",SERVICE(snum));
704 break;
705 case 3:
706 case 4:
707 case 5:
708 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
709 break;
710 case 51:
711 PACKI(desc,"K",printq_status(status->status));
712 break;
715 if (uLevel == 1 || uLevel == 2) {
716 PACKS(desc,"B",""); /* alignment */
717 PACKI(desc,"W",5); /* priority */
718 PACKI(desc,"W",0); /* start time */
719 PACKI(desc,"W",0); /* until time */
720 PACKS(desc,"z",""); /* pSepFile */
721 PACKS(desc,"z","lpd"); /* pPrProc */
722 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
723 PACKS(desc,"z",""); /* pParms */
724 if (snum < 0) {
725 PACKS(desc,"z","UNKNOWN PRINTER");
726 PACKI(desc,"W",LPSTAT_ERROR);
728 else if (!status || !status->message[0]) {
729 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
730 PACKI(desc,"W",LPSTAT_OK); /* status */
731 } else {
732 PACKS(desc,"z",status->message);
733 PACKI(desc,"W",printq_status(status->status)); /* status */
735 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
738 if (uLevel == 3 || uLevel == 4) {
739 pstring drivername;
741 PACKI(desc,"W",5); /* uPriority */
742 PACKI(desc,"W",0); /* uStarttime */
743 PACKI(desc,"W",0); /* uUntiltime */
744 PACKI(desc,"W",5); /* pad1 */
745 PACKS(desc,"z",""); /* pszSepFile */
746 PACKS(desc,"z","WinPrint"); /* pszPrProc */
747 PACKS(desc,"z",NULL); /* pszParms */
748 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
749 /* "don't ask" that it's done this way to fix corrupted
750 Win9X/ME printer comments. */
751 if (!status) {
752 PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
753 } else {
754 PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
756 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
757 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
758 get_driver_name(snum,drivername);
759 PACKS(desc,"z",drivername); /* pszDriverName */
760 PackDriverData(desc); /* pDriverData */
763 if (uLevel == 2 || uLevel == 4) {
764 int i;
765 for (i=0;i<count;i++)
766 fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
769 if (uLevel==52) {
770 fill_printq_info_52(conn, snum, uLevel, desc, count, queue, status);
774 /* This function returns the number of files for a given driver */
775 static int get_printerdrivernumber(int snum)
777 int i, result = 0;
778 BOOL ok = False;
779 pstring tok;
780 char *p;
781 char **lines = NULL;
782 pstring gen_line;
783 pstring drivername;
786 * Check in the tdb *first* before checking the legacy
787 * files. This allows an NT upload to take precedence over
788 * the existing fileset. JRA.
790 * we need to lookup the driver name prior to making the call
791 * to get_a_printer_driver_9x_compatible() and not rely on the
792 * 'print driver' parameter --jerry
795 if ((get_driver_name(snum,drivername)) &&
796 (ok = get_a_printer_driver_9x_compatible(gen_line, drivername) == True))
798 p = gen_line;
799 DEBUG(10,("9x compatable driver line for [%s]: [%s]\n", drivername, gen_line));
801 else
803 /* didn't find driver in tdb */
805 DEBUG(10,("snum: %d\nprinterdriver: [%s]\nlp_driverfile: [%s]\n",
806 snum, drivername, lp_driverfile(snum)));
808 lines = file_lines_load(lp_driverfile(snum), NULL, False);
809 if (!lines)
811 DEBUG(3,("Can't open %s - %s\n", lp_driverfile(snum),strerror(errno)));
812 goto done;
815 /* lookup the long printer driver name in the file description */
816 for (i=0;lines[i] && !ok;i++)
818 p = lines[i];
819 if (next_token(&p,tok,":",sizeof(tok)) &&
820 (strlen(drivername) == strlen(tok)) &&
821 (!strncmp(tok,drivername,strlen(drivername))))
823 ok = True;
828 if( ok )
830 /* skip 5 fields */
831 i = 5;
832 while (*p && i) {
833 if (*p++ == ':') i--;
835 if (!*p || i) {
836 DEBUG(3,("Can't determine number of printer driver files\n"));
837 goto done;
840 /* count the number of files */
841 while (next_token(&p,tok,",",sizeof(tok)))
842 i++;
844 result = i;
847 done:
849 file_lines_free(lines);
851 return result;
854 static BOOL api_DosPrintQGetInfo(connection_struct *conn,
855 uint16 vuid, char *param,char *data,
856 int mdrcnt,int mprcnt,
857 char **rdata,char **rparam,
858 int *rdata_len,int *rparam_len)
860 char *str1 = param+2;
861 char *str2 = skip_string(str1,1);
862 char *p = skip_string(str2,1);
863 char *QueueName = p;
864 int uLevel;
865 int count=0;
866 int snum;
867 char* str3;
868 struct pack_desc desc;
869 print_queue_struct *queue=NULL;
870 print_status_struct status;
871 char* tmpdata=NULL;
873 memset((char *)&status,'\0',sizeof(status));
874 memset((char *)&desc,'\0',sizeof(desc));
876 p = skip_string(p,1);
877 uLevel = SVAL(p,0);
878 str3 = p + 4;
880 /* remove any trailing username */
881 if ((p = strchr(QueueName,'%')))
882 *p = 0;
884 DEBUG(3,("api_DosPrintQGetInfo: uLevel=%d name=%s\n",uLevel,QueueName));
886 /* check it's a supported varient */
887 if (!prefix_ok(str1,"zWrLh"))
888 return False;
889 if (!check_printq_info(&desc,uLevel,str2,str3)) {
891 * Patch from Scott Moomaw <scott@bridgewater.edu>
892 * to return the 'invalid info level' error if an
893 * unknown level was requested.
895 *rdata_len = 0;
896 *rparam_len = 6;
897 *rparam = REALLOC(*rparam,*rparam_len);
898 SSVALS(*rparam,0,ERRunknownlevel);
899 SSVAL(*rparam,2,0);
900 SSVAL(*rparam,4,0);
901 return(True);
904 snum = lp_servicenumber(QueueName);
905 if (snum < 0 && pcap_printername_ok(QueueName,NULL)) {
906 int pnum = lp_servicenumber(PRINTERS_NAME);
907 if (pnum >= 0) {
908 lp_add_printer(QueueName,pnum);
909 snum = lp_servicenumber(QueueName);
913 if (snum < 0 || !VALID_SNUM(snum))
914 return(False);
916 if (uLevel==52) {
917 count = get_printerdrivernumber(snum);
918 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
919 } else {
920 count = print_queue_status(snum, &queue,&status);
923 if (mdrcnt > 0) {
924 *rdata = REALLOC(*rdata,mdrcnt);
925 desc.base = *rdata;
926 desc.buflen = mdrcnt;
927 } else {
929 * Don't return data but need to get correct length
930 * init_package will return wrong size if buflen=0
932 desc.buflen = getlen(desc.format);
933 desc.base = tmpdata = (char *) malloc (desc.buflen);
936 if (init_package(&desc,1,count)) {
937 desc.subcount = count;
938 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
942 * We must set the return code to ERRbuftoosmall
943 * in order to support lanman style printing with Win NT/2k
944 * clients --jerry
946 if (!mdrcnt && lp_disable_spoolss())
947 desc.errcode = ERRbuftoosmall;
949 *rdata_len = desc.usedlen;
951 *rparam_len = 6;
952 *rparam = REALLOC(*rparam,*rparam_len);
953 SSVALS(*rparam,0,desc.errcode);
954 SSVAL(*rparam,2,0);
955 SSVAL(*rparam,4,desc.neededlen);
957 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
959 SAFE_FREE(queue);
960 SAFE_FREE(tmpdata);
962 return(True);
965 /****************************************************************************
966 View list of all print jobs on all queues.
967 ****************************************************************************/
969 static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param, char* data,
970 int mdrcnt, int mprcnt,
971 char **rdata, char** rparam,
972 int *rdata_len, int *rparam_len)
974 char *param_format = param+2;
975 char *output_format1 = skip_string(param_format,1);
976 char *p = skip_string(output_format1,1);
977 int uLevel = SVAL(p,0);
978 char *output_format2 = p + 4;
979 int services = lp_numservices();
980 int i, n;
981 struct pack_desc desc;
982 print_queue_struct **queue = NULL;
983 print_status_struct *status = NULL;
984 int* subcntarr = NULL;
985 int queuecnt, subcnt=0, succnt=0;
987 memset((char *)&desc,'\0',sizeof(desc));
989 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
991 if (!prefix_ok(param_format,"WrLeh")) return False;
992 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
994 * Patch from Scott Moomaw <scott@bridgewater.edu>
995 * to return the 'invalid info level' error if an
996 * unknown level was requested.
998 *rdata_len = 0;
999 *rparam_len = 6;
1000 *rparam = REALLOC(*rparam,*rparam_len);
1001 SSVALS(*rparam,0,ERRunknownlevel);
1002 SSVAL(*rparam,2,0);
1003 SSVAL(*rparam,4,0);
1004 return(True);
1007 queuecnt = 0;
1008 for (i = 0; i < services; i++)
1009 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
1010 queuecnt++;
1011 if (uLevel > 0) {
1012 if((queue = (print_queue_struct**)malloc(queuecnt*sizeof(print_queue_struct*))) == NULL) {
1013 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1014 return False;
1016 memset(queue,0,queuecnt*sizeof(print_queue_struct*));
1017 if((status = (print_status_struct*)malloc(queuecnt*sizeof(print_status_struct))) == NULL) {
1018 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1019 return False;
1021 memset(status,0,queuecnt*sizeof(print_status_struct));
1022 if((subcntarr = (int*)malloc(queuecnt*sizeof(int))) == NULL) {
1023 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1024 return False;
1026 subcnt = 0;
1027 n = 0;
1028 for (i = 0; i < services; i++)
1029 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1030 subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
1031 subcnt += subcntarr[n];
1032 n++;
1035 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
1036 desc.base = *rdata;
1037 desc.buflen = mdrcnt;
1039 if (init_package(&desc,queuecnt,subcnt)) {
1040 n = 0;
1041 succnt = 0;
1042 for (i = 0; i < services; i++)
1043 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1044 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1045 n++;
1046 if (desc.errcode == NERR_Success) succnt = n;
1050 SAFE_FREE(subcntarr);
1052 *rdata_len = desc.usedlen;
1053 *rparam_len = 8;
1054 *rparam = REALLOC(*rparam,*rparam_len);
1055 SSVALS(*rparam,0,desc.errcode);
1056 SSVAL(*rparam,2,0);
1057 SSVAL(*rparam,4,succnt);
1058 SSVAL(*rparam,6,queuecnt);
1060 for (i = 0; i < queuecnt; i++) {
1061 if (queue) SAFE_FREE(queue[i]);
1064 SAFE_FREE(queue);
1065 SAFE_FREE(status);
1067 return True;
1070 /****************************************************************************
1071 get info level for a server list query
1072 ****************************************************************************/
1073 static BOOL check_server_info(int uLevel, char* id)
1075 switch( uLevel ) {
1076 case 0:
1077 if (strcmp(id,"B16") != 0) return False;
1078 break;
1079 case 1:
1080 if (strcmp(id,"B16BBDz") != 0) return False;
1081 break;
1082 default:
1083 return False;
1085 return True;
1088 struct srv_info_struct
1090 fstring name;
1091 uint32 type;
1092 fstring comment;
1093 fstring domain;
1094 BOOL server_added;
1098 /*******************************************************************
1099 get server info lists from the files saved by nmbd. Return the
1100 number of entries
1101 ******************************************************************/
1102 static int get_server_info(uint32 servertype,
1103 struct srv_info_struct **servers,
1104 char *domain)
1106 int count=0;
1107 int alloced=0;
1108 char **lines;
1109 BOOL local_list_only;
1110 int i;
1112 lines = file_lines_load(lock_path(SERVER_LIST), NULL, False);
1113 if (!lines) {
1114 DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
1115 return(0);
1118 /* request for everything is code for request all servers */
1119 if (servertype == SV_TYPE_ALL)
1120 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1122 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1124 DEBUG(4,("Servertype search: %8x\n",servertype));
1126 for (i=0;lines[i];i++) {
1127 fstring stype;
1128 struct srv_info_struct *s;
1129 char *ptr = lines[i];
1130 BOOL ok = True;
1132 if (!*ptr) continue;
1134 if (count == alloced) {
1135 struct srv_info_struct *ts;
1137 alloced += 10;
1138 ts = (struct srv_info_struct *)
1139 Realloc(*servers,sizeof(**servers)*alloced);
1140 if (!ts) {
1141 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1142 return(0);
1144 else *servers = ts;
1145 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1147 s = &(*servers)[count];
1149 if (!next_token(&ptr,s->name , NULL, sizeof(s->name))) continue;
1150 if (!next_token(&ptr,stype , NULL, sizeof(stype))) continue;
1151 if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) continue;
1152 if (!next_token(&ptr,s->domain , NULL, sizeof(s->domain))) {
1153 /* this allows us to cope with an old nmbd */
1154 pstrcpy(s->domain,global_myworkgroup);
1157 if (sscanf(stype,"%X",&s->type) != 1) {
1158 DEBUG(4,("r:host file "));
1159 ok = False;
1162 /* Filter the servers/domains we return based on what was asked for. */
1164 /* Check to see if we are being asked for a local list only. */
1165 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1166 DEBUG(4,("r: local list only"));
1167 ok = False;
1170 /* doesn't match up: don't want it */
1171 if (!(servertype & s->type)) {
1172 DEBUG(4,("r:serv type "));
1173 ok = False;
1176 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1177 (s->type & SV_TYPE_DOMAIN_ENUM))
1179 DEBUG(4,("s: dom mismatch "));
1180 ok = False;
1183 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM))
1185 ok = False;
1188 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1189 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1191 if (ok)
1193 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1194 s->name, s->type, s->comment, s->domain));
1196 s->server_added = True;
1197 count++;
1199 else
1201 DEBUG(4,("%20s %8x %25s %15s\n",
1202 s->name, s->type, s->comment, s->domain));
1206 file_lines_free(lines);
1207 return(count);
1211 /*******************************************************************
1212 fill in a server info structure
1213 ******************************************************************/
1214 static int fill_srv_info(struct srv_info_struct *service,
1215 int uLevel, char **buf, int *buflen,
1216 char **stringbuf, int *stringspace, char *baseaddr)
1218 int struct_len;
1219 char* p;
1220 char* p2;
1221 int l2;
1222 int len;
1224 switch (uLevel) {
1225 case 0: struct_len = 16; break;
1226 case 1: struct_len = 26; break;
1227 default: return -1;
1230 if (!buf)
1232 len = 0;
1233 switch (uLevel)
1235 case 1:
1236 len = strlen(service->comment)+1;
1237 break;
1240 if (buflen) *buflen = struct_len;
1241 if (stringspace) *stringspace = len;
1242 return struct_len + len;
1245 len = struct_len;
1246 p = *buf;
1247 if (*buflen < struct_len) return -1;
1248 if (stringbuf)
1250 p2 = *stringbuf;
1251 l2 = *stringspace;
1253 else
1255 p2 = p + struct_len;
1256 l2 = *buflen - struct_len;
1258 if (!baseaddr) baseaddr = p;
1260 switch (uLevel)
1262 case 0:
1263 StrnCpy(p,service->name,15);
1264 break;
1266 case 1:
1267 StrnCpy(p,service->name,15);
1268 SIVAL(p,18,service->type);
1269 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1270 len += CopyAndAdvance(&p2,service->comment,&l2);
1271 break;
1274 if (stringbuf)
1276 *buf = p + struct_len;
1277 *buflen -= struct_len;
1278 *stringbuf = p2;
1279 *stringspace = l2;
1281 else
1283 *buf = p2;
1284 *buflen -= len;
1286 return len;
1290 static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1292 return(strcmp(s1->name,s2->name));
1295 /****************************************************************************
1296 view list of servers available (or possibly domains). The info is
1297 extracted from lists saved by nmbd on the local host
1298 ****************************************************************************/
1299 static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param, char *data,
1300 int mdrcnt, int mprcnt, char **rdata,
1301 char **rparam, int *rdata_len, int *rparam_len)
1303 char *str1 = param+2;
1304 char *str2 = skip_string(str1,1);
1305 char *p = skip_string(str2,1);
1306 int uLevel = SVAL(p,0);
1307 int buf_len = SVAL(p,2);
1308 uint32 servertype = IVAL(p,4);
1309 char *p2;
1310 int data_len, fixed_len, string_len;
1311 int f_len = 0, s_len = 0;
1312 struct srv_info_struct *servers=NULL;
1313 int counted=0,total=0;
1314 int i,missed;
1315 fstring domain;
1316 BOOL domain_request;
1317 BOOL local_request;
1319 /* If someone sets all the bits they don't really mean to set
1320 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1321 known servers. */
1323 if (servertype == SV_TYPE_ALL)
1324 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1326 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1327 any other bit (they may just set this bit on it's own) they
1328 want all the locally seen servers. However this bit can be
1329 set on its own so set the requested servers to be
1330 ALL - DOMAIN_ENUM. */
1332 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM))
1333 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1335 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1336 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1338 p += 8;
1340 if (!prefix_ok(str1,"WrLehD")) return False;
1341 if (!check_server_info(uLevel,str2)) return False;
1343 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1344 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1345 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1347 if (strcmp(str1, "WrLehDz") == 0) {
1348 StrnCpy(domain, p, sizeof(fstring)-1);
1349 } else {
1350 StrnCpy(domain, global_myworkgroup, sizeof(fstring)-1);
1353 if (lp_browse_list())
1354 total = get_server_info(servertype,&servers,domain);
1356 data_len = fixed_len = string_len = 0;
1357 missed = 0;
1359 if (total > 0)
1360 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1363 char *lastname=NULL;
1365 for (i=0;i<total;i++)
1367 struct srv_info_struct *s = &servers[i];
1368 if (lastname && strequal(lastname,s->name)) continue;
1369 lastname = s->name;
1370 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1371 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1372 s->name, s->type, s->comment, s->domain));
1374 if (data_len <= buf_len) {
1375 counted++;
1376 fixed_len += f_len;
1377 string_len += s_len;
1378 } else {
1379 missed++;
1384 *rdata_len = fixed_len + string_len;
1385 *rdata = REALLOC(*rdata,*rdata_len);
1386 memset(*rdata,'\0',*rdata_len);
1388 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1389 p = *rdata;
1390 f_len = fixed_len;
1391 s_len = string_len;
1394 char *lastname=NULL;
1395 int count2 = counted;
1396 for (i = 0; i < total && count2;i++)
1398 struct srv_info_struct *s = &servers[i];
1399 if (lastname && strequal(lastname,s->name)) continue;
1400 lastname = s->name;
1401 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1402 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1403 s->name, s->type, s->comment, s->domain));
1404 count2--;
1408 *rparam_len = 8;
1409 *rparam = REALLOC(*rparam,*rparam_len);
1410 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1411 SSVAL(*rparam,2,0);
1412 SSVAL(*rparam,4,counted);
1413 SSVAL(*rparam,6,counted+missed);
1415 SAFE_FREE(servers);
1417 DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1418 domain,uLevel,counted,counted+missed));
1420 return(True);
1423 /****************************************************************************
1424 command 0x34 - suspected of being a "Lookup Names" stub api
1425 ****************************************************************************/
1426 static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid, char *param, char *data,
1427 int mdrcnt, int mprcnt, char **rdata,
1428 char **rparam, int *rdata_len, int *rparam_len)
1430 char *str1 = param+2;
1431 char *str2 = skip_string(str1,1);
1432 char *p = skip_string(str2,1);
1433 int uLevel = SVAL(p,0);
1434 int buf_len = SVAL(p,2);
1435 int counted=0;
1436 int missed=0;
1438 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1439 str1, str2, p, uLevel, buf_len));
1441 if (!prefix_ok(str1,"zWrLeh")) return False;
1443 *rdata_len = 0;
1445 *rparam_len = 8;
1446 *rparam = REALLOC(*rparam,*rparam_len);
1448 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1449 SSVAL(*rparam,2,0);
1450 SSVAL(*rparam,4,counted);
1451 SSVAL(*rparam,6,counted+missed);
1453 return(True);
1456 /****************************************************************************
1457 get info about a share
1458 ****************************************************************************/
1459 static BOOL check_share_info(int uLevel, char* id)
1461 switch( uLevel ) {
1462 case 0:
1463 if (strcmp(id,"B13") != 0) return False;
1464 break;
1465 case 1:
1466 if (strcmp(id,"B13BWz") != 0) return False;
1467 break;
1468 case 2:
1469 if (strcmp(id,"B13BWzWWWzB9B") != 0) return False;
1470 break;
1471 case 91:
1472 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) return False;
1473 break;
1474 default: return False;
1476 return True;
1479 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1480 char** buf, int* buflen,
1481 char** stringbuf, int* stringspace, char* baseaddr)
1483 int struct_len;
1484 char* p;
1485 char* p2;
1486 int l2;
1487 int len;
1489 switch( uLevel ) {
1490 case 0: struct_len = 13; break;
1491 case 1: struct_len = 20; break;
1492 case 2: struct_len = 40; break;
1493 case 91: struct_len = 68; break;
1494 default: return -1;
1498 if (!buf)
1500 len = 0;
1501 if (uLevel > 0) len += StrlenExpanded(conn,snum,lp_comment(snum));
1502 if (uLevel > 1) len += strlen(lp_pathname(snum)) + 1;
1503 if (buflen) *buflen = struct_len;
1504 if (stringspace) *stringspace = len;
1505 return struct_len + len;
1508 len = struct_len;
1509 p = *buf;
1510 if ((*buflen) < struct_len) return -1;
1511 if (stringbuf)
1513 p2 = *stringbuf;
1514 l2 = *stringspace;
1516 else
1518 p2 = p + struct_len;
1519 l2 = (*buflen) - struct_len;
1521 if (!baseaddr) baseaddr = p;
1523 StrnCpy(p,lp_servicename(snum),13);
1525 if (uLevel > 0)
1527 int type;
1528 SCVAL(p,13,0);
1529 type = STYPE_DISKTREE;
1530 if (lp_print_ok(snum)) type = STYPE_PRINTQ;
1531 if (strequal("IPC$",lp_servicename(snum))) type = STYPE_IPC;
1532 SSVAL(p,14,type); /* device type */
1533 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1534 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1537 if (uLevel > 1)
1539 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1540 SSVALS(p,22,-1); /* max uses */
1541 SSVAL(p,24,1); /* current uses */
1542 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1543 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1544 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1547 if (uLevel > 2)
1549 memset(p+40,0,SHPWLEN+2);
1550 SSVAL(p,50,0);
1551 SIVAL(p,52,0);
1552 SSVAL(p,56,0);
1553 SSVAL(p,58,0);
1554 SIVAL(p,60,0);
1555 SSVAL(p,64,0);
1556 SSVAL(p,66,0);
1559 if (stringbuf)
1561 (*buf) = p + struct_len;
1562 (*buflen) -= struct_len;
1563 (*stringbuf) = p2;
1564 (*stringspace) = l2;
1566 else
1568 (*buf) = p2;
1569 (*buflen) -= len;
1571 return len;
1574 static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
1575 int mdrcnt,int mprcnt,
1576 char **rdata,char **rparam,
1577 int *rdata_len,int *rparam_len)
1579 char *str1 = param+2;
1580 char *str2 = skip_string(str1,1);
1581 char *netname = skip_string(str2,1);
1582 char *p = skip_string(netname,1);
1583 int uLevel = SVAL(p,0);
1584 int snum = find_service(netname);
1586 if (snum < 0) return False;
1588 /* check it's a supported varient */
1589 if (!prefix_ok(str1,"zWrLh")) return False;
1590 if (!check_share_info(uLevel,str2)) return False;
1592 *rdata = REALLOC(*rdata,mdrcnt);
1593 p = *rdata;
1594 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1595 if (*rdata_len < 0) return False;
1597 *rparam_len = 6;
1598 *rparam = REALLOC(*rparam,*rparam_len);
1599 SSVAL(*rparam,0,NERR_Success);
1600 SSVAL(*rparam,2,0); /* converter word */
1601 SSVAL(*rparam,4,*rdata_len);
1603 return(True);
1606 /****************************************************************************
1607 view list of shares available
1608 ****************************************************************************/
1609 static BOOL api_RNetShareEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
1610 int mdrcnt,int mprcnt,
1611 char **rdata,char **rparam,
1612 int *rdata_len,int *rparam_len)
1614 char *str1 = param+2;
1615 char *str2 = skip_string(str1,1);
1616 char *p = skip_string(str2,1);
1617 int uLevel = SVAL(p,0);
1618 int buf_len = SVAL(p,2);
1619 char *p2;
1620 int count=lp_numservices();
1621 int total=0,counted=0;
1622 BOOL missed = False;
1623 int i;
1624 int data_len, fixed_len, string_len;
1625 int f_len = 0, s_len = 0;
1627 if (!prefix_ok(str1,"WrLeh")) return False;
1628 if (!check_share_info(uLevel,str2)) return False;
1630 data_len = fixed_len = string_len = 0;
1631 for (i=0;i<count;i++)
1632 if (lp_browseable(i) && lp_snum_ok(i))
1634 total++;
1635 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1636 if (data_len <= buf_len)
1638 counted++;
1639 fixed_len += f_len;
1640 string_len += s_len;
1642 else
1643 missed = True;
1645 *rdata_len = fixed_len + string_len;
1646 *rdata = REALLOC(*rdata,*rdata_len);
1647 memset(*rdata,0,*rdata_len);
1649 p2 = (*rdata) + fixed_len; /* auxillery data (strings) will go here */
1650 p = *rdata;
1651 f_len = fixed_len;
1652 s_len = string_len;
1653 for (i = 0; i < count;i++)
1654 if (lp_browseable(i) && lp_snum_ok(i))
1655 if (fill_share_info(conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata) < 0)
1656 break;
1658 *rparam_len = 8;
1659 *rparam = REALLOC(*rparam,*rparam_len);
1660 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1661 SSVAL(*rparam,2,0);
1662 SSVAL(*rparam,4,counted);
1663 SSVAL(*rparam,6,total);
1665 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1666 counted,total,uLevel,
1667 buf_len,*rdata_len,mdrcnt));
1668 return(True);
1673 /****************************************************************************
1674 get the time of day info
1675 ****************************************************************************/
1676 static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid, char *param,char *data,
1677 int mdrcnt,int mprcnt,
1678 char **rdata,char **rparam,
1679 int *rdata_len,int *rparam_len)
1681 char *p;
1682 *rparam_len = 4;
1683 *rparam = REALLOC(*rparam,*rparam_len);
1685 *rdata_len = 21;
1686 *rdata = REALLOC(*rdata,*rdata_len);
1688 SSVAL(*rparam,0,NERR_Success);
1689 SSVAL(*rparam,2,0); /* converter word */
1691 p = *rdata;
1694 struct tm *t;
1695 time_t unixdate = time(NULL);
1697 put_dos_date3(p,0,unixdate); /* this is the time that is looked at
1698 by NT in a "net time" operation,
1699 it seems to ignore the one below */
1701 /* the client expects to get localtime, not GMT, in this bit
1702 (I think, this needs testing) */
1703 t = LocalTime(&unixdate);
1705 SIVAL(p,4,0); /* msecs ? */
1706 SCVAL(p,8,t->tm_hour);
1707 SCVAL(p,9,t->tm_min);
1708 SCVAL(p,10,t->tm_sec);
1709 SCVAL(p,11,0); /* hundredths of seconds */
1710 SSVALS(p,12,TimeDiff(unixdate)/60); /* timezone in minutes from GMT */
1711 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
1712 SCVAL(p,16,t->tm_mday);
1713 SCVAL(p,17,t->tm_mon + 1);
1714 SSVAL(p,18,1900+t->tm_year);
1715 SCVAL(p,20,t->tm_wday);
1719 return(True);
1722 /****************************************************************************
1723 Set the user password.
1724 *****************************************************************************/
1726 static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1727 int mdrcnt,int mprcnt,
1728 char **rdata,char **rparam,
1729 int *rdata_len,int *rparam_len)
1731 char *p = skip_string(param+2,2);
1732 fstring user;
1733 fstring pass1,pass2;
1735 fstrcpy(user,p);
1737 p = skip_string(p,1);
1739 memset(pass1,'\0',sizeof(pass1));
1740 memset(pass2,'\0',sizeof(pass2));
1741 memcpy(pass1,p,16);
1742 memcpy(pass2,p+16,16);
1744 *rparam_len = 4;
1745 *rparam = REALLOC(*rparam,*rparam_len);
1747 *rdata_len = 0;
1749 SSVAL(*rparam,0,NERR_badpass);
1750 SSVAL(*rparam,2,0); /* converter word */
1752 DEBUG(3,("Set password for <%s>\n",user));
1755 * Pass the user through the NT -> unix user mapping
1756 * function.
1759 (void)map_username(user);
1762 * Do any UNIX username case mangling.
1764 (void)Get_Pwnam( user, True);
1767 * Attempt to verify the old password against smbpasswd entries
1768 * Win98 clients send old and new password in plaintext for this call.
1772 fstring saved_pass2;
1773 SAM_ACCOUNT *sampass = NULL;
1776 * Save the new password as change_oem_password overwrites it
1777 * with zeros.
1780 fstrcpy(saved_pass2, pass2);
1782 if (check_plaintext_password(user,pass1,strlen(pass1),&sampass) &&
1783 change_oem_password(sampass,pass2,False))
1785 SSVAL(*rparam,0,NERR_Success);
1788 * If unix password sync was requested, attempt to change
1789 * the /etc/passwd database also. Return failure if this cannot
1790 * be done.
1793 if(lp_unix_password_sync() && !chgpasswd(user,pass1,saved_pass2,False))
1794 SSVAL(*rparam,0,NERR_badpass);
1797 pdb_free_sam(sampass);
1801 * If the above failed, attempt the plaintext password change.
1802 * This tests against the /etc/passwd database only.
1805 if(SVAL(*rparam,0) != NERR_Success)
1807 if (password_ok(user, pass1,strlen(pass1),NULL) &&
1808 chgpasswd(user,pass1,pass2,False))
1810 SSVAL(*rparam,0,NERR_Success);
1815 * If the plaintext change failed, attempt
1816 * the old encrypted method. NT will generate this
1817 * after trying the samr method. Note that this
1818 * method is done as a last resort as this
1819 * password change method loses the NT password hash
1820 * and cannot change the UNIX password as no plaintext
1821 * is received.
1824 if(SVAL(*rparam,0) != NERR_Success)
1826 SAM_ACCOUNT *sampass = NULL;
1828 if(check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &sampass) &&
1829 change_lanman_password(sampass,(unsigned char *)pass1,(unsigned char *)pass2))
1831 SSVAL(*rparam,0,NERR_Success);
1833 pdb_free_sam(sampass);
1836 memset((char *)pass1,'\0',sizeof(fstring));
1837 memset((char *)pass2,'\0',sizeof(fstring));
1839 return(True);
1842 /****************************************************************************
1843 Set the user password (SamOEM version - gets plaintext).
1844 ****************************************************************************/
1846 static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1847 int mdrcnt,int mprcnt,
1848 char **rdata,char **rparam,
1849 int *rdata_len,int *rparam_len)
1851 fstring user;
1852 char *p = param + 2;
1853 *rparam_len = 2;
1854 *rparam = REALLOC(*rparam,*rparam_len);
1856 *rdata_len = 0;
1858 SSVAL(*rparam,0,NERR_badpass);
1861 * Check the parameter definition is correct.
1863 if(!strequal(param + 2, "zsT")) {
1864 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", param + 2));
1865 return False;
1867 p = skip_string(p, 1);
1869 if(!strequal(p, "B516B16")) {
1870 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
1871 return False;
1873 p = skip_string(p,1);
1875 fstrcpy(user,p);
1876 p = skip_string(p,1);
1878 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
1881 * Pass the user through the NT -> unix user mapping
1882 * function.
1885 (void)map_username(user);
1888 * Do any UNIX username case mangling.
1890 (void)Get_Pwnam( user, True);
1892 if (pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL))
1894 SSVAL(*rparam,0,NERR_Success);
1897 return(True);
1900 /****************************************************************************
1901 delete a print job
1902 Form: <W> <>
1903 ****************************************************************************/
1904 static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param,char *data,
1905 int mdrcnt,int mprcnt,
1906 char **rdata,char **rparam,
1907 int *rdata_len,int *rparam_len)
1909 int function = SVAL(param,0);
1910 char *str1 = param+2;
1911 char *str2 = skip_string(str1,1);
1912 char *p = skip_string(str2,1);
1913 int jobid, errcode;
1914 extern struct current_user current_user;
1915 WERROR werr = WERR_OK;
1917 jobid = SVAL(p,0);
1919 /* check it's a supported varient */
1920 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
1921 return(False);
1923 *rparam_len = 4;
1924 *rparam = REALLOC(*rparam,*rparam_len);
1925 *rdata_len = 0;
1927 if (!print_job_exists(jobid)) {
1928 errcode = NERR_JobNotFound;
1929 goto out;
1932 errcode = NERR_notsupported;
1934 switch (function) {
1935 case 81: /* delete */
1936 if (print_job_delete(&current_user, jobid, &werr))
1937 errcode = NERR_Success;
1938 break;
1939 case 82: /* pause */
1940 if (print_job_pause(&current_user, jobid, &werr))
1941 errcode = NERR_Success;
1942 break;
1943 case 83: /* resume */
1944 if (print_job_resume(&current_user, jobid, &werr))
1945 errcode = NERR_Success;
1946 break;
1949 if (!W_ERROR_IS_OK(werr))
1950 errcode = W_ERROR_V(werr);
1952 out:
1953 SSVAL(*rparam,0,errcode);
1954 SSVAL(*rparam,2,0); /* converter word */
1956 return(True);
1959 /****************************************************************************
1960 Purge a print queue - or pause or resume it.
1961 ****************************************************************************/
1962 static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid, char *param,char *data,
1963 int mdrcnt,int mprcnt,
1964 char **rdata,char **rparam,
1965 int *rdata_len,int *rparam_len)
1967 int function = SVAL(param,0);
1968 char *str1 = param+2;
1969 char *str2 = skip_string(str1,1);
1970 char *QueueName = skip_string(str2,1);
1971 int errcode = NERR_notsupported;
1972 int snum;
1973 WERROR werr = WERR_OK;
1974 extern struct current_user current_user;
1976 /* check it's a supported varient */
1977 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
1978 return(False);
1980 *rparam_len = 4;
1981 *rparam = REALLOC(*rparam,*rparam_len);
1982 *rdata_len = 0;
1984 snum = print_queue_snum(QueueName);
1986 if (snum == -1) {
1987 errcode = NERR_JobNotFound;
1988 goto out;
1991 switch (function) {
1992 case 74: /* Pause queue */
1993 if (print_queue_pause(&current_user, snum, &werr)) errcode = NERR_Success;
1994 break;
1995 case 75: /* Resume queue */
1996 if (print_queue_resume(&current_user, snum, &werr)) errcode = NERR_Success;
1997 break;
1998 case 103: /* Purge */
1999 if (print_queue_purge(&current_user, snum, &werr)) errcode = NERR_Success;
2000 break;
2003 if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr);
2004 out:
2005 SSVAL(*rparam,0,errcode);
2006 SSVAL(*rparam,2,0); /* converter word */
2008 return(True);
2012 /****************************************************************************
2013 set the property of a print job (undocumented?)
2014 ? function = 0xb -> set name of print job
2015 ? function = 0x6 -> move print job up/down
2016 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
2017 or <WWsTP> <WB21BB16B10zWWzDDz>
2018 ****************************************************************************/
2019 static int check_printjob_info(struct pack_desc* desc,
2020 int uLevel, char* id)
2022 desc->subformat = NULL;
2023 switch( uLevel ) {
2024 case 0: desc->format = "W"; break;
2025 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2026 case 2: desc->format = "WWzWWDDzz"; break;
2027 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2028 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2029 default: return False;
2031 if (strcmp(desc->format,id) != 0) return False;
2032 return True;
2035 static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,char *data,
2036 int mdrcnt,int mprcnt,
2037 char **rdata,char **rparam,
2038 int *rdata_len,int *rparam_len)
2040 struct pack_desc desc;
2041 char *str1 = param+2;
2042 char *str2 = skip_string(str1,1);
2043 char *p = skip_string(str2,1);
2044 int jobid;
2045 int uLevel = SVAL(p,2);
2046 int function = SVAL(p,4);
2047 int place, errcode;
2049 jobid = SVAL(p,0);
2050 *rparam_len = 4;
2051 *rparam = REALLOC(*rparam,*rparam_len);
2053 *rdata_len = 0;
2055 /* check it's a supported varient */
2056 if ((strcmp(str1,"WWsTP")) ||
2057 (!check_printjob_info(&desc,uLevel,str2)))
2058 return(False);
2060 if (!print_job_exists(jobid)) {
2061 errcode=NERR_JobNotFound;
2062 goto out;
2065 errcode = NERR_notsupported;
2067 switch (function) {
2068 case 0x6:
2069 /* change job place in the queue,
2070 data gives the new place */
2071 place = SVAL(data,0);
2072 if (print_job_set_place(jobid, place)) {
2073 errcode=NERR_Success;
2075 break;
2077 case 0xb:
2078 /* change print job name, data gives the name */
2079 if (print_job_set_name(jobid, data)) {
2080 errcode=NERR_Success;
2082 break;
2084 default:
2085 return False;
2088 out:
2089 SSVALS(*rparam,0,errcode);
2090 SSVAL(*rparam,2,0); /* converter word */
2092 return(True);
2096 /****************************************************************************
2097 get info about the server
2098 ****************************************************************************/
2099 static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2100 int mdrcnt,int mprcnt,
2101 char **rdata,char **rparam,
2102 int *rdata_len,int *rparam_len)
2104 char *str1 = param+2;
2105 char *str2 = skip_string(str1,1);
2106 char *p = skip_string(str2,1);
2107 int uLevel = SVAL(p,0);
2108 char *p2;
2109 int struct_len;
2111 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2113 /* check it's a supported varient */
2114 if (!prefix_ok(str1,"WrLh")) return False;
2115 switch( uLevel ) {
2116 case 0:
2117 if (strcmp(str2,"B16") != 0) return False;
2118 struct_len = 16;
2119 break;
2120 case 1:
2121 if (strcmp(str2,"B16BBDz") != 0) return False;
2122 struct_len = 26;
2123 break;
2124 case 2:
2125 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")
2126 != 0) return False;
2127 struct_len = 134;
2128 break;
2129 case 3:
2130 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz")
2131 != 0) return False;
2132 struct_len = 144;
2133 break;
2134 case 20:
2135 if (strcmp(str2,"DN") != 0) return False;
2136 struct_len = 6;
2137 break;
2138 case 50:
2139 if (strcmp(str2,"B16BBDzWWzzz") != 0) return False;
2140 struct_len = 42;
2141 break;
2142 default: return False;
2145 *rdata_len = mdrcnt;
2146 *rdata = REALLOC(*rdata,*rdata_len);
2148 p = *rdata;
2149 p2 = p + struct_len;
2150 if (uLevel != 20) {
2151 StrnCpy(p,local_machine,16);
2152 strupper(p);
2154 p += 16;
2155 if (uLevel > 0)
2157 struct srv_info_struct *servers=NULL;
2158 int i,count;
2159 pstring comment;
2160 uint32 servertype= lp_default_server_announce();
2162 pstrcpy(comment,string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH));
2164 if ((count=get_server_info(SV_TYPE_ALL,&servers,global_myworkgroup))>0) {
2165 for (i=0;i<count;i++)
2166 if (strequal(servers[i].name,local_machine))
2168 servertype = servers[i].type;
2169 pstrcpy(comment,servers[i].comment);
2172 SAFE_FREE(servers);
2174 SCVAL(p,0,lp_major_announce_version());
2175 SCVAL(p,1,lp_minor_announce_version());
2176 SIVAL(p,2,servertype);
2178 if (mdrcnt == struct_len) {
2179 SIVAL(p,6,0);
2180 } else {
2181 SIVAL(p,6,PTR_DIFF(p2,*rdata));
2182 standard_sub_conn(conn,comment,sizeof(comment));
2183 StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2184 p2 = skip_string(p2,1);
2187 if (uLevel > 1)
2189 return False; /* not yet implemented */
2192 *rdata_len = PTR_DIFF(p2,*rdata);
2194 *rparam_len = 6;
2195 *rparam = REALLOC(*rparam,*rparam_len);
2196 SSVAL(*rparam,0,NERR_Success);
2197 SSVAL(*rparam,2,0); /* converter word */
2198 SSVAL(*rparam,4,*rdata_len);
2200 return(True);
2204 /****************************************************************************
2205 get info about the server
2206 ****************************************************************************/
2207 static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2208 int mdrcnt,int mprcnt,
2209 char **rdata,char **rparam,
2210 int *rdata_len,int *rparam_len)
2212 char *str1 = param+2;
2213 char *str2 = skip_string(str1,1);
2214 char *p = skip_string(str2,1);
2215 char *p2;
2216 extern userdom_struct current_user_info;
2217 int level = SVAL(p,0);
2219 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2221 *rparam_len = 6;
2222 *rparam = REALLOC(*rparam,*rparam_len);
2224 /* check it's a supported varient */
2225 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz")))
2226 return(False);
2228 *rdata_len = mdrcnt + 1024;
2229 *rdata = REALLOC(*rdata,*rdata_len);
2231 SSVAL(*rparam,0,NERR_Success);
2232 SSVAL(*rparam,2,0); /* converter word */
2234 p = *rdata;
2235 p2 = p + 22;
2238 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2239 pstrcpy(p2,local_machine);
2240 strupper(p2);
2241 p2 = skip_string(p2,1);
2242 p += 4;
2244 SIVAL(p,0,PTR_DIFF(p2,*rdata));
2245 pstrcpy(p2,current_user_info.smb_name);
2246 p2 = skip_string(p2,1);
2247 p += 4;
2249 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
2250 pstrcpy(p2,global_myworkgroup);
2251 strupper(p2);
2252 p2 = skip_string(p2,1);
2253 p += 4;
2255 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
2256 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
2257 p += 2;
2259 SIVAL(p,0,PTR_DIFF(p2,*rdata));
2260 pstrcpy(p2,global_myworkgroup); /* don't know. login domain?? */
2261 p2 = skip_string(p2,1);
2262 p += 4;
2264 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
2265 pstrcpy(p2,"");
2266 p2 = skip_string(p2,1);
2267 p += 4;
2269 *rdata_len = PTR_DIFF(p2,*rdata);
2271 SSVAL(*rparam,4,*rdata_len);
2273 return(True);
2276 /****************************************************************************
2277 get info about a user
2279 struct user_info_11 {
2280 char usri11_name[21]; 0-20
2281 char usri11_pad; 21
2282 char *usri11_comment; 22-25
2283 char *usri11_usr_comment; 26-29
2284 unsigned short usri11_priv; 30-31
2285 unsigned long usri11_auth_flags; 32-35
2286 long usri11_password_age; 36-39
2287 char *usri11_homedir; 40-43
2288 char *usri11_parms; 44-47
2289 long usri11_last_logon; 48-51
2290 long usri11_last_logoff; 52-55
2291 unsigned short usri11_bad_pw_count; 56-57
2292 unsigned short usri11_num_logons; 58-59
2293 char *usri11_logon_server; 60-63
2294 unsigned short usri11_country_code; 64-65
2295 char *usri11_workstations; 66-69
2296 unsigned long usri11_max_storage; 70-73
2297 unsigned short usri11_units_per_week; 74-75
2298 unsigned char *usri11_logon_hours; 76-79
2299 unsigned short usri11_code_page; 80-81
2302 where:
2304 usri11_name specifies the user name for which information is retireved
2306 usri11_pad aligns the next data structure element to a word boundary
2308 usri11_comment is a null terminated ASCII comment
2310 usri11_user_comment is a null terminated ASCII comment about the user
2312 usri11_priv specifies the level of the privilege assigned to the user.
2313 The possible values are:
2315 Name Value Description
2316 USER_PRIV_GUEST 0 Guest privilege
2317 USER_PRIV_USER 1 User privilege
2318 USER_PRV_ADMIN 2 Administrator privilege
2320 usri11_auth_flags specifies the account operator privileges. The
2321 possible values are:
2323 Name Value Description
2324 AF_OP_PRINT 0 Print operator
2327 Leach, Naik [Page 28]
2331 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
2334 AF_OP_COMM 1 Communications operator
2335 AF_OP_SERVER 2 Server operator
2336 AF_OP_ACCOUNTS 3 Accounts operator
2339 usri11_password_age specifies how many seconds have elapsed since the
2340 password was last changed.
2342 usri11_home_dir points to a null terminated ASCII string that contains
2343 the path name of the user's home directory.
2345 usri11_parms points to a null terminated ASCII string that is set
2346 aside for use by applications.
2348 usri11_last_logon specifies the time when the user last logged on.
2349 This value is stored as the number of seconds elapsed since
2350 00:00:00, January 1, 1970.
2352 usri11_last_logoff specifies the time when the user last logged off.
2353 This value is stored as the number of seconds elapsed since
2354 00:00:00, January 1, 1970. A value of 0 means the last logoff
2355 time is unknown.
2357 usri11_bad_pw_count specifies the number of incorrect passwords
2358 entered since the last successful logon.
2360 usri11_log1_num_logons specifies the number of times this user has
2361 logged on. A value of -1 means the number of logons is unknown.
2363 usri11_logon_server points to a null terminated ASCII string that
2364 contains the name of the server to which logon requests are sent.
2365 A null string indicates logon requests should be sent to the
2366 domain controller.
2368 usri11_country_code specifies the country code for the user's language
2369 of choice.
2371 usri11_workstations points to a null terminated ASCII string that
2372 contains the names of workstations the user may log on from.
2373 There may be up to 8 workstations, with the names separated by
2374 commas. A null strings indicates there are no restrictions.
2376 usri11_max_storage specifies the maximum amount of disk space the user
2377 can occupy. A value of 0xffffffff indicates there are no
2378 restrictions.
2380 usri11_units_per_week specifies the equal number of time units into
2381 which a week is divided. This value must be equal to 168.
2383 usri11_logon_hours points to a 21 byte (168 bits) string that
2384 specifies the time during which the user can log on. Each bit
2385 represents one unique hour in a week. The first bit (bit 0, word
2386 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
2390 Leach, Naik [Page 29]
2394 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
2397 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
2398 are no restrictions.
2400 usri11_code_page specifies the code page for the user's language of
2401 choice
2403 All of the pointers in this data structure need to be treated
2404 specially. The pointer is a 32 bit pointer. The higher 16 bits need
2405 to be ignored. The converter word returned in the parameters section
2406 needs to be subtracted from the lower 16 bits to calculate an offset
2407 into the return buffer where this ASCII string resides.
2409 There is no auxiliary data in the response.
2411 ****************************************************************************/
2413 #define usri11_name 0
2414 #define usri11_pad 21
2415 #define usri11_comment 22
2416 #define usri11_usr_comment 26
2417 #define usri11_full_name 30
2418 #define usri11_priv 34
2419 #define usri11_auth_flags 36
2420 #define usri11_password_age 40
2421 #define usri11_homedir 44
2422 #define usri11_parms 48
2423 #define usri11_last_logon 52
2424 #define usri11_last_logoff 56
2425 #define usri11_bad_pw_count 60
2426 #define usri11_num_logons 62
2427 #define usri11_logon_server 64
2428 #define usri11_country_code 68
2429 #define usri11_workstations 70
2430 #define usri11_max_storage 74
2431 #define usri11_units_per_week 78
2432 #define usri11_logon_hours 80
2433 #define usri11_code_page 84
2434 #define usri11_end 86
2436 #define USER_PRIV_GUEST 0
2437 #define USER_PRIV_USER 1
2438 #define USER_PRIV_ADMIN 2
2440 #define AF_OP_PRINT 0
2441 #define AF_OP_COMM 1
2442 #define AF_OP_SERVER 2
2443 #define AF_OP_ACCOUNTS 3
2446 static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2447 int mdrcnt,int mprcnt,
2448 char **rdata,char **rparam,
2449 int *rdata_len,int *rparam_len)
2451 char *str1 = param+2;
2452 char *str2 = skip_string(str1,1);
2453 char *UserName = skip_string(str2,1);
2454 char *p = skip_string(UserName,1);
2455 int uLevel = SVAL(p,0);
2456 char *p2;
2458 /* get NIS home of a previously validated user - simeon */
2459 /* With share level security vuid will always be zero.
2460 Don't depend on vuser being non-null !!. JRA */
2461 user_struct *vuser = get_valid_user_struct(vuid);
2462 if(vuser != NULL)
2463 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
2464 vuser->user.unix_name));
2466 *rparam_len = 6;
2467 *rparam = REALLOC(*rparam,*rparam_len);
2469 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
2471 /* check it's a supported variant */
2472 if (strcmp(str1,"zWrLh") != 0) return False;
2473 switch( uLevel )
2475 case 0: p2 = "B21"; break;
2476 case 1: p2 = "B21BB16DWzzWz"; break;
2477 case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
2478 case 10: p2 = "B21Bzzz"; break;
2479 case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
2480 default: return False;
2483 if (strcmp(p2,str2) != 0) return False;
2485 *rdata_len = mdrcnt + 1024;
2486 *rdata = REALLOC(*rdata,*rdata_len);
2488 SSVAL(*rparam,0,NERR_Success);
2489 SSVAL(*rparam,2,0); /* converter word */
2491 p = *rdata;
2492 p2 = p + usri11_end;
2494 memset(p,0,21);
2495 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
2497 if (uLevel > 0)
2499 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
2500 *p2 = 0;
2502 if (uLevel >= 10)
2504 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
2505 pstrcpy(p2,"Comment");
2506 p2 = skip_string(p2,1);
2508 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
2509 pstrcpy(p2,"UserComment");
2510 p2 = skip_string(p2,1);
2512 /* EEK! the cifsrap.txt doesn't have this in!!!! */
2513 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
2514 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2515 p2 = skip_string(p2,1);
2518 if (uLevel == 11) /* modelled after NTAS 3.51 reply */
2520 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2521 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
2522 SIVALS(p,usri11_password_age,-1); /* password age */
2523 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
2524 pstrcpy(p2, lp_logon_home());
2525 standard_sub_conn(conn, p2,*rdata_len-(p2 - *rdata));
2526 p2 = skip_string(p2,1);
2527 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
2528 pstrcpy(p2,"");
2529 p2 = skip_string(p2,1);
2530 SIVAL(p,usri11_last_logon,0); /* last logon */
2531 SIVAL(p,usri11_last_logoff,0); /* last logoff */
2532 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
2533 SSVALS(p,usri11_num_logons,-1); /* num logons */
2534 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
2535 pstrcpy(p2,"\\\\*");
2536 p2 = skip_string(p2,1);
2537 SSVAL(p,usri11_country_code,0); /* country code */
2539 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
2540 pstrcpy(p2,"");
2541 p2 = skip_string(p2,1);
2543 SIVALS(p,usri11_max_storage,-1); /* max storage */
2544 SSVAL(p,usri11_units_per_week,168); /* units per week */
2545 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
2547 /* a simple way to get logon hours at all times. */
2548 memset(p2,0xff,21);
2549 SCVAL(p2,21,0); /* fix zero termination */
2550 p2 = skip_string(p2,1);
2552 SSVAL(p,usri11_code_page,0); /* code page */
2554 if (uLevel == 1 || uLevel == 2)
2556 memset(p+22,' ',16); /* password */
2557 SIVALS(p,38,-1); /* password age */
2558 SSVAL(p,42,
2559 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2560 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
2561 pstrcpy(p2,lp_logon_home());
2562 standard_sub_conn(conn, p2,*rdata_len-(p2 - *rdata));
2563 p2 = skip_string(p2,1);
2564 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
2565 *p2++ = 0;
2566 SSVAL(p,52,0); /* flags */
2567 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
2568 pstrcpy(p2,lp_logon_script());
2569 standard_sub_conn( conn, p2,*rdata_len-(p2 - *rdata));
2570 p2 = skip_string(p2,1);
2571 if (uLevel == 2)
2573 SIVAL(p,60,0); /* auth_flags */
2574 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
2575 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2576 p2 = skip_string(p2,1);
2577 SIVAL(p,68,0); /* urs_comment */
2578 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
2579 pstrcpy(p2,"");
2580 p2 = skip_string(p2,1);
2581 SIVAL(p,76,0); /* workstations */
2582 SIVAL(p,80,0); /* last_logon */
2583 SIVAL(p,84,0); /* last_logoff */
2584 SIVALS(p,88,-1); /* acct_expires */
2585 SIVALS(p,92,-1); /* max_storage */
2586 SSVAL(p,96,168); /* units_per_week */
2587 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
2588 memset(p2,-1,21);
2589 p2 += 21;
2590 SSVALS(p,102,-1); /* bad_pw_count */
2591 SSVALS(p,104,-1); /* num_logons */
2592 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
2593 pstrcpy(p2,"\\\\%L");
2594 standard_sub_conn(conn, p2,*rdata_len-(p2 - *rdata));
2595 p2 = skip_string(p2,1);
2596 SSVAL(p,110,49); /* country_code */
2597 SSVAL(p,112,860); /* code page */
2601 *rdata_len = PTR_DIFF(p2,*rdata);
2603 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
2605 return(True);
2608 /*******************************************************************
2609 get groups that a user is a member of
2610 ******************************************************************/
2611 static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *param,char *data,
2612 int mdrcnt,int mprcnt,
2613 char **rdata,char **rparam,
2614 int *rdata_len,int *rparam_len)
2616 char *str1 = param+2;
2617 char *str2 = skip_string(str1,1);
2618 char *UserName = skip_string(str2,1);
2619 char *p = skip_string(UserName,1);
2620 int uLevel = SVAL(p,0);
2621 char *p2;
2622 int count=0;
2624 *rparam_len = 8;
2625 *rparam = REALLOC(*rparam,*rparam_len);
2627 /* check it's a supported varient */
2628 if (strcmp(str1,"zWrLeh") != 0) return False;
2629 switch( uLevel ) {
2630 case 0: p2 = "B21"; break;
2631 default: return False;
2633 if (strcmp(p2,str2) != 0) return False;
2635 *rdata_len = mdrcnt + 1024;
2636 *rdata = REALLOC(*rdata,*rdata_len);
2638 SSVAL(*rparam,0,NERR_Success);
2639 SSVAL(*rparam,2,0); /* converter word */
2641 p = *rdata;
2643 /* XXXX we need a real SAM database some day */
2644 pstrcpy(p,"Users"); p += 21; count++;
2645 pstrcpy(p,"Domain Users"); p += 21; count++;
2646 pstrcpy(p,"Guests"); p += 21; count++;
2647 pstrcpy(p,"Domain Guests"); p += 21; count++;
2649 *rdata_len = PTR_DIFF(p,*rdata);
2651 SSVAL(*rparam,4,count); /* is this right?? */
2652 SSVAL(*rparam,6,count); /* is this right?? */
2654 return(True);
2658 static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param,char *data,
2659 int mdrcnt,int mprcnt,
2660 char **rdata,char **rparam,
2661 int *rdata_len,int *rparam_len)
2663 char *str1 = param+2;
2664 char *str2 = skip_string(str1,1);
2665 char *p = skip_string(str2,1);
2666 int uLevel;
2667 struct pack_desc desc;
2668 char* name;
2670 uLevel = SVAL(p,0);
2671 name = p + 2;
2673 memset((char *)&desc,'\0',sizeof(desc));
2675 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
2677 /* check it's a supported varient */
2678 if (strcmp(str1,"OOWb54WrLh") != 0) return False;
2679 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) return False;
2680 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2681 desc.base = *rdata;
2682 desc.buflen = mdrcnt;
2683 desc.subformat = NULL;
2684 desc.format = str2;
2686 if (init_package(&desc,1,0))
2688 PACKI(&desc,"W",0); /* code */
2689 PACKS(&desc,"B21",name); /* eff. name */
2690 PACKS(&desc,"B",""); /* pad */
2691 PACKI(&desc,"W",
2692 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2693 PACKI(&desc,"D",0); /* auth flags XXX */
2694 PACKI(&desc,"W",0); /* num logons */
2695 PACKI(&desc,"W",0); /* bad pw count */
2696 PACKI(&desc,"D",0); /* last logon */
2697 PACKI(&desc,"D",-1); /* last logoff */
2698 PACKI(&desc,"D",-1); /* logoff time */
2699 PACKI(&desc,"D",-1); /* kickoff time */
2700 PACKI(&desc,"D",0); /* password age */
2701 PACKI(&desc,"D",0); /* password can change */
2702 PACKI(&desc,"D",-1); /* password must change */
2704 fstring mypath;
2705 fstrcpy(mypath,"\\\\");
2706 fstrcat(mypath,local_machine);
2707 strupper(mypath);
2708 PACKS(&desc,"z",mypath); /* computer */
2710 PACKS(&desc,"z",global_myworkgroup);/* domain */
2712 /* JHT - By calling lp_logon_script() and standard_sub() we have */
2713 /* made sure all macros are fully substituted and available */
2715 pstring logon_script;
2716 pstrcpy(logon_script,lp_logon_script());
2717 standard_sub_conn( conn, logon_script,sizeof(logon_script) );
2718 PACKS(&desc,"z", logon_script); /* script path */
2720 /* End of JHT mods */
2722 PACKI(&desc,"D",0x00000000); /* reserved */
2725 *rdata_len = desc.usedlen;
2726 *rparam_len = 6;
2727 *rparam = REALLOC(*rparam,*rparam_len);
2728 SSVALS(*rparam,0,desc.errcode);
2729 SSVAL(*rparam,2,0);
2730 SSVAL(*rparam,4,desc.neededlen);
2732 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
2733 return(True);
2737 /****************************************************************************
2738 api_WAccessGetUserPerms
2739 ****************************************************************************/
2740 static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid, char *param,char *data,
2741 int mdrcnt,int mprcnt,
2742 char **rdata,char **rparam,
2743 int *rdata_len,int *rparam_len)
2745 char *str1 = param+2;
2746 char *str2 = skip_string(str1,1);
2747 char *user = skip_string(str2,1);
2748 char *resource = skip_string(user,1);
2750 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
2752 /* check it's a supported varient */
2753 if (strcmp(str1,"zzh") != 0) return False;
2754 if (strcmp(str2,"") != 0) return False;
2756 *rparam_len = 6;
2757 *rparam = REALLOC(*rparam,*rparam_len);
2758 SSVALS(*rparam,0,0); /* errorcode */
2759 SSVAL(*rparam,2,0); /* converter word */
2760 SSVAL(*rparam,4,0x7f); /* permission flags */
2762 return(True);
2765 /****************************************************************************
2766 api_WPrintJobEnumerate
2767 ****************************************************************************/
2768 static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2769 int mdrcnt,int mprcnt,
2770 char **rdata,char **rparam,
2771 int *rdata_len,int *rparam_len)
2773 char *str1 = param+2;
2774 char *str2 = skip_string(str1,1);
2775 char *p = skip_string(str2,1);
2776 int uLevel;
2777 int count;
2778 int i;
2779 int snum;
2780 int job;
2781 struct pack_desc desc;
2782 print_queue_struct *queue=NULL;
2783 print_status_struct status;
2784 char *tmpdata=NULL;
2786 uLevel = SVAL(p,2);
2788 memset((char *)&desc,'\0',sizeof(desc));
2789 memset((char *)&status,'\0',sizeof(status));
2791 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
2793 /* check it's a supported varient */
2794 if (strcmp(str1,"WWrLh") != 0) return False;
2795 if (!check_printjob_info(&desc,uLevel,str2)) return False;
2797 job = SVAL(p,0);
2798 snum = print_job_snum(job);
2800 if (snum < 0 || !VALID_SNUM(snum)) return(False);
2802 count = print_queue_status(snum,&queue,&status);
2803 for (i = 0; i < count; i++) {
2804 if (queue[i].job == job) break;
2807 if (mdrcnt > 0) {
2808 *rdata = REALLOC(*rdata,mdrcnt);
2809 desc.base = *rdata;
2810 desc.buflen = mdrcnt;
2811 } else {
2813 * Don't return data but need to get correct length
2814 * init_package will return wrong size if buflen=0
2816 desc.buflen = getlen(desc.format);
2817 desc.base = tmpdata = (char *)malloc ( desc.buflen );
2820 if (init_package(&desc,1,0)) {
2821 if (i < count) {
2822 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2823 *rdata_len = desc.usedlen;
2825 else {
2826 desc.errcode = NERR_JobNotFound;
2827 *rdata_len = 0;
2831 *rparam_len = 6;
2832 *rparam = REALLOC(*rparam,*rparam_len);
2833 SSVALS(*rparam,0,desc.errcode);
2834 SSVAL(*rparam,2,0);
2835 SSVAL(*rparam,4,desc.neededlen);
2837 SAFE_FREE(queue);
2838 SAFE_FREE(tmpdata);
2840 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
2841 return(True);
2844 static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *param,char *data,
2845 int mdrcnt,int mprcnt,
2846 char **rdata,char **rparam,
2847 int *rdata_len,int *rparam_len)
2849 char *str1 = param+2;
2850 char *str2 = skip_string(str1,1);
2851 char *p = skip_string(str2,1);
2852 char* name = p;
2853 int uLevel;
2854 int count;
2855 int i, succnt=0;
2856 int snum;
2857 struct pack_desc desc;
2858 print_queue_struct *queue=NULL;
2859 print_status_struct status;
2861 memset((char *)&desc,'\0',sizeof(desc));
2862 memset((char *)&status,'\0',sizeof(status));
2864 p = skip_string(p,1);
2865 uLevel = SVAL(p,0);
2867 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
2869 /* check it's a supported varient */
2870 if (strcmp(str1,"zWrLeh") != 0) return False;
2871 if (uLevel > 2) return False; /* defined only for uLevel 0,1,2 */
2872 if (!check_printjob_info(&desc,uLevel,str2)) return False;
2874 snum = lp_servicenumber(name);
2875 if (snum < 0 && pcap_printername_ok(name,NULL)) {
2876 int pnum = lp_servicenumber(PRINTERS_NAME);
2877 if (pnum >= 0) {
2878 lp_add_printer(name,pnum);
2879 snum = lp_servicenumber(name);
2883 if (snum < 0 || !VALID_SNUM(snum)) return(False);
2885 count = print_queue_status(snum,&queue,&status);
2886 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2887 desc.base = *rdata;
2888 desc.buflen = mdrcnt;
2890 if (init_package(&desc,count,0)) {
2891 succnt = 0;
2892 for (i = 0; i < count; i++) {
2893 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2894 if (desc.errcode == NERR_Success) succnt = i+1;
2898 *rdata_len = desc.usedlen;
2900 *rparam_len = 8;
2901 *rparam = REALLOC(*rparam,*rparam_len);
2902 SSVALS(*rparam,0,desc.errcode);
2903 SSVAL(*rparam,2,0);
2904 SSVAL(*rparam,4,succnt);
2905 SSVAL(*rparam,6,count);
2907 SAFE_FREE(queue);
2909 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
2910 return(True);
2913 static int check_printdest_info(struct pack_desc* desc,
2914 int uLevel, char* id)
2916 desc->subformat = NULL;
2917 switch( uLevel ) {
2918 case 0: desc->format = "B9"; break;
2919 case 1: desc->format = "B9B21WWzW"; break;
2920 case 2: desc->format = "z"; break;
2921 case 3: desc->format = "zzzWWzzzWW"; break;
2922 default: return False;
2924 if (strcmp(desc->format,id) != 0) return False;
2925 return True;
2928 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
2929 struct pack_desc* desc)
2931 char buf[100];
2932 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
2933 buf[sizeof(buf)-1] = 0;
2934 strupper(buf);
2935 if (uLevel <= 1) {
2936 PACKS(desc,"B9",buf); /* szName */
2937 if (uLevel == 1) {
2938 PACKS(desc,"B21",""); /* szUserName */
2939 PACKI(desc,"W",0); /* uJobId */
2940 PACKI(desc,"W",0); /* fsStatus */
2941 PACKS(desc,"z",""); /* pszStatus */
2942 PACKI(desc,"W",0); /* time */
2945 if (uLevel == 2 || uLevel == 3) {
2946 PACKS(desc,"z",buf); /* pszPrinterName */
2947 if (uLevel == 3) {
2948 PACKS(desc,"z",""); /* pszUserName */
2949 PACKS(desc,"z",""); /* pszLogAddr */
2950 PACKI(desc,"W",0); /* uJobId */
2951 PACKI(desc,"W",0); /* fsStatus */
2952 PACKS(desc,"z",""); /* pszStatus */
2953 PACKS(desc,"z",""); /* pszComment */
2954 PACKS(desc,"z","NULL"); /* pszDrivers */
2955 PACKI(desc,"W",0); /* time */
2956 PACKI(desc,"W",0); /* pad1 */
2961 static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2962 int mdrcnt,int mprcnt,
2963 char **rdata,char **rparam,
2964 int *rdata_len,int *rparam_len)
2966 char *str1 = param+2;
2967 char *str2 = skip_string(str1,1);
2968 char *p = skip_string(str2,1);
2969 char* PrinterName = p;
2970 int uLevel;
2971 struct pack_desc desc;
2972 int snum;
2973 char *tmpdata=NULL;
2975 memset((char *)&desc,'\0',sizeof(desc));
2977 p = skip_string(p,1);
2978 uLevel = SVAL(p,0);
2980 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
2982 /* check it's a supported varient */
2983 if (strcmp(str1,"zWrLh") != 0) return False;
2984 if (!check_printdest_info(&desc,uLevel,str2)) return False;
2986 snum = lp_servicenumber(PrinterName);
2987 if (snum < 0 && pcap_printername_ok(PrinterName,NULL)) {
2988 int pnum = lp_servicenumber(PRINTERS_NAME);
2989 if (pnum >= 0) {
2990 lp_add_printer(PrinterName,pnum);
2991 snum = lp_servicenumber(PrinterName);
2995 if (snum < 0) {
2996 *rdata_len = 0;
2997 desc.errcode = NERR_DestNotFound;
2998 desc.neededlen = 0;
3000 else {
3001 if (mdrcnt > 0) {
3002 *rdata = REALLOC(*rdata,mdrcnt);
3003 desc.base = *rdata;
3004 desc.buflen = mdrcnt;
3005 } else {
3007 * Don't return data but need to get correct length
3008 * init_package will return wrong size if buflen=0
3010 desc.buflen = getlen(desc.format);
3011 desc.base = tmpdata = (char *)malloc ( desc.buflen );
3013 if (init_package(&desc,1,0)) {
3014 fill_printdest_info(conn,snum,uLevel,&desc);
3016 *rdata_len = desc.usedlen;
3019 *rparam_len = 6;
3020 *rparam = REALLOC(*rparam,*rparam_len);
3021 SSVALS(*rparam,0,desc.errcode);
3022 SSVAL(*rparam,2,0);
3023 SSVAL(*rparam,4,desc.neededlen);
3025 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
3026 SAFE_FREE(tmpdata);
3027 return(True);
3030 static BOOL api_WPrintDestEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3031 int mdrcnt,int mprcnt,
3032 char **rdata,char **rparam,
3033 int *rdata_len,int *rparam_len)
3035 char *str1 = param+2;
3036 char *str2 = skip_string(str1,1);
3037 char *p = skip_string(str2,1);
3038 int uLevel;
3039 int queuecnt;
3040 int i, n, succnt=0;
3041 struct pack_desc desc;
3042 int services = lp_numservices();
3044 memset((char *)&desc,'\0',sizeof(desc));
3046 uLevel = SVAL(p,0);
3048 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
3050 /* check it's a supported varient */
3051 if (strcmp(str1,"WrLeh") != 0) return False;
3052 if (!check_printdest_info(&desc,uLevel,str2)) return False;
3054 queuecnt = 0;
3055 for (i = 0; i < services; i++)
3056 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
3057 queuecnt++;
3059 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3060 desc.base = *rdata;
3061 desc.buflen = mdrcnt;
3062 if (init_package(&desc,queuecnt,0)) {
3063 succnt = 0;
3064 n = 0;
3065 for (i = 0; i < services; i++) {
3066 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3067 fill_printdest_info(conn,i,uLevel,&desc);
3068 n++;
3069 if (desc.errcode == NERR_Success) succnt = n;
3074 *rdata_len = desc.usedlen;
3076 *rparam_len = 8;
3077 *rparam = REALLOC(*rparam,*rparam_len);
3078 SSVALS(*rparam,0,desc.errcode);
3079 SSVAL(*rparam,2,0);
3080 SSVAL(*rparam,4,succnt);
3081 SSVAL(*rparam,6,queuecnt);
3083 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
3084 return(True);
3087 static BOOL api_WPrintDriverEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3088 int mdrcnt,int mprcnt,
3089 char **rdata,char **rparam,
3090 int *rdata_len,int *rparam_len)
3092 char *str1 = param+2;
3093 char *str2 = skip_string(str1,1);
3094 char *p = skip_string(str2,1);
3095 int uLevel;
3096 int succnt;
3097 struct pack_desc desc;
3099 memset((char *)&desc,'\0',sizeof(desc));
3101 uLevel = SVAL(p,0);
3103 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
3105 /* check it's a supported varient */
3106 if (strcmp(str1,"WrLeh") != 0) return False;
3107 if (uLevel != 0 || strcmp(str2,"B41") != 0) return False;
3109 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3110 desc.base = *rdata;
3111 desc.buflen = mdrcnt;
3112 if (init_package(&desc,1,0)) {
3113 PACKS(&desc,"B41","NULL");
3116 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3118 *rdata_len = desc.usedlen;
3120 *rparam_len = 8;
3121 *rparam = REALLOC(*rparam,*rparam_len);
3122 SSVALS(*rparam,0,desc.errcode);
3123 SSVAL(*rparam,2,0);
3124 SSVAL(*rparam,4,succnt);
3125 SSVAL(*rparam,6,1);
3127 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
3128 return(True);
3131 static BOOL api_WPrintQProcEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3132 int mdrcnt,int mprcnt,
3133 char **rdata,char **rparam,
3134 int *rdata_len,int *rparam_len)
3136 char *str1 = param+2;
3137 char *str2 = skip_string(str1,1);
3138 char *p = skip_string(str2,1);
3139 int uLevel;
3140 int succnt;
3141 struct pack_desc desc;
3143 memset((char *)&desc,'\0',sizeof(desc));
3145 uLevel = SVAL(p,0);
3147 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
3149 /* check it's a supported varient */
3150 if (strcmp(str1,"WrLeh") != 0) return False;
3151 if (uLevel != 0 || strcmp(str2,"B13") != 0) return False;
3153 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3154 desc.base = *rdata;
3155 desc.buflen = mdrcnt;
3156 desc.format = str2;
3157 if (init_package(&desc,1,0)) {
3158 PACKS(&desc,"B13","lpd");
3161 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3163 *rdata_len = desc.usedlen;
3165 *rparam_len = 8;
3166 *rparam = REALLOC(*rparam,*rparam_len);
3167 SSVALS(*rparam,0,desc.errcode);
3168 SSVAL(*rparam,2,0);
3169 SSVAL(*rparam,4,succnt);
3170 SSVAL(*rparam,6,1);
3172 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
3173 return(True);
3176 static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3177 int mdrcnt,int mprcnt,
3178 char **rdata,char **rparam,
3179 int *rdata_len,int *rparam_len)
3181 char *str1 = param+2;
3182 char *str2 = skip_string(str1,1);
3183 char *p = skip_string(str2,1);
3184 int uLevel;
3185 int succnt;
3186 struct pack_desc desc;
3188 memset((char *)&desc,'\0',sizeof(desc));
3190 uLevel = SVAL(p,0);
3192 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
3194 /* check it's a supported varient */
3195 if (strcmp(str1,"WrLeh") != 0) return False;
3196 if (uLevel != 0 || strcmp(str2,"B9") != 0) return False;
3198 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3199 memset((char *)&desc,'\0',sizeof(desc));
3200 desc.base = *rdata;
3201 desc.buflen = mdrcnt;
3202 desc.format = str2;
3203 if (init_package(&desc,1,0)) {
3204 PACKS(&desc,"B13","lp0");
3207 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3209 *rdata_len = desc.usedlen;
3211 *rparam_len = 8;
3212 *rparam = REALLOC(*rparam,*rparam_len);
3213 SSVALS(*rparam,0,desc.errcode);
3214 SSVAL(*rparam,2,0);
3215 SSVAL(*rparam,4,succnt);
3216 SSVAL(*rparam,6,1);
3218 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
3219 return(True);
3222 /****************************************************************************
3223 The buffer was too small
3224 ****************************************************************************/
3226 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
3227 int mdrcnt,int mprcnt,
3228 char **rdata,char **rparam,
3229 int *rdata_len,int *rparam_len)
3231 *rparam_len = MIN(*rparam_len,mprcnt);
3232 *rparam = REALLOC(*rparam,*rparam_len);
3234 *rdata_len = 0;
3236 SSVAL(*rparam,0,NERR_BufTooSmall);
3238 DEBUG(3,("Supplied buffer too small in API command\n"));
3240 return(True);
3244 /****************************************************************************
3245 The request is not supported
3246 ****************************************************************************/
3248 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
3249 int mdrcnt,int mprcnt,
3250 char **rdata,char **rparam,
3251 int *rdata_len,int *rparam_len)
3253 *rparam_len = 4;
3254 *rparam = REALLOC(*rparam,*rparam_len);
3256 *rdata_len = 0;
3258 SSVAL(*rparam,0,NERR_notsupported);
3259 SSVAL(*rparam,2,0); /* converter word */
3261 DEBUG(3,("Unsupported API command\n"));
3263 return(True);
3269 struct
3271 char *name;
3272 int id;
3273 BOOL (*fn)(connection_struct *,uint16,char *,char *,
3274 int,int,char **,char **,int *,int *);
3275 int flags;
3276 } api_commands[] = {
3277 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum,0},
3278 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo,0},
3279 #if 0 /* Not yet implemented. */
3280 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd,0},
3281 #endif
3282 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo,0},
3283 #if 0 /* Not yet implemented. */
3284 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum,0},
3285 #endif
3286 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers,0},
3287 #if 0 /* Not yet implemented. */
3288 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum,0},
3289 #endif
3290 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo,0},
3291 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups,0},
3292 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo,0},
3293 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum,0},
3294 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo,0},
3295 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl,0},
3296 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl,0},
3297 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate,0},
3298 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo,0},
3299 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel,0},
3300 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel,0},
3301 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel,0},
3302 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum,0},
3303 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo,0},
3304 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD,0},
3305 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl,0},
3306 {"NetServerEnum", RAP_NetServerEnum2, api_RNetServerEnum,0},
3307 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms,0},
3308 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword,0},
3309 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon,0},
3310 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo,0},
3311 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum,0},
3312 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum,0},
3313 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum,0},
3314 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword,0},
3315 {NULL, -1, api_Unsupported,0}};
3318 /****************************************************************************
3319 Handle remote api calls
3320 ****************************************************************************/
3322 int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *params,
3323 int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
3325 int api_command;
3326 char *rdata = NULL;
3327 char *rparam = NULL;
3328 int rdata_len = 0;
3329 int rparam_len = 0;
3330 BOOL reply=False;
3331 int i;
3333 if (!params) {
3334 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
3335 return 0;
3338 api_command = SVAL(params,0);
3340 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
3341 api_command,
3342 params+2,
3343 skip_string(params+2,1),
3344 tdscnt,tpscnt,mdrcnt,mprcnt));
3346 for (i=0;api_commands[i].name;i++) {
3347 if (api_commands[i].id == api_command && api_commands[i].fn) {
3348 DEBUG(3,("Doing %s\n",api_commands[i].name));
3349 break;
3353 rdata = (char *)malloc(1024);
3354 if (rdata)
3355 memset(rdata,'\0',1024);
3357 rparam = (char *)malloc(1024);
3358 if (rparam)
3359 memset(rparam,'\0',1024);
3361 if(!rdata || !rparam) {
3362 DEBUG(0,("api_reply: malloc fail !\n"));
3363 return -1;
3366 reply = api_commands[i].fn(conn,vuid,params,data,mdrcnt,mprcnt,
3367 &rdata,&rparam,&rdata_len,&rparam_len);
3370 if (rdata_len > mdrcnt ||
3371 rparam_len > mprcnt) {
3372 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
3373 &rdata,&rparam,&rdata_len,&rparam_len);
3376 /* if we get False back then it's actually unsupported */
3377 if (!reply)
3378 api_Unsupported(conn,vuid,params,data,mdrcnt,mprcnt,
3379 &rdata,&rparam,&rdata_len,&rparam_len);
3381 send_trans_reply(outbuf, rparam, rparam_len, rdata, rdata_len, False);
3383 SAFE_FREE(rdata);
3384 SAFE_FREE(rparam);
3386 return -1;