s3/libsmb: adjust smb2 code for new idl structs & generated ndr push/pull funcs.
[samba.git] / source3 / libsmb / clirap2.c
1 /*
2    Samba Unix/Linux SMB client library
3    More client RAP (SMB Remote Procedure Calls) functions
4    Copyright (C) 2001 Steve French (sfrench@us.ibm.com)
5    Copyright (C) 2001 Jim McDonough (jmcd@us.ibm.com)
6    Copyright (C) 2007 Jeremy Allison. jra@samba.org
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 /*****************************************************/
23 /*                                                   */
24 /*   Additional RAP functionality                    */
25 /*                                                   */
26 /*   RAP is the original SMB RPC, documented         */
27 /*   by Microsoft and X/Open in the 1990s and        */
28 /*   supported by most SMB/CIFS servers although     */
29 /*   it is unlikely that any one implementation      */
30 /*   supports all RAP command codes since some       */
31 /*   are quite obsolete and a few are specific       */
32 /*   to a particular network operating system        */
33 /*                                                   */
34 /*   Although it has largely been replaced           */
35 /*   for complex remote admistration and management  */
36 /*   (of servers) by the relatively newer            */
37 /*   DCE/RPC based remote API (which better handles  */
38 /*   large >64K data structures), there are many     */
39 /*   important administrative and resource location  */
40 /*   tasks and user tasks (e.g. password change)     */
41 /*   that are performed via RAP.                     */
42 /*                                                   */
43 /*   Although a few of the RAP calls are implemented */
44 /*   in the Samba client library already (clirap.c)  */
45 /*   the new ones are in clirap2.c for easy patching */
46 /*   and integration and a corresponding header      */
47 /*   file, rap.h, has been created.                  */
48 /*                                                   */
49 /*   This is based on data from the CIFS spec        */
50 /*   and the LAN Server and LAN Manager              */
51 /*   Programming Reference books and published       */
52 /*   RAP document and CIFS forum postings and        */
53 /*   lots of trial and error                         */
54 /*                                                   */
55 /*   Function names changed from API_ (as they are   */
56 /*   in the CIFS specification) to RAP_ in order     */
57 /*   to avoid confusion with other API calls         */
58 /*   sent via DCE RPC                                */
59 /*                                                   */
60 /*****************************************************/
61
62 /*****************************************************/
63 /*                                                   */
64 /* cifsrap.c already includes support for:           */
65 /*                                                   */
66 /* WshareEnum ( API number 0, level 1)               */
67 /* NetServerEnum2 (API num 104, level 1)             */
68 /* WWkstaUserLogon (132)                             */
69 /* SamOEMchgPasswordUser2_P (214)                    */
70 /*                                                   */
71 /* cifsprint.c already includes support for:         */
72 /*                                                   */
73 /* WPrintJobEnum (API num 76, level 2)               */
74 /* WPrintJobDel  (API num 81)                        */
75 /*                                                   */
76 /*****************************************************/
77
78 #include "includes.h"
79 #include "libsmb/libsmb.h"
80 #include "../librpc/gen_ndr/rap.h"
81 #include "../librpc/gen_ndr/svcctl.h"
82 #include "libsmb/clirap.h"
83 #include "../libcli/smb/smbXcli_base.h"
84
85 #define WORDSIZE 2
86 #define DWORDSIZE 4
87
88 #define PUTBYTE(p,b) do {SCVAL(p,0,b); p++;} while(0)
89
90 #define GETBYTE(p,b,endp) \
91         do {\
92                 if (p+1 < endp) {\
93                         b = CVAL(p,0);\
94                 }\
95                 p++;\
96         } while(0)
97
98 #define PUTWORD(p,w) do {SSVAL(p,0,w); p += WORDSIZE;} while(0)
99
100 #define GETWORD(p,w,endp) \
101         do {\
102                 if (p+WORDSIZE < endp) {\
103                         w = SVAL(p,0);\
104                 }\
105                 p += WORDSIZE;\
106         } while(0)
107
108 #define PUTDWORD(p,d) do {SIVAL(p,0,d); p += DWORDSIZE;} while(0)
109
110 #define GETDWORD(p,d,endp) \
111         do {\
112                 if (p+DWORDSIZE < endp) {\
113                         d = IVAL(p,0);\
114                 }\
115                 p += DWORDSIZE;\
116         } while(0)
117
118 #define GETRES(p,endp) ((p && p+2 < endp) ? SVAL(p,0) : -1)
119
120 /* put string s at p with max len n and increment p past string */
121 #define PUTSTRING(p,s,n) \
122         do {\
123                 push_ascii(p,s?s:"",n?n:256,STR_TERMINATE);\
124                 p = push_skip_string(p);\
125         } while(0)
126
127 /* put string s and p, using fixed len l, and increment p by l */
128 #define PUTSTRINGF(p,s,l) \
129         do {\
130                 push_ascii(p,s?s:"",l,STR_TERMINATE);\
131                 p += l;\
132         } while (0)
133
134 /* put string pointer at p, supplying offset o from rdata r, store   */
135 /* dword offset at p, increment p by 4 and o by length of s.  This   */
136 /* means on the first call, you must calc the offset yourself!       */
137
138 #define PUTSTRINGP(p,s,r,o) \
139         do {\
140                 if (s) {\
141                         push_ascii(r+o,s,strlen(s)+1,STR_TERMINATE);\
142                         PUTDWORD(p,o);\
143                         o += strlen(s) + 1;\
144                 } else {\
145                         PUTDWORD(p,0);\
146                 }\
147         }while(0);
148
149 /* get asciiz string dest from src, return increment past string */
150
151 static size_t rap_getstring(TALLOC_CTX *ctx, char *src, char **dest, const char *endp)
152 {
153         char *p1;
154         size_t len;
155
156         *dest = NULL;
157         for (p1 = src, len = 0; *p1 && p1 < endp; len++)
158                 p1++;
159         if (!*p1) {
160                 len++;
161         }
162         pull_string_talloc(ctx,src,0,dest,src,len,STR_ASCII);
163         return len;
164 }
165
166 /* get fixed length l string dest from src, return increment for src */
167
168 static size_t rap_getstringf(char *src, char *dest, size_t l, size_t dlen, char *endp)
169 {
170         char *p1;
171         size_t len;
172
173         if (dlen) {
174                 dest[0] = '\0';
175         }
176         for (p1 = src, len = 0; *p1 && p1 < endp; len++) {
177                 p1++;
178         }
179         if (!*p1) {
180                 len++;
181         }
182         if (len > l) {
183                 len = l;
184         }
185         if (len) {
186                 pull_ascii(dest,src,len,len,STR_ASCII);
187         }
188         return l;
189 }
190
191 /* get string dest from offset (obtained at p) from rdata r - converter c */
192 static size_t rap_getstringp(TALLOC_CTX *ctx, char *p, char **dest, char *r, uint16_t c, char *endp)
193 {
194         uint32_t off = 0;
195         const char *src;
196         size_t len=0;
197
198         *dest = NULL;
199         if (p+4 < endp) {
200                 GETDWORD(p,off,endp);
201                 off &= 0x0000FFFF; /* mask the obsolete segment number from the offset */
202                 off -= c;
203         }
204         if (r+off > endp || r+off < r) {
205                 src="";
206                 len=1;
207         } else {
208                 const char *p1;
209                 src=r+off;
210                 for (p1 = src, len = 0; *p1 && p1 < endp; len++) {
211                         p1++;
212                 }
213                 if (!*p1) {
214                         len++;
215                 }
216         }
217         pull_string_talloc(ctx,src,0,dest,src,len,STR_ASCII);
218         return 4;
219 }
220
221 static char *make_header(char *param, uint16_t apinum, const char *reqfmt, const char *datafmt)
222 {
223         PUTWORD(param,apinum);
224         if (reqfmt)
225                 PUTSTRING(param,reqfmt,0);
226         else
227                 *param++ = (char) 0;
228
229         if (datafmt)
230                 PUTSTRING(param,datafmt,0);
231         else
232                 *param++ = (char) 0;
233
234         return param;
235 }
236
237 /****************************************************************************
238  call a NetGroupDelete - delete user group from remote server
239 ****************************************************************************/
240
241 int cli_NetGroupDelete(struct cli_state *cli, const char *group_name)
242 {
243         char *rparam = NULL;
244         char *rdata = NULL;
245         char *p;
246         unsigned int rdrcnt,rprcnt;
247         int res = -1;
248         char param[WORDSIZE                    /* api number    */
249             +sizeof(RAP_NetGroupDel_REQ) /* parm string   */
250             +1                           /* no ret string */
251             +RAP_GROUPNAME_LEN           /* group to del  */
252             +WORDSIZE];                  /* reserved word */
253
254         /* now send a SMBtrans command with api GroupDel */
255         p = make_header(param, RAP_WGroupDel, RAP_NetGroupDel_REQ, NULL);
256         PUTSTRING(p, group_name, RAP_GROUPNAME_LEN);
257         PUTWORD(p,0);  /* reserved word MBZ on input */
258
259         if (cli_api(cli,
260               param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
261               NULL, 0, 200,       /* data, length, maxlen */
262               &rparam, &rprcnt,   /* return params, length */
263               &rdata, &rdrcnt))   /* return data, length */
264         {
265                 char *endp = rparam + rprcnt;
266                 res = GETRES(rparam,endp);
267
268                 if (res == 0) {
269                         /* nothing to do */
270                 } else if ((res == 5) || (res == 65)) {
271                         DEBUG(1, ("Access Denied\n"));
272                 } else if (res == 2220) {
273                         DEBUG (1, ("Group does not exist\n"));
274                 } else {
275                         DEBUG(4,("NetGroupDelete res=%d\n", res));
276                 }
277         } else {
278                 res = -1;
279                 DEBUG(4,("NetGroupDelete failed\n"));
280         }
281
282         SAFE_FREE(rparam);
283         SAFE_FREE(rdata);
284
285         return res;
286 }
287
288 /****************************************************************************
289  call a NetGroupAdd - add user group to remote server
290 ****************************************************************************/
291
292 int cli_NetGroupAdd(struct cli_state *cli, struct rap_group_info_1 *grinfo)
293 {
294         char *rparam = NULL;
295         char *rdata = NULL;
296         char *p;
297         unsigned int rdrcnt,rprcnt;
298         int res = -1;
299         char param[WORDSIZE                    /* api number    */
300             +sizeof(RAP_NetGroupAdd_REQ) /* req string    */
301             +sizeof(RAP_GROUP_INFO_L1)   /* return string */
302             +WORDSIZE                    /* info level    */
303             +WORDSIZE];                  /* reserved word */
304
305         /* offset into data of free format strings.  Will be updated */
306         /* by PUTSTRINGP macro and end up with total data length.    */
307         int soffset = RAP_GROUPNAME_LEN + 1 + DWORDSIZE;
308         char *data;
309         size_t data_size;
310
311         /* Allocate data. */
312         data_size = MAX(soffset + strlen(grinfo->comment) + 1, 1024);
313
314         data = SMB_MALLOC_ARRAY(char, data_size);
315         if (!data) {
316                 DEBUG (1, ("Malloc fail\n"));
317                 return -1;
318         }
319
320         /* now send a SMBtrans command with api WGroupAdd */
321
322         p = make_header(param, RAP_WGroupAdd,
323                         RAP_NetGroupAdd_REQ, RAP_GROUP_INFO_L1);
324         PUTWORD(p, 1); /* info level */
325         PUTWORD(p, 0); /* reserved word 0 */
326
327         p = data;
328         PUTSTRINGF(p, (const char *)grinfo->group_name, RAP_GROUPNAME_LEN);
329         PUTBYTE(p, 0); /* pad byte 0 */
330         PUTSTRINGP(p, grinfo->comment, data, soffset);
331
332         if (cli_api(cli,
333               param, sizeof(param), 1024, /* Param, length, maxlen */
334               data, soffset, data_size, /* data, length, maxlen */
335               &rparam, &rprcnt,   /* return params, length */
336               &rdata, &rdrcnt))   /* return data, length */
337         {
338                 char *endp = rparam + rprcnt;
339                 res = GETRES(rparam, endp);
340
341                 if (res == 0) {
342                         /* nothing to do */
343                 } else if ((res == 5) || (res == 65)) {
344                         DEBUG(1, ("Access Denied\n"));
345                 } else if (res == 2223) {
346                         DEBUG (1, ("Group already exists\n"));
347                 } else {
348                         DEBUG(4,("NetGroupAdd res=%d\n", res));
349                 }
350         } else {
351                 res = -1;
352                 DEBUG(4,("NetGroupAdd failed\n"));
353         }
354
355         SAFE_FREE(data);
356         SAFE_FREE(rparam);
357         SAFE_FREE(rdata);
358
359         return res;
360 }
361
362 /****************************************************************************
363  Call a NetGroupEnum - try and list user groups on a different host.
364 ****************************************************************************/
365
366 int cli_RNetGroupEnum(struct cli_state *cli, void (*fn)(const char *, const char *, void *), void *state)
367 {
368         char param[WORDSIZE                     /* api number    */
369             +sizeof(RAP_NetGroupEnum_REQ) /* parm string   */
370             +sizeof(RAP_GROUP_INFO_L1)    /* return string */
371             +WORDSIZE                     /* info level    */
372             +WORDSIZE];                   /* buffer size   */
373         char *p;
374         char *rparam = NULL;
375         char *rdata = NULL;
376         unsigned int rprcnt, rdrcnt;
377         int res = -1;
378
379         memset(param, '\0', sizeof(param));
380         p = make_header(param, RAP_WGroupEnum,
381                   RAP_NetGroupEnum_REQ, RAP_GROUP_INFO_L1);
382         PUTWORD(p,1); /* Info level 1 */  /* add level 0 */
383         PUTWORD(p,0xFFE0); /* Return buffer size */
384
385         if (cli_api(cli,
386               param, PTR_DIFF(p,param),8,
387               NULL, 0, 0xFFE0 /* data area size */,
388               &rparam, &rprcnt,
389               &rdata, &rdrcnt)) {
390                 char *endp = rparam + rdrcnt;
391
392                 res = GETRES(rparam, endp);
393                 cli->rap_error = res;
394                 if(cli->rap_error == 234) {
395                         DEBUG(1,("Not all group names were returned (such as those longer than 21 characters)\n"));
396                 } else if (cli->rap_error != 0) {
397                         DEBUG(1,("NetGroupEnum gave error %d\n", cli->rap_error));
398                 }
399         }
400
401         if (!rdata) {
402                 DEBUG(4,("NetGroupEnum no data returned\n"));
403                 goto out;
404         }
405
406         if (res == 0 || res == ERRmoredata) {
407                 char *endp = rparam + rprcnt;
408                 int i, converter = 0, count = 0;
409                 TALLOC_CTX *frame = talloc_stackframe();
410
411                 p = rparam + WORDSIZE; /* skip result */
412                 GETWORD(p, converter, endp);
413                 GETWORD(p, count, endp);
414
415                 endp = rdata + rdrcnt;
416                 for (i=0,p=rdata; i<count && p < endp;i++) {
417                         char *comment = NULL;
418                         char groupname[RAP_GROUPNAME_LEN];
419
420                         p += rap_getstringf(p,
421                                         groupname,
422                                         RAP_GROUPNAME_LEN,
423                                         RAP_GROUPNAME_LEN,
424                                         endp);
425                         p++; /* pad byte */
426                         p += rap_getstringp(frame,
427                                         p,
428                                         &comment,
429                                         rdata,
430                                         converter,
431                                         endp);
432
433                         if (!comment || !groupname[0]) {
434                                 break;
435                         }
436
437                         fn(groupname, comment, cli);
438                 }
439                 TALLOC_FREE(frame);
440         } else {
441                 DEBUG(4,("NetGroupEnum res=%d\n", res));
442         }
443
444   out:
445
446         SAFE_FREE(rparam);
447         SAFE_FREE(rdata);
448
449         return res;
450 }
451
452 int cli_RNetGroupEnum0(struct cli_state *cli,
453                        void (*fn)(const char *, void *),
454                        void *state)
455 {
456         char param[WORDSIZE                     /* api number    */
457                 +sizeof(RAP_NetGroupEnum_REQ) /* parm string   */
458                 +sizeof(RAP_GROUP_INFO_L0)    /* return string */
459                 +WORDSIZE                     /* info level    */
460                 +WORDSIZE];                   /* buffer size   */
461         char *p;
462         char *rparam = NULL;
463         char *rdata = NULL;
464         unsigned int rprcnt, rdrcnt;
465         int res = -1;
466
467         memset(param, '\0', sizeof(param));
468         p = make_header(param, RAP_WGroupEnum,
469                 RAP_NetGroupEnum_REQ, RAP_GROUP_INFO_L0);
470         PUTWORD(p,0); /* Info level 0 */ /* Hmmm. I *very* much suspect this
471                                       is the resume count, at least
472                                       that's what smbd believes... */
473         PUTWORD(p,0xFFE0); /* Return buffer size */
474
475         if (cli_api(cli,
476                         param, PTR_DIFF(p,param),8,
477                         NULL, 0, 0xFFE0 /* data area size */,
478                         &rparam, &rprcnt,
479                         &rdata, &rdrcnt)) {
480                 char *endp = rparam+rprcnt;
481                 res = GETRES(rparam,endp);
482                 cli->rap_error = res;
483                 if(cli->rap_error == 234) {
484                         DEBUG(1,("Not all group names were returned (such as those longer than 21 characters)\n"));
485                 } else if (cli->rap_error != 0) {
486                         DEBUG(1,("NetGroupEnum gave error %d\n", cli->rap_error));
487                 }
488         }
489
490         if (!rdata) {
491                 DEBUG(4,("NetGroupEnum no data returned\n"));
492                 goto out;
493         }
494
495         if (res == 0 || res == ERRmoredata) {
496                 char *endp = rparam + rprcnt;
497                 int i, count = 0;
498
499                 p = rparam + WORDSIZE + WORDSIZE; /* skip result and converter */
500                 GETWORD(p, count, endp);
501
502                 endp = rdata + rdrcnt;
503                 for (i=0,p=rdata; i<count && p < endp;i++) {
504                         char groupname[RAP_GROUPNAME_LEN];
505
506                         p += rap_getstringf(p,
507                                         groupname,
508                                         RAP_GROUPNAME_LEN,
509                                         RAP_GROUPNAME_LEN,
510                                         endp);
511                         if (groupname[0]) {
512                                 fn(groupname, cli);
513                         }
514                 }
515         } else {
516                 DEBUG(4,("NetGroupEnum res=%d\n", res));
517         }
518
519   out:
520
521         SAFE_FREE(rparam);
522         SAFE_FREE(rdata);
523
524         return res;
525 }
526
527 int cli_NetGroupDelUser(struct cli_state * cli, const char *group_name, const char *user_name)
528 {
529         char *rparam = NULL;
530         char *rdata = NULL;
531         char *p;
532         unsigned int rdrcnt,rprcnt;
533         int res = -1;
534         char param[WORDSIZE                        /* api number    */
535                 +sizeof(RAP_NetGroupDelUser_REQ) /* parm string   */
536                 +1                               /* no ret string */
537                 +RAP_GROUPNAME_LEN               /* group name    */
538                 +RAP_USERNAME_LEN];              /* user to del   */
539
540         /* now send a SMBtrans command with api GroupMemberAdd */
541         p = make_header(param, RAP_WGroupDelUser, RAP_NetGroupDelUser_REQ, NULL);
542         PUTSTRING(p,group_name,RAP_GROUPNAME_LEN);
543         PUTSTRING(p,user_name,RAP_USERNAME_LEN);
544
545         if (cli_api(cli,
546                         param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
547                         NULL, 0, 200,       /* data, length, maxlen */
548                         &rparam, &rprcnt,   /* return params, length */
549                         &rdata, &rdrcnt))   /* return data, length */
550         {
551                 char *endp = rparam + rprcnt;
552                 res = GETRES(rparam,endp);
553
554                 switch(res) {
555                 case 0:
556                         break;
557                 case 5:
558                 case 65:
559                         DEBUG(1, ("Access Denied\n"));
560                         break;
561                 case 50:
562                         DEBUG(1, ("Not supported by server\n"));
563                         break;
564                 case 2220:
565                         DEBUG(1, ("Group does not exist\n"));
566                         break;
567                 case 2221:
568                         DEBUG(1, ("User does not exist\n"));
569                         break;
570                 case 2237:
571                         DEBUG(1, ("User is not in group\n"));
572                         break;
573                 default:
574                         DEBUG(4,("NetGroupDelUser res=%d\n", res));
575                 }
576         } else {
577                 res = -1;
578                 DEBUG(4,("NetGroupDelUser failed\n"));
579         }
580
581         SAFE_FREE(rparam);
582         SAFE_FREE(rdata);
583
584         return res;
585 }
586
587 int cli_NetGroupAddUser(struct cli_state * cli, const char *group_name, const char *user_name)
588 {
589         char *rparam = NULL;
590         char *rdata = NULL;
591         char *p;
592         unsigned int rdrcnt,rprcnt;
593         int res = -1;
594         char param[WORDSIZE                        /* api number    */
595                 +sizeof(RAP_NetGroupAddUser_REQ) /* parm string   */
596                 +1                               /* no ret string */
597                 +RAP_GROUPNAME_LEN               /* group name    */
598                 +RAP_USERNAME_LEN];              /* user to add   */
599
600         /* now send a SMBtrans command with api GroupMemberAdd */
601         p = make_header(param, RAP_WGroupAddUser, RAP_NetGroupAddUser_REQ, NULL);
602         PUTSTRING(p,group_name,RAP_GROUPNAME_LEN);
603         PUTSTRING(p,user_name,RAP_USERNAME_LEN);
604
605         if (cli_api(cli,
606                         param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
607                         NULL, 0, 200,       /* data, length, maxlen */
608                         &rparam, &rprcnt,   /* return params, length */
609                         &rdata, &rdrcnt))   /* return data, length */
610         {
611                 char *endp = rparam + rprcnt;
612                 res = GETRES(rparam,endp);
613
614                 switch(res) {
615                 case 0:
616                         break;
617                 case 5:
618                 case 65:
619                         DEBUG(1, ("Access Denied\n"));
620                         break;
621                 case 50:
622                         DEBUG(1, ("Not supported by server\n"));
623                         break;
624                 case 2220:
625                         DEBUG(1, ("Group does not exist\n"));
626                         break;
627                 case 2221:
628                         DEBUG(1, ("User does not exist\n"));
629                         break;
630                 default:
631                         DEBUG(4,("NetGroupAddUser res=%d\n", res));
632                 }
633         } else {
634                 res = -1;
635                 DEBUG(4,("NetGroupAddUser failed\n"));
636         }
637
638         SAFE_FREE(rparam);
639         SAFE_FREE(rdata);
640
641         return res;
642 }
643
644
645 int cli_NetGroupGetUsers(struct cli_state * cli, const char *group_name, void (*fn)(const char *, void *), void *state )
646 {
647         char *rparam = NULL;
648         char *rdata = NULL;
649         char *p;
650         unsigned int rdrcnt,rprcnt;
651         int res = -1;
652         char param[WORDSIZE                        /* api number    */
653                 +sizeof(RAP_NetGroupGetUsers_REQ)/* parm string   */
654                 +sizeof(RAP_GROUP_USERS_INFO_0)  /* return string */
655                 +RAP_GROUPNAME_LEN               /* group name    */
656                 +WORDSIZE                        /* info level    */
657                 +WORDSIZE];                      /* buffer size   */
658
659         /* now send a SMBtrans command with api GroupGetUsers */
660         p = make_header(param, RAP_WGroupGetUsers,
661                 RAP_NetGroupGetUsers_REQ, RAP_GROUP_USERS_INFO_0);
662         PUTSTRING(p,group_name,RAP_GROUPNAME_LEN-1);
663         PUTWORD(p,0); /* info level 0 */
664         PUTWORD(p,0xFFE0); /* return buffer size */
665
666         if (cli_api(cli,
667                         param, PTR_DIFF(p,param),PTR_DIFF(p,param),
668                         NULL, 0, CLI_BUFFER_SIZE,
669                         &rparam, &rprcnt,
670                         &rdata, &rdrcnt)) {
671                 char *endp = rparam + rprcnt;
672                 res = GETRES(rparam,endp);
673                 cli->rap_error = res;
674                 if (res != 0) {
675                         DEBUG(1,("NetGroupGetUsers gave error %d\n", res));
676                 }
677         }
678
679         if (!rdata) {
680                 DEBUG(4,("NetGroupGetUsers no data returned\n"));
681                 goto out;
682         }
683
684         if (res == 0 || res == ERRmoredata) {
685                 char *endp = rparam + rprcnt;
686                 int i, count = 0;
687                 char username[RAP_USERNAME_LEN];
688
689                 p = rparam + WORDSIZE + WORDSIZE;
690                 GETWORD(p, count, endp);
691
692                 endp = rdata + rdrcnt;
693                 for (i=0,p=rdata; i<count && p < endp; i++) {
694                         p += rap_getstringf(p,
695                                         username,
696                                         RAP_USERNAME_LEN,
697                                         RAP_USERNAME_LEN,
698                                         endp);
699                         if (username[0]) {
700                                 fn(username, state);
701                         }
702                 }
703         } else {
704                 DEBUG(4,("NetGroupGetUsers res=%d\n", res));
705         }
706
707   out:
708
709         SAFE_FREE(rdata);
710         SAFE_FREE(rparam);
711         return res;
712 }
713
714 int cli_NetUserGetGroups(struct cli_state * cli, const char *user_name, void (*fn)(const char *, void *), void *state )
715 {
716         char *rparam = NULL;
717         char *rdata = NULL;
718         char *p;
719         unsigned int rdrcnt,rprcnt;
720         int res = -1;
721         char param[WORDSIZE                        /* api number    */
722                 +sizeof(RAP_NetUserGetGroups_REQ)/* parm string   */
723                 +sizeof(RAP_GROUP_USERS_INFO_0)  /* return string */
724                 +RAP_USERNAME_LEN               /* user name    */
725                 +WORDSIZE                        /* info level    */
726                 +WORDSIZE];                      /* buffer size   */
727
728         /* now send a SMBtrans command with api GroupGetUsers */
729         p = make_header(param, RAP_WUserGetGroups,
730                 RAP_NetUserGetGroups_REQ, RAP_GROUP_USERS_INFO_0);
731         PUTSTRING(p,user_name,RAP_USERNAME_LEN-1);
732         PUTWORD(p,0); /* info level 0 */
733         PUTWORD(p,0xFFE0); /* return buffer size */
734
735         if (cli_api(cli,
736                         param, PTR_DIFF(p,param),PTR_DIFF(p,param),
737                         NULL, 0, CLI_BUFFER_SIZE,
738                         &rparam, &rprcnt,
739                         &rdata, &rdrcnt)) {
740                 char *endp = rparam + rprcnt;
741                 res = GETRES(rparam,endp);
742                 cli->rap_error = res;
743                 if (res != 0) {
744                         DEBUG(1,("NetUserGetGroups gave error %d\n", res));
745                 }
746         }
747
748         if (!rdata) {
749                 DEBUG(4,("NetUserGetGroups no data returned\n"));
750                 goto out;
751         }
752
753         if (res == 0 || res == ERRmoredata) {
754                 char *endp = rparam + rprcnt;
755                 int i, count = 0;
756                 char groupname[RAP_GROUPNAME_LEN];
757
758                 p = rparam + WORDSIZE + WORDSIZE;
759                 GETWORD(p, count, endp);
760
761                 endp = rdata + rdrcnt;
762                 for (i=0,p=rdata; i<count && p < endp; i++) {
763                         p += rap_getstringf(p,
764                                         groupname,
765                                         RAP_GROUPNAME_LEN,
766                                         RAP_GROUPNAME_LEN,
767                                         endp);
768                         if (groupname[0]) {
769                                 fn(groupname, state);
770                         }
771                 }
772         } else {
773                 DEBUG(4,("NetUserGetGroups res=%d\n", res));
774         }
775
776   out:
777
778         SAFE_FREE(rdata);
779         SAFE_FREE(rparam);
780         return res;
781 }
782
783 /****************************************************************************
784  Call a NetUserDelete - delete user from remote server.
785 ****************************************************************************/
786
787 int cli_NetUserDelete(struct cli_state *cli, const char * user_name )
788 {
789         char *rparam = NULL;
790         char *rdata = NULL;
791         char *p;
792         unsigned int rdrcnt,rprcnt;
793         int res = -1;
794         char param[WORDSIZE                    /* api number    */
795                 +sizeof(RAP_NetGroupDel_REQ) /* parm string   */
796                 +1                           /* no ret string */
797                 +RAP_USERNAME_LEN            /* user to del   */
798                 +WORDSIZE];                  /* reserved word */
799
800         /* now send a SMBtrans command with api UserDel */
801         p = make_header(param, RAP_WUserDel, RAP_NetGroupDel_REQ, NULL);
802         PUTSTRING(p, user_name, RAP_USERNAME_LEN);
803         PUTWORD(p,0);  /* reserved word MBZ on input */
804
805         if (cli_api(cli,
806                         param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
807                         NULL, 0, 200,       /* data, length, maxlen */
808                         &rparam, &rprcnt,   /* return params, length */
809                         &rdata, &rdrcnt))   /* return data, length */
810         {
811                 char *endp = rparam + rprcnt;
812                 res = GETRES(rparam,endp);
813
814                 if (res == 0) {
815                         /* nothing to do */
816                 } else if ((res == 5) || (res == 65)) {
817                         DEBUG(1, ("Access Denied\n"));
818                 } else if (res == 2221) {
819                         DEBUG (1, ("User does not exist\n"));
820                 } else {
821                         DEBUG(4,("NetUserDelete res=%d\n", res));
822                 }
823         } else {
824                 res = -1;
825                 DEBUG(4,("NetUserDelete failed\n"));
826         }
827
828         SAFE_FREE(rparam);
829         SAFE_FREE(rdata);
830
831         return res;
832 }
833
834 /****************************************************************************
835  Call a NetUserAdd - add user to remote server.
836 ****************************************************************************/
837
838 int cli_NetUserAdd(struct cli_state *cli, struct rap_user_info_1 * userinfo )
839 {
840         char *rparam = NULL;
841         char *rdata = NULL;
842         char *p;
843         unsigned int rdrcnt,rprcnt;
844         int res = -1;
845         char param[WORDSIZE                    /* api number    */
846                 +sizeof(RAP_NetUserAdd2_REQ) /* req string    */
847                 +sizeof(RAP_USER_INFO_L1)    /* data string   */
848                 +WORDSIZE                    /* info level    */
849                 +WORDSIZE                    /* buffer length */
850                 +WORDSIZE];                  /* reserved      */
851
852         char data[1024];
853                 /* offset into data of free format strings.  Will be updated */
854                 /* by PUTSTRINGP macro and end up with total data length.    */
855         int soffset=RAP_USERNAME_LEN+1 /* user name + pad */
856                 + RAP_UPASSWD_LEN            /* password        */
857                 + DWORDSIZE                  /* password age    */
858                 + WORDSIZE                   /* privilege       */
859                 + DWORDSIZE                  /* home dir ptr    */
860                 + DWORDSIZE                  /* comment ptr     */
861                 + WORDSIZE                   /* flags           */
862                 + DWORDSIZE;                 /* login script ptr*/
863
864         /* now send a SMBtrans command with api NetUserAdd */
865         p = make_header(param, RAP_WUserAdd2,
866                 RAP_NetUserAdd2_REQ, RAP_USER_INFO_L1);
867
868         PUTWORD(p, 1); /* info level */
869         PUTWORD(p, 0); /* pwencrypt */
870         PUTWORD(p, MIN(strlen((const char *)userinfo->passwrd),
871                        RAP_UPASSWD_LEN));
872
873         p = data;
874         memset(data, '\0', soffset);
875
876         PUTSTRINGF(p, (const char *)userinfo->user_name, RAP_USERNAME_LEN);
877         PUTBYTE(p, 0); /* pad byte 0 */
878         PUTSTRINGF(p, (const char *)userinfo->passwrd, RAP_UPASSWD_LEN);
879         PUTDWORD(p, 0); /* pw age - n.a. on user add */
880         PUTWORD(p, userinfo->priv);
881         PUTSTRINGP(p, userinfo->home_dir, data, soffset);
882         PUTSTRINGP(p, userinfo->comment, data, soffset);
883         PUTWORD(p, userinfo->userflags);
884         PUTSTRINGP(p, userinfo->logon_script, data, soffset);
885
886         if (cli_api(cli,
887                       param, sizeof(param), 1024, /* Param, length, maxlen */
888                       data, soffset, sizeof(data), /* data, length, maxlen */
889                       &rparam, &rprcnt,   /* return params, length */
890                       &rdata, &rdrcnt))   /* return data, length */
891         {
892                 char *endp = rparam + rprcnt;
893                 res = GETRES(rparam, endp);
894
895                 if (res == 0) {
896                         /* nothing to do */
897                 } else if ((res == 5) || (res == 65)) {
898                         DEBUG(1, ("Access Denied\n"));
899                 } else if (res == 2224) {
900                         DEBUG (1, ("User already exists\n"));
901                 } else {
902                         DEBUG(4,("NetUserAdd res=%d\n", res));
903                 }
904         } else {
905                 res = -1;
906                 DEBUG(4,("NetUserAdd failed\n"));
907         }
908
909         SAFE_FREE(rparam);
910         SAFE_FREE(rdata);
911
912         return res;
913 }
914
915 /****************************************************************************
916 call a NetUserEnum - try and list users on a different host
917 ****************************************************************************/
918
919 int cli_RNetUserEnum(struct cli_state *cli, void (*fn)(const char *, const char *, const char *, const char *, void *), void *state)
920 {
921         char param[WORDSIZE                 /* api number    */
922                 +sizeof(RAP_NetUserEnum_REQ) /* parm string   */
923                 +sizeof(RAP_USER_INFO_L1)    /* return string */
924                 +WORDSIZE                 /* info level    */
925                 +WORDSIZE];               /* buffer size   */
926         char *p;
927         char *rparam = NULL;
928         char *rdata = NULL;
929         unsigned int rprcnt, rdrcnt;
930         int res = -1;
931
932         memset(param, '\0', sizeof(param));
933         p = make_header(param, RAP_WUserEnum,
934                 RAP_NetUserEnum_REQ, RAP_USER_INFO_L1);
935         PUTWORD(p,1); /* Info level 1 */
936         PUTWORD(p,0xFF00); /* Return buffer size */
937
938         /* BB Fix handling of large numbers of users to be returned */
939         if (cli_api(cli,
940                         param, PTR_DIFF(p,param),8,
941                         NULL, 0, CLI_BUFFER_SIZE,
942                         &rparam, &rprcnt,
943                         &rdata, &rdrcnt)) {
944                 char *endp = rparam + rprcnt;
945                 res = GETRES(rparam,endp);
946                 cli->rap_error = res;
947                 if (cli->rap_error != 0) {
948                         DEBUG(1,("NetUserEnum gave error %d\n", cli->rap_error));
949                 }
950         }
951
952         if (!rdata) {
953                 DEBUG(4,("NetUserEnum no data returned\n"));
954                 goto out;
955         }
956
957         if (res == 0 || res == ERRmoredata) {
958                 int i, converter = 0, count = 0;
959                 char username[RAP_USERNAME_LEN];
960                 char userpw[RAP_UPASSWD_LEN];
961                 char *endp = rparam + rprcnt;
962                 char *comment, *homedir, *logonscript;
963                 TALLOC_CTX *frame = talloc_stackframe();
964
965                 p = rparam + WORDSIZE; /* skip result */
966                 GETWORD(p, converter, endp);
967                 GETWORD(p, count, endp);
968
969                 endp = rdata + rdrcnt;
970                 for (i=0,p=rdata;i<count && p < endp;i++) {
971                         p += rap_getstringf(p,
972                                         username,
973                                         RAP_USERNAME_LEN,
974                                         RAP_USERNAME_LEN,
975                                         endp);
976                         p++; /* pad byte */
977                         p += rap_getstringf(p,
978                                         userpw,
979                                         RAP_UPASSWD_LEN,
980                                         RAP_UPASSWD_LEN,
981                                         endp);
982                         p += DWORDSIZE; /* skip password age */
983                         p += WORDSIZE;  /* skip priv: 0=guest, 1=user, 2=admin */
984                         p += rap_getstringp(frame,
985                                         p,
986                                         &homedir,
987                                         rdata,
988                                         converter,
989                                         endp);
990                         p += rap_getstringp(frame,
991                                         p,
992                                         &comment,
993                                         rdata,
994                                         converter,
995                                         endp);
996                         p += WORDSIZE;  /* skip flags */
997                         p += rap_getstringp(frame,
998                                         p,
999                                         &logonscript,
1000                                         rdata,
1001                                         converter,
1002                                         endp);
1003                         if (username[0] && comment &&
1004                                         homedir && logonscript) {
1005                                 fn(username,
1006                                         comment,
1007                                         homedir,
1008                                         logonscript,
1009                                         cli);
1010                         }
1011                 }
1012                 TALLOC_FREE(frame);
1013         } else {
1014                 DEBUG(4,("NetUserEnum res=%d\n", res));
1015         }
1016
1017   out:
1018
1019         SAFE_FREE(rparam);
1020         SAFE_FREE(rdata);
1021
1022         return res;
1023 }
1024
1025 int cli_RNetUserEnum0(struct cli_state *cli,
1026                       void (*fn)(const char *, void *),
1027                       void *state)
1028 {
1029         char param[WORDSIZE                 /* api number    */
1030                 +sizeof(RAP_NetUserEnum_REQ) /* parm string   */
1031                 +sizeof(RAP_USER_INFO_L0)    /* return string */
1032                 +WORDSIZE                 /* info level    */
1033                 +WORDSIZE];               /* buffer size   */
1034         char *p;
1035         char *rparam = NULL;
1036         char *rdata = NULL;
1037         unsigned int rprcnt, rdrcnt;
1038         int res = -1;
1039
1040         memset(param, '\0', sizeof(param));
1041         p = make_header(param, RAP_WUserEnum,
1042                 RAP_NetUserEnum_REQ, RAP_USER_INFO_L0);
1043         PUTWORD(p,0); /* Info level 1 */
1044         PUTWORD(p,0xFF00); /* Return buffer size */
1045
1046         /* BB Fix handling of large numbers of users to be returned */
1047         if (cli_api(cli,
1048                         param, PTR_DIFF(p,param),8,
1049                         NULL, 0, CLI_BUFFER_SIZE,
1050                         &rparam, &rprcnt,
1051                         &rdata, &rdrcnt)) {
1052                 char *endp = rparam + rprcnt;
1053                 res = GETRES(rparam,endp);
1054                 cli->rap_error = res;
1055                 if (cli->rap_error != 0) {
1056                         DEBUG(1,("NetUserEnum gave error %d\n", cli->rap_error));
1057                 }
1058         }
1059
1060         if (!rdata) {
1061                 DEBUG(4,("NetUserEnum no data returned\n"));
1062                 goto out;
1063         }
1064
1065         if (res == 0 || res == ERRmoredata) {
1066                 int i, count = 0;
1067                 char *endp = rparam + rprcnt;
1068                 char username[RAP_USERNAME_LEN];
1069
1070                 p = rparam + WORDSIZE + WORDSIZE; /* skip result and converter */
1071                 GETWORD(p, count, endp);
1072
1073                 endp = rdata + rdrcnt;
1074                 for (i=0,p=rdata;i<count && p < endp;i++) {
1075                         p += rap_getstringf(p,
1076                                         username,
1077                                         RAP_USERNAME_LEN,
1078                                         RAP_USERNAME_LEN,
1079                                         endp);
1080                         if (username[0]) {
1081                                 fn(username, cli);
1082                         }
1083                 }
1084         } else {
1085                 DEBUG(4,("NetUserEnum res=%d\n", res));
1086         }
1087
1088   out:
1089
1090         SAFE_FREE(rparam);
1091         SAFE_FREE(rdata);
1092
1093         return res;
1094 }
1095
1096 /****************************************************************************
1097  Call a NetFileClose2 - close open file on another session to server.
1098 ****************************************************************************/
1099
1100 int cli_NetFileClose(struct cli_state *cli, uint32_t file_id )
1101 {
1102         char *rparam = NULL;
1103         char *rdata = NULL;
1104         char *p;
1105         unsigned int rdrcnt,rprcnt;
1106         char param[WORDSIZE                    /* api number    */
1107                 +sizeof(RAP_WFileClose2_REQ) /* req string    */
1108                 +1                           /* no ret string */
1109                 +DWORDSIZE];                 /* file ID          */
1110         int res = -1;
1111
1112         /* now send a SMBtrans command with api RNetShareEnum */
1113         p = make_header(param, RAP_WFileClose2, RAP_WFileClose2_REQ, NULL);
1114         PUTDWORD(p, file_id);
1115
1116         if (cli_api(cli,
1117                         param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
1118                         NULL, 0, 200,       /* data, length, maxlen */
1119                         &rparam, &rprcnt,   /* return params, length */
1120                         &rdata, &rdrcnt))   /* return data, length */
1121         {
1122                 char *endp = rparam + rprcnt;
1123                 res = GETRES(rparam, endp);
1124
1125                 if (res == 0) {
1126                         /* nothing to do */
1127                 } else if (res == 2314){
1128                         DEBUG(1, ("NetFileClose2 - attempt to close non-existent file open instance\n"));
1129                 } else {
1130                         DEBUG(4,("NetFileClose2 res=%d\n", res));
1131                 }
1132         } else {
1133                 res = -1;
1134                 DEBUG(4,("NetFileClose2 failed\n"));
1135         }
1136
1137         SAFE_FREE(rparam);
1138         SAFE_FREE(rdata);
1139
1140         return res;
1141 }
1142
1143 /****************************************************************************
1144  Call a NetFileGetInfo - get information about server file opened from other
1145  workstation.
1146 ****************************************************************************/
1147
1148 int cli_NetFileGetInfo(struct cli_state *cli, uint32_t file_id, void (*fn)(const char *, const char *, uint16_t, uint16_t, uint32_t))
1149 {
1150         char *rparam = NULL;
1151         char *rdata = NULL;
1152         char *p;
1153         unsigned int rdrcnt,rprcnt;
1154         int res = -1;
1155         char param[WORDSIZE                      /* api number      */
1156                 +sizeof(RAP_WFileGetInfo2_REQ) /* req string      */
1157                 +sizeof(RAP_FILE_INFO_L3)      /* return string   */
1158                 +DWORDSIZE                     /* file ID          */
1159                 +WORDSIZE                      /* info level      */
1160                 +WORDSIZE];                    /* buffer size     */
1161
1162         /* now send a SMBtrans command with api RNetShareEnum */
1163         p = make_header(param, RAP_WFileGetInfo2,
1164                 RAP_WFileGetInfo2_REQ, RAP_FILE_INFO_L3);
1165         PUTDWORD(p, file_id);
1166         PUTWORD(p, 3);  /* info level */
1167         PUTWORD(p, 0x1000);   /* buffer size */
1168         if (cli_api(cli,
1169                         param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
1170                         NULL, 0, 0x1000,  /* data, length, maxlen */
1171                         &rparam, &rprcnt,               /* return params, length */
1172                         &rdata, &rdrcnt))               /* return data, length */
1173         {
1174                 char *endp = rparam + rprcnt;
1175                 res = GETRES(rparam,endp);
1176                 if (res == 0 || res == ERRmoredata) {
1177                         TALLOC_CTX *frame = talloc_stackframe();
1178                         int converter = 0,id = 0, perms = 0, locks = 0;
1179                         char *fpath, *fuser;
1180
1181                         p = rparam + WORDSIZE; /* skip result */
1182                         GETWORD(p, converter, endp);
1183
1184                         p = rdata;
1185                         endp = rdata + rdrcnt;
1186
1187                         GETDWORD(p, id, endp);
1188                         GETWORD(p, perms, endp);
1189                         GETWORD(p, locks, endp);
1190
1191                         p += rap_getstringp(frame,
1192                                         p,
1193                                         &fpath,
1194                                         rdata,
1195                                         converter,
1196                                         endp);
1197                         p += rap_getstringp(frame,
1198                                         p,
1199                                         &fuser,
1200                                         rdata,
1201                                         converter,
1202                                         endp);
1203
1204                         if (fpath && fuser) {
1205                                 fn(fpath, fuser, perms, locks, id);
1206                         }
1207
1208                         TALLOC_FREE(frame);
1209                 } else {
1210                         DEBUG(4,("NetFileGetInfo2 res=%d\n", res));
1211                 }
1212         } else {
1213                 res = -1;
1214                 DEBUG(4,("NetFileGetInfo2 failed\n"));
1215         }
1216
1217         SAFE_FREE(rparam);
1218         SAFE_FREE(rdata);
1219
1220         return res;
1221 }
1222
1223 /****************************************************************************
1224 * Call a NetFileEnum2 - list open files on an SMB server
1225 *
1226 * PURPOSE:  Remotes a NetFileEnum API call to the current server or target
1227 *           server listing the files open via the network (and their
1228 *           corresponding open instance ids)
1229 *
1230 * Dependencies: none
1231 *
1232 * Parameters:
1233 *             cli    - pointer to cli_state structure
1234 *             user   - if present, return only files opened by this remote user
1235 *             base_path - if present, return only files opened below this
1236 *                         base path
1237 *             fn     - display function to invoke for each entry in the result
1238 *
1239 *
1240 * Returns:
1241 *             True      - success
1242 *             False     - failure
1243 *
1244 ****************************************************************************/
1245
1246 int cli_NetFileEnum(struct cli_state *cli, const char * user,
1247                     const char * base_path,
1248                     void (*fn)(const char *, const char *, uint16_t, uint16_t,
1249                                uint32_t))
1250 {
1251         char *rparam = NULL;
1252         char *rdata = NULL;
1253         char *p;
1254         unsigned int rdrcnt,rprcnt;
1255         char param[WORDSIZE                   /* api number      */
1256                 +sizeof(RAP_WFileEnum2_REQ) /* req string      */
1257                 +sizeof(RAP_FILE_INFO_L3)   /* return string   */
1258                 +1024                        /* base path (opt) */
1259                 +RAP_USERNAME_LEN           /* user name (opt) */
1260                 +WORDSIZE                   /* info level      */
1261                 +WORDSIZE                   /* buffer size     */
1262                 +DWORDSIZE                  /* resume key ?    */
1263                 +DWORDSIZE];                /* resume key ?    */
1264         int count = -1;
1265         int res = -1;
1266
1267         /* now send a SMBtrans command with api RNetShareEnum */
1268         p = make_header(param, RAP_WFileEnum2,
1269                 RAP_WFileEnum2_REQ, RAP_FILE_INFO_L3);
1270
1271         PUTSTRING(p, base_path, 1024);
1272         PUTSTRING(p, user, RAP_USERNAME_LEN);
1273         PUTWORD(p, 3); /* info level */
1274         PUTWORD(p, 0xFF00);  /* buffer size */
1275         PUTDWORD(p, 0);  /* zero out the resume key */
1276         PUTDWORD(p, 0);  /* or is this one the resume key? */
1277
1278         if (cli_api(cli,
1279                         param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
1280                         NULL, 0, 0xFF00,  /* data, length, maxlen */
1281                         &rparam, &rprcnt,               /* return params, length */
1282                         &rdata, &rdrcnt))               /* return data, length */
1283         {
1284                 char *endp = rparam + rprcnt;
1285                 res = GETRES(rparam, endp);
1286
1287                 if (res == 0 || res == ERRmoredata) {
1288                         TALLOC_CTX *frame = talloc_stackframe();
1289                         int converter = 0, i;
1290
1291                         p = rparam + WORDSIZE; /* skip result */
1292                         GETWORD(p, converter, endp);
1293                         GETWORD(p, count, endp);
1294
1295                         p = rdata;
1296                         endp = rdata + rdrcnt;
1297                         for (i=0; i<count && p < endp; i++) {
1298                                 int id = 0, perms = 0, locks = 0;
1299                                 char *fpath, *fuser;
1300
1301                                 GETDWORD(p, id, endp);
1302                                 GETWORD(p, perms, endp);
1303                                 GETWORD(p, locks, endp);
1304                                 p += rap_getstringp(frame,
1305                                         p,
1306                                         &fpath,
1307                                         rdata,
1308                                         converter,
1309                                         endp);
1310                                 p += rap_getstringp(frame,
1311                                         p,
1312                                         &fuser,
1313                                         rdata,
1314                                         converter,
1315                                         endp);
1316
1317                                 if (fpath && fuser) {
1318                                         fn(fpath, fuser, perms, locks, id);
1319                                 }
1320                         }  /* BB fix ERRmoredata case to send resume request */
1321                         TALLOC_FREE(frame);
1322                 } else {
1323                         DEBUG(4,("NetFileEnum2 res=%d\n", res));
1324                 }
1325         } else {
1326                 DEBUG(4,("NetFileEnum2 failed\n"));
1327         }
1328
1329         SAFE_FREE(rparam);
1330         SAFE_FREE(rdata);
1331
1332         return count;
1333 }
1334
1335 /****************************************************************************
1336  Call a NetShareAdd - share/export directory on remote server.
1337 ****************************************************************************/
1338
1339 int cli_NetShareAdd(struct cli_state *cli, struct rap_share_info_2 * sinfo )
1340 {
1341         char *rparam = NULL;
1342         char *rdata = NULL;
1343         char *p;
1344         unsigned int rdrcnt,rprcnt;
1345         int res = -1;
1346         char param[WORDSIZE                  /* api number    */
1347                 +sizeof(RAP_WShareAdd_REQ) /* req string    */
1348                 +sizeof(RAP_SHARE_INFO_L2) /* return string */
1349                 +WORDSIZE                  /* info level    */
1350                 +WORDSIZE];                /* reserved word */
1351         char data[1024];
1352         /* offset to free format string section following fixed length data.  */
1353         /* will be updated by PUTSTRINGP macro and will end up with total len */
1354         int soffset = RAP_SHARENAME_LEN + 1 /* share name + pad   */
1355                 + WORDSIZE                        /* share type    */
1356                 + DWORDSIZE                       /* comment pointer */
1357                 + WORDSIZE                        /* permissions */
1358                 + WORDSIZE                        /* max users */
1359                 + WORDSIZE                        /* active users */
1360                 + DWORDSIZE                       /* share path */
1361                 + RAP_SPASSWD_LEN + 1;            /* share password + pad */
1362
1363         memset(param,'\0',sizeof(param));
1364         /* now send a SMBtrans command with api RNetShareAdd */
1365         p = make_header(param, RAP_WshareAdd,
1366                 RAP_WShareAdd_REQ, RAP_SHARE_INFO_L2);
1367         PUTWORD(p, 2); /* info level */
1368         PUTWORD(p, 0); /* reserved word 0 */
1369
1370         p = data;
1371         PUTSTRINGF(p, (const char *)sinfo->share_name, RAP_SHARENAME_LEN);
1372         PUTBYTE(p, 0); /* pad byte 0 */
1373
1374         PUTWORD(p, sinfo->share_type);
1375         PUTSTRINGP(p, sinfo->comment, data, soffset);
1376         PUTWORD(p, sinfo->perms);
1377         PUTWORD(p, sinfo->maximum_users);
1378         PUTWORD(p, sinfo->active_users);
1379         PUTSTRINGP(p, sinfo->path, data, soffset);
1380         PUTSTRINGF(p, (const char *)sinfo->password, RAP_SPASSWD_LEN);
1381         SCVAL(p,-1,0x0A); /* required 0x0A at end of password */
1382
1383         if (cli_api(cli,
1384                         param, sizeof(param), 1024, /* Param, length, maxlen */
1385                         data, soffset, sizeof(data), /* data, length, maxlen */
1386                         &rparam, &rprcnt,   /* return params, length */
1387                         &rdata, &rdrcnt))   /* return data, length */
1388         {
1389                 char *endp = rparam + rprcnt;
1390                 res = GETRES(rparam, endp);
1391
1392                 if (res == 0) {
1393                         /* nothing to do */
1394                 } else {
1395                         DEBUG(4,("NetShareAdd res=%d\n", res));
1396                 }
1397         } else {
1398                 DEBUG(4,("NetShareAdd failed\n"));
1399         }
1400
1401         SAFE_FREE(rparam);
1402         SAFE_FREE(rdata);
1403
1404         return res;
1405 }
1406
1407 /****************************************************************************
1408  Call a NetShareDelete - unshare exported directory on remote server.
1409 ****************************************************************************/
1410
1411 int cli_NetShareDelete(struct cli_state *cli, const char * share_name )
1412 {
1413         char *rparam = NULL;
1414         char *rdata = NULL;
1415         char *p;
1416         unsigned int rdrcnt,rprcnt;
1417         int res = -1;
1418         char param[WORDSIZE                  /* api number    */
1419                 +sizeof(RAP_WShareDel_REQ) /* req string    */
1420                 +1                         /* no ret string */
1421                 +RAP_SHARENAME_LEN         /* share to del  */
1422                 +WORDSIZE];                /* reserved word */
1423
1424         /* now send a SMBtrans command with api RNetShareDelete */
1425         p = make_header(param, RAP_WshareDel, RAP_WShareDel_REQ, NULL);
1426         PUTSTRING(p,share_name,RAP_SHARENAME_LEN);
1427         PUTWORD(p,0);  /* reserved word MBZ on input */
1428
1429         if (cli_api(cli,
1430                         param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
1431                         NULL, 0, 200,       /* data, length, maxlen */
1432                         &rparam, &rprcnt,   /* return params, length */
1433                         &rdata, &rdrcnt))   /* return data, length */
1434         {
1435                 char *endp = rparam + rprcnt;
1436                 res = GETRES(rparam, endp);
1437
1438                 if (res == 0) {
1439                         /* nothing to do */
1440                 } else {
1441                         DEBUG(4,("NetShareDelete res=%d\n", res));
1442                 }
1443         } else {
1444                 DEBUG(4,("NetShareDelete failed\n"));
1445         }
1446
1447         SAFE_FREE(rparam);
1448         SAFE_FREE(rdata);
1449
1450         return res;
1451 }
1452
1453 /*************************************************************************
1454 *
1455 * Function Name:  cli_get_pdc_name
1456 *
1457 * PURPOSE:  Remotes a NetServerEnum API call to the current server
1458 *           requesting the name of a server matching the server
1459 *           type of SV_TYPE_DOMAIN_CTRL (PDC).
1460 *
1461 * Dependencies: none
1462 *
1463 * Parameters:
1464 *             cli       - pointer to cli_state structure
1465 *             workgroup - pointer to string containing name of domain
1466 *             pdc_name  - pointer to string that will contain PDC name
1467 *                         on successful return
1468 *
1469 * Returns:
1470 *             True      - success
1471 *             False     - failure
1472 *
1473 ************************************************************************/
1474
1475 bool cli_get_pdc_name(struct cli_state *cli, const char *workgroup, char **pdc_name)
1476 {
1477         char *rparam = NULL;
1478         char *rdata = NULL;
1479         unsigned int rdrcnt,rprcnt;
1480         char *p;
1481         char param[WORDSIZE                       /* api number    */
1482                 +sizeof(RAP_NetServerEnum2_REQ) /* req string    */
1483                 +sizeof(RAP_SERVER_INFO_L1)     /* return string */
1484                 +WORDSIZE                       /* info level    */
1485                 +WORDSIZE                       /* buffer size   */
1486                 +DWORDSIZE                      /* server type   */
1487                 +RAP_MACHNAME_LEN];             /* workgroup     */
1488         int count = -1;
1489         int res = -1;
1490
1491         *pdc_name = NULL;
1492
1493         /* send a SMBtrans command with api NetServerEnum */
1494         p = make_header(param, RAP_NetServerEnum2,
1495                 RAP_NetServerEnum2_REQ, RAP_SERVER_INFO_L1);
1496         PUTWORD(p, 1); /* info level */
1497         PUTWORD(p, CLI_BUFFER_SIZE);
1498         PUTDWORD(p, SV_TYPE_DOMAIN_CTRL);
1499         PUTSTRING(p, workgroup, RAP_MACHNAME_LEN);
1500
1501         if (cli_api(cli,
1502                         param, PTR_DIFF(p,param), 8,        /* params, length, max */
1503                         NULL, 0, CLI_BUFFER_SIZE,               /* data, length, max */
1504                         &rparam, &rprcnt,                   /* return params, return size */
1505                         &rdata, &rdrcnt                     /* return data, return size */
1506                         )) {
1507
1508                 char *endp = rparam + rprcnt;
1509                 res = GETRES(rparam, endp);
1510                 cli->rap_error = res;
1511
1512                 /*
1513                  * We only really care to copy a name if the
1514                  * API succeeded and we got back a name.
1515                  */
1516                 if (cli->rap_error == 0) {
1517                         p = rparam + WORDSIZE + WORDSIZE; /* skip result and converter */
1518                         GETWORD(p, count, endp);
1519                         p = rdata;
1520                         endp = rdata + rdrcnt;
1521
1522                         if (count > 0) {
1523                                 TALLOC_CTX *frame = talloc_stackframe();
1524                                 char *dcname;
1525                                 p += rap_getstring(frame,
1526                                         p,
1527                                         &dcname,
1528                                         endp);
1529                                 if (dcname) {
1530                                         *pdc_name = SMB_STRDUP(dcname);
1531                                 }
1532                                 TALLOC_FREE(frame);
1533                         }
1534                 } else {
1535                         DEBUG(4, ("cli_get_pdc_name: machine %s failed the "
1536                                   "NetServerEnum call. Error was : %s.\n",
1537                                   smbXcli_conn_remote_name(cli->conn),
1538                                   win_errstr(W_ERROR(cli->rap_error))));
1539                 }
1540         }
1541
1542         SAFE_FREE(rparam);
1543         SAFE_FREE(rdata);
1544
1545         return(count > 0);
1546 }
1547
1548 bool cli_get_server_name(TALLOC_CTX *mem_ctx, struct cli_state *cli,
1549                          char **servername)
1550 {
1551         char *rparam = NULL;
1552         char *rdata = NULL;
1553         unsigned int rdrcnt,rprcnt;
1554         char *p;
1555         char param[WORDSIZE                       /* api number    */
1556                    +sizeof(RAP_WserverGetInfo_REQ) /* req string    */
1557                    +sizeof(RAP_SERVER_INFO_L1)     /* return string */
1558                    +WORDSIZE                       /* info level    */
1559                    +WORDSIZE];                     /* buffer size   */
1560         bool res = false;
1561         char *endp;
1562         fstring tmp;
1563
1564         /* send a SMBtrans command with api NetServerGetInfo */
1565         p = make_header(param, RAP_WserverGetInfo,
1566                         RAP_WserverGetInfo_REQ, RAP_SERVER_INFO_L1);
1567         PUTWORD(p, 1); /* info level */
1568         PUTWORD(p, CLI_BUFFER_SIZE);
1569
1570         if (!cli_api(cli,
1571                      param, PTR_DIFF(p,param), 8, /* params, length, max */
1572                      NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
1573                      &rparam, &rprcnt,         /* return params, return size */
1574                      &rdata, &rdrcnt           /* return data, return size */
1575                     )) {
1576                 goto failed;
1577         }
1578
1579         endp = rparam + rprcnt;
1580         if (GETRES(rparam, endp) != 0) {
1581                 goto failed;
1582         }
1583
1584         if (rdrcnt < 16) {
1585                 DEBUG(10, ("invalid data count %d, expected >= 16\n", rdrcnt));
1586                 goto failed;
1587         }
1588
1589         if (pull_ascii(tmp, rdata, sizeof(tmp)-1, 16, STR_TERMINATE) == -1) {
1590                 DEBUG(10, ("pull_ascii failed\n"));
1591                 goto failed;
1592         }
1593
1594         if (!(*servername = talloc_strdup(mem_ctx, tmp))) {
1595                 DEBUG(1, ("talloc_strdup failed\n"));
1596                 goto failed;
1597         }
1598
1599         res = true;
1600
1601  failed:
1602         SAFE_FREE(rparam);
1603         SAFE_FREE(rdata);
1604         return res;
1605 }
1606
1607 /*************************************************************************
1608 *
1609 * Function Name:  cli_ns_check_server_type
1610 *
1611 * PURPOSE:  Remotes a NetServerEnum2 API call to the current server
1612 *           requesting server_info_0 level information of machines
1613 *           matching the given server type. If the returned server
1614 *           list contains the machine name contained in smbXcli_conn_remote_name(->conn)
1615 *           then we conclude the server type checks out. This routine
1616 *           is useful to retrieve list of server's of a certain
1617 *           type when all you have is a null session connection and
1618 *           can't remote API calls such as NetWkstaGetInfo or
1619 *           NetServerGetInfo.
1620 *
1621 * Dependencies: none
1622 *
1623 * Parameters:
1624 *             cli       - pointer to cli_state structure
1625 *             workgroup - pointer to string containing domain
1626 *             stype     - server type
1627 *
1628 * Returns:
1629 *             True      - success
1630 *             False     - failure
1631 *
1632 ************************************************************************/
1633
1634 bool cli_ns_check_server_type(struct cli_state *cli, char *workgroup, uint32_t stype)
1635 {
1636         char *rparam = NULL;
1637         char *rdata = NULL;
1638         unsigned int rdrcnt,rprcnt;
1639         char *p;
1640         char param[WORDSIZE                       /* api number    */
1641                 +sizeof(RAP_NetServerEnum2_REQ) /* req string    */
1642                 +sizeof(RAP_SERVER_INFO_L0)     /* return string */
1643                 +WORDSIZE                       /* info level    */
1644                 +WORDSIZE                       /* buffer size   */
1645                 +DWORDSIZE                      /* server type   */
1646                 +RAP_MACHNAME_LEN];             /* workgroup     */
1647         bool found_server = false;
1648         int res = -1;
1649         const char *remote_name = smbXcli_conn_remote_name(cli->conn);
1650
1651         /* send a SMBtrans command with api NetServerEnum */
1652         p = make_header(param, RAP_NetServerEnum2,
1653                         RAP_NetServerEnum2_REQ, RAP_SERVER_INFO_L0);
1654         PUTWORD(p, 0); /* info level 0 */
1655         PUTWORD(p, CLI_BUFFER_SIZE);
1656         PUTDWORD(p, stype);
1657         PUTSTRING(p, workgroup, RAP_MACHNAME_LEN);
1658
1659         if (cli_api(cli,
1660                         param, PTR_DIFF(p,param), 8, /* params, length, max */
1661                         NULL, 0, CLI_BUFFER_SIZE,  /* data, length, max */
1662                         &rparam, &rprcnt,          /* return params, return size */
1663                         &rdata, &rdrcnt            /* return data, return size */
1664                         )) {
1665                 char *endp = rparam + rprcnt;
1666                 res = GETRES(rparam,endp);
1667                 cli->rap_error = res;
1668
1669                 if (res == 0 || res == ERRmoredata) {
1670                         int i, count = 0;
1671
1672                         p = rparam + WORDSIZE + WORDSIZE;
1673                         GETWORD(p, count,endp);
1674
1675                         p = rdata;
1676                         endp = rdata + rdrcnt;
1677                         for (i = 0;i < count && p < endp;i++, p += 16) {
1678                                 char ret_server[RAP_MACHNAME_LEN];
1679
1680                                 p += rap_getstringf(p,
1681                                                 ret_server,
1682                                                 RAP_MACHNAME_LEN,
1683                                                 RAP_MACHNAME_LEN,
1684                                                 endp);
1685                                 if (strequal(ret_server, remote_name)) {
1686                                         found_server = true;
1687                                         break;
1688                                 }
1689                         }
1690                 } else {
1691                         DEBUG(4, ("cli_ns_check_server_type: machine %s "
1692                                   "failed the NetServerEnum call. Error was : "
1693                                   "%s.\n", remote_name,
1694                                   win_errstr(W_ERROR(cli->rap_error))));
1695                 }
1696         }
1697
1698         SAFE_FREE(rparam);
1699         SAFE_FREE(rdata);
1700
1701         return found_server;
1702 }
1703
1704 /****************************************************************************
1705  Perform a NetWkstaUserLogoff.
1706 ****************************************************************************/
1707
1708 bool cli_NetWkstaUserLogoff(struct cli_state *cli, const char *user, const char *workstation)
1709 {
1710         char *rparam = NULL;
1711         char *rdata = NULL;
1712         char *p;
1713         unsigned int rdrcnt,rprcnt;
1714         char param[WORDSIZE                           /* api number    */
1715                         +sizeof(RAP_NetWkstaUserLogoff_REQ) /* req string    */
1716                         +sizeof(RAP_USER_LOGOFF_INFO_L1)    /* return string */
1717                         +RAP_USERNAME_LEN+1                 /* user name+pad */
1718                         +RAP_MACHNAME_LEN                   /* wksta name    */
1719                         +WORDSIZE                           /* buffer size   */
1720                         +WORDSIZE];                         /* buffer size?  */
1721         char upperbuf[MAX(RAP_USERNAME_LEN,RAP_MACHNAME_LEN)];
1722         int res = -1;
1723         char *tmp = NULL;
1724
1725         memset(param, 0, sizeof(param));
1726
1727         /* send a SMBtrans command with api NetWkstaUserLogoff */
1728         p = make_header(param, RAP_WWkstaUserLogoff,
1729                 RAP_NetWkstaUserLogoff_REQ, RAP_USER_LOGOFF_INFO_L1);
1730         PUTDWORD(p, 0); /* Null pointer */
1731         PUTDWORD(p, 0); /* Null pointer */
1732         strlcpy(upperbuf, user, sizeof(upperbuf));
1733         if (!strupper_m(upperbuf)) {
1734                 return false;
1735         }
1736         tmp = upperbuf;
1737         PUTSTRINGF(p, tmp, RAP_USERNAME_LEN);
1738         p++; /* strange format, but ok */
1739         strlcpy(upperbuf, workstation, sizeof(upperbuf));
1740         if (!strupper_m(upperbuf)) {
1741                 return false;
1742         }
1743         tmp = upperbuf;
1744         PUTSTRINGF(p, tmp, RAP_MACHNAME_LEN);
1745         PUTWORD(p, CLI_BUFFER_SIZE);
1746         PUTWORD(p, CLI_BUFFER_SIZE);
1747
1748         if (cli_api(cli,
1749                         param, PTR_DIFF(p,param),1024,  /* param, length, max */
1750                         NULL, 0, CLI_BUFFER_SIZE,       /* data, length, max */
1751                         &rparam, &rprcnt,               /* return params, return size */
1752                         &rdata, &rdrcnt                 /* return data, return size */
1753                         )) {
1754                 char *endp = rparam + rprcnt;
1755                 res = GETRES(rparam,endp);
1756                 cli->rap_error = res;
1757
1758                 if (cli->rap_error != 0) {
1759                         DEBUG(4,("NetwkstaUserLogoff gave error %d\n", cli->rap_error));
1760                 }
1761         }
1762
1763         SAFE_FREE(rparam);
1764         SAFE_FREE(rdata);
1765         return (cli->rap_error == 0);
1766 }
1767
1768 int cli_NetPrintQEnum(struct cli_state *cli,
1769                 void (*qfn)(const char*,uint16_t,uint16_t,uint16_t,const char*,const char*,const char*,const char*,const char*,uint16_t,uint16_t),
1770                 void (*jfn)(uint16_t,const char*,const char*,const char*,const char*,uint16_t,uint16_t,const char*,unsigned int,unsigned int,const char*))
1771 {
1772         char param[WORDSIZE                         /* api number    */
1773                 +sizeof(RAP_NetPrintQEnum_REQ)    /* req string    */
1774                 +sizeof(RAP_PRINTQ_INFO_L2)       /* return string */
1775                 +WORDSIZE                         /* info level    */
1776                 +WORDSIZE                         /* buffer size   */
1777                 +sizeof(RAP_SMB_PRINT_JOB_L1)];   /* more ret data */
1778         char *p;
1779         char *rparam = NULL;
1780         char *rdata = NULL;
1781         unsigned int rprcnt, rdrcnt;
1782         int res = -1;
1783
1784         memset(param, '\0',sizeof(param));
1785         p = make_header(param, RAP_WPrintQEnum,
1786                 RAP_NetPrintQEnum_REQ, RAP_PRINTQ_INFO_L2);
1787         PUTWORD(p,2); /* Info level 2 */
1788         PUTWORD(p,0xFFE0); /* Return buffer size */
1789         PUTSTRING(p, RAP_SMB_PRINT_JOB_L1, 0);
1790
1791         if (cli_api(cli,
1792                         param, PTR_DIFF(p,param),1024,
1793                         NULL, 0, CLI_BUFFER_SIZE,
1794                         &rparam, &rprcnt,
1795                         &rdata, &rdrcnt)) {
1796                 char *endp = rparam + rprcnt;
1797                 res = GETRES(rparam, endp);
1798                 cli->rap_error = res;
1799                 if (res != 0) {
1800                         DEBUG(1,("NetPrintQEnum gave error %d\n", res));
1801                 }
1802         }
1803
1804         if (!rdata) {
1805                 DEBUG(4,("NetPrintQEnum no data returned\n"));
1806                 goto out;
1807         }
1808
1809         if (res == 0 || res == ERRmoredata) {
1810                 TALLOC_CTX *frame = talloc_stackframe();
1811                 char *endp = rparam + rprcnt;
1812                 int i, converter = 0, count = 0;
1813
1814                 p = rparam + WORDSIZE;
1815                 GETWORD(p, converter, endp);
1816                 GETWORD(p, count, endp);
1817
1818                 p = rdata;
1819                 endp = rdata + rdrcnt;
1820                 for (i=0;i<count && p < endp;i++) {
1821                         char qname[RAP_SHARENAME_LEN];
1822                         char *sep_file, *print_proc, *dest, *parms, *comment;
1823                         uint16_t jobcount = 0, priority = 0;
1824                         uint16_t start_time = 0, until_time = 0, status = 0;
1825
1826                         p += rap_getstringf(p,
1827                                         qname,
1828                                         RAP_SHARENAME_LEN,
1829                                         RAP_SHARENAME_LEN,
1830                                         endp);
1831                         p++; /* pad */
1832                         GETWORD(p, priority, endp);
1833                         GETWORD(p, start_time, endp);
1834                         GETWORD(p, until_time, endp);
1835                         p += rap_getstringp(frame,
1836                                         p,
1837                                         &sep_file,
1838                                         rdata,
1839                                         converter,
1840                                         endp);
1841                         p += rap_getstringp(frame,
1842                                         p,
1843                                         &print_proc,
1844                                         rdata,
1845                                         converter,
1846                                         endp);
1847                         p += rap_getstringp(frame,
1848                                         p,
1849                                         &dest,
1850                                         rdata,
1851                                         converter,
1852                                         endp);
1853                         p += rap_getstringp(frame,
1854                                         p,
1855                                         &parms,
1856                                         rdata,
1857                                         converter,
1858                                         endp);
1859                         p += rap_getstringp(frame,
1860                                         p,
1861                                         &comment,
1862                                         rdata,
1863                                         converter,
1864                                         endp);
1865                         GETWORD(p, status, endp);
1866                         GETWORD(p, jobcount, endp);
1867
1868                         if (sep_file && print_proc && dest && parms &&
1869                                         comment) {
1870                                 qfn(qname, priority, start_time, until_time, sep_file, print_proc,
1871                                         dest, parms, comment, status, jobcount);
1872                         }
1873
1874                         if (jobcount) {
1875                                 int j;
1876                                 for (j=0;j<jobcount;j++) {
1877                                         uint16_t jid = 0, pos = 0, fsstatus = 0;
1878                                         char ownername[RAP_USERNAME_LEN];
1879                                         char notifyname[RAP_MACHNAME_LEN];
1880                                         char datatype[RAP_DATATYPE_LEN];
1881                                         char *jparms, *jstatus, *jcomment;
1882                                         unsigned int submitted = 0, jsize = 0;
1883
1884                                         GETWORD(p, jid, endp);
1885                                         p += rap_getstringf(p,
1886                                                         ownername,
1887                                                         RAP_USERNAME_LEN,
1888                                                         RAP_USERNAME_LEN,
1889                                                         endp);
1890                                         p++; /* pad byte */
1891                                         p += rap_getstringf(p,
1892                                                         notifyname,
1893                                                         RAP_MACHNAME_LEN,
1894                                                         RAP_MACHNAME_LEN,
1895                                                         endp);
1896                                         p += rap_getstringf(p,
1897                                                         datatype,
1898                                                         RAP_DATATYPE_LEN,
1899                                                         RAP_DATATYPE_LEN,
1900                                                         endp);
1901                                         p += rap_getstringp(frame,
1902                                                         p,
1903                                                         &jparms,
1904                                                         rdata,
1905                                                         converter,
1906                                                         endp);
1907                                         GETWORD(p, pos, endp);
1908                                         GETWORD(p, fsstatus, endp);
1909                                         p += rap_getstringp(frame,
1910                                                         p,
1911                                                         &jstatus,
1912                                                         rdata,
1913                                                         converter,
1914                                                         endp);
1915                                         GETDWORD(p, submitted, endp);
1916                                         GETDWORD(p, jsize, endp);
1917                                         p += rap_getstringp(frame,
1918                                                         p,
1919                                                         &jcomment,
1920                                                         rdata,
1921                                                         converter,
1922                                                         endp);
1923
1924                                         if (jparms && jstatus && jcomment) {
1925                                                 jfn(jid, ownername, notifyname, datatype, jparms, pos, fsstatus,
1926                                                         jstatus, submitted, jsize, jcomment);
1927                                         }
1928                                 }
1929                         }
1930                 }
1931                 TALLOC_FREE(frame);
1932         } else {
1933                 DEBUG(4,("NetPrintQEnum res=%d\n", res));
1934         }
1935
1936   out:
1937
1938         SAFE_FREE(rparam);
1939         SAFE_FREE(rdata);
1940
1941         return res;
1942 }
1943
1944 int cli_NetPrintQGetInfo(struct cli_state *cli, const char *printer,
1945         void (*qfn)(const char*,uint16_t,uint16_t,uint16_t,const char*,const char*,const char*,const char*,const char*,uint16_t,uint16_t),
1946         void (*jfn)(uint16_t,const char*,const char*,const char*,const char*,uint16_t,uint16_t,const char*,unsigned int,unsigned int,const char*))
1947 {
1948         char param[WORDSIZE                         /* api number    */
1949                 +sizeof(RAP_NetPrintQGetInfo_REQ) /* req string    */
1950                 +sizeof(RAP_PRINTQ_INFO_L2)       /* return string */
1951                 +RAP_SHARENAME_LEN                /* printer name  */
1952                 +WORDSIZE                         /* info level    */
1953                 +WORDSIZE                         /* buffer size   */
1954                 +sizeof(RAP_SMB_PRINT_JOB_L1)];   /* more ret data */
1955         char *p;
1956         char *rparam = NULL;
1957         char *rdata = NULL;
1958         unsigned int rprcnt, rdrcnt;
1959         int res = -1;
1960
1961         memset(param, '\0',sizeof(param));
1962         p = make_header(param, RAP_WPrintQGetInfo,
1963                 RAP_NetPrintQGetInfo_REQ, RAP_PRINTQ_INFO_L2);
1964         PUTSTRING(p, printer, RAP_SHARENAME_LEN-1);
1965         PUTWORD(p, 2);     /* Info level 2 */
1966         PUTWORD(p,0xFFE0); /* Return buffer size */
1967         PUTSTRING(p, RAP_SMB_PRINT_JOB_L1, 0);
1968
1969         if (cli_api(cli,
1970                         param, PTR_DIFF(p,param),1024,
1971                         NULL, 0, CLI_BUFFER_SIZE,
1972                         &rparam, &rprcnt,
1973                         &rdata, &rdrcnt)) {
1974                 char *endp = rparam + rprcnt;
1975                 res = GETRES(rparam, endp);
1976                 cli->rap_error = res;
1977                 if (res != 0) {
1978                         DEBUG(1,("NetPrintQGetInfo gave error %d\n", res));
1979                 }
1980         }
1981
1982         if (!rdata) {
1983                 DEBUG(4,("NetPrintQGetInfo no data returned\n"));
1984                 goto out;
1985         }
1986
1987         if (res == 0 || res == ERRmoredata) {
1988                 TALLOC_CTX *frame = talloc_stackframe();
1989                 char *endp = rparam + rprcnt;
1990                 int rsize = 0, converter = 0;
1991                 char qname[RAP_SHARENAME_LEN];
1992                 char *sep_file, *print_proc, *dest, *parms, *comment;
1993                 uint16_t jobcount = 0, priority = 0;
1994                 uint16_t start_time = 0, until_time = 0, status = 0;
1995
1996                 p = rparam + WORDSIZE;
1997                 GETWORD(p, converter, endp);
1998                 GETWORD(p, rsize, endp);
1999
2000                 p = rdata;
2001                 endp = rdata + rdrcnt;
2002                 p += rap_getstringf(p,
2003                                 qname,
2004                                 RAP_SHARENAME_LEN,
2005                                 RAP_SHARENAME_LEN,
2006                                 endp);
2007                 p++; /* pad */
2008                 GETWORD(p, priority, endp);
2009                 GETWORD(p, start_time, endp);
2010                 GETWORD(p, until_time, endp);
2011                 p += rap_getstringp(frame,
2012                                 p,
2013                                 &sep_file,
2014                                 rdata,
2015                                 converter,
2016                                 endp);
2017                 p += rap_getstringp(frame,
2018                                 p,
2019                                 &print_proc,
2020                                 rdata,
2021                                 converter,
2022                                 endp);
2023                 p += rap_getstringp(frame,
2024                                 p,
2025                                 &dest,
2026                                 rdata,
2027                                 converter,
2028                                 endp);
2029                 p += rap_getstringp(frame,
2030                                 p,
2031                                 &parms,
2032                                 rdata,
2033                                 converter,
2034                                 endp);
2035                 p += rap_getstringp(frame,
2036                                 p,
2037                                 &comment,
2038                                 rdata,
2039                                 converter,
2040                                 endp);
2041                 GETWORD(p, status, endp);
2042                 GETWORD(p, jobcount, endp);
2043
2044                 if (sep_file && print_proc && dest &&
2045                                 parms && comment) {
2046                         qfn(qname, priority, start_time, until_time, sep_file, print_proc,
2047                                 dest, parms, comment, status, jobcount);
2048                 }
2049                 if (jobcount) {
2050                         int j;
2051                         for (j=0;(j<jobcount)&&(PTR_DIFF(p,rdata)< rsize)&&
2052                                         p<endp;j++) {
2053                                 uint16_t jid = 0, pos = 0, fsstatus = 0;
2054                                 char ownername[RAP_USERNAME_LEN];
2055                                 char notifyname[RAP_MACHNAME_LEN];
2056                                 char datatype[RAP_DATATYPE_LEN];
2057                                 char *jparms, *jstatus, *jcomment;
2058                                 unsigned int submitted = 0, jsize = 0;
2059
2060                                 GETWORD(p, jid, endp);
2061                                 p += rap_getstringf(p,
2062                                                 ownername,
2063                                                 RAP_USERNAME_LEN,
2064                                                 RAP_USERNAME_LEN,
2065                                                 endp);
2066                                 p++; /* pad byte */
2067                                 p += rap_getstringf(p,
2068                                                 notifyname,
2069                                                 RAP_MACHNAME_LEN,
2070                                                 RAP_MACHNAME_LEN,
2071                                                 endp);
2072                                 p += rap_getstringf(p,
2073                                                 datatype,
2074                                                 RAP_DATATYPE_LEN,
2075                                                 RAP_DATATYPE_LEN,
2076                                                 endp);
2077                                 p += rap_getstringp(frame,
2078                                                 p,
2079                                                 &jparms,
2080                                                 rdata,
2081                                                 converter,
2082                                                 endp);
2083                                 GETWORD(p, pos,endp);
2084                                 GETWORD(p, fsstatus,endp);
2085                                 p += rap_getstringp(frame,
2086                                                 p,
2087                                                 &jstatus,
2088                                                 rdata,
2089                                                 converter,
2090                                                 endp);
2091                                 GETDWORD(p, submitted,endp);
2092                                 GETDWORD(p, jsize,endp);
2093                                 p += rap_getstringp(frame,
2094                                                 p,
2095                                                 &jcomment,
2096                                                 rdata,
2097                                                 converter,
2098                                                 endp);
2099
2100                                 if (jparms && jstatus && jcomment) {
2101                                         jfn(jid, ownername, notifyname, datatype, jparms, pos, fsstatus,
2102                                                 jstatus, submitted, jsize, jcomment);
2103                                 }
2104                         }
2105                 }
2106                 TALLOC_FREE(frame);
2107         } else {
2108                 DEBUG(4,("NetPrintQGetInfo res=%d\n", res));
2109         }
2110
2111   out:
2112
2113         SAFE_FREE(rparam);
2114         SAFE_FREE(rdata);
2115
2116         return res;
2117 }
2118
2119 /****************************************************************************
2120  Call a NetServiceEnum - list running services on a different host.
2121 ****************************************************************************/
2122
2123 int cli_RNetServiceEnum(struct cli_state *cli, void (*fn)(const char *, const char *, void *), void *state)
2124 {
2125         char param[WORDSIZE                     /* api number    */
2126                 +sizeof(RAP_NetServiceEnum_REQ) /* parm string   */
2127                 +sizeof(RAP_SERVICE_INFO_L2)    /* return string */
2128                 +WORDSIZE                     /* info level    */
2129                 +WORDSIZE];                   /* buffer size   */
2130         char *p;
2131         char *rparam = NULL;
2132         char *rdata = NULL;
2133         unsigned int rprcnt, rdrcnt;
2134         int res = -1;
2135
2136         memset(param, '\0', sizeof(param));
2137         p = make_header(param, RAP_WServiceEnum,
2138                 RAP_NetServiceEnum_REQ, RAP_SERVICE_INFO_L2);
2139         PUTWORD(p,2); /* Info level 2 */
2140         PUTWORD(p,0xFFE0); /* Return buffer size */
2141
2142         if (cli_api(cli,
2143                         param, PTR_DIFF(p,param),8,
2144                         NULL, 0, 0xFFE0 /* data area size */,
2145                         &rparam, &rprcnt,
2146                         &rdata, &rdrcnt)) {
2147                 char *endp = rparam + rprcnt;
2148                 res = GETRES(rparam, endp);
2149                 cli->rap_error = res;
2150                 if(cli->rap_error == 234) {
2151                         DEBUG(1,("Not all service names were returned (such as those longer than 15 characters)\n"));
2152                 } else if (cli->rap_error != 0) {
2153                         DEBUG(1,("NetServiceEnum gave error %d\n", cli->rap_error));
2154                 }
2155         }
2156
2157         if (!rdata) {
2158                 DEBUG(4,("NetServiceEnum no data returned\n"));
2159                 goto out;
2160         }
2161
2162         if (res == 0 || res == ERRmoredata) {
2163                 char *endp = rparam + rprcnt;
2164                 int i, count = 0;
2165
2166                 p = rparam + WORDSIZE + WORDSIZE; /* skip result and converter */
2167                 GETWORD(p, count,endp);
2168
2169                 endp = rdata + rdrcnt;
2170                 for (i=0,p=rdata;i<count && p < endp;i++) {
2171                         char comment[RAP_SRVCCMNT_LEN];
2172                         char servicename[RAP_SRVCNAME_LEN];
2173
2174                         p += rap_getstringf(p,
2175                                         servicename,
2176                                         RAP_SRVCNAME_LEN,
2177                                         RAP_SRVCNAME_LEN,
2178                                         endp);
2179                         p+=8; /* pass status words */
2180                         p += rap_getstringf(p,
2181                                         comment,
2182                                         RAP_SRVCCMNT_LEN,
2183                                         RAP_SRVCCMNT_LEN,
2184                                         endp);
2185
2186                         if (servicename[0]) {
2187                                 fn(servicename, comment, cli);  /* BB add status too */
2188                         }
2189                 }
2190         } else {
2191                 DEBUG(4,("NetServiceEnum res=%d\n", res));
2192         }
2193
2194   out:
2195
2196         SAFE_FREE(rparam);
2197         SAFE_FREE(rdata);
2198
2199         return res;
2200 }
2201
2202 /****************************************************************************
2203  Call a NetSessionEnum - list workstations with sessions to an SMB server.
2204 ****************************************************************************/
2205
2206 int cli_NetSessionEnum(struct cli_state *cli, void (*fn)(char *, char *, uint16_t, uint16_t, uint16_t, unsigned int, unsigned int, unsigned int, char *))
2207 {
2208         char param[WORDSIZE                       /* api number    */
2209                 +sizeof(RAP_NetSessionEnum_REQ) /* parm string   */
2210                 +sizeof(RAP_SESSION_INFO_L2)    /* return string */
2211                 +WORDSIZE                       /* info level    */
2212                 +WORDSIZE];                     /* buffer size   */
2213         char *p;
2214         char *rparam = NULL;
2215         char *rdata = NULL;
2216         unsigned int rprcnt, rdrcnt;
2217         int res = -1;
2218
2219         memset(param, '\0', sizeof(param));
2220         p = make_header(param, RAP_WsessionEnum,
2221                         RAP_NetSessionEnum_REQ, RAP_SESSION_INFO_L2);
2222         PUTWORD(p,2);    /* Info level 2 */
2223         PUTWORD(p,0xFF); /* Return buffer size */
2224
2225         if (cli_api(cli,
2226                         param, PTR_DIFF(p,param),8,
2227                         NULL, 0, CLI_BUFFER_SIZE,
2228                         &rparam, &rprcnt,
2229                         &rdata, &rdrcnt)) {
2230                 char *endp = rparam + rprcnt;
2231                 res = GETRES(rparam, endp);
2232                 cli->rap_error = res;
2233                 if (res != 0) {
2234                         DEBUG(1,("NetSessionEnum gave error %d\n", res));
2235                 }
2236         }
2237
2238         if (!rdata) {
2239                 DEBUG(4,("NetSesssionEnum no data returned\n"));
2240                 goto out;
2241         }
2242
2243         if (res == 0 || res == ERRmoredata) {
2244                 TALLOC_CTX *frame = talloc_stackframe();
2245                 char *endp = rparam + rprcnt;
2246                 int i, converter = 0, count = 0;
2247
2248                 p = rparam + WORDSIZE;
2249                 GETWORD(p, converter, endp);
2250                 GETWORD(p, count, endp);
2251
2252                 endp = rdata + rdrcnt;
2253                 for (i=0,p=rdata;i<count && p < endp;i++) {
2254                         char *wsname, *username, *clitype_name;
2255                         uint16_t num_conns = 0, num_opens = 0, num_users = 0;
2256                         unsigned int sess_time = 0, idle_time = 0, user_flags = 0;
2257
2258                         p += rap_getstringp(frame,
2259                                         p,
2260                                         &wsname,
2261                                         rdata,
2262                                         converter,
2263                                         endp);
2264                         p += rap_getstringp(frame,
2265                                         p,
2266                                         &username,
2267                                         rdata,
2268                                         converter,
2269                                         endp);
2270                         GETWORD(p, num_conns, endp);
2271                         GETWORD(p, num_opens, endp);
2272                         GETWORD(p, num_users, endp);
2273                         GETDWORD(p, sess_time, endp);
2274                         GETDWORD(p, idle_time, endp);
2275                         GETDWORD(p, user_flags, endp);
2276                         p += rap_getstringp(frame,
2277                                         p,
2278                                         &clitype_name,
2279                                         rdata,
2280                                         converter,
2281                                         endp);
2282
2283                         if (wsname && username && clitype_name) {
2284                                 fn(wsname, username, num_conns, num_opens, num_users, sess_time,
2285                                         idle_time, user_flags, clitype_name);
2286                         }
2287                 }
2288                 TALLOC_FREE(frame);
2289         } else {
2290                 DEBUG(4,("NetSessionEnum res=%d\n", res));
2291         }
2292
2293   out:
2294
2295         SAFE_FREE(rparam);
2296         SAFE_FREE(rdata);
2297
2298         return res;
2299 }
2300
2301 /****************************************************************************
2302  Call a NetSessionGetInfo - get information about other session to an SMB server.
2303 ****************************************************************************/
2304
2305 int cli_NetSessionGetInfo(struct cli_state *cli, const char *workstation,
2306                 void (*fn)(const char *, const char *, uint16_t, uint16_t, uint16_t, unsigned int, unsigned int, unsigned int, const char *))
2307 {
2308         char param[WORDSIZE                          /* api number    */
2309                 +sizeof(RAP_NetSessionGetInfo_REQ) /* req string    */
2310                 +sizeof(RAP_SESSION_INFO_L2)       /* return string */
2311                 +RAP_MACHNAME_LEN                  /* wksta name    */
2312                 +WORDSIZE                          /* info level    */
2313                 +WORDSIZE];                        /* buffer size   */
2314         char *p;
2315         char *rparam = NULL;
2316         char *rdata = NULL;
2317         unsigned int rprcnt, rdrcnt;
2318         char *endp;
2319         int res = -1;
2320
2321         memset(param, '\0', sizeof(param));
2322         p = make_header(param, RAP_WsessionGetInfo,
2323                         RAP_NetSessionGetInfo_REQ, RAP_SESSION_INFO_L2);
2324         PUTSTRING(p, workstation, RAP_MACHNAME_LEN-1);
2325         PUTWORD(p,2); /* Info level 2 */
2326         PUTWORD(p,0xFF); /* Return buffer size */
2327
2328         if (cli_api(cli,
2329                         param, PTR_DIFF(p,param),PTR_DIFF(p,param),
2330                         NULL, 0, CLI_BUFFER_SIZE,
2331                         &rparam, &rprcnt,
2332                         &rdata, &rdrcnt)) {
2333                 endp = rparam + rprcnt;
2334                 res = GETRES(rparam, endp);
2335                 cli->rap_error = res;
2336                 if (cli->rap_error != 0) {
2337                         DEBUG(1,("NetSessionGetInfo gave error %d\n", cli->rap_error));
2338                 }
2339         }
2340
2341         if (!rdata) {
2342                 DEBUG(4,("NetSessionGetInfo no data returned\n"));
2343                 goto out;
2344         }
2345
2346         endp = rparam + rprcnt;
2347         res = GETRES(rparam, endp);
2348
2349         if (res == 0 || res == ERRmoredata) {
2350                 TALLOC_CTX *frame = talloc_stackframe();
2351                 int converter = 0;
2352                 char *wsname, *username, *clitype_name;
2353                 uint16_t num_conns = 0, num_opens = 0, num_users = 0;
2354                 unsigned int sess_time = 0, idle_time = 0, user_flags = 0;
2355
2356                 p = rparam + WORDSIZE;
2357                 GETWORD(p, converter,endp);
2358                 p += WORDSIZE;            /* skip rsize */
2359
2360                 p = rdata;
2361                 endp = rdata + rdrcnt;
2362                 p += rap_getstringp(frame,
2363                                 p,
2364                                 &wsname,
2365                                 rdata,
2366                                 converter,
2367                                 endp);
2368                 p += rap_getstringp(frame,
2369                                 p,
2370                                 &username,
2371                                 rdata,
2372                                 converter,
2373                                 endp);
2374                 GETWORD(p, num_conns, endp);
2375                 GETWORD(p, num_opens, endp);
2376                 GETWORD(p, num_users, endp);
2377                 GETDWORD(p, sess_time, endp);
2378                 GETDWORD(p, idle_time, endp);
2379                 GETDWORD(p, user_flags, endp);
2380                 p += rap_getstringp(frame,
2381                                 p,
2382                                 &clitype_name,
2383                                 rdata,
2384                                 converter,
2385                                 endp);
2386
2387                 if (wsname && username && clitype_name) {
2388                         fn(wsname, username, num_conns, num_opens, num_users, sess_time,
2389                                 idle_time, user_flags, clitype_name);
2390                 }
2391                 TALLOC_FREE(frame);
2392         } else {
2393                 DEBUG(4,("NetSessionGetInfo res=%d\n", res));
2394         }
2395
2396   out:
2397
2398         SAFE_FREE(rparam);
2399         SAFE_FREE(rdata);
2400
2401         return res;
2402 }
2403
2404 /****************************************************************************
2405  Call a NetSessionDel - close a session to an SMB server.
2406 ****************************************************************************/
2407
2408 int cli_NetSessionDel(struct cli_state *cli, const char *workstation)
2409 {
2410         char param[WORDSIZE                      /* api number       */
2411                 +sizeof(RAP_NetSessionDel_REQ) /* req string       */
2412                 +1                             /* no return string */
2413                 +RAP_MACHNAME_LEN              /* workstation name */
2414                 +WORDSIZE];                    /* reserved (0)     */
2415         char *p;
2416         char *rparam = NULL;
2417         char *rdata = NULL;
2418         unsigned int rprcnt, rdrcnt;
2419         int res = -1;
2420
2421         memset(param, '\0', sizeof(param));
2422         p = make_header(param, RAP_WsessionDel, RAP_NetSessionDel_REQ, NULL);
2423         PUTSTRING(p, workstation, RAP_MACHNAME_LEN-1);
2424         PUTWORD(p,0); /* reserved word of 0 */
2425
2426         if (cli_api(cli,
2427                         param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
2428                         NULL, 0, 200,       /* data, length, maxlen */
2429                         &rparam, &rprcnt,   /* return params, length */
2430                         &rdata, &rdrcnt))   /* return data, length */
2431         {
2432                 char *endp = rparam + rprcnt;
2433                 res = GETRES(rparam, endp);
2434                 cli->rap_error = res;
2435
2436                 if (res == 0) {
2437                         /* nothing to do */
2438                 } else {
2439                         DEBUG(4,("NetFileClose2 res=%d\n", res));
2440                 }
2441         } else {
2442                 res = -1;
2443                 DEBUG(4,("NetFileClose2 failed\n"));
2444         }
2445
2446         SAFE_FREE(rparam);
2447         SAFE_FREE(rdata);
2448
2449         return res;
2450 }
2451
2452 int cli_NetConnectionEnum(struct cli_state *cli, const char *qualifier,
2453                         void (*fn)(uint16_t conid, uint16_t contype,
2454                                 uint16_t numopens, uint16_t numusers,
2455                                 uint32_t contime, const char *username,
2456                                 const char *netname))
2457 {
2458         char param[WORDSIZE                          /* api number    */
2459                 +sizeof(RAP_NetConnectionEnum_REQ) /* req string    */
2460                 +sizeof(RAP_CONNECTION_INFO_L1)    /* return string */
2461                 +RAP_MACHNAME_LEN                  /* wksta name    */
2462                 +WORDSIZE                          /* info level    */
2463                 +WORDSIZE];                        /* buffer size   */
2464         char *p;
2465         char *rparam = NULL;
2466         char *rdata = NULL;
2467         unsigned int rprcnt, rdrcnt;
2468         int res = -1;
2469
2470         memset(param, '\0', sizeof(param));
2471         p = make_header(param, RAP_WconnectionEnum,
2472                 RAP_NetConnectionEnum_REQ, RAP_CONNECTION_INFO_L1);
2473         PUTSTRING(p, qualifier, RAP_MACHNAME_LEN-1);/* Workstation name */
2474         PUTWORD(p,1);            /* Info level 1 */
2475         PUTWORD(p,0xFFE0);       /* Return buffer size */
2476
2477         if (cli_api(cli,
2478                         param, PTR_DIFF(p,param),PTR_DIFF(p,param),
2479                         NULL, 0, CLI_BUFFER_SIZE,
2480                         &rparam, &rprcnt,
2481                         &rdata, &rdrcnt)) {
2482                 char *endp = rparam + rprcnt;
2483                 res = GETRES(rparam, endp);
2484                 cli->rap_error = res;
2485                 if (res != 0) {
2486                         DEBUG(1,("NetConnectionEnum gave error %d\n", res));
2487                 }
2488         }
2489
2490         if (!rdata) {
2491                 DEBUG(4,("NetConnectionEnum no data returned\n"));
2492                 goto out;
2493         }
2494
2495         if (res == 0 || res == ERRmoredata) {
2496                 TALLOC_CTX *frame = talloc_stackframe();
2497                 char *endp = rparam + rprcnt;
2498                 int i, converter = 0, count = 0;
2499
2500                 p = rparam + WORDSIZE;
2501                 GETWORD(p, converter, endp);
2502                 GETWORD(p, count, endp);
2503
2504                 endp = rdata + rdrcnt;
2505                 for (i=0,p=rdata;i<count && p < endp;i++) {
2506                         char *netname, *username;
2507                         uint16_t conn_id = 0, conn_type = 0, num_opens = 0, num_users = 0;
2508                         unsigned int conn_time = 0;
2509
2510                         GETWORD(p,conn_id, endp);
2511                         GETWORD(p,conn_type, endp);
2512                         GETWORD(p,num_opens, endp);
2513                         GETWORD(p,num_users, endp);
2514                         GETDWORD(p,conn_time, endp);
2515                         p += rap_getstringp(frame,
2516                                         p,
2517                                         &username,
2518                                         rdata,
2519                                         converter,
2520                                         endp);
2521                         p += rap_getstringp(frame,
2522                                         p,
2523                                         &netname,
2524                                         rdata,
2525                                         converter,
2526                                         endp);
2527
2528                         if (username && netname) {
2529                                 fn(conn_id, conn_type, num_opens, num_users, conn_time,
2530                                         username, netname);
2531                         }
2532                 }
2533                 TALLOC_FREE(frame);
2534         } else {
2535                 DEBUG(4,("NetConnectionEnum res=%d\n", res));
2536         }
2537
2538   out:
2539
2540         SAFE_FREE(rdata);
2541         SAFE_FREE(rparam);
2542         return res;
2543 }