include/rpc_spoolss.h: Added JOB_STATUS_XXX defines.
[Samba.git] / source / smbd / lanman.c
blobc29f0df4341b8948d0c1f69936d52c11895e6e44
1 #define OLD_NTDOMAIN 1
2 /*
3 Unix SMB/Netbios implementation.
4 Version 1.9.
5 Inter-process communication and named pipe handling
6 Copyright (C) Andrew Tridgell 1992-1998
8 SMB Version handling
9 Copyright (C) John H Terpstra 1995-1998
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 This file handles the named pipe and mailslot calls
27 in the SMBtrans protocol
30 #include "includes.h"
32 #ifdef CHECK_TYPES
33 #undef CHECK_TYPES
34 #endif
35 #define CHECK_TYPES 0
37 extern int DEBUGLEVEL;
39 extern fstring local_machine;
40 extern pstring global_myname;
41 extern fstring global_myworkgroup;
43 #define NERR_Success 0
44 #define NERR_badpass 86
45 #define NERR_notsupported 50
47 #define NERR_BASE (2100)
48 #define NERR_BufTooSmall (NERR_BASE+23)
49 #define NERR_JobNotFound (NERR_BASE+51)
50 #define NERR_DestNotFound (NERR_BASE+52)
52 #define ACCESS_READ 0x01
53 #define ACCESS_WRITE 0x02
54 #define ACCESS_CREATE 0x04
56 #define SHPWLEN 8 /* share password length */
58 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
59 int mdrcnt,int mprcnt,
60 char **rdata,char **rparam,
61 int *rdata_len,int *rparam_len);
62 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
63 int mdrcnt,int mprcnt,
64 char **rdata,char **rparam,
65 int *rdata_len,int *rparam_len);
68 static int CopyExpanded(connection_struct *conn,
69 int snum, char** dst, char* src, int* n)
71 pstring buf;
72 int l;
74 if (!src || !dst || !n || !(*dst)) return(0);
76 StrnCpy(buf,src,sizeof(buf)/2);
77 pstring_sub(buf,"%S",lp_servicename(snum));
78 standard_sub_conn(conn,buf);
79 StrnCpy(*dst,buf,*n-1);
80 l = strlen(*dst) + 1;
81 (*dst) += l;
82 (*n) -= l;
83 return l;
86 static int CopyAndAdvance(char** dst, char* src, int* n)
88 int l;
89 if (!src || !dst || !n || !(*dst)) return(0);
90 StrnCpy(*dst,src,*n-1);
91 l = strlen(*dst) + 1;
92 (*dst) += l;
93 (*n) -= l;
94 return l;
97 static int StrlenExpanded(connection_struct *conn, int snum, char* s)
99 pstring buf;
100 if (!s) return(0);
101 StrnCpy(buf,s,sizeof(buf)/2);
102 pstring_sub(buf,"%S",lp_servicename(snum));
103 standard_sub_conn(conn,buf);
104 return strlen(buf) + 1;
107 static char* Expand(connection_struct *conn, int snum, char* s)
109 static pstring buf;
110 if (!s) return(NULL);
111 StrnCpy(buf,s,sizeof(buf)/2);
112 pstring_sub(buf,"%S",lp_servicename(snum));
113 standard_sub_conn(conn,buf);
114 return &buf[0];
117 /*******************************************************************
118 check a API string for validity when we only need to check the prefix
119 ******************************************************************/
120 static BOOL prefix_ok(char *str,char *prefix)
122 return(strncmp(str,prefix,strlen(prefix)) == 0);
125 struct pack_desc {
126 char* format; /* formatstring for structure */
127 char* subformat; /* subformat for structure */
128 char* base; /* baseaddress of buffer */
129 int buflen; /* remaining size for fixed part; on init: length of base */
130 int subcount; /* count of substructures */
131 char* structbuf; /* pointer into buffer for remaining fixed part */
132 int stringlen; /* remaining size for variable part */
133 char* stringbuf; /* pointer into buffer for remaining variable part */
134 int neededlen; /* total needed size */
135 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
136 char* curpos; /* current position; pointer into format or subformat */
137 int errcode;
140 static int get_counter(char** p)
142 int i, n;
143 if (!p || !(*p)) return(1);
144 if (!isdigit((int)**p)) return 1;
145 for (n = 0;;) {
146 i = **p;
147 if (isdigit(i))
148 n = 10 * n + (i - '0');
149 else
150 return n;
151 (*p)++;
155 static int getlen(char* p)
157 int n = 0;
158 if (!p) return(0);
159 while (*p) {
160 switch( *p++ ) {
161 case 'W': /* word (2 byte) */
162 n += 2;
163 break;
164 case 'K': /* status word? (2 byte) */
165 n += 2;
166 break;
167 case 'N': /* count of substructures (word) at end */
168 n += 2;
169 break;
170 case 'D': /* double word (4 byte) */
171 case 'z': /* offset to zero terminated string (4 byte) */
172 case 'l': /* offset to user data (4 byte) */
173 n += 4;
174 break;
175 case 'b': /* offset to data (with counter) (4 byte) */
176 n += 4;
177 get_counter(&p);
178 break;
179 case 'B': /* byte (with optional counter) */
180 n += get_counter(&p);
181 break;
184 return n;
187 static BOOL init_package(struct pack_desc* p, int count, int subcount)
189 int n = p->buflen;
190 int i;
192 if (!p->format || !p->base) return(False);
194 i = count * getlen(p->format);
195 if (p->subformat) i += subcount * getlen(p->subformat);
196 p->structbuf = p->base;
197 p->neededlen = 0;
198 p->usedlen = 0;
199 p->subcount = 0;
200 p->curpos = p->format;
201 if (i > n) {
202 p->neededlen = i;
203 i = n = 0;
204 #if 0
206 * This is the old error code we used. Aparently
207 * WinNT/2k systems return ERRbuftoosmall (2123) and
208 * OS/2 needs this. I'm leaving this here so we can revert
209 * if needed. JRA.
211 p->errcode = ERRmoredata;
212 #else
213 p->errcode = ERRbuftoosmall;
214 #endif
216 else
217 p->errcode = NERR_Success;
218 p->buflen = i;
219 n -= i;
220 p->stringbuf = p->base + i;
221 p->stringlen = n;
222 return(p->errcode == NERR_Success);
225 #ifdef HAVE_STDARG_H
226 static int package(struct pack_desc* p, ...)
228 #else
229 static int package(va_alist)
230 va_dcl
232 struct pack_desc* p;
233 #endif
234 va_list args;
235 int needed=0, stringneeded;
236 char* str=NULL;
237 int is_string=0, stringused;
238 int32 temp;
240 #ifdef HAVE_STDARG_H
241 va_start(args,p);
242 #else
243 va_start(args);
244 p = va_arg(args,struct pack_desc *);
245 #endif
247 if (!*p->curpos) {
248 if (!p->subcount)
249 p->curpos = p->format;
250 else {
251 p->curpos = p->subformat;
252 p->subcount--;
255 #if CHECK_TYPES
256 str = va_arg(args,char*);
257 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
258 #endif
259 stringneeded = -1;
261 if (!p->curpos) {
262 va_end(args);
263 return(0);
266 switch( *p->curpos++ ) {
267 case 'W': /* word (2 byte) */
268 needed = 2;
269 temp = va_arg(args,int);
270 if (p->buflen >= needed) SSVAL(p->structbuf,0,temp);
271 break;
272 case 'K': /* status word? (2 byte) */
273 needed = 2;
274 temp = va_arg(args,int);
275 if (p->buflen >= needed) SSVAL(p->structbuf,0,temp);
276 break;
277 case 'N': /* count of substructures (word) at end */
278 needed = 2;
279 p->subcount = va_arg(args,int);
280 if (p->buflen >= needed) SSVAL(p->structbuf,0,p->subcount);
281 break;
282 case 'D': /* double word (4 byte) */
283 needed = 4;
284 temp = va_arg(args,int);
285 if (p->buflen >= needed) SIVAL(p->structbuf,0,temp);
286 break;
287 case 'B': /* byte (with optional counter) */
288 needed = get_counter(&p->curpos);
290 char *s = va_arg(args,char*);
291 if (p->buflen >= needed) StrnCpy(p->structbuf,s?s:"",needed-1);
293 break;
294 case 'z': /* offset to zero terminated string (4 byte) */
295 str = va_arg(args,char*);
296 stringneeded = (str ? strlen(str)+1 : 0);
297 is_string = 1;
298 break;
299 case 'l': /* offset to user data (4 byte) */
300 str = va_arg(args,char*);
301 stringneeded = va_arg(args,int);
302 is_string = 0;
303 break;
304 case 'b': /* offset to data (with counter) (4 byte) */
305 str = va_arg(args,char*);
306 stringneeded = get_counter(&p->curpos);
307 is_string = 0;
308 break;
310 va_end(args);
311 if (stringneeded >= 0) {
312 needed = 4;
313 if (p->buflen >= needed) {
314 stringused = stringneeded;
315 if (stringused > p->stringlen) {
316 stringused = (is_string ? p->stringlen : 0);
317 if (p->errcode == NERR_Success) p->errcode = ERRmoredata;
319 if (!stringused)
320 SIVAL(p->structbuf,0,0);
321 else {
322 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
323 memcpy(p->stringbuf,str?str:"",stringused);
324 if (is_string) p->stringbuf[stringused-1] = '\0';
325 p->stringbuf += stringused;
326 p->stringlen -= stringused;
327 p->usedlen += stringused;
330 p->neededlen += stringneeded;
332 p->neededlen += needed;
333 if (p->buflen >= needed) {
334 p->structbuf += needed;
335 p->buflen -= needed;
336 p->usedlen += needed;
338 else {
339 if (p->errcode == NERR_Success) p->errcode = ERRmoredata;
341 return 1;
344 #if CHECK_TYPES
345 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
346 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
347 #else
348 #define PACK(desc,t,v) package(desc,v)
349 #define PACKl(desc,t,v,l) package(desc,v,l)
350 #endif
352 static void PACKI(struct pack_desc* desc,char *t,int v)
354 PACK(desc,t,v);
357 static void PACKS(struct pack_desc* desc,char *t,char *v)
359 PACK(desc,t,v);
363 /****************************************************************************
364 get a print queue
365 ****************************************************************************/
366 static void PackDriverData(struct pack_desc* desc)
368 char drivdata[4+4+32];
369 SIVAL(drivdata,0,sizeof drivdata); /* cb */
370 SIVAL(drivdata,4,1000); /* lVersion */
371 memset(drivdata+8,0,32); /* szDeviceName */
372 pstrcpy(drivdata+8,"NULL");
373 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
376 static int check_printq_info(struct pack_desc* desc,
377 int uLevel, char *id1, char *id2)
379 desc->subformat = NULL;
380 switch( uLevel ) {
381 case 0:
382 desc->format = "B13";
383 break;
384 case 1:
385 desc->format = "B13BWWWzzzzzWW";
386 break;
387 case 2:
388 desc->format = "B13BWWWzzzzzWN";
389 desc->subformat = "WB21BB16B10zWWzDDz";
390 break;
391 case 3:
392 desc->format = "zWWWWzzzzWWzzl";
393 break;
394 case 4:
395 desc->format = "zWWWWzzzzWNzzl";
396 desc->subformat = "WWzWWDDzz";
397 break;
398 case 5:
399 desc->format = "z";
400 break;
401 case 51:
402 desc->format = "K";
403 break;
404 case 52:
405 desc->format = "WzzzzzzzzN";
406 desc->subformat = "z";
407 break;
408 default: return False;
410 if (strcmp(desc->format,id1) != 0) return False;
411 if (desc->subformat && strcmp(desc->subformat,id2) != 0) return False;
412 return True;
416 #define RAP_JOB_STATUS_QUEUED 0
417 #define RAP_JOB_STATUS_PAUSED 1
418 #define RAP_JOB_STATUS_SPOOLING 2
419 #define RAP_JOB_STATUS_PRINTING 3
420 #define RAP_JOB_STATUS_PRINTED 4
422 #define RAP_QUEUE_STATUS_PAUSED 1
423 #define RAP_QUEUE_STATUS_ERROR 2
425 /* turn a print job status into a on the wire status
427 static int printj_status(int v)
429 switch (v) {
430 case LPQ_QUEUED:
431 return RAP_JOB_STATUS_QUEUED;
432 case LPQ_PAUSED:
433 return RAP_JOB_STATUS_PAUSED;
434 case LPQ_SPOOLING:
435 return RAP_JOB_STATUS_SPOOLING;
436 case LPQ_PRINTING:
437 return RAP_JOB_STATUS_PRINTING;
439 return 0;
442 /* turn a print queue status into a on the wire status
444 static int printq_status(int v)
446 switch (v) {
447 case LPQ_QUEUED:
448 return 0;
449 case LPQ_PAUSED:
450 return RAP_QUEUE_STATUS_PAUSED;
452 return RAP_QUEUE_STATUS_ERROR;
455 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
456 struct pack_desc* desc,
457 print_queue_struct* queue, int n)
459 time_t t = queue->time;
461 /* the client expects localtime */
462 t -= TimeDiff(t);
464 PACKI(desc,"W",queue->job); /* uJobId */
465 if (uLevel == 1) {
466 PACKS(desc,"B21",queue->user); /* szUserName */
467 PACKS(desc,"B",""); /* pad */
468 PACKS(desc,"B16",""); /* szNotifyName */
469 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
470 PACKS(desc,"z",""); /* pszParms */
471 PACKI(desc,"W",n+1); /* uPosition */
472 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
473 PACKS(desc,"z",""); /* pszStatus */
474 PACKI(desc,"D",t); /* ulSubmitted */
475 PACKI(desc,"D",queue->size); /* ulSize */
476 PACKS(desc,"z",queue->file); /* pszComment */
478 if (uLevel == 2 || uLevel == 3) {
479 PACKI(desc,"W",queue->priority); /* uPriority */
480 PACKS(desc,"z",queue->user); /* pszUserName */
481 PACKI(desc,"W",n+1); /* uPosition */
482 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
483 PACKI(desc,"D",t); /* ulSubmitted */
484 PACKI(desc,"D",queue->size); /* ulSize */
485 PACKS(desc,"z","Samba"); /* pszComment */
486 PACKS(desc,"z",queue->file); /* pszDocument */
487 if (uLevel == 3) {
488 PACKS(desc,"z",""); /* pszNotifyName */
489 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
490 PACKS(desc,"z",""); /* pszParms */
491 PACKS(desc,"z",""); /* pszStatus */
492 PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
493 PACKS(desc,"z","lpd"); /* pszQProcName */
494 PACKS(desc,"z",""); /* pszQProcParms */
495 PACKS(desc,"z","NULL"); /* pszDriverName */
496 PackDriverData(desc); /* pDriverData */
497 PACKS(desc,"z",""); /* pszPrinterName */
502 /********************************************************************
503 Return a driver name given an snum.
504 Looks in a tdb first. Returns True if from tdb, False otherwise.
505 ********************************************************************/
507 static BOOL get_driver_name(int snum, pstring drivername)
509 NT_PRINTER_INFO_LEVEL *info = NULL;
510 BOOL in_tdb = False;
512 get_a_printer (&info, 2, lp_servicename(snum));
513 if (info != NULL) {
514 pstrcpy( drivername, info->info_2->drivername);
515 in_tdb = True;
516 free_a_printer(&info, 2);
517 } else {
518 pstrcpy( drivername, lp_printerdriver(snum));
521 return in_tdb;
524 /********************************************************************
525 Respond to the DosPrintQInfo command with a level of 52
526 This is used to get printer driver information for Win9x clients
527 ********************************************************************/
528 static void fill_printq_info_52(connection_struct *conn, int snum, int uLevel,
529 struct pack_desc* desc,
530 int count, print_queue_struct* queue,
531 print_status_struct* status)
533 int i;
534 BOOL ok = False;
535 pstring tok,driver,datafile,langmon,helpfile,datatype;
536 char *p;
537 char **lines = NULL;
538 pstring gen_line;
539 BOOL in_tdb = False;
540 fstring location;
541 pstring drivername;
544 * Check in the tdb *first* before checking the legacy
545 * files. This allows an NT upload to take precedence over
546 * the existing fileset. JRA.
548 * we need to lookup the driver name prior to making the call
549 * to get_a_printer_driver_9x_compatible() and not rely on the
550 * 'print driver' parameter --jerry
554 if ((get_driver_name(snum,drivername)) &&
555 ((ok = get_a_printer_driver_9x_compatible(gen_line, drivername)) == True))
557 in_tdb = True;
558 p = gen_line;
559 DEBUG(10,("9x compatable driver line for [%s]: [%s]\n", drivername, gen_line));
561 else
563 /* didn't find driver in tdb */
565 DEBUG(10,("snum: %d\nprinterdriver: [%s]\nlp_driverfile: [%s]\n",
566 snum, drivername, lp_driverfile(snum)));
568 lines = file_lines_load(lp_driverfile(snum),NULL, False);
569 if (!lines)
571 DEBUG(3,("Can't open %s - %s\n", lp_driverfile(snum),
572 strerror(errno)));
573 desc->errcode=NERR_notsupported;
574 goto done;
577 /* lookup the long printer driver name in the file description */
578 for (i=0;lines[i] && !ok;i++)
580 p = lines[i];
581 if (next_token(&p,tok,":",sizeof(tok)) &&
582 (strlen(drivername) == strlen(tok)) &&
583 (!strncmp(tok,drivername,strlen(drivername))))
585 ok = True;
590 if (ok)
592 /* driver file name */
593 if (!next_token(&p,driver,":",sizeof(driver)))
594 goto err;
596 /* data file name */
597 if (!next_token(&p,datafile,":",sizeof(datafile)))
598 goto err;
601 * for the next tokens - which may be empty - I have
602 * to check for empty tokens first because the
603 * next_token function will skip all empty token
604 * fields */
606 /* help file */
607 if (*p == ':')
609 *helpfile = '\0';
610 p++;
612 else if (!next_token(&p,helpfile,":",sizeof(helpfile)))
613 goto err;
615 /* language monitor */
616 if (*p == ':')
618 *langmon = '\0';
619 p++;
621 else if (!next_token(&p,langmon,":",sizeof(langmon)))
622 goto err;
624 /* default data type */
625 if (!next_token(&p,datatype,":",sizeof(datatype)))
626 goto err;
628 PACKI(desc,"W",0x0400); /* don't know */
629 PACKS(desc,"z",drivername); /* long printer name */
630 PACKS(desc,"z",driver); /* Driverfile Name */
631 PACKS(desc,"z",datafile); /* Datafile name */
632 PACKS(desc,"z",langmon); /* language monitor */
633 if (in_tdb)
635 fstrcpy(location, "\\\\");
636 fstrcat(location, global_myname);
637 fstrcat(location, "\\print$\\WIN40\\0");
638 PACKS(desc,"z",location); /* share to retrieve files */
640 else
642 PACKS(desc,"z",lp_driverlocation(snum)); /* share to retrieve files */
644 PACKS(desc,"z",datatype); /* default data type */
645 PACKS(desc,"z",helpfile); /* helpfile name */
646 PACKS(desc,"z",driver); /* driver name */
648 DEBUG(3,("printerdriver:%s:\n",drivername));
649 DEBUG(3,("Driver:%s:\n",driver));
650 DEBUG(3,("Data File:%s:\n",datafile));
651 DEBUG(3,("Language Monitor:%s:\n",langmon));
652 if (in_tdb)
653 DEBUG(3,("lp_driverlocation:%s:\n",location));
654 else
655 DEBUG(3,("lp_driverlocation:%s:\n",lp_driverlocation(snum)));
656 DEBUG(3,("Data Type:%s:\n",datatype));
657 DEBUG(3,("Help File:%s:\n",helpfile));
658 PACKI(desc,"N",count); /* number of files to copy */
660 for (i=0;i<count;i++)
662 /* no need to check return value here
663 * - it was already tested in
664 * get_printerdrivernumber */
665 next_token(&p,tok,",",sizeof(tok));
666 PACKS(desc,"z",tok); /* driver files to copy */
667 DEBUG(3,("file:%s:\n",tok));
670 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n",
671 SERVICE(snum),count));
673 desc->errcode=NERR_Success;
674 goto done;
677 err:
679 DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
680 desc->errcode=NERR_notsupported;
682 done:
683 file_lines_free(lines);
687 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
688 struct pack_desc* desc,
689 int count, print_queue_struct* queue,
690 print_status_struct* status)
692 switch (uLevel) {
693 case 1:
694 case 2:
695 PACKS(desc,"B13",SERVICE(snum));
696 break;
697 case 3:
698 case 4:
699 case 5:
700 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
701 break;
702 case 51:
703 PACKI(desc,"K",printq_status(status->status));
704 break;
707 if (uLevel == 1 || uLevel == 2) {
708 PACKS(desc,"B",""); /* alignment */
709 PACKI(desc,"W",5); /* priority */
710 PACKI(desc,"W",0); /* start time */
711 PACKI(desc,"W",0); /* until time */
712 PACKS(desc,"z",""); /* pSepFile */
713 PACKS(desc,"z","lpd"); /* pPrProc */
714 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
715 PACKS(desc,"z",""); /* pParms */
716 if (snum < 0) {
717 PACKS(desc,"z","UNKNOWN PRINTER");
718 PACKI(desc,"W",LPSTAT_ERROR);
720 else if (!status || !status->message[0]) {
721 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
722 PACKI(desc,"W",LPSTAT_OK); /* status */
723 } else {
724 PACKS(desc,"z",status->message);
725 PACKI(desc,"W",printq_status(status->status)); /* status */
727 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
730 if (uLevel == 3 || uLevel == 4) {
731 pstring drivername;
733 PACKI(desc,"W",5); /* uPriority */
734 PACKI(desc,"W",0); /* uStarttime */
735 PACKI(desc,"W",0); /* uUntiltime */
736 PACKI(desc,"W",5); /* pad1 */
737 PACKS(desc,"z",""); /* pszSepFile */
738 PACKS(desc,"z","WinPrint"); /* pszPrProc */
739 PACKS(desc,"z",NULL); /* pszParms */
740 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
741 /* "don't ask" that it's done this way to fix corrupted
742 Win9X/ME printer comments. */
743 if (!status) {
744 PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
745 } else {
746 PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
748 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
749 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
750 get_driver_name(snum,drivername);
751 PACKS(desc,"z",drivername); /* pszDriverName */
752 PackDriverData(desc); /* pDriverData */
755 if (uLevel == 2 || uLevel == 4) {
756 int i;
757 for (i=0;i<count;i++)
758 fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
761 if (uLevel==52) {
762 fill_printq_info_52(conn, snum, uLevel, desc, count, queue, status);
766 /* This function returns the number of files for a given driver */
767 static int get_printerdrivernumber(int snum)
769 int i, result = 0;
770 BOOL ok = False;
771 pstring tok;
772 char *p;
773 char **lines = NULL;
774 pstring gen_line;
775 pstring drivername;
778 * Check in the tdb *first* before checking the legacy
779 * files. This allows an NT upload to take precedence over
780 * the existing fileset. JRA.
782 * we need to lookup the driver name prior to making the call
783 * to get_a_printer_driver_9x_compatible() and not rely on the
784 * 'print driver' parameter --jerry
787 if ((get_driver_name(snum,drivername)) &&
788 (ok = get_a_printer_driver_9x_compatible(gen_line, drivername) == True))
790 p = gen_line;
791 DEBUG(10,("9x compatable driver line for [%s]: [%s]\n", drivername, gen_line));
793 else
795 /* didn't find driver in tdb */
797 DEBUG(10,("snum: %d\nprinterdriver: [%s]\nlp_driverfile: [%s]\n",
798 snum, drivername, lp_driverfile(snum)));
800 lines = file_lines_load(lp_driverfile(snum), NULL, False);
801 if (!lines)
803 DEBUG(3,("Can't open %s - %s\n", lp_driverfile(snum),strerror(errno)));
804 goto done;
807 /* lookup the long printer driver name in the file description */
808 for (i=0;lines[i] && !ok;i++)
810 p = lines[i];
811 if (next_token(&p,tok,":",sizeof(tok)) &&
812 (strlen(drivername) == strlen(tok)) &&
813 (!strncmp(tok,drivername,strlen(drivername))))
815 ok = True;
820 if( ok )
822 /* skip 5 fields */
823 i = 5;
824 while (*p && i) {
825 if (*p++ == ':') i--;
827 if (!*p || i) {
828 DEBUG(3,("Can't determine number of printer driver files\n"));
829 goto done;
832 /* count the number of files */
833 while (next_token(&p,tok,",",sizeof(tok)))
834 i++;
836 result = i;
839 done:
841 file_lines_free(lines);
843 return result;
846 static BOOL api_DosPrintQGetInfo(connection_struct *conn,
847 uint16 vuid, char *param,char *data,
848 int mdrcnt,int mprcnt,
849 char **rdata,char **rparam,
850 int *rdata_len,int *rparam_len)
852 char *str1 = param+2;
853 char *str2 = skip_string(str1,1);
854 char *p = skip_string(str2,1);
855 char *QueueName = p;
856 int uLevel;
857 int count=0;
858 int snum;
859 char* str3;
860 struct pack_desc desc;
861 print_queue_struct *queue=NULL;
862 print_status_struct status;
864 memset((char *)&status,'\0',sizeof(status));
865 memset((char *)&desc,'\0',sizeof(desc));
867 p = skip_string(p,1);
868 uLevel = SVAL(p,0);
869 str3 = p + 4;
871 /* remove any trailing username */
872 if ((p = strchr(QueueName,'%'))) *p = 0;
874 DEBUG(3,("PrintQueue uLevel=%d name=%s\n",uLevel,QueueName));
876 /* check it's a supported varient */
877 if (!prefix_ok(str1,"zWrLh")) return False;
878 if (!check_printq_info(&desc,uLevel,str2,str3)) {
880 * Patch from Scott Moomaw <scott@bridgewater.edu>
881 * to return the 'invalid info level' error if an
882 * unknown level was requested.
884 *rdata_len = 0;
885 *rparam_len = 6;
886 *rparam = REALLOC(*rparam,*rparam_len);
887 SSVALS(*rparam,0,ERROR_INVALID_LEVEL);
888 SSVAL(*rparam,2,0);
889 SSVAL(*rparam,4,0);
890 return(True);
893 snum = lp_servicenumber(QueueName);
894 if (snum < 0 && pcap_printername_ok(QueueName,NULL)) {
895 int pnum = lp_servicenumber(PRINTERS_NAME);
896 if (pnum >= 0) {
897 lp_add_printer(QueueName,pnum);
898 snum = lp_servicenumber(QueueName);
902 if (snum < 0 || !VALID_SNUM(snum)) return(False);
904 if (uLevel==52) {
905 count = get_printerdrivernumber(snum);
906 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
907 } else {
908 count = print_queue_status(snum, &queue,&status);
911 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
912 desc.base = *rdata;
913 desc.buflen = mdrcnt;
914 if (init_package(&desc,1,count)) {
915 desc.subcount = count;
916 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
917 } else if(uLevel == 0) {
918 #if 0
920 * This is a *disgusting* hack.
921 * This is *so* bad that even I'm embarrassed (and I
922 * have no shame). Here's the deal :
923 * Until we get the correct SPOOLSS code into smbd
924 * then when we're running with NT SMB support then
925 * NT makes this call with a level of zero, and then
926 * immediately follows it with an open request to
927 * the \\SRVSVC pipe. If we allow that open to
928 * succeed then NT barfs when it cannot open the
929 * \\SPOOLSS pipe immediately after and continually
930 * whines saying "Printer name is invalid" forever
931 * after. If we cause *JUST THIS NEXT OPEN* of \\SRVSVC
932 * to fail, then NT downgrades to using the downlevel code
933 * and everything works as well as before. I hate
934 * myself for adding this code.... JRA.
937 fail_next_srvsvc_open();
938 #endif
941 *rdata_len = desc.usedlen;
943 *rparam_len = 6;
944 *rparam = REALLOC(*rparam,*rparam_len);
945 SSVALS(*rparam,0,desc.errcode);
946 SSVAL(*rparam,2,0);
947 SSVAL(*rparam,4,desc.neededlen);
949 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
951 if (queue) free(queue);
953 return(True);
956 /****************************************************************************
957 View list of all print jobs on all queues.
958 ****************************************************************************/
960 static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param, char* data,
961 int mdrcnt, int mprcnt,
962 char **rdata, char** rparam,
963 int *rdata_len, int *rparam_len)
965 char *param_format = param+2;
966 char *output_format1 = skip_string(param_format,1);
967 char *p = skip_string(output_format1,1);
968 int uLevel = SVAL(p,0);
969 char *output_format2 = p + 4;
970 int services = lp_numservices();
971 int i, n;
972 struct pack_desc desc;
973 print_queue_struct **queue = NULL;
974 print_status_struct *status = NULL;
975 int* subcntarr = NULL;
976 int queuecnt, subcnt=0, succnt=0;
978 memset((char *)&desc,'\0',sizeof(desc));
980 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
982 if (!prefix_ok(param_format,"WrLeh")) return False;
983 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
985 * Patch from Scott Moomaw <scott@bridgewater.edu>
986 * to return the 'invalid info level' error if an
987 * unknown level was requested.
989 *rdata_len = 0;
990 *rparam_len = 6;
991 *rparam = REALLOC(*rparam,*rparam_len);
992 SSVALS(*rparam,0,ERROR_INVALID_LEVEL);
993 SSVAL(*rparam,2,0);
994 SSVAL(*rparam,4,0);
995 return(True);
998 queuecnt = 0;
999 for (i = 0; i < services; i++)
1000 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
1001 queuecnt++;
1002 if (uLevel > 0) {
1003 if((queue = (print_queue_struct**)malloc(queuecnt*sizeof(print_queue_struct*))) == NULL) {
1004 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1005 return False;
1007 memset(queue,0,queuecnt*sizeof(print_queue_struct*));
1008 if((status = (print_status_struct*)malloc(queuecnt*sizeof(print_status_struct))) == NULL) {
1009 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1010 return False;
1012 memset(status,0,queuecnt*sizeof(print_status_struct));
1013 if((subcntarr = (int*)malloc(queuecnt*sizeof(int))) == NULL) {
1014 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1015 return False;
1017 subcnt = 0;
1018 n = 0;
1019 for (i = 0; i < services; i++)
1020 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1021 subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
1022 subcnt += subcntarr[n];
1023 n++;
1026 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
1027 desc.base = *rdata;
1028 desc.buflen = mdrcnt;
1030 if (init_package(&desc,queuecnt,subcnt)) {
1031 n = 0;
1032 succnt = 0;
1033 for (i = 0; i < services; i++)
1034 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1035 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1036 n++;
1037 if (desc.errcode == NERR_Success) succnt = n;
1041 if (subcntarr) free(subcntarr);
1043 *rdata_len = desc.usedlen;
1044 *rparam_len = 8;
1045 *rparam = REALLOC(*rparam,*rparam_len);
1046 SSVALS(*rparam,0,desc.errcode);
1047 SSVAL(*rparam,2,0);
1048 SSVAL(*rparam,4,succnt);
1049 SSVAL(*rparam,6,queuecnt);
1051 for (i = 0; i < queuecnt; i++) {
1052 if (queue && queue[i]) free(queue[i]);
1055 if (queue) free(queue);
1056 if (status) free(status);
1058 return True;
1061 /****************************************************************************
1062 get info level for a server list query
1063 ****************************************************************************/
1064 static BOOL check_server_info(int uLevel, char* id)
1066 switch( uLevel ) {
1067 case 0:
1068 if (strcmp(id,"B16") != 0) return False;
1069 break;
1070 case 1:
1071 if (strcmp(id,"B16BBDz") != 0) return False;
1072 break;
1073 default:
1074 return False;
1076 return True;
1079 struct srv_info_struct
1081 fstring name;
1082 uint32 type;
1083 fstring comment;
1084 fstring domain;
1085 BOOL server_added;
1089 /*******************************************************************
1090 get server info lists from the files saved by nmbd. Return the
1091 number of entries
1092 ******************************************************************/
1093 static int get_server_info(uint32 servertype,
1094 struct srv_info_struct **servers,
1095 char *domain)
1097 int count=0;
1098 int alloced=0;
1099 char **lines;
1100 BOOL local_list_only;
1101 int i;
1103 lines = file_lines_load(lock_path(SERVER_LIST), NULL, False);
1104 if (!lines) {
1105 DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
1106 return(0);
1109 /* request for everything is code for request all servers */
1110 if (servertype == SV_TYPE_ALL)
1111 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1113 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1115 DEBUG(4,("Servertype search: %8x\n",servertype));
1117 for (i=0;lines[i];i++) {
1118 fstring stype;
1119 struct srv_info_struct *s;
1120 char *ptr = lines[i];
1121 BOOL ok = True;
1123 if (!*ptr) continue;
1125 if (count == alloced) {
1126 alloced += 10;
1127 (*servers) = (struct srv_info_struct *)
1128 Realloc(*servers,sizeof(**servers)*alloced);
1129 if (!(*servers)) return(0);
1130 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1132 s = &(*servers)[count];
1134 if (!next_token(&ptr,s->name , NULL, sizeof(s->name))) continue;
1135 if (!next_token(&ptr,stype , NULL, sizeof(stype))) continue;
1136 if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) continue;
1137 if (!next_token(&ptr,s->domain , NULL, sizeof(s->domain))) {
1138 /* this allows us to cope with an old nmbd */
1139 pstrcpy(s->domain,global_myworkgroup);
1142 if (sscanf(stype,"%X",&s->type) != 1) {
1143 DEBUG(4,("r:host file "));
1144 ok = False;
1147 /* Filter the servers/domains we return based on what was asked for. */
1149 /* Check to see if we are being asked for a local list only. */
1150 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1151 DEBUG(4,("r: local list only"));
1152 ok = False;
1155 /* doesn't match up: don't want it */
1156 if (!(servertype & s->type)) {
1157 DEBUG(4,("r:serv type "));
1158 ok = False;
1161 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1162 (s->type & SV_TYPE_DOMAIN_ENUM))
1164 DEBUG(4,("s: dom mismatch "));
1165 ok = False;
1168 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM))
1170 ok = False;
1173 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1174 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1176 if (ok)
1178 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1179 s->name, s->type, s->comment, s->domain));
1181 s->server_added = True;
1182 count++;
1184 else
1186 DEBUG(4,("%20s %8x %25s %15s\n",
1187 s->name, s->type, s->comment, s->domain));
1191 file_lines_free(lines);
1192 return(count);
1196 /*******************************************************************
1197 fill in a server info structure
1198 ******************************************************************/
1199 static int fill_srv_info(struct srv_info_struct *service,
1200 int uLevel, char **buf, int *buflen,
1201 char **stringbuf, int *stringspace, char *baseaddr)
1203 int struct_len;
1204 char* p;
1205 char* p2;
1206 int l2;
1207 int len;
1209 switch (uLevel) {
1210 case 0: struct_len = 16; break;
1211 case 1: struct_len = 26; break;
1212 default: return -1;
1215 if (!buf)
1217 len = 0;
1218 switch (uLevel)
1220 case 1:
1221 len = strlen(service->comment)+1;
1222 break;
1225 if (buflen) *buflen = struct_len;
1226 if (stringspace) *stringspace = len;
1227 return struct_len + len;
1230 len = struct_len;
1231 p = *buf;
1232 if (*buflen < struct_len) return -1;
1233 if (stringbuf)
1235 p2 = *stringbuf;
1236 l2 = *stringspace;
1238 else
1240 p2 = p + struct_len;
1241 l2 = *buflen - struct_len;
1243 if (!baseaddr) baseaddr = p;
1245 switch (uLevel)
1247 case 0:
1248 StrnCpy(p,service->name,15);
1249 break;
1251 case 1:
1252 StrnCpy(p,service->name,15);
1253 SIVAL(p,18,service->type);
1254 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1255 len += CopyAndAdvance(&p2,service->comment,&l2);
1256 break;
1259 if (stringbuf)
1261 *buf = p + struct_len;
1262 *buflen -= struct_len;
1263 *stringbuf = p2;
1264 *stringspace = l2;
1266 else
1268 *buf = p2;
1269 *buflen -= len;
1271 return len;
1275 static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1277 return(strcmp(s1->name,s2->name));
1280 /****************************************************************************
1281 view list of servers available (or possibly domains). The info is
1282 extracted from lists saved by nmbd on the local host
1283 ****************************************************************************/
1284 static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param, char *data,
1285 int mdrcnt, int mprcnt, char **rdata,
1286 char **rparam, int *rdata_len, int *rparam_len)
1288 char *str1 = param+2;
1289 char *str2 = skip_string(str1,1);
1290 char *p = skip_string(str2,1);
1291 int uLevel = SVAL(p,0);
1292 int buf_len = SVAL(p,2);
1293 uint32 servertype = IVAL(p,4);
1294 char *p2;
1295 int data_len, fixed_len, string_len;
1296 int f_len = 0, s_len = 0;
1297 struct srv_info_struct *servers=NULL;
1298 int counted=0,total=0;
1299 int i,missed;
1300 fstring domain;
1301 BOOL domain_request;
1302 BOOL local_request;
1304 /* If someone sets all the bits they don't really mean to set
1305 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1306 known servers. */
1308 if (servertype == SV_TYPE_ALL)
1309 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1311 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1312 any other bit (they may just set this bit on it's own) they
1313 want all the locally seen servers. However this bit can be
1314 set on its own so set the requested servers to be
1315 ALL - DOMAIN_ENUM. */
1317 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM))
1318 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1320 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1321 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1323 p += 8;
1325 if (!prefix_ok(str1,"WrLehD")) return False;
1326 if (!check_server_info(uLevel,str2)) return False;
1328 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1329 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1330 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1332 if (strcmp(str1, "WrLehDz") == 0) {
1333 StrnCpy(domain, p, sizeof(fstring)-1);
1334 } else {
1335 StrnCpy(domain, global_myworkgroup, sizeof(fstring)-1);
1338 if (lp_browse_list())
1339 total = get_server_info(servertype,&servers,domain);
1341 data_len = fixed_len = string_len = 0;
1342 missed = 0;
1344 if (total > 0)
1345 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1348 char *lastname=NULL;
1350 for (i=0;i<total;i++)
1352 struct srv_info_struct *s = &servers[i];
1353 if (lastname && strequal(lastname,s->name)) continue;
1354 lastname = s->name;
1355 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1356 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1357 s->name, s->type, s->comment, s->domain));
1359 if (data_len <= buf_len) {
1360 counted++;
1361 fixed_len += f_len;
1362 string_len += s_len;
1363 } else {
1364 missed++;
1369 *rdata_len = fixed_len + string_len;
1370 *rdata = REALLOC(*rdata,*rdata_len);
1371 memset(*rdata,'\0',*rdata_len);
1373 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1374 p = *rdata;
1375 f_len = fixed_len;
1376 s_len = string_len;
1379 char *lastname=NULL;
1380 int count2 = counted;
1381 for (i = 0; i < total && count2;i++)
1383 struct srv_info_struct *s = &servers[i];
1384 if (lastname && strequal(lastname,s->name)) continue;
1385 lastname = s->name;
1386 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1387 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1388 s->name, s->type, s->comment, s->domain));
1389 count2--;
1393 *rparam_len = 8;
1394 *rparam = REALLOC(*rparam,*rparam_len);
1395 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1396 SSVAL(*rparam,2,0);
1397 SSVAL(*rparam,4,counted);
1398 SSVAL(*rparam,6,counted+missed);
1400 if (servers) free(servers);
1402 DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1403 domain,uLevel,counted,counted+missed));
1405 return(True);
1408 /****************************************************************************
1409 command 0x34 - suspected of being a "Lookup Names" stub api
1410 ****************************************************************************/
1411 static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid, char *param, char *data,
1412 int mdrcnt, int mprcnt, char **rdata,
1413 char **rparam, int *rdata_len, int *rparam_len)
1415 char *str1 = param+2;
1416 char *str2 = skip_string(str1,1);
1417 char *p = skip_string(str2,1);
1418 int uLevel = SVAL(p,0);
1419 int buf_len = SVAL(p,2);
1420 int counted=0;
1421 int missed=0;
1423 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1424 str1, str2, p, uLevel, buf_len));
1426 if (!prefix_ok(str1,"zWrLeh")) return False;
1428 *rdata_len = 0;
1430 *rparam_len = 8;
1431 *rparam = REALLOC(*rparam,*rparam_len);
1433 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1434 SSVAL(*rparam,2,0);
1435 SSVAL(*rparam,4,counted);
1436 SSVAL(*rparam,6,counted+missed);
1438 return(True);
1441 /****************************************************************************
1442 get info about a share
1443 ****************************************************************************/
1444 static BOOL check_share_info(int uLevel, char* id)
1446 switch( uLevel ) {
1447 case 0:
1448 if (strcmp(id,"B13") != 0) return False;
1449 break;
1450 case 1:
1451 if (strcmp(id,"B13BWz") != 0) return False;
1452 break;
1453 case 2:
1454 if (strcmp(id,"B13BWzWWWzB9B") != 0) return False;
1455 break;
1456 case 91:
1457 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) return False;
1458 break;
1459 default: return False;
1461 return True;
1464 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1465 char** buf, int* buflen,
1466 char** stringbuf, int* stringspace, char* baseaddr)
1468 int struct_len;
1469 char* p;
1470 char* p2;
1471 int l2;
1472 int len;
1474 switch( uLevel ) {
1475 case 0: struct_len = 13; break;
1476 case 1: struct_len = 20; break;
1477 case 2: struct_len = 40; break;
1478 case 91: struct_len = 68; break;
1479 default: return -1;
1483 if (!buf)
1485 len = 0;
1486 if (uLevel > 0) len += StrlenExpanded(conn,snum,lp_comment(snum));
1487 if (uLevel > 1) len += strlen(lp_pathname(snum)) + 1;
1488 if (buflen) *buflen = struct_len;
1489 if (stringspace) *stringspace = len;
1490 return struct_len + len;
1493 len = struct_len;
1494 p = *buf;
1495 if ((*buflen) < struct_len) return -1;
1496 if (stringbuf)
1498 p2 = *stringbuf;
1499 l2 = *stringspace;
1501 else
1503 p2 = p + struct_len;
1504 l2 = (*buflen) - struct_len;
1506 if (!baseaddr) baseaddr = p;
1508 StrnCpy(p,lp_servicename(snum),13);
1510 if (uLevel > 0)
1512 int type;
1513 CVAL(p,13) = 0;
1514 type = STYPE_DISKTREE;
1515 if (lp_print_ok(snum)) type = STYPE_PRINTQ;
1516 if (strequal("IPC$",lp_servicename(snum))) type = STYPE_IPC;
1517 SSVAL(p,14,type); /* device type */
1518 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1519 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1522 if (uLevel > 1)
1524 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1525 SSVALS(p,22,-1); /* max uses */
1526 SSVAL(p,24,1); /* current uses */
1527 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1528 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1529 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1532 if (uLevel > 2)
1534 memset(p+40,0,SHPWLEN+2);
1535 SSVAL(p,50,0);
1536 SIVAL(p,52,0);
1537 SSVAL(p,56,0);
1538 SSVAL(p,58,0);
1539 SIVAL(p,60,0);
1540 SSVAL(p,64,0);
1541 SSVAL(p,66,0);
1544 if (stringbuf)
1546 (*buf) = p + struct_len;
1547 (*buflen) -= struct_len;
1548 (*stringbuf) = p2;
1549 (*stringspace) = l2;
1551 else
1553 (*buf) = p2;
1554 (*buflen) -= len;
1556 return len;
1559 static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
1560 int mdrcnt,int mprcnt,
1561 char **rdata,char **rparam,
1562 int *rdata_len,int *rparam_len)
1564 char *str1 = param+2;
1565 char *str2 = skip_string(str1,1);
1566 char *netname = skip_string(str2,1);
1567 char *p = skip_string(netname,1);
1568 int uLevel = SVAL(p,0);
1569 int snum = find_service(netname);
1571 if (snum < 0) return False;
1573 /* check it's a supported varient */
1574 if (!prefix_ok(str1,"zWrLh")) return False;
1575 if (!check_share_info(uLevel,str2)) return False;
1577 *rdata = REALLOC(*rdata,mdrcnt);
1578 p = *rdata;
1579 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1580 if (*rdata_len < 0) return False;
1582 *rparam_len = 6;
1583 *rparam = REALLOC(*rparam,*rparam_len);
1584 SSVAL(*rparam,0,NERR_Success);
1585 SSVAL(*rparam,2,0); /* converter word */
1586 SSVAL(*rparam,4,*rdata_len);
1588 return(True);
1591 /****************************************************************************
1592 view list of shares available
1593 ****************************************************************************/
1594 static BOOL api_RNetShareEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
1595 int mdrcnt,int mprcnt,
1596 char **rdata,char **rparam,
1597 int *rdata_len,int *rparam_len)
1599 char *str1 = param+2;
1600 char *str2 = skip_string(str1,1);
1601 char *p = skip_string(str2,1);
1602 int uLevel = SVAL(p,0);
1603 int buf_len = SVAL(p,2);
1604 char *p2;
1605 int count=lp_numservices();
1606 int total=0,counted=0;
1607 BOOL missed = False;
1608 int i;
1609 int data_len, fixed_len, string_len;
1610 int f_len = 0, s_len = 0;
1612 if (!prefix_ok(str1,"WrLeh")) return False;
1613 if (!check_share_info(uLevel,str2)) return False;
1615 data_len = fixed_len = string_len = 0;
1616 for (i=0;i<count;i++)
1617 if (lp_browseable(i) && lp_snum_ok(i))
1619 total++;
1620 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1621 if (data_len <= buf_len)
1623 counted++;
1624 fixed_len += f_len;
1625 string_len += s_len;
1627 else
1628 missed = True;
1630 *rdata_len = fixed_len + string_len;
1631 *rdata = REALLOC(*rdata,*rdata_len);
1632 memset(*rdata,0,*rdata_len);
1634 p2 = (*rdata) + fixed_len; /* auxillery data (strings) will go here */
1635 p = *rdata;
1636 f_len = fixed_len;
1637 s_len = string_len;
1638 for (i = 0; i < count;i++)
1639 if (lp_browseable(i) && lp_snum_ok(i))
1640 if (fill_share_info(conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata) < 0)
1641 break;
1643 *rparam_len = 8;
1644 *rparam = REALLOC(*rparam,*rparam_len);
1645 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1646 SSVAL(*rparam,2,0);
1647 SSVAL(*rparam,4,counted);
1648 SSVAL(*rparam,6,total);
1650 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1651 counted,total,uLevel,
1652 buf_len,*rdata_len,mdrcnt));
1653 return(True);
1658 /****************************************************************************
1659 get the time of day info
1660 ****************************************************************************/
1661 static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid, char *param,char *data,
1662 int mdrcnt,int mprcnt,
1663 char **rdata,char **rparam,
1664 int *rdata_len,int *rparam_len)
1666 char *p;
1667 *rparam_len = 4;
1668 *rparam = REALLOC(*rparam,*rparam_len);
1670 *rdata_len = 21;
1671 *rdata = REALLOC(*rdata,*rdata_len);
1673 SSVAL(*rparam,0,NERR_Success);
1674 SSVAL(*rparam,2,0); /* converter word */
1676 p = *rdata;
1679 struct tm *t;
1680 time_t unixdate = time(NULL);
1682 put_dos_date3(p,0,unixdate); /* this is the time that is looked at
1683 by NT in a "net time" operation,
1684 it seems to ignore the one below */
1686 /* the client expects to get localtime, not GMT, in this bit
1687 (I think, this needs testing) */
1688 t = LocalTime(&unixdate);
1690 SIVAL(p,4,0); /* msecs ? */
1691 CVAL(p,8) = t->tm_hour;
1692 CVAL(p,9) = t->tm_min;
1693 CVAL(p,10) = t->tm_sec;
1694 CVAL(p,11) = 0; /* hundredths of seconds */
1695 SSVALS(p,12,TimeDiff(unixdate)/60); /* timezone in minutes from GMT */
1696 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
1697 CVAL(p,16) = t->tm_mday;
1698 CVAL(p,17) = t->tm_mon + 1;
1699 SSVAL(p,18,1900+t->tm_year);
1700 CVAL(p,20) = t->tm_wday;
1704 return(True);
1707 /****************************************************************************
1708 Set the user password.
1709 *****************************************************************************/
1711 static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1712 int mdrcnt,int mprcnt,
1713 char **rdata,char **rparam,
1714 int *rdata_len,int *rparam_len)
1716 char *p = skip_string(param+2,2);
1717 fstring user;
1718 fstring pass1,pass2;
1720 fstrcpy(user,p);
1722 p = skip_string(p,1);
1724 memset(pass1,'\0',sizeof(pass1));
1725 memset(pass2,'\0',sizeof(pass2));
1726 memcpy(pass1,p,16);
1727 memcpy(pass2,p+16,16);
1729 *rparam_len = 4;
1730 *rparam = REALLOC(*rparam,*rparam_len);
1732 *rdata_len = 0;
1734 SSVAL(*rparam,0,NERR_badpass);
1735 SSVAL(*rparam,2,0); /* converter word */
1737 DEBUG(3,("Set password for <%s>\n",user));
1740 * Pass the user through the NT -> unix user mapping
1741 * function.
1744 (void)map_username(user);
1747 * Do any UNIX username case mangling.
1749 (void)Get_Pwnam( user, True);
1752 * Attempt to verify the old password against smbpasswd entries
1753 * Win98 clients send old and new password in plaintext for this call.
1757 fstring saved_pass2;
1758 SAM_ACCOUNT *sampass;
1761 * Save the new password as change_oem_password overwrites it
1762 * with zeros.
1765 fstrcpy(saved_pass2, pass2);
1767 if (check_plaintext_password(user,pass1,strlen(pass1),&sampass) &&
1768 change_oem_password(sampass,pass2,False))
1770 SSVAL(*rparam,0,NERR_Success);
1773 * If unix password sync was requested, attempt to change
1774 * the /etc/passwd database also. Return failure if this cannot
1775 * be done.
1778 if(lp_unix_password_sync() && !chgpasswd(user,pass1,saved_pass2,False))
1779 SSVAL(*rparam,0,NERR_badpass);
1784 * If the above failed, attempt the plaintext password change.
1785 * This tests against the /etc/passwd database only.
1788 if(SVAL(*rparam,0) != NERR_Success)
1790 if (password_ok(user, pass1,strlen(pass1),NULL) &&
1791 chgpasswd(user,pass1,pass2,False))
1793 SSVAL(*rparam,0,NERR_Success);
1798 * If the plaintext change failed, attempt
1799 * the old encrypted method. NT will generate this
1800 * after trying the samr method. Note that this
1801 * method is done as a last resort as this
1802 * password change method loses the NT password hash
1803 * and cannot change the UNIX password as no plaintext
1804 * is received.
1807 if(SVAL(*rparam,0) != NERR_Success)
1809 SAM_ACCOUNT *hnd = NULL;
1811 if(check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd) &&
1812 change_lanman_password(hnd,(unsigned char *)pass1,(unsigned char *)pass2))
1814 SSVAL(*rparam,0,NERR_Success);
1818 memset((char *)pass1,'\0',sizeof(fstring));
1819 memset((char *)pass2,'\0',sizeof(fstring));
1821 return(True);
1824 /****************************************************************************
1825 Set the user password (SamOEM version - gets plaintext).
1826 ****************************************************************************/
1828 static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1829 int mdrcnt,int mprcnt,
1830 char **rdata,char **rparam,
1831 int *rdata_len,int *rparam_len)
1833 fstring user;
1834 char *p = param + 2;
1835 *rparam_len = 2;
1836 *rparam = REALLOC(*rparam,*rparam_len);
1838 *rdata_len = 0;
1840 SSVAL(*rparam,0,NERR_badpass);
1843 * Check the parameter definition is correct.
1845 if(!strequal(param + 2, "zsT")) {
1846 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", param + 2));
1847 return False;
1849 p = skip_string(p, 1);
1851 if(!strequal(p, "B516B16")) {
1852 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
1853 return False;
1855 p = skip_string(p,1);
1857 fstrcpy(user,p);
1858 p = skip_string(p,1);
1860 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
1863 * Pass the user through the NT -> unix user mapping
1864 * function.
1867 (void)map_username(user);
1870 * Do any UNIX username case mangling.
1872 (void)Get_Pwnam( user, True);
1874 if (pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL))
1876 SSVAL(*rparam,0,NERR_Success);
1879 return(True);
1882 /****************************************************************************
1883 delete a print job
1884 Form: <W> <>
1885 ****************************************************************************/
1886 static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param,char *data,
1887 int mdrcnt,int mprcnt,
1888 char **rdata,char **rparam,
1889 int *rdata_len,int *rparam_len)
1891 int function = SVAL(param,0);
1892 char *str1 = param+2;
1893 char *str2 = skip_string(str1,1);
1894 char *p = skip_string(str2,1);
1895 int jobid, errcode;
1896 extern struct current_user current_user;
1898 jobid = SVAL(p,0);
1900 /* check it's a supported varient */
1901 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
1902 return(False);
1904 *rparam_len = 4;
1905 *rparam = REALLOC(*rparam,*rparam_len);
1906 *rdata_len = 0;
1908 if (!print_job_exists(jobid)) {
1909 errcode = NERR_JobNotFound;
1910 goto out;
1913 errcode = NERR_notsupported;
1915 switch (function) {
1916 case 81: /* delete */
1917 if (print_job_delete(&current_user, jobid, &errcode))
1918 errcode = NERR_Success;
1919 break;
1920 case 82: /* pause */
1921 if (print_job_pause(&current_user, jobid, &errcode))
1922 errcode = NERR_Success;
1923 break;
1924 case 83: /* resume */
1925 if (print_job_resume(&current_user, jobid, &errcode))
1926 errcode = NERR_Success;
1927 break;
1930 out:
1931 SSVAL(*rparam,0,errcode);
1932 SSVAL(*rparam,2,0); /* converter word */
1934 return(True);
1937 /****************************************************************************
1938 Purge a print queue - or pause or resume it.
1939 ****************************************************************************/
1940 static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid, char *param,char *data,
1941 int mdrcnt,int mprcnt,
1942 char **rdata,char **rparam,
1943 int *rdata_len,int *rparam_len)
1945 int function = SVAL(param,0);
1946 char *str1 = param+2;
1947 char *str2 = skip_string(str1,1);
1948 char *QueueName = skip_string(str2,1);
1949 int errcode = NERR_notsupported;
1950 int snum;
1951 extern struct current_user current_user;
1953 /* check it's a supported varient */
1954 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
1955 return(False);
1957 *rparam_len = 4;
1958 *rparam = REALLOC(*rparam,*rparam_len);
1959 *rdata_len = 0;
1961 snum = print_queue_snum(QueueName);
1963 if (snum == -1) {
1964 errcode = NERR_JobNotFound;
1965 goto out;
1968 switch (function) {
1969 case 74: /* Pause queue */
1970 if (print_queue_pause(&current_user, snum, &errcode)) errcode = NERR_Success;
1971 break;
1972 case 75: /* Resume queue */
1973 if (print_queue_resume(&current_user, snum, &errcode)) errcode = NERR_Success;
1974 break;
1975 case 103: /* Purge */
1976 if (print_queue_purge(&current_user, snum, &errcode)) errcode = NERR_Success;
1977 break;
1980 out:
1981 SSVAL(*rparam,0,errcode);
1982 SSVAL(*rparam,2,0); /* converter word */
1984 return(True);
1988 /****************************************************************************
1989 set the property of a print job (undocumented?)
1990 ? function = 0xb -> set name of print job
1991 ? function = 0x6 -> move print job up/down
1992 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
1993 or <WWsTP> <WB21BB16B10zWWzDDz>
1994 ****************************************************************************/
1995 static int check_printjob_info(struct pack_desc* desc,
1996 int uLevel, char* id)
1998 desc->subformat = NULL;
1999 switch( uLevel ) {
2000 case 0: desc->format = "W"; break;
2001 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2002 case 2: desc->format = "WWzWWDDzz"; break;
2003 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2004 default: return False;
2006 if (strcmp(desc->format,id) != 0) return False;
2007 return True;
2010 static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,char *data,
2011 int mdrcnt,int mprcnt,
2012 char **rdata,char **rparam,
2013 int *rdata_len,int *rparam_len)
2015 struct pack_desc desc;
2016 char *str1 = param+2;
2017 char *str2 = skip_string(str1,1);
2018 char *p = skip_string(str2,1);
2019 int jobid;
2020 int uLevel = SVAL(p,2);
2021 int function = SVAL(p,4);
2022 int place, errcode;
2024 jobid = SVAL(p,0);
2025 *rparam_len = 4;
2026 *rparam = REALLOC(*rparam,*rparam_len);
2028 *rdata_len = 0;
2030 /* check it's a supported varient */
2031 if ((strcmp(str1,"WWsTP")) ||
2032 (!check_printjob_info(&desc,uLevel,str2)))
2033 return(False);
2035 if (!print_job_exists(jobid)) {
2036 errcode=NERR_JobNotFound;
2037 goto out;
2040 errcode = NERR_notsupported;
2042 switch (function) {
2043 case 0x6:
2044 /* change job place in the queue,
2045 data gives the new place */
2046 place = SVAL(data,0);
2047 if (print_job_set_place(jobid, place)) {
2048 errcode=NERR_Success;
2050 break;
2052 case 0xb:
2053 /* change print job name, data gives the name */
2054 if (print_job_set_name(jobid, data)) {
2055 errcode=NERR_Success;
2057 break;
2059 default:
2060 return False;
2063 out:
2064 SSVALS(*rparam,0,errcode);
2065 SSVAL(*rparam,2,0); /* converter word */
2067 return(True);
2071 /****************************************************************************
2072 get info about the server
2073 ****************************************************************************/
2074 static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2075 int mdrcnt,int mprcnt,
2076 char **rdata,char **rparam,
2077 int *rdata_len,int *rparam_len)
2079 char *str1 = param+2;
2080 char *str2 = skip_string(str1,1);
2081 char *p = skip_string(str2,1);
2082 int uLevel = SVAL(p,0);
2083 char *p2;
2084 int struct_len;
2086 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2088 /* check it's a supported varient */
2089 if (!prefix_ok(str1,"WrLh")) return False;
2090 switch( uLevel ) {
2091 case 0:
2092 if (strcmp(str2,"B16") != 0) return False;
2093 struct_len = 16;
2094 break;
2095 case 1:
2096 if (strcmp(str2,"B16BBDz") != 0) return False;
2097 struct_len = 26;
2098 break;
2099 case 2:
2100 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")
2101 != 0) return False;
2102 struct_len = 134;
2103 break;
2104 case 3:
2105 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz")
2106 != 0) return False;
2107 struct_len = 144;
2108 break;
2109 case 20:
2110 if (strcmp(str2,"DN") != 0) return False;
2111 struct_len = 6;
2112 break;
2113 case 50:
2114 if (strcmp(str2,"B16BBDzWWzzz") != 0) return False;
2115 struct_len = 42;
2116 break;
2117 default: return False;
2120 *rdata_len = mdrcnt;
2121 *rdata = REALLOC(*rdata,*rdata_len);
2123 p = *rdata;
2124 p2 = p + struct_len;
2125 if (uLevel != 20) {
2126 StrnCpy(p,local_machine,16);
2127 strupper(p);
2129 p += 16;
2130 if (uLevel > 0)
2132 struct srv_info_struct *servers=NULL;
2133 int i,count;
2134 pstring comment;
2135 uint32 servertype= lp_default_server_announce();
2137 pstrcpy(comment,string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH));
2139 if ((count=get_server_info(SV_TYPE_ALL,&servers,global_myworkgroup))>0) {
2140 for (i=0;i<count;i++)
2141 if (strequal(servers[i].name,local_machine))
2143 servertype = servers[i].type;
2144 pstrcpy(comment,servers[i].comment);
2147 if (servers) free(servers);
2149 SCVAL(p,0,lp_major_announce_version());
2150 SCVAL(p,1,lp_minor_announce_version());
2151 SIVAL(p,2,servertype);
2153 if (mdrcnt == struct_len) {
2154 SIVAL(p,6,0);
2155 } else {
2156 SIVAL(p,6,PTR_DIFF(p2,*rdata));
2157 standard_sub_conn(conn,comment);
2158 StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2159 p2 = skip_string(p2,1);
2162 if (uLevel > 1)
2164 return False; /* not yet implemented */
2167 *rdata_len = PTR_DIFF(p2,*rdata);
2169 *rparam_len = 6;
2170 *rparam = REALLOC(*rparam,*rparam_len);
2171 SSVAL(*rparam,0,NERR_Success);
2172 SSVAL(*rparam,2,0); /* converter word */
2173 SSVAL(*rparam,4,*rdata_len);
2175 return(True);
2179 /****************************************************************************
2180 get info about the server
2181 ****************************************************************************/
2182 static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2183 int mdrcnt,int mprcnt,
2184 char **rdata,char **rparam,
2185 int *rdata_len,int *rparam_len)
2187 char *str1 = param+2;
2188 char *str2 = skip_string(str1,1);
2189 char *p = skip_string(str2,1);
2190 char *p2;
2191 extern userdom_struct current_user_info;
2192 int level = SVAL(p,0);
2194 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2196 *rparam_len = 6;
2197 *rparam = REALLOC(*rparam,*rparam_len);
2199 /* check it's a supported varient */
2200 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz")))
2201 return(False);
2203 *rdata_len = mdrcnt + 1024;
2204 *rdata = REALLOC(*rdata,*rdata_len);
2206 SSVAL(*rparam,0,NERR_Success);
2207 SSVAL(*rparam,2,0); /* converter word */
2209 p = *rdata;
2210 p2 = p + 22;
2213 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2214 pstrcpy(p2,local_machine);
2215 strupper(p2);
2216 p2 = skip_string(p2,1);
2217 p += 4;
2219 SIVAL(p,0,PTR_DIFF(p2,*rdata));
2220 pstrcpy(p2,current_user_info.smb_name);
2221 p2 = skip_string(p2,1);
2222 p += 4;
2224 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
2225 pstrcpy(p2,global_myworkgroup);
2226 strupper(p2);
2227 p2 = skip_string(p2,1);
2228 p += 4;
2230 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
2231 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
2232 p += 2;
2234 SIVAL(p,0,PTR_DIFF(p2,*rdata));
2235 pstrcpy(p2,global_myworkgroup); /* don't know. login domain?? */
2236 p2 = skip_string(p2,1);
2237 p += 4;
2239 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
2240 pstrcpy(p2,"");
2241 p2 = skip_string(p2,1);
2242 p += 4;
2244 *rdata_len = PTR_DIFF(p2,*rdata);
2246 SSVAL(*rparam,4,*rdata_len);
2248 return(True);
2251 /****************************************************************************
2252 get info about a user
2254 struct user_info_11 {
2255 char usri11_name[21]; 0-20
2256 char usri11_pad; 21
2257 char *usri11_comment; 22-25
2258 char *usri11_usr_comment; 26-29
2259 unsigned short usri11_priv; 30-31
2260 unsigned long usri11_auth_flags; 32-35
2261 long usri11_password_age; 36-39
2262 char *usri11_homedir; 40-43
2263 char *usri11_parms; 44-47
2264 long usri11_last_logon; 48-51
2265 long usri11_last_logoff; 52-55
2266 unsigned short usri11_bad_pw_count; 56-57
2267 unsigned short usri11_num_logons; 58-59
2268 char *usri11_logon_server; 60-63
2269 unsigned short usri11_country_code; 64-65
2270 char *usri11_workstations; 66-69
2271 unsigned long usri11_max_storage; 70-73
2272 unsigned short usri11_units_per_week; 74-75
2273 unsigned char *usri11_logon_hours; 76-79
2274 unsigned short usri11_code_page; 80-81
2277 where:
2279 usri11_name specifies the user name for which information is retireved
2281 usri11_pad aligns the next data structure element to a word boundary
2283 usri11_comment is a null terminated ASCII comment
2285 usri11_user_comment is a null terminated ASCII comment about the user
2287 usri11_priv specifies the level of the privilege assigned to the user.
2288 The possible values are:
2290 Name Value Description
2291 USER_PRIV_GUEST 0 Guest privilege
2292 USER_PRIV_USER 1 User privilege
2293 USER_PRV_ADMIN 2 Administrator privilege
2295 usri11_auth_flags specifies the account operator privileges. The
2296 possible values are:
2298 Name Value Description
2299 AF_OP_PRINT 0 Print operator
2302 Leach, Naik [Page 28]
2306 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
2309 AF_OP_COMM 1 Communications operator
2310 AF_OP_SERVER 2 Server operator
2311 AF_OP_ACCOUNTS 3 Accounts operator
2314 usri11_password_age specifies how many seconds have elapsed since the
2315 password was last changed.
2317 usri11_home_dir points to a null terminated ASCII string that contains
2318 the path name of the user's home directory.
2320 usri11_parms points to a null terminated ASCII string that is set
2321 aside for use by applications.
2323 usri11_last_logon specifies the time when the user last logged on.
2324 This value is stored as the number of seconds elapsed since
2325 00:00:00, January 1, 1970.
2327 usri11_last_logoff specifies the time when the user last logged off.
2328 This value is stored as the number of seconds elapsed since
2329 00:00:00, January 1, 1970. A value of 0 means the last logoff
2330 time is unknown.
2332 usri11_bad_pw_count specifies the number of incorrect passwords
2333 entered since the last successful logon.
2335 usri11_log1_num_logons specifies the number of times this user has
2336 logged on. A value of -1 means the number of logons is unknown.
2338 usri11_logon_server points to a null terminated ASCII string that
2339 contains the name of the server to which logon requests are sent.
2340 A null string indicates logon requests should be sent to the
2341 domain controller.
2343 usri11_country_code specifies the country code for the user's language
2344 of choice.
2346 usri11_workstations points to a null terminated ASCII string that
2347 contains the names of workstations the user may log on from.
2348 There may be up to 8 workstations, with the names separated by
2349 commas. A null strings indicates there are no restrictions.
2351 usri11_max_storage specifies the maximum amount of disk space the user
2352 can occupy. A value of 0xffffffff indicates there are no
2353 restrictions.
2355 usri11_units_per_week specifies the equal number of time units into
2356 which a week is divided. This value must be equal to 168.
2358 usri11_logon_hours points to a 21 byte (168 bits) string that
2359 specifies the time during which the user can log on. Each bit
2360 represents one unique hour in a week. The first bit (bit 0, word
2361 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
2365 Leach, Naik [Page 29]
2369 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
2372 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
2373 are no restrictions.
2375 usri11_code_page specifies the code page for the user's language of
2376 choice
2378 All of the pointers in this data structure need to be treated
2379 specially. The pointer is a 32 bit pointer. The higher 16 bits need
2380 to be ignored. The converter word returned in the parameters section
2381 needs to be subtracted from the lower 16 bits to calculate an offset
2382 into the return buffer where this ASCII string resides.
2384 There is no auxiliary data in the response.
2386 ****************************************************************************/
2388 #define usri11_name 0
2389 #define usri11_pad 21
2390 #define usri11_comment 22
2391 #define usri11_usr_comment 26
2392 #define usri11_full_name 30
2393 #define usri11_priv 34
2394 #define usri11_auth_flags 36
2395 #define usri11_password_age 40
2396 #define usri11_homedir 44
2397 #define usri11_parms 48
2398 #define usri11_last_logon 52
2399 #define usri11_last_logoff 56
2400 #define usri11_bad_pw_count 60
2401 #define usri11_num_logons 62
2402 #define usri11_logon_server 64
2403 #define usri11_country_code 68
2404 #define usri11_workstations 70
2405 #define usri11_max_storage 74
2406 #define usri11_units_per_week 78
2407 #define usri11_logon_hours 80
2408 #define usri11_code_page 84
2409 #define usri11_end 86
2411 #define USER_PRIV_GUEST 0
2412 #define USER_PRIV_USER 1
2413 #define USER_PRIV_ADMIN 2
2415 #define AF_OP_PRINT 0
2416 #define AF_OP_COMM 1
2417 #define AF_OP_SERVER 2
2418 #define AF_OP_ACCOUNTS 3
2421 static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2422 int mdrcnt,int mprcnt,
2423 char **rdata,char **rparam,
2424 int *rdata_len,int *rparam_len)
2426 char *str1 = param+2;
2427 char *str2 = skip_string(str1,1);
2428 char *UserName = skip_string(str2,1);
2429 char *p = skip_string(UserName,1);
2430 int uLevel = SVAL(p,0);
2431 char *p2;
2433 /* get NIS home of a previously validated user - simeon */
2434 /* With share level security vuid will always be zero.
2435 Don't depend on vuser being non-null !!. JRA */
2436 user_struct *vuser = get_valid_user_struct(vuid);
2437 if(vuser != NULL)
2438 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
2439 vuser->user.unix_name));
2441 *rparam_len = 6;
2442 *rparam = REALLOC(*rparam,*rparam_len);
2444 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
2446 /* check it's a supported variant */
2447 if (strcmp(str1,"zWrLh") != 0) return False;
2448 switch( uLevel )
2450 case 0: p2 = "B21"; break;
2451 case 1: p2 = "B21BB16DWzzWz"; break;
2452 case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
2453 case 10: p2 = "B21Bzzz"; break;
2454 case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
2455 default: return False;
2458 if (strcmp(p2,str2) != 0) return False;
2460 *rdata_len = mdrcnt + 1024;
2461 *rdata = REALLOC(*rdata,*rdata_len);
2463 SSVAL(*rparam,0,NERR_Success);
2464 SSVAL(*rparam,2,0); /* converter word */
2466 p = *rdata;
2467 p2 = p + usri11_end;
2469 memset(p,0,21);
2470 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
2472 if (uLevel > 0)
2474 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
2475 *p2 = 0;
2477 if (uLevel >= 10)
2479 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
2480 pstrcpy(p2,"Comment");
2481 p2 = skip_string(p2,1);
2483 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
2484 pstrcpy(p2,"UserComment");
2485 p2 = skip_string(p2,1);
2487 /* EEK! the cifsrap.txt doesn't have this in!!!! */
2488 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
2489 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2490 p2 = skip_string(p2,1);
2493 if (uLevel == 11) /* modelled after NTAS 3.51 reply */
2495 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2496 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
2497 SIVALS(p,usri11_password_age,-1); /* password age */
2498 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
2499 pstrcpy(p2, lp_logon_home());
2500 standard_sub_conn(conn, p2);
2501 p2 = skip_string(p2,1);
2502 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
2503 pstrcpy(p2,"");
2504 p2 = skip_string(p2,1);
2505 SIVAL(p,usri11_last_logon,0); /* last logon */
2506 SIVAL(p,usri11_last_logoff,0); /* last logoff */
2507 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
2508 SSVALS(p,usri11_num_logons,-1); /* num logons */
2509 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
2510 pstrcpy(p2,"\\\\*");
2511 p2 = skip_string(p2,1);
2512 SSVAL(p,usri11_country_code,0); /* country code */
2514 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
2515 pstrcpy(p2,"");
2516 p2 = skip_string(p2,1);
2518 SIVALS(p,usri11_max_storage,-1); /* max storage */
2519 SSVAL(p,usri11_units_per_week,168); /* units per week */
2520 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
2522 /* a simple way to get logon hours at all times. */
2523 memset(p2,0xff,21);
2524 SCVAL(p2,21,0); /* fix zero termination */
2525 p2 = skip_string(p2,1);
2527 SSVAL(p,usri11_code_page,0); /* code page */
2529 if (uLevel == 1 || uLevel == 2)
2531 memset(p+22,' ',16); /* password */
2532 SIVALS(p,38,-1); /* password age */
2533 SSVAL(p,42,
2534 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2535 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
2536 pstrcpy(p2,lp_logon_home());
2537 standard_sub_conn(conn, p2);
2538 p2 = skip_string(p2,1);
2539 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
2540 *p2++ = 0;
2541 SSVAL(p,52,0); /* flags */
2542 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
2543 pstrcpy(p2,lp_logon_script());
2544 standard_sub_conn( conn, p2 );
2545 p2 = skip_string(p2,1);
2546 if (uLevel == 2)
2548 SIVAL(p,60,0); /* auth_flags */
2549 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
2550 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2551 p2 = skip_string(p2,1);
2552 SIVAL(p,68,0); /* urs_comment */
2553 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
2554 pstrcpy(p2,"");
2555 p2 = skip_string(p2,1);
2556 SIVAL(p,76,0); /* workstations */
2557 SIVAL(p,80,0); /* last_logon */
2558 SIVAL(p,84,0); /* last_logoff */
2559 SIVALS(p,88,-1); /* acct_expires */
2560 SIVALS(p,92,-1); /* max_storage */
2561 SSVAL(p,96,168); /* units_per_week */
2562 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
2563 memset(p2,-1,21);
2564 p2 += 21;
2565 SSVALS(p,102,-1); /* bad_pw_count */
2566 SSVALS(p,104,-1); /* num_logons */
2567 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
2568 pstrcpy(p2,"\\\\%L");
2569 standard_sub_conn(conn, p2);
2570 p2 = skip_string(p2,1);
2571 SSVAL(p,110,49); /* country_code */
2572 SSVAL(p,112,860); /* code page */
2576 *rdata_len = PTR_DIFF(p2,*rdata);
2578 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
2580 return(True);
2583 /*******************************************************************
2584 get groups that a user is a member of
2585 ******************************************************************/
2586 static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *param,char *data,
2587 int mdrcnt,int mprcnt,
2588 char **rdata,char **rparam,
2589 int *rdata_len,int *rparam_len)
2591 char *str1 = param+2;
2592 char *str2 = skip_string(str1,1);
2593 char *UserName = skip_string(str2,1);
2594 char *p = skip_string(UserName,1);
2595 int uLevel = SVAL(p,0);
2596 char *p2;
2597 int count=0;
2599 *rparam_len = 8;
2600 *rparam = REALLOC(*rparam,*rparam_len);
2602 /* check it's a supported varient */
2603 if (strcmp(str1,"zWrLeh") != 0) return False;
2604 switch( uLevel ) {
2605 case 0: p2 = "B21"; break;
2606 default: return False;
2608 if (strcmp(p2,str2) != 0) return False;
2610 *rdata_len = mdrcnt + 1024;
2611 *rdata = REALLOC(*rdata,*rdata_len);
2613 SSVAL(*rparam,0,NERR_Success);
2614 SSVAL(*rparam,2,0); /* converter word */
2616 p = *rdata;
2618 /* XXXX we need a real SAM database some day */
2619 pstrcpy(p,"Users"); p += 21; count++;
2620 pstrcpy(p,"Domain Users"); p += 21; count++;
2621 pstrcpy(p,"Guests"); p += 21; count++;
2622 pstrcpy(p,"Domain Guests"); p += 21; count++;
2624 *rdata_len = PTR_DIFF(p,*rdata);
2626 SSVAL(*rparam,4,count); /* is this right?? */
2627 SSVAL(*rparam,6,count); /* is this right?? */
2629 return(True);
2633 static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param,char *data,
2634 int mdrcnt,int mprcnt,
2635 char **rdata,char **rparam,
2636 int *rdata_len,int *rparam_len)
2638 char *str1 = param+2;
2639 char *str2 = skip_string(str1,1);
2640 char *p = skip_string(str2,1);
2641 int uLevel;
2642 struct pack_desc desc;
2643 char* name;
2645 uLevel = SVAL(p,0);
2646 name = p + 2;
2648 memset((char *)&desc,'\0',sizeof(desc));
2650 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
2652 /* check it's a supported varient */
2653 if (strcmp(str1,"OOWb54WrLh") != 0) return False;
2654 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) return False;
2655 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2656 desc.base = *rdata;
2657 desc.buflen = mdrcnt;
2658 desc.subformat = NULL;
2659 desc.format = str2;
2661 if (init_package(&desc,1,0))
2663 PACKI(&desc,"W",0); /* code */
2664 PACKS(&desc,"B21",name); /* eff. name */
2665 PACKS(&desc,"B",""); /* pad */
2666 PACKI(&desc,"W",
2667 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2668 PACKI(&desc,"D",0); /* auth flags XXX */
2669 PACKI(&desc,"W",0); /* num logons */
2670 PACKI(&desc,"W",0); /* bad pw count */
2671 PACKI(&desc,"D",0); /* last logon */
2672 PACKI(&desc,"D",-1); /* last logoff */
2673 PACKI(&desc,"D",-1); /* logoff time */
2674 PACKI(&desc,"D",-1); /* kickoff time */
2675 PACKI(&desc,"D",0); /* password age */
2676 PACKI(&desc,"D",0); /* password can change */
2677 PACKI(&desc,"D",-1); /* password must change */
2679 fstring mypath;
2680 fstrcpy(mypath,"\\\\");
2681 fstrcat(mypath,local_machine);
2682 strupper(mypath);
2683 PACKS(&desc,"z",mypath); /* computer */
2685 PACKS(&desc,"z",global_myworkgroup);/* domain */
2687 /* JHT - By calling lp_logon_script() and standard_sub() we have */
2688 /* made sure all macros are fully substituted and available */
2690 pstring logon_script;
2691 pstrcpy(logon_script,lp_logon_script());
2692 standard_sub_conn( conn, logon_script );
2693 PACKS(&desc,"z", logon_script); /* script path */
2695 /* End of JHT mods */
2697 PACKI(&desc,"D",0x00000000); /* reserved */
2700 *rdata_len = desc.usedlen;
2701 *rparam_len = 6;
2702 *rparam = REALLOC(*rparam,*rparam_len);
2703 SSVALS(*rparam,0,desc.errcode);
2704 SSVAL(*rparam,2,0);
2705 SSVAL(*rparam,4,desc.neededlen);
2707 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
2708 return(True);
2712 /****************************************************************************
2713 api_WAccessGetUserPerms
2714 ****************************************************************************/
2715 static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid, char *param,char *data,
2716 int mdrcnt,int mprcnt,
2717 char **rdata,char **rparam,
2718 int *rdata_len,int *rparam_len)
2720 char *str1 = param+2;
2721 char *str2 = skip_string(str1,1);
2722 char *user = skip_string(str2,1);
2723 char *resource = skip_string(user,1);
2725 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
2727 /* check it's a supported varient */
2728 if (strcmp(str1,"zzh") != 0) return False;
2729 if (strcmp(str2,"") != 0) return False;
2731 *rparam_len = 6;
2732 *rparam = REALLOC(*rparam,*rparam_len);
2733 SSVALS(*rparam,0,0); /* errorcode */
2734 SSVAL(*rparam,2,0); /* converter word */
2735 SSVAL(*rparam,4,0x7f); /* permission flags */
2737 return(True);
2740 /****************************************************************************
2741 api_WPrintJobEnumerate
2742 ****************************************************************************/
2743 static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2744 int mdrcnt,int mprcnt,
2745 char **rdata,char **rparam,
2746 int *rdata_len,int *rparam_len)
2748 char *str1 = param+2;
2749 char *str2 = skip_string(str1,1);
2750 char *p = skip_string(str2,1);
2751 int uLevel;
2752 int count;
2753 int i;
2754 int snum;
2755 int job;
2756 struct pack_desc desc;
2757 print_queue_struct *queue=NULL;
2758 print_status_struct status;
2760 uLevel = SVAL(p,2);
2762 memset((char *)&desc,'\0',sizeof(desc));
2763 memset((char *)&status,'\0',sizeof(status));
2765 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
2767 /* check it's a supported varient */
2768 if (strcmp(str1,"WWrLh") != 0) return False;
2769 if (!check_printjob_info(&desc,uLevel,str2)) return False;
2771 job = SVAL(p,0);
2772 snum = print_job_snum(job);
2774 if (snum < 0 || !VALID_SNUM(snum)) return(False);
2776 count = print_queue_status(snum,&queue,&status);
2777 for (i = 0; i < count; i++) {
2778 if (queue[i].job == job) break;
2780 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2781 desc.base = *rdata;
2782 desc.buflen = mdrcnt;
2784 if (init_package(&desc,1,0)) {
2785 if (i < count) {
2786 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2787 *rdata_len = desc.usedlen;
2789 else {
2790 desc.errcode = NERR_JobNotFound;
2791 *rdata_len = 0;
2795 *rparam_len = 6;
2796 *rparam = REALLOC(*rparam,*rparam_len);
2797 SSVALS(*rparam,0,desc.errcode);
2798 SSVAL(*rparam,2,0);
2799 SSVAL(*rparam,4,desc.neededlen);
2801 if (queue) free(queue);
2803 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
2804 return(True);
2807 static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *param,char *data,
2808 int mdrcnt,int mprcnt,
2809 char **rdata,char **rparam,
2810 int *rdata_len,int *rparam_len)
2812 char *str1 = param+2;
2813 char *str2 = skip_string(str1,1);
2814 char *p = skip_string(str2,1);
2815 char* name = p;
2816 int uLevel;
2817 int count;
2818 int i, succnt=0;
2819 int snum;
2820 struct pack_desc desc;
2821 print_queue_struct *queue=NULL;
2822 print_status_struct status;
2824 memset((char *)&desc,'\0',sizeof(desc));
2825 memset((char *)&status,'\0',sizeof(status));
2827 p = skip_string(p,1);
2828 uLevel = SVAL(p,0);
2830 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
2832 /* check it's a supported varient */
2833 if (strcmp(str1,"zWrLeh") != 0) return False;
2834 if (uLevel > 2) return False; /* defined only for uLevel 0,1,2 */
2835 if (!check_printjob_info(&desc,uLevel,str2)) return False;
2837 snum = lp_servicenumber(name);
2838 if (snum < 0 && pcap_printername_ok(name,NULL)) {
2839 int pnum = lp_servicenumber(PRINTERS_NAME);
2840 if (pnum >= 0) {
2841 lp_add_printer(name,pnum);
2842 snum = lp_servicenumber(name);
2846 if (snum < 0 || !VALID_SNUM(snum)) return(False);
2848 count = print_queue_status(snum,&queue,&status);
2849 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2850 desc.base = *rdata;
2851 desc.buflen = mdrcnt;
2853 if (init_package(&desc,count,0)) {
2854 succnt = 0;
2855 for (i = 0; i < count; i++) {
2856 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2857 if (desc.errcode == NERR_Success) succnt = i+1;
2861 *rdata_len = desc.usedlen;
2863 *rparam_len = 8;
2864 *rparam = REALLOC(*rparam,*rparam_len);
2865 SSVALS(*rparam,0,desc.errcode);
2866 SSVAL(*rparam,2,0);
2867 SSVAL(*rparam,4,succnt);
2868 SSVAL(*rparam,6,count);
2870 if (queue) free(queue);
2872 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
2873 return(True);
2876 static int check_printdest_info(struct pack_desc* desc,
2877 int uLevel, char* id)
2879 desc->subformat = NULL;
2880 switch( uLevel ) {
2881 case 0: desc->format = "B9"; break;
2882 case 1: desc->format = "B9B21WWzW"; break;
2883 case 2: desc->format = "z"; break;
2884 case 3: desc->format = "zzzWWzzzWW"; break;
2885 default: return False;
2887 if (strcmp(desc->format,id) != 0) return False;
2888 return True;
2891 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
2892 struct pack_desc* desc)
2894 char buf[100];
2895 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
2896 buf[sizeof(buf)-1] = 0;
2897 strupper(buf);
2898 if (uLevel <= 1) {
2899 PACKS(desc,"B9",buf); /* szName */
2900 if (uLevel == 1) {
2901 PACKS(desc,"B21",""); /* szUserName */
2902 PACKI(desc,"W",0); /* uJobId */
2903 PACKI(desc,"W",0); /* fsStatus */
2904 PACKS(desc,"z",""); /* pszStatus */
2905 PACKI(desc,"W",0); /* time */
2908 if (uLevel == 2 || uLevel == 3) {
2909 PACKS(desc,"z",buf); /* pszPrinterName */
2910 if (uLevel == 3) {
2911 PACKS(desc,"z",""); /* pszUserName */
2912 PACKS(desc,"z",""); /* pszLogAddr */
2913 PACKI(desc,"W",0); /* uJobId */
2914 PACKI(desc,"W",0); /* fsStatus */
2915 PACKS(desc,"z",""); /* pszStatus */
2916 PACKS(desc,"z",""); /* pszComment */
2917 PACKS(desc,"z","NULL"); /* pszDrivers */
2918 PACKI(desc,"W",0); /* time */
2919 PACKI(desc,"W",0); /* pad1 */
2924 static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2925 int mdrcnt,int mprcnt,
2926 char **rdata,char **rparam,
2927 int *rdata_len,int *rparam_len)
2929 char *str1 = param+2;
2930 char *str2 = skip_string(str1,1);
2931 char *p = skip_string(str2,1);
2932 char* PrinterName = p;
2933 int uLevel;
2934 struct pack_desc desc;
2935 int snum;
2937 memset((char *)&desc,'\0',sizeof(desc));
2939 p = skip_string(p,1);
2940 uLevel = SVAL(p,0);
2942 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
2944 /* check it's a supported varient */
2945 if (strcmp(str1,"zWrLh") != 0) return False;
2946 if (!check_printdest_info(&desc,uLevel,str2)) return False;
2948 snum = lp_servicenumber(PrinterName);
2949 if (snum < 0 && pcap_printername_ok(PrinterName,NULL)) {
2950 int pnum = lp_servicenumber(PRINTERS_NAME);
2951 if (pnum >= 0) {
2952 lp_add_printer(PrinterName,pnum);
2953 snum = lp_servicenumber(PrinterName);
2957 if (snum < 0) {
2958 *rdata_len = 0;
2959 desc.errcode = NERR_DestNotFound;
2960 desc.neededlen = 0;
2962 else {
2963 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2964 desc.base = *rdata;
2965 desc.buflen = mdrcnt;
2966 if (init_package(&desc,1,0)) {
2967 fill_printdest_info(conn,snum,uLevel,&desc);
2969 *rdata_len = desc.usedlen;
2972 *rparam_len = 6;
2973 *rparam = REALLOC(*rparam,*rparam_len);
2974 SSVALS(*rparam,0,desc.errcode);
2975 SSVAL(*rparam,2,0);
2976 SSVAL(*rparam,4,desc.neededlen);
2978 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
2979 return(True);
2982 static BOOL api_WPrintDestEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
2983 int mdrcnt,int mprcnt,
2984 char **rdata,char **rparam,
2985 int *rdata_len,int *rparam_len)
2987 char *str1 = param+2;
2988 char *str2 = skip_string(str1,1);
2989 char *p = skip_string(str2,1);
2990 int uLevel;
2991 int queuecnt;
2992 int i, n, succnt=0;
2993 struct pack_desc desc;
2994 int services = lp_numservices();
2996 memset((char *)&desc,'\0',sizeof(desc));
2998 uLevel = SVAL(p,0);
3000 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
3002 /* check it's a supported varient */
3003 if (strcmp(str1,"WrLeh") != 0) return False;
3004 if (!check_printdest_info(&desc,uLevel,str2)) return False;
3006 queuecnt = 0;
3007 for (i = 0; i < services; i++)
3008 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
3009 queuecnt++;
3011 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3012 desc.base = *rdata;
3013 desc.buflen = mdrcnt;
3014 if (init_package(&desc,queuecnt,0)) {
3015 succnt = 0;
3016 n = 0;
3017 for (i = 0; i < services; i++) {
3018 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3019 fill_printdest_info(conn,i,uLevel,&desc);
3020 n++;
3021 if (desc.errcode == NERR_Success) succnt = n;
3026 *rdata_len = desc.usedlen;
3028 *rparam_len = 8;
3029 *rparam = REALLOC(*rparam,*rparam_len);
3030 SSVALS(*rparam,0,desc.errcode);
3031 SSVAL(*rparam,2,0);
3032 SSVAL(*rparam,4,succnt);
3033 SSVAL(*rparam,6,queuecnt);
3035 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
3036 return(True);
3039 static BOOL api_WPrintDriverEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3040 int mdrcnt,int mprcnt,
3041 char **rdata,char **rparam,
3042 int *rdata_len,int *rparam_len)
3044 char *str1 = param+2;
3045 char *str2 = skip_string(str1,1);
3046 char *p = skip_string(str2,1);
3047 int uLevel;
3048 int succnt;
3049 struct pack_desc desc;
3051 memset((char *)&desc,'\0',sizeof(desc));
3053 uLevel = SVAL(p,0);
3055 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
3057 /* check it's a supported varient */
3058 if (strcmp(str1,"WrLeh") != 0) return False;
3059 if (uLevel != 0 || strcmp(str2,"B41") != 0) return False;
3061 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3062 desc.base = *rdata;
3063 desc.buflen = mdrcnt;
3064 if (init_package(&desc,1,0)) {
3065 PACKS(&desc,"B41","NULL");
3068 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3070 *rdata_len = desc.usedlen;
3072 *rparam_len = 8;
3073 *rparam = REALLOC(*rparam,*rparam_len);
3074 SSVALS(*rparam,0,desc.errcode);
3075 SSVAL(*rparam,2,0);
3076 SSVAL(*rparam,4,succnt);
3077 SSVAL(*rparam,6,1);
3079 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
3080 return(True);
3083 static BOOL api_WPrintQProcEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3084 int mdrcnt,int mprcnt,
3085 char **rdata,char **rparam,
3086 int *rdata_len,int *rparam_len)
3088 char *str1 = param+2;
3089 char *str2 = skip_string(str1,1);
3090 char *p = skip_string(str2,1);
3091 int uLevel;
3092 int succnt;
3093 struct pack_desc desc;
3095 memset((char *)&desc,'\0',sizeof(desc));
3097 uLevel = SVAL(p,0);
3099 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
3101 /* check it's a supported varient */
3102 if (strcmp(str1,"WrLeh") != 0) return False;
3103 if (uLevel != 0 || strcmp(str2,"B13") != 0) return False;
3105 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3106 desc.base = *rdata;
3107 desc.buflen = mdrcnt;
3108 desc.format = str2;
3109 if (init_package(&desc,1,0)) {
3110 PACKS(&desc,"B13","lpd");
3113 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3115 *rdata_len = desc.usedlen;
3117 *rparam_len = 8;
3118 *rparam = REALLOC(*rparam,*rparam_len);
3119 SSVALS(*rparam,0,desc.errcode);
3120 SSVAL(*rparam,2,0);
3121 SSVAL(*rparam,4,succnt);
3122 SSVAL(*rparam,6,1);
3124 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
3125 return(True);
3128 static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3129 int mdrcnt,int mprcnt,
3130 char **rdata,char **rparam,
3131 int *rdata_len,int *rparam_len)
3133 char *str1 = param+2;
3134 char *str2 = skip_string(str1,1);
3135 char *p = skip_string(str2,1);
3136 int uLevel;
3137 int succnt;
3138 struct pack_desc desc;
3140 memset((char *)&desc,'\0',sizeof(desc));
3142 uLevel = SVAL(p,0);
3144 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
3146 /* check it's a supported varient */
3147 if (strcmp(str1,"WrLeh") != 0) return False;
3148 if (uLevel != 0 || strcmp(str2,"B9") != 0) return False;
3150 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3151 memset((char *)&desc,'\0',sizeof(desc));
3152 desc.base = *rdata;
3153 desc.buflen = mdrcnt;
3154 desc.format = str2;
3155 if (init_package(&desc,1,0)) {
3156 PACKS(&desc,"B13","lp0");
3159 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3161 *rdata_len = desc.usedlen;
3163 *rparam_len = 8;
3164 *rparam = REALLOC(*rparam,*rparam_len);
3165 SSVALS(*rparam,0,desc.errcode);
3166 SSVAL(*rparam,2,0);
3167 SSVAL(*rparam,4,succnt);
3168 SSVAL(*rparam,6,1);
3170 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
3171 return(True);
3174 /****************************************************************************
3175 The buffer was too small
3176 ****************************************************************************/
3178 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
3179 int mdrcnt,int mprcnt,
3180 char **rdata,char **rparam,
3181 int *rdata_len,int *rparam_len)
3183 *rparam_len = MIN(*rparam_len,mprcnt);
3184 *rparam = REALLOC(*rparam,*rparam_len);
3186 *rdata_len = 0;
3188 SSVAL(*rparam,0,NERR_BufTooSmall);
3190 DEBUG(3,("Supplied buffer too small in API command\n"));
3192 return(True);
3196 /****************************************************************************
3197 The request is not supported
3198 ****************************************************************************/
3200 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
3201 int mdrcnt,int mprcnt,
3202 char **rdata,char **rparam,
3203 int *rdata_len,int *rparam_len)
3205 *rparam_len = 4;
3206 *rparam = REALLOC(*rparam,*rparam_len);
3208 *rdata_len = 0;
3210 SSVAL(*rparam,0,NERR_notsupported);
3211 SSVAL(*rparam,2,0); /* converter word */
3213 DEBUG(3,("Unsupported API command\n"));
3215 return(True);
3221 struct
3223 char *name;
3224 int id;
3225 BOOL (*fn)(connection_struct *,uint16,char *,char *,
3226 int,int,char **,char **,int *,int *);
3227 int flags;
3228 } api_commands[] = {
3229 {"RNetShareEnum", 0, api_RNetShareEnum,0},
3230 {"RNetShareGetInfo", 1, api_RNetShareGetInfo,0},
3231 {"RNetServerGetInfo", 13, api_RNetServerGetInfo,0},
3232 {"RNetGroupGetUsers", 52, api_RNetGroupGetUsers,0},
3233 {"RNetUserGetInfo", 56, api_RNetUserGetInfo,0},
3234 {"NetUserGetGroups", 59, api_NetUserGetGroups,0},
3235 {"NetWkstaGetInfo", 63, api_NetWkstaGetInfo,0},
3236 {"DosPrintQEnum", 69, api_DosPrintQEnum,0},
3237 {"DosPrintQGetInfo", 70, api_DosPrintQGetInfo,0},
3238 {"WPrintQueuePause", 74, api_WPrintQueueCtrl,0},
3239 {"WPrintQueueResume", 75, api_WPrintQueueCtrl,0},
3240 {"WPrintJobEnumerate",76, api_WPrintJobEnumerate,0},
3241 {"WPrintJobGetInfo", 77, api_WPrintJobGetInfo,0},
3242 {"RDosPrintJobDel", 81, api_RDosPrintJobDel,0},
3243 {"RDosPrintJobPause", 82, api_RDosPrintJobDel,0},
3244 {"RDosPrintJobResume",83, api_RDosPrintJobDel,0},
3245 {"WPrintDestEnum", 84, api_WPrintDestEnum,0},
3246 {"WPrintDestGetInfo", 85, api_WPrintDestGetInfo,0},
3247 {"NetRemoteTOD", 91, api_NetRemoteTOD,0},
3248 {"WPrintQueuePurge", 103, api_WPrintQueueCtrl,0},
3249 {"NetServerEnum", 104, api_RNetServerEnum,0},
3250 {"WAccessGetUserPerms",105, api_WAccessGetUserPerms,0},
3251 {"SetUserPassword", 115, api_SetUserPassword,0},
3252 {"WWkstaUserLogon", 132, api_WWkstaUserLogon,0},
3253 {"PrintJobInfo", 147, api_PrintJobInfo,0},
3254 {"WPrintDriverEnum", 205, api_WPrintDriverEnum,0},
3255 {"WPrintQProcEnum", 206, api_WPrintQProcEnum,0},
3256 {"WPrintPortEnum", 207, api_WPrintPortEnum,0},
3257 {"SamOEMChangePassword", 214, api_SamOEMChangePassword,0},
3258 {NULL, -1, api_Unsupported,0}};
3261 /****************************************************************************
3262 Handle remote api calls
3263 ****************************************************************************/
3265 int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *params,
3266 int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
3268 int api_command;
3269 char *rdata = NULL;
3270 char *rparam = NULL;
3271 int rdata_len = 0;
3272 int rparam_len = 0;
3273 BOOL reply=False;
3274 int i;
3276 if (!params) {
3277 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
3278 return 0;
3281 api_command = SVAL(params,0);
3283 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
3284 api_command,
3285 params+2,
3286 skip_string(params+2,1),
3287 tdscnt,tpscnt,mdrcnt,mprcnt));
3289 for (i=0;api_commands[i].name;i++) {
3290 if (api_commands[i].id == api_command && api_commands[i].fn) {
3291 DEBUG(3,("Doing %s\n",api_commands[i].name));
3292 break;
3296 rdata = (char *)malloc(1024);
3297 if (rdata)
3298 memset(rdata,'\0',1024);
3300 rparam = (char *)malloc(1024);
3301 if (rparam)
3302 memset(rparam,'\0',1024);
3304 if(!rdata || !rparam) {
3305 DEBUG(0,("api_reply: malloc fail !\n"));
3306 return -1;
3309 reply = api_commands[i].fn(conn,vuid,params,data,mdrcnt,mprcnt,
3310 &rdata,&rparam,&rdata_len,&rparam_len);
3313 if (rdata_len > mdrcnt ||
3314 rparam_len > mprcnt) {
3315 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
3316 &rdata,&rparam,&rdata_len,&rparam_len);
3319 /* if we get False back then it's actually unsupported */
3320 if (!reply)
3321 api_Unsupported(conn,vuid,params,data,mdrcnt,mprcnt,
3322 &rdata,&rparam,&rdata_len,&rparam_len);
3324 send_trans_reply(outbuf, rparam, rparam_len, rdata, rdata_len, False);
3326 if (rdata )
3327 free(rdata);
3328 if (rparam)
3329 free(rparam);
3331 return -1;
3335 #undef OLD_NTDOMAIN