1333f468f47f9b10eef00cd6442a67ad8df070ab
[kai/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 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, sizeof(data), /* 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         if(userinfo->passwrd)
871                 PUTWORD(p,MIN(strlen((const char *)userinfo->passwrd), RAP_UPASSWD_LEN));
872         else
873                 PUTWORD(p, 0); /* password length */
874
875         p = data;
876         memset(data, '\0', soffset);
877
878         PUTSTRINGF(p, (const char *)userinfo->user_name, RAP_USERNAME_LEN);
879         PUTBYTE(p, 0); /* pad byte 0 */
880         PUTSTRINGF(p, (const char *)userinfo->passwrd, RAP_UPASSWD_LEN);
881         PUTDWORD(p, 0); /* pw age - n.a. on user add */
882         PUTWORD(p, userinfo->priv);
883         PUTSTRINGP(p, userinfo->home_dir, data, soffset);
884         PUTSTRINGP(p, userinfo->comment, data, soffset);
885         PUTWORD(p, userinfo->userflags);
886         PUTSTRINGP(p, userinfo->logon_script, data, soffset);
887
888         if (cli_api(cli,
889                       param, sizeof(param), 1024, /* Param, length, maxlen */
890                       data, soffset, sizeof(data), /* data, length, maxlen */
891                       &rparam, &rprcnt,   /* return params, length */
892                       &rdata, &rdrcnt))   /* return data, length */
893         {
894                 char *endp = rparam + rprcnt;
895                 res = GETRES(rparam, endp);
896
897                 if (res == 0) {
898                         /* nothing to do */
899                 } else if ((res == 5) || (res == 65)) {
900                         DEBUG(1, ("Access Denied\n"));
901                 } else if (res == 2224) {
902                         DEBUG (1, ("User already exists\n"));
903                 } else {
904                         DEBUG(4,("NetUserAdd res=%d\n", res));
905                 }
906         } else {
907                 res = -1;
908                 DEBUG(4,("NetUserAdd failed\n"));
909         }
910
911         SAFE_FREE(rparam);
912         SAFE_FREE(rdata);
913
914         return res;
915 }
916
917 /****************************************************************************
918 call a NetUserEnum - try and list users on a different host
919 ****************************************************************************/
920
921 int cli_RNetUserEnum(struct cli_state *cli, void (*fn)(const char *, const char *, const char *, const char *, void *), void *state)
922 {
923         char param[WORDSIZE                 /* api number    */
924                 +sizeof(RAP_NetUserEnum_REQ) /* parm string   */
925                 +sizeof(RAP_USER_INFO_L1)    /* return string */
926                 +WORDSIZE                 /* info level    */
927                 +WORDSIZE];               /* buffer size   */
928         char *p;
929         char *rparam = NULL;
930         char *rdata = NULL;
931         unsigned int rprcnt, rdrcnt;
932         int res = -1;
933
934         memset(param, '\0', sizeof(param));
935         p = make_header(param, RAP_WUserEnum,
936                 RAP_NetUserEnum_REQ, RAP_USER_INFO_L1);
937         PUTWORD(p,1); /* Info level 1 */
938         PUTWORD(p,0xFF00); /* Return buffer size */
939
940         /* BB Fix handling of large numbers of users to be returned */
941         if (cli_api(cli,
942                         param, PTR_DIFF(p,param),8,
943                         NULL, 0, CLI_BUFFER_SIZE,
944                         &rparam, &rprcnt,
945                         &rdata, &rdrcnt)) {
946                 char *endp = rparam + rprcnt;
947                 res = GETRES(rparam,endp);
948                 cli->rap_error = res;
949                 if (cli->rap_error != 0) {
950                         DEBUG(1,("NetUserEnum gave error %d\n", cli->rap_error));
951                 }
952         }
953
954         if (!rdata) {
955                 DEBUG(4,("NetUserEnum no data returned\n"));
956                 goto out;
957         }
958
959         if (res == 0 || res == ERRmoredata) {
960                 int i, converter = 0, count = 0;
961                 char username[RAP_USERNAME_LEN];
962                 char userpw[RAP_UPASSWD_LEN];
963                 char *endp = rparam + rprcnt;
964                 char *comment, *homedir, *logonscript;
965                 TALLOC_CTX *frame = talloc_stackframe();
966
967                 p = rparam + WORDSIZE; /* skip result */
968                 GETWORD(p, converter, endp);
969                 GETWORD(p, count, endp);
970
971                 endp = rdata + rdrcnt;
972                 for (i=0,p=rdata;i<count && p < endp;i++) {
973                         p += rap_getstringf(p,
974                                         username,
975                                         RAP_USERNAME_LEN,
976                                         RAP_USERNAME_LEN,
977                                         endp);
978                         p++; /* pad byte */
979                         p += rap_getstringf(p,
980                                         userpw,
981                                         RAP_UPASSWD_LEN,
982                                         RAP_UPASSWD_LEN,
983                                         endp);
984                         p += DWORDSIZE; /* skip password age */
985                         p += WORDSIZE;  /* skip priv: 0=guest, 1=user, 2=admin */
986                         p += rap_getstringp(frame,
987                                         p,
988                                         &homedir,
989                                         rdata,
990                                         converter,
991                                         endp);
992                         p += rap_getstringp(frame,
993                                         p,
994                                         &comment,
995                                         rdata,
996                                         converter,
997                                         endp);
998                         p += WORDSIZE;  /* skip flags */
999                         p += rap_getstringp(frame,
1000                                         p,
1001                                         &logonscript,
1002                                         rdata,
1003                                         converter,
1004                                         endp);
1005                         if (username[0] && comment &&
1006                                         homedir && logonscript) {
1007                                 fn(username,
1008                                         comment,
1009                                         homedir,
1010                                         logonscript,
1011                                         cli);
1012                         }
1013                 }
1014                 TALLOC_FREE(frame);
1015         } else {
1016                 DEBUG(4,("NetUserEnum res=%d\n", res));
1017         }
1018
1019   out:
1020
1021         SAFE_FREE(rparam);
1022         SAFE_FREE(rdata);
1023
1024         return res;
1025 }
1026
1027 int cli_RNetUserEnum0(struct cli_state *cli,
1028                       void (*fn)(const char *, void *),
1029                       void *state)
1030 {
1031         char param[WORDSIZE                 /* api number    */
1032                 +sizeof(RAP_NetUserEnum_REQ) /* parm string   */
1033                 +sizeof(RAP_USER_INFO_L0)    /* return string */
1034                 +WORDSIZE                 /* info level    */
1035                 +WORDSIZE];               /* buffer size   */
1036         char *p;
1037         char *rparam = NULL;
1038         char *rdata = NULL;
1039         unsigned int rprcnt, rdrcnt;
1040         int res = -1;
1041
1042         memset(param, '\0', sizeof(param));
1043         p = make_header(param, RAP_WUserEnum,
1044                 RAP_NetUserEnum_REQ, RAP_USER_INFO_L0);
1045         PUTWORD(p,0); /* Info level 1 */
1046         PUTWORD(p,0xFF00); /* Return buffer size */
1047
1048         /* BB Fix handling of large numbers of users to be returned */
1049         if (cli_api(cli,
1050                         param, PTR_DIFF(p,param),8,
1051                         NULL, 0, CLI_BUFFER_SIZE,
1052                         &rparam, &rprcnt,
1053                         &rdata, &rdrcnt)) {
1054                 char *endp = rparam + rprcnt;
1055                 res = GETRES(rparam,endp);
1056                 cli->rap_error = res;
1057                 if (cli->rap_error != 0) {
1058                         DEBUG(1,("NetUserEnum gave error %d\n", cli->rap_error));
1059                 }
1060         }
1061
1062         if (!rdata) {
1063                 DEBUG(4,("NetUserEnum no data returned\n"));
1064                 goto out;
1065         }
1066
1067         if (res == 0 || res == ERRmoredata) {
1068                 int i, count = 0;
1069                 char *endp = rparam + rprcnt;
1070                 char username[RAP_USERNAME_LEN];
1071
1072                 p = rparam + WORDSIZE + WORDSIZE; /* skip result and converter */
1073                 GETWORD(p, count, endp);
1074
1075                 endp = rdata + rdrcnt;
1076                 for (i=0,p=rdata;i<count && p < endp;i++) {
1077                         p += rap_getstringf(p,
1078                                         username,
1079                                         RAP_USERNAME_LEN,
1080                                         RAP_USERNAME_LEN,
1081                                         endp);
1082                         if (username[0]) {
1083                                 fn(username, cli);
1084                         }
1085                 }
1086         } else {
1087                 DEBUG(4,("NetUserEnum res=%d\n", res));
1088         }
1089
1090   out:
1091
1092         SAFE_FREE(rparam);
1093         SAFE_FREE(rdata);
1094
1095         return res;
1096 }
1097
1098 /****************************************************************************
1099  Call a NetFileClose2 - close open file on another session to server.
1100 ****************************************************************************/
1101
1102 int cli_NetFileClose(struct cli_state *cli, uint32 file_id )
1103 {
1104         char *rparam = NULL;
1105         char *rdata = NULL;
1106         char *p;
1107         unsigned int rdrcnt,rprcnt;
1108         char param[WORDSIZE                    /* api number    */
1109                 +sizeof(RAP_WFileClose2_REQ) /* req string    */
1110                 +1                           /* no ret string */
1111                 +DWORDSIZE];                 /* file ID          */
1112         int res = -1;
1113
1114         /* now send a SMBtrans command with api RNetShareEnum */
1115         p = make_header(param, RAP_WFileClose2, RAP_WFileClose2_REQ, NULL);
1116         PUTDWORD(p, file_id);
1117
1118         if (cli_api(cli,
1119                         param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
1120                         NULL, 0, 200,       /* data, length, maxlen */
1121                         &rparam, &rprcnt,   /* return params, length */
1122                         &rdata, &rdrcnt))   /* return data, length */
1123         {
1124                 char *endp = rparam + rprcnt;
1125                 res = GETRES(rparam, endp);
1126
1127                 if (res == 0) {
1128                         /* nothing to do */
1129                 } else if (res == 2314){
1130                         DEBUG(1, ("NetFileClose2 - attempt to close non-existent file open instance\n"));
1131                 } else {
1132                         DEBUG(4,("NetFileClose2 res=%d\n", res));
1133                 }
1134         } else {
1135                 res = -1;
1136                 DEBUG(4,("NetFileClose2 failed\n"));
1137         }
1138
1139         SAFE_FREE(rparam);
1140         SAFE_FREE(rdata);
1141
1142         return res;
1143 }
1144
1145 /****************************************************************************
1146  Call a NetFileGetInfo - get information about server file opened from other
1147  workstation.
1148 ****************************************************************************/
1149
1150 int cli_NetFileGetInfo(struct cli_state *cli, uint32 file_id, void (*fn)(const char *, const char *, uint16, uint16, uint32))
1151 {
1152         char *rparam = NULL;
1153         char *rdata = NULL;
1154         char *p;
1155         unsigned int rdrcnt,rprcnt;
1156         int res = -1;
1157         char param[WORDSIZE                      /* api number      */
1158                 +sizeof(RAP_WFileGetInfo2_REQ) /* req string      */
1159                 +sizeof(RAP_FILE_INFO_L3)      /* return string   */
1160                 +DWORDSIZE                     /* file ID          */
1161                 +WORDSIZE                      /* info level      */
1162                 +WORDSIZE];                    /* buffer size     */
1163
1164         /* now send a SMBtrans command with api RNetShareEnum */
1165         p = make_header(param, RAP_WFileGetInfo2,
1166                 RAP_WFileGetInfo2_REQ, RAP_FILE_INFO_L3);
1167         PUTDWORD(p, file_id);
1168         PUTWORD(p, 3);  /* info level */
1169         PUTWORD(p, 0x1000);   /* buffer size */
1170         if (cli_api(cli,
1171                         param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
1172                         NULL, 0, 0x1000,  /* data, length, maxlen */
1173                         &rparam, &rprcnt,               /* return params, length */
1174                         &rdata, &rdrcnt))               /* return data, length */
1175         {
1176                 char *endp = rparam + rprcnt;
1177                 res = GETRES(rparam,endp);
1178                 if (res == 0 || res == ERRmoredata) {
1179                         TALLOC_CTX *frame = talloc_stackframe();
1180                         int converter = 0,id = 0, perms = 0, locks = 0;
1181                         char *fpath, *fuser;
1182
1183                         p = rparam + WORDSIZE; /* skip result */
1184                         GETWORD(p, converter, endp);
1185
1186                         p = rdata;
1187                         endp = rdata + rdrcnt;
1188
1189                         GETDWORD(p, id, endp);
1190                         GETWORD(p, perms, endp);
1191                         GETWORD(p, locks, endp);
1192
1193                         p += rap_getstringp(frame,
1194                                         p,
1195                                         &fpath,
1196                                         rdata,
1197                                         converter,
1198                                         endp);
1199                         p += rap_getstringp(frame,
1200                                         p,
1201                                         &fuser,
1202                                         rdata,
1203                                         converter,
1204                                         endp);
1205
1206                         if (fpath && fuser) {
1207                                 fn(fpath, fuser, perms, locks, id);
1208                         }
1209
1210                         TALLOC_FREE(frame);
1211                 } else {
1212                         DEBUG(4,("NetFileGetInfo2 res=%d\n", res));
1213                 }
1214         } else {
1215                 res = -1;
1216                 DEBUG(4,("NetFileGetInfo2 failed\n"));
1217         }
1218
1219         SAFE_FREE(rparam);
1220         SAFE_FREE(rdata);
1221
1222         return res;
1223 }
1224
1225 /****************************************************************************
1226 * Call a NetFileEnum2 - list open files on an SMB server
1227 *
1228 * PURPOSE:  Remotes a NetFileEnum API call to the current server or target
1229 *           server listing the files open via the network (and their
1230 *           corresponding open instance ids)
1231 *
1232 * Dependencies: none
1233 *
1234 * Parameters:
1235 *             cli    - pointer to cli_state structure
1236 *             user   - if present, return only files opened by this remote user
1237 *             base_path - if present, return only files opened below this
1238 *                         base path
1239 *             fn     - display function to invoke for each entry in the result
1240 *
1241 *
1242 * Returns:
1243 *             True      - success
1244 *             False     - failure
1245 *
1246 ****************************************************************************/
1247
1248 int cli_NetFileEnum(struct cli_state *cli, const char * user,
1249                     const char * base_path,
1250                     void (*fn)(const char *, const char *, uint16, uint16,
1251                                uint32))
1252 {
1253         char *rparam = NULL;
1254         char *rdata = NULL;
1255         char *p;
1256         unsigned int rdrcnt,rprcnt;
1257         char param[WORDSIZE                   /* api number      */
1258                 +sizeof(RAP_WFileEnum2_REQ) /* req string      */
1259                 +sizeof(RAP_FILE_INFO_L3)   /* return string   */
1260                 +1024                        /* base path (opt) */
1261                 +RAP_USERNAME_LEN           /* user name (opt) */
1262                 +WORDSIZE                   /* info level      */
1263                 +WORDSIZE                   /* buffer size     */
1264                 +DWORDSIZE                  /* resume key ?    */
1265                 +DWORDSIZE];                /* resume key ?    */
1266         int count = -1;
1267         int res = -1;
1268
1269         /* now send a SMBtrans command with api RNetShareEnum */
1270         p = make_header(param, RAP_WFileEnum2,
1271                 RAP_WFileEnum2_REQ, RAP_FILE_INFO_L3);
1272
1273         PUTSTRING(p, base_path, 1024);
1274         PUTSTRING(p, user, RAP_USERNAME_LEN);
1275         PUTWORD(p, 3); /* info level */
1276         PUTWORD(p, 0xFF00);  /* buffer size */
1277         PUTDWORD(p, 0);  /* zero out the resume key */
1278         PUTDWORD(p, 0);  /* or is this one the resume key? */
1279
1280         if (cli_api(cli,
1281                         param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
1282                         NULL, 0, 0xFF00,  /* data, length, maxlen */
1283                         &rparam, &rprcnt,               /* return params, length */
1284                         &rdata, &rdrcnt))               /* return data, length */
1285         {
1286                 char *endp = rparam + rprcnt;
1287                 res = GETRES(rparam, endp);
1288
1289                 if (res == 0 || res == ERRmoredata) {
1290                         TALLOC_CTX *frame = talloc_stackframe();
1291                         int converter = 0, i;
1292
1293                         p = rparam + WORDSIZE; /* skip result */
1294                         GETWORD(p, converter, endp);
1295                         GETWORD(p, count, endp);
1296
1297                         p = rdata;
1298                         endp = rdata + rdrcnt;
1299                         for (i=0; i<count && p < endp; i++) {
1300                                 int id = 0, perms = 0, locks = 0;
1301                                 char *fpath, *fuser;
1302
1303                                 GETDWORD(p, id, endp);
1304                                 GETWORD(p, perms, endp);
1305                                 GETWORD(p, locks, endp);
1306                                 p += rap_getstringp(frame,
1307                                         p,
1308                                         &fpath,
1309                                         rdata,
1310                                         converter,
1311                                         endp);
1312                                 p += rap_getstringp(frame,
1313                                         p,
1314                                         &fuser,
1315                                         rdata,
1316                                         converter,
1317                                         endp);
1318
1319                                 if (fpath && fuser) {
1320                                         fn(fpath, fuser, perms, locks, id);
1321                                 }
1322                         }  /* BB fix ERRmoredata case to send resume request */
1323                         TALLOC_FREE(frame);
1324                 } else {
1325                         DEBUG(4,("NetFileEnum2 res=%d\n", res));
1326                 }
1327         } else {
1328                 DEBUG(4,("NetFileEnum2 failed\n"));
1329         }
1330
1331         SAFE_FREE(rparam);
1332         SAFE_FREE(rdata);
1333
1334         return count;
1335 }
1336
1337 /****************************************************************************
1338  Call a NetShareAdd - share/export directory on remote server.
1339 ****************************************************************************/
1340
1341 int cli_NetShareAdd(struct cli_state *cli, struct rap_share_info_2 * sinfo )
1342 {
1343         char *rparam = NULL;
1344         char *rdata = NULL;
1345         char *p;
1346         unsigned int rdrcnt,rprcnt;
1347         int res = -1;
1348         char param[WORDSIZE                  /* api number    */
1349                 +sizeof(RAP_WShareAdd_REQ) /* req string    */
1350                 +sizeof(RAP_SHARE_INFO_L2) /* return string */
1351                 +WORDSIZE                  /* info level    */
1352                 +WORDSIZE];                /* reserved word */
1353         char data[1024];
1354         /* offset to free format string section following fixed length data.  */
1355         /* will be updated by PUTSTRINGP macro and will end up with total len */
1356         int soffset = RAP_SHARENAME_LEN + 1 /* share name + pad   */
1357                 + WORDSIZE                        /* share type    */
1358                 + DWORDSIZE                       /* comment pointer */
1359                 + WORDSIZE                        /* permissions */
1360                 + WORDSIZE                        /* max users */
1361                 + WORDSIZE                        /* active users */
1362                 + DWORDSIZE                       /* share path */
1363                 + RAP_SPASSWD_LEN + 1;            /* share password + pad */
1364
1365         memset(param,'\0',sizeof(param));
1366         /* now send a SMBtrans command with api RNetShareAdd */
1367         p = make_header(param, RAP_WshareAdd,
1368                 RAP_WShareAdd_REQ, RAP_SHARE_INFO_L2);
1369         PUTWORD(p, 2); /* info level */
1370         PUTWORD(p, 0); /* reserved word 0 */
1371
1372         p = data;
1373         PUTSTRINGF(p, (const char *)sinfo->share_name, RAP_SHARENAME_LEN);
1374         PUTBYTE(p, 0); /* pad byte 0 */
1375
1376         PUTWORD(p, sinfo->share_type);
1377         PUTSTRINGP(p, sinfo->comment, data, soffset);
1378         PUTWORD(p, sinfo->perms);
1379         PUTWORD(p, sinfo->maximum_users);
1380         PUTWORD(p, sinfo->active_users);
1381         PUTSTRINGP(p, sinfo->path, data, soffset);
1382         PUTSTRINGF(p, (const char *)sinfo->password, RAP_SPASSWD_LEN);
1383         SCVAL(p,-1,0x0A); /* required 0x0A at end of password */
1384
1385         if (cli_api(cli,
1386                         param, sizeof(param), 1024, /* Param, length, maxlen */
1387                         data, soffset, sizeof(data), /* data, length, maxlen */
1388                         &rparam, &rprcnt,   /* return params, length */
1389                         &rdata, &rdrcnt))   /* return data, length */
1390         {
1391                 char *endp = rparam + rprcnt;
1392                 res = GETRES(rparam, endp);
1393
1394                 if (res == 0) {
1395                         /* nothing to do */
1396                 } else {
1397                         DEBUG(4,("NetShareAdd res=%d\n", res));
1398                 }
1399         } else {
1400                 DEBUG(4,("NetShareAdd failed\n"));
1401         }
1402
1403         SAFE_FREE(rparam);
1404         SAFE_FREE(rdata);
1405
1406         return res;
1407 }
1408
1409 /****************************************************************************
1410  Call a NetShareDelete - unshare exported directory on remote server.
1411 ****************************************************************************/
1412
1413 int cli_NetShareDelete(struct cli_state *cli, const char * share_name )
1414 {
1415         char *rparam = NULL;
1416         char *rdata = NULL;
1417         char *p;
1418         unsigned int rdrcnt,rprcnt;
1419         int res = -1;
1420         char param[WORDSIZE                  /* api number    */
1421                 +sizeof(RAP_WShareDel_REQ) /* req string    */
1422                 +1                         /* no ret string */
1423                 +RAP_SHARENAME_LEN         /* share to del  */
1424                 +WORDSIZE];                /* reserved word */
1425
1426         /* now send a SMBtrans command with api RNetShareDelete */
1427         p = make_header(param, RAP_WshareDel, RAP_WShareDel_REQ, NULL);
1428         PUTSTRING(p,share_name,RAP_SHARENAME_LEN);
1429         PUTWORD(p,0);  /* reserved word MBZ on input */
1430
1431         if (cli_api(cli,
1432                         param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
1433                         NULL, 0, 200,       /* data, length, maxlen */
1434                         &rparam, &rprcnt,   /* return params, length */
1435                         &rdata, &rdrcnt))   /* return data, length */
1436         {
1437                 char *endp = rparam + rprcnt;
1438                 res = GETRES(rparam, endp);
1439
1440                 if (res == 0) {
1441                         /* nothing to do */
1442                 } else {
1443                         DEBUG(4,("NetShareDelete res=%d\n", res));
1444                 }
1445         } else {
1446                 DEBUG(4,("NetShareDelete failed\n"));
1447         }
1448
1449         SAFE_FREE(rparam);
1450         SAFE_FREE(rdata);
1451
1452         return res;
1453 }
1454
1455 /*************************************************************************
1456 *
1457 * Function Name:  cli_get_pdc_name
1458 *
1459 * PURPOSE:  Remotes a NetServerEnum API call to the current server
1460 *           requesting the name of a server matching the server
1461 *           type of SV_TYPE_DOMAIN_CTRL (PDC).
1462 *
1463 * Dependencies: none
1464 *
1465 * Parameters:
1466 *             cli       - pointer to cli_state structure
1467 *             workgroup - pointer to string containing name of domain
1468 *             pdc_name  - pointer to string that will contain PDC name
1469 *                         on successful return
1470 *
1471 * Returns:
1472 *             True      - success
1473 *             False     - failure
1474 *
1475 ************************************************************************/
1476
1477 bool cli_get_pdc_name(struct cli_state *cli, const char *workgroup, char **pdc_name)
1478 {
1479         char *rparam = NULL;
1480         char *rdata = NULL;
1481         unsigned int rdrcnt,rprcnt;
1482         char *p;
1483         char param[WORDSIZE                       /* api number    */
1484                 +sizeof(RAP_NetServerEnum2_REQ) /* req string    */
1485                 +sizeof(RAP_SERVER_INFO_L1)     /* return string */
1486                 +WORDSIZE                       /* info level    */
1487                 +WORDSIZE                       /* buffer size   */
1488                 +DWORDSIZE                      /* server type   */
1489                 +RAP_MACHNAME_LEN];             /* workgroup     */
1490         int count = -1;
1491         int res = -1;
1492
1493         *pdc_name = NULL;
1494
1495         /* send a SMBtrans command with api NetServerEnum */
1496         p = make_header(param, RAP_NetServerEnum2,
1497                 RAP_NetServerEnum2_REQ, RAP_SERVER_INFO_L1);
1498         PUTWORD(p, 1); /* info level */
1499         PUTWORD(p, CLI_BUFFER_SIZE);
1500         PUTDWORD(p, SV_TYPE_DOMAIN_CTRL);
1501         PUTSTRING(p, workgroup, RAP_MACHNAME_LEN);
1502
1503         if (cli_api(cli,
1504                         param, PTR_DIFF(p,param), 8,        /* params, length, max */
1505                         NULL, 0, CLI_BUFFER_SIZE,               /* data, length, max */
1506                         &rparam, &rprcnt,                   /* return params, return size */
1507                         &rdata, &rdrcnt                     /* return data, return size */
1508                         )) {
1509
1510                 char *endp = rparam + rprcnt;
1511                 res = GETRES(rparam, endp);
1512                 cli->rap_error = res;
1513
1514                 /*
1515                  * We only really care to copy a name if the
1516                  * API succeeded and we got back a name.
1517                  */
1518                 if (cli->rap_error == 0) {
1519                         p = rparam + WORDSIZE + WORDSIZE; /* skip result and converter */
1520                         GETWORD(p, count, endp);
1521                         p = rdata;
1522                         endp = rdata + rdrcnt;
1523
1524                         if (count > 0) {
1525                                 TALLOC_CTX *frame = talloc_stackframe();
1526                                 char *dcname;
1527                                 p += rap_getstring(frame,
1528                                         p,
1529                                         &dcname,
1530                                         endp);
1531                                 if (dcname) {
1532                                         *pdc_name = SMB_STRDUP(dcname);
1533                                 }
1534                                 TALLOC_FREE(frame);
1535                         }
1536                 } else {
1537                         DEBUG(4, ("cli_get_pdc_name: machine %s failed the "
1538                                   "NetServerEnum call. Error was : %s.\n",
1539                                   smbXcli_conn_remote_name(cli->conn),
1540                                   win_errstr(W_ERROR(cli->rap_error))));
1541                 }
1542         }
1543
1544         SAFE_FREE(rparam);
1545         SAFE_FREE(rdata);
1546
1547         return(count > 0);
1548 }
1549
1550 /*************************************************************************
1551 *
1552 * Function Name:  cli_get_server_domain
1553 *
1554 * PURPOSE:  Remotes a NetWkstaGetInfo API call to the current server
1555 *           requesting wksta_info_10 level information to determine
1556 *           the domain the server belongs to. On success, this
1557 *           routine sets the server_domain field in the cli_state structure
1558 *           to the server's domain name.
1559 *
1560 * Dependencies: none
1561 *
1562 * Parameters:
1563 *             cli       - pointer to cli_state structure
1564 *
1565 * Returns:
1566 *             True      - success
1567 *             False     - failure
1568 *
1569 * Origins:  samba 2.0.6 source/libsmb/clientgen.c cli_NetServerEnum()
1570 *
1571 ************************************************************************/
1572
1573 bool cli_get_server_domain(struct cli_state *cli)
1574 {
1575         char *rparam = NULL;
1576         char *rdata = NULL;
1577         unsigned int rdrcnt,rprcnt;
1578         char *p;
1579         char param[WORDSIZE                      /* api number    */
1580                         +sizeof(RAP_WWkstaGetInfo_REQ) /* req string    */
1581                         +sizeof(RAP_WKSTA_INFO_L10)    /* return string */
1582                         +WORDSIZE                      /* info level    */
1583                         +WORDSIZE];                    /* buffer size   */
1584         int res = -1;
1585
1586         /* send a SMBtrans command with api NetWkstaGetInfo */
1587         p = make_header(param, RAP_WWkstaGetInfo,
1588                 RAP_WWkstaGetInfo_REQ, RAP_WKSTA_INFO_L10);
1589         PUTWORD(p, 10); /* info level */
1590         PUTWORD(p, CLI_BUFFER_SIZE);
1591
1592         if (cli_api(cli, param, PTR_DIFF(p,param), 8, /* params, length, max */
1593                         NULL, 0, CLI_BUFFER_SIZE,         /* data, length, max */
1594                         &rparam, &rprcnt,         /* return params, return size */
1595                         &rdata, &rdrcnt)) {       /* return data, return size */
1596                 char *endp = rparam + rprcnt;
1597                 res = GETRES(rparam, endp);
1598
1599                 if (res == 0) {
1600                         TALLOC_CTX *frame = talloc_stackframe();
1601                         char *server_domain;
1602                         int converter = 0;
1603
1604                         p = rparam + WORDSIZE;
1605                         GETWORD(p, converter, endp);
1606
1607                         p = rdata + DWORDSIZE + DWORDSIZE; /* skip computer & user names */
1608                         endp = rdata + rdrcnt;
1609                         p += rap_getstringp(frame,
1610                                 p,
1611                                 &server_domain,
1612                                 rdata,
1613                                 converter,
1614                                 endp);
1615
1616                         if (server_domain) {
1617                                 fstrcpy(cli->server_domain, server_domain);
1618                         }
1619                         TALLOC_FREE(frame);
1620                 }
1621         }
1622
1623         SAFE_FREE(rparam);
1624         SAFE_FREE(rdata);
1625
1626         return(res == 0);
1627 }
1628
1629 /*************************************************************************
1630 *
1631 * Function Name:  cli_get_server_type
1632 *
1633 * PURPOSE:  Remotes a NetServerGetInfo API call to the current server
1634 *           requesting server_info_1 level information to retrieve
1635 *           the server type.
1636 *
1637 * Dependencies: none
1638 *
1639 * Parameters:
1640 *             cli       - pointer to cli_state structure
1641 *             pstype    - pointer to uint32 to contain returned server type
1642 *
1643 * Returns:
1644 *             True      - success
1645 *             False     - failure
1646 *
1647 * Origins:  samba 2.0.6 source/libsmb/clientgen.c cli_NetServerEnum()
1648 *
1649 ************************************************************************/
1650
1651 bool cli_get_server_type(struct cli_state *cli, uint32 *pstype)
1652 {
1653         char *rparam = NULL;
1654         char *rdata = NULL;
1655         unsigned int rdrcnt,rprcnt;
1656         char *p;
1657         char param[WORDSIZE                       /* api number    */
1658                 +sizeof(RAP_WserverGetInfo_REQ) /* req string    */
1659                 +sizeof(RAP_SERVER_INFO_L1)     /* return string */
1660                 +WORDSIZE                       /* info level    */
1661                 +WORDSIZE];                     /* buffer size   */
1662         int res = -1;
1663
1664         /* send a SMBtrans command with api NetServerGetInfo */
1665         p = make_header(param, RAP_WserverGetInfo,
1666                 RAP_WserverGetInfo_REQ, RAP_SERVER_INFO_L1);
1667         PUTWORD(p, 1); /* info level */
1668         PUTWORD(p, CLI_BUFFER_SIZE);
1669
1670         if (cli_api(cli,
1671                         param, PTR_DIFF(p,param), 8, /* params, length, max */
1672                         NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
1673                         &rparam, &rprcnt,         /* return params, return size */
1674                         &rdata, &rdrcnt           /* return data, return size */
1675                         )) {
1676                 char *endp = rparam + rprcnt;
1677                 res = GETRES(rparam,endp);
1678
1679                 if (res == 0 || res == ERRmoredata) {
1680                         p = rdata;
1681                         endp = rparam + rprcnt;
1682                         p += 18;
1683                         GETDWORD(p,*pstype,endp);
1684                         *pstype &= ~SV_TYPE_LOCAL_LIST_ONLY;
1685                 }
1686         }
1687
1688         SAFE_FREE(rparam);
1689         SAFE_FREE(rdata);
1690
1691         return(res == 0 || res == ERRmoredata);
1692 }
1693
1694 bool cli_get_server_name(TALLOC_CTX *mem_ctx, struct cli_state *cli,
1695                          char **servername)
1696 {
1697         char *rparam = NULL;
1698         char *rdata = NULL;
1699         unsigned int rdrcnt,rprcnt;
1700         char *p;
1701         char param[WORDSIZE                       /* api number    */
1702                    +sizeof(RAP_WserverGetInfo_REQ) /* req string    */
1703                    +sizeof(RAP_SERVER_INFO_L1)     /* return string */
1704                    +WORDSIZE                       /* info level    */
1705                    +WORDSIZE];                     /* buffer size   */
1706         bool res = false;
1707         char *endp;
1708         fstring tmp;
1709
1710         /* send a SMBtrans command with api NetServerGetInfo */
1711         p = make_header(param, RAP_WserverGetInfo,
1712                         RAP_WserverGetInfo_REQ, RAP_SERVER_INFO_L1);
1713         PUTWORD(p, 1); /* info level */
1714         PUTWORD(p, CLI_BUFFER_SIZE);
1715
1716         if (!cli_api(cli,
1717                      param, PTR_DIFF(p,param), 8, /* params, length, max */
1718                      NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
1719                      &rparam, &rprcnt,         /* return params, return size */
1720                      &rdata, &rdrcnt           /* return data, return size */
1721                     )) {
1722                 goto failed;
1723         }
1724
1725         endp = rparam + rprcnt;
1726         if (GETRES(rparam, endp) != 0) {
1727                 goto failed;
1728         }
1729
1730         if (rdrcnt < 16) {
1731                 DEBUG(10, ("invalid data count %d, expected >= 16\n", rdrcnt));
1732                 goto failed;
1733         }
1734
1735         if (pull_ascii(tmp, rdata, sizeof(tmp)-1, 16, STR_TERMINATE) == -1) {
1736                 DEBUG(10, ("pull_ascii failed\n"));
1737                 goto failed;
1738         }
1739
1740         if (!(*servername = talloc_strdup(mem_ctx, tmp))) {
1741                 DEBUG(1, ("talloc_strdup failed\n"));
1742                 goto failed;
1743         }
1744
1745         res = true;
1746
1747  failed:
1748         SAFE_FREE(rparam);
1749         SAFE_FREE(rdata);
1750         return res;
1751 }
1752
1753 /*************************************************************************
1754 *
1755 * Function Name:  cli_ns_check_server_type
1756 *
1757 * PURPOSE:  Remotes a NetServerEnum2 API call to the current server
1758 *           requesting server_info_0 level information of machines
1759 *           matching the given server type. If the returned server
1760 *           list contains the machine name contained in smbXcli_conn_remote_name(->conn)
1761 *           then we conclude the server type checks out. This routine
1762 *           is useful to retrieve list of server's of a certain
1763 *           type when all you have is a null session connection and
1764 *           can't remote API calls such as NetWkstaGetInfo or
1765 *           NetServerGetInfo.
1766 *
1767 * Dependencies: none
1768 *
1769 * Parameters:
1770 *             cli       - pointer to cli_state structure
1771 *             workgroup - pointer to string containing domain
1772 *             stype     - server type
1773 *
1774 * Returns:
1775 *             True      - success
1776 *             False     - failure
1777 *
1778 ************************************************************************/
1779
1780 bool cli_ns_check_server_type(struct cli_state *cli, char *workgroup, uint32 stype)
1781 {
1782         char *rparam = NULL;
1783         char *rdata = NULL;
1784         unsigned int rdrcnt,rprcnt;
1785         char *p;
1786         char param[WORDSIZE                       /* api number    */
1787                 +sizeof(RAP_NetServerEnum2_REQ) /* req string    */
1788                 +sizeof(RAP_SERVER_INFO_L0)     /* return string */
1789                 +WORDSIZE                       /* info level    */
1790                 +WORDSIZE                       /* buffer size   */
1791                 +DWORDSIZE                      /* server type   */
1792                 +RAP_MACHNAME_LEN];             /* workgroup     */
1793         bool found_server = false;
1794         int res = -1;
1795         const char *remote_name = smbXcli_conn_remote_name(cli->conn);
1796
1797         /* send a SMBtrans command with api NetServerEnum */
1798         p = make_header(param, RAP_NetServerEnum2,
1799                         RAP_NetServerEnum2_REQ, RAP_SERVER_INFO_L0);
1800         PUTWORD(p, 0); /* info level 0 */
1801         PUTWORD(p, CLI_BUFFER_SIZE);
1802         PUTDWORD(p, stype);
1803         PUTSTRING(p, workgroup, RAP_MACHNAME_LEN);
1804
1805         if (cli_api(cli,
1806                         param, PTR_DIFF(p,param), 8, /* params, length, max */
1807                         NULL, 0, CLI_BUFFER_SIZE,  /* data, length, max */
1808                         &rparam, &rprcnt,          /* return params, return size */
1809                         &rdata, &rdrcnt            /* return data, return size */
1810                         )) {
1811                 char *endp = rparam + rprcnt;
1812                 res = GETRES(rparam,endp);
1813                 cli->rap_error = res;
1814
1815                 if (res == 0 || res == ERRmoredata) {
1816                         int i, count = 0;
1817
1818                         p = rparam + WORDSIZE + WORDSIZE;
1819                         GETWORD(p, count,endp);
1820
1821                         p = rdata;
1822                         endp = rdata + rdrcnt;
1823                         for (i = 0;i < count && p < endp;i++, p += 16) {
1824                                 char ret_server[RAP_MACHNAME_LEN];
1825
1826                                 p += rap_getstringf(p,
1827                                                 ret_server,
1828                                                 RAP_MACHNAME_LEN,
1829                                                 RAP_MACHNAME_LEN,
1830                                                 endp);
1831                                 if (strequal(ret_server, remote_name)) {
1832                                         found_server = true;
1833                                         break;
1834                                 }
1835                         }
1836                 } else {
1837                         DEBUG(4, ("cli_ns_check_server_type: machine %s "
1838                                   "failed the NetServerEnum call. Error was : "
1839                                   "%s.\n", remote_name,
1840                                   win_errstr(W_ERROR(cli->rap_error))));
1841                 }
1842         }
1843
1844         SAFE_FREE(rparam);
1845         SAFE_FREE(rdata);
1846
1847         return found_server;
1848 }
1849
1850 /****************************************************************************
1851  Perform a NetWkstaUserLogoff.
1852 ****************************************************************************/
1853
1854 bool cli_NetWkstaUserLogoff(struct cli_state *cli, const char *user, const char *workstation)
1855 {
1856         char *rparam = NULL;
1857         char *rdata = NULL;
1858         char *p;
1859         unsigned int rdrcnt,rprcnt;
1860         char param[WORDSIZE                           /* api number    */
1861                         +sizeof(RAP_NetWkstaUserLogoff_REQ) /* req string    */
1862                         +sizeof(RAP_USER_LOGOFF_INFO_L1)    /* return string */
1863                         +RAP_USERNAME_LEN+1                 /* user name+pad */
1864                         +RAP_MACHNAME_LEN                   /* wksta name    */
1865                         +WORDSIZE                           /* buffer size   */
1866                         +WORDSIZE];                         /* buffer size?  */
1867         char upperbuf[MAX(RAP_USERNAME_LEN,RAP_MACHNAME_LEN)];
1868         int res = -1;
1869         char *tmp = NULL;
1870
1871         memset(param, 0, sizeof(param));
1872
1873         /* send a SMBtrans command with api NetWkstaUserLogoff */
1874         p = make_header(param, RAP_WWkstaUserLogoff,
1875                 RAP_NetWkstaUserLogoff_REQ, RAP_USER_LOGOFF_INFO_L1);
1876         PUTDWORD(p, 0); /* Null pointer */
1877         PUTDWORD(p, 0); /* Null pointer */
1878         strlcpy(upperbuf, user, sizeof(upperbuf));
1879         strupper_m(upperbuf);
1880         tmp = upperbuf;
1881         PUTSTRINGF(p, tmp, RAP_USERNAME_LEN);
1882         p++; /* strange format, but ok */
1883         strlcpy(upperbuf, workstation, sizeof(upperbuf));
1884         strupper_m(upperbuf);
1885         tmp = upperbuf;
1886         PUTSTRINGF(p, tmp, RAP_MACHNAME_LEN);
1887         PUTWORD(p, CLI_BUFFER_SIZE);
1888         PUTWORD(p, CLI_BUFFER_SIZE);
1889
1890         if (cli_api(cli,
1891                         param, PTR_DIFF(p,param),1024,  /* param, length, max */
1892                         NULL, 0, CLI_BUFFER_SIZE,       /* data, length, max */
1893                         &rparam, &rprcnt,               /* return params, return size */
1894                         &rdata, &rdrcnt                 /* return data, return size */
1895                         )) {
1896                 char *endp = rparam + rprcnt;
1897                 res = GETRES(rparam,endp);
1898                 cli->rap_error = res;
1899
1900                 if (cli->rap_error != 0) {
1901                         DEBUG(4,("NetwkstaUserLogoff gave error %d\n", cli->rap_error));
1902                 }
1903         }
1904
1905         SAFE_FREE(rparam);
1906         SAFE_FREE(rdata);
1907         return (cli->rap_error == 0);
1908 }
1909
1910 int cli_NetPrintQEnum(struct cli_state *cli,
1911                 void (*qfn)(const char*,uint16,uint16,uint16,const char*,const char*,const char*,const char*,const char*,uint16,uint16),
1912                 void (*jfn)(uint16,const char*,const char*,const char*,const char*,uint16,uint16,const char*,unsigned int,unsigned int,const char*))
1913 {
1914         char param[WORDSIZE                         /* api number    */
1915                 +sizeof(RAP_NetPrintQEnum_REQ)    /* req string    */
1916                 +sizeof(RAP_PRINTQ_INFO_L2)       /* return string */
1917                 +WORDSIZE                         /* info level    */
1918                 +WORDSIZE                         /* buffer size   */
1919                 +sizeof(RAP_SMB_PRINT_JOB_L1)];   /* more ret data */
1920         char *p;
1921         char *rparam = NULL;
1922         char *rdata = NULL;
1923         unsigned int rprcnt, rdrcnt;
1924         int res = -1;
1925
1926         memset(param, '\0',sizeof(param));
1927         p = make_header(param, RAP_WPrintQEnum,
1928                 RAP_NetPrintQEnum_REQ, RAP_PRINTQ_INFO_L2);
1929         PUTWORD(p,2); /* Info level 2 */
1930         PUTWORD(p,0xFFE0); /* Return buffer size */
1931         PUTSTRING(p, RAP_SMB_PRINT_JOB_L1, 0);
1932
1933         if (cli_api(cli,
1934                         param, PTR_DIFF(p,param),1024,
1935                         NULL, 0, CLI_BUFFER_SIZE,
1936                         &rparam, &rprcnt,
1937                         &rdata, &rdrcnt)) {
1938                 char *endp = rparam + rprcnt;
1939                 res = GETRES(rparam, endp);
1940                 cli->rap_error = res;
1941                 if (res != 0) {
1942                         DEBUG(1,("NetPrintQEnum gave error %d\n", res));
1943                 }
1944         }
1945
1946         if (!rdata) {
1947                 DEBUG(4,("NetPrintQEnum no data returned\n"));
1948                 goto out;
1949         }
1950
1951         if (res == 0 || res == ERRmoredata) {
1952                 TALLOC_CTX *frame = talloc_stackframe();
1953                 char *endp = rparam + rprcnt;
1954                 int i, converter = 0, count = 0;
1955
1956                 p = rparam + WORDSIZE;
1957                 GETWORD(p, converter, endp);
1958                 GETWORD(p, count, endp);
1959
1960                 p = rdata;
1961                 endp = rdata + rdrcnt;
1962                 for (i=0;i<count && p < endp;i++) {
1963                         char qname[RAP_SHARENAME_LEN];
1964                         char *sep_file, *print_proc, *dest, *parms, *comment;
1965                         uint16_t jobcount = 0, priority = 0;
1966                         uint16_t start_time = 0, until_time = 0, status = 0;
1967
1968                         p += rap_getstringf(p,
1969                                         qname,
1970                                         RAP_SHARENAME_LEN,
1971                                         RAP_SHARENAME_LEN,
1972                                         endp);
1973                         p++; /* pad */
1974                         GETWORD(p, priority, endp);
1975                         GETWORD(p, start_time, endp);
1976                         GETWORD(p, until_time, endp);
1977                         p += rap_getstringp(frame,
1978                                         p,
1979                                         &sep_file,
1980                                         rdata,
1981                                         converter,
1982                                         endp);
1983                         p += rap_getstringp(frame,
1984                                         p,
1985                                         &print_proc,
1986                                         rdata,
1987                                         converter,
1988                                         endp);
1989                         p += rap_getstringp(frame,
1990                                         p,
1991                                         &dest,
1992                                         rdata,
1993                                         converter,
1994                                         endp);
1995                         p += rap_getstringp(frame,
1996                                         p,
1997                                         &parms,
1998                                         rdata,
1999                                         converter,
2000                                         endp);
2001                         p += rap_getstringp(frame,
2002                                         p,
2003                                         &comment,
2004                                         rdata,
2005                                         converter,
2006                                         endp);
2007                         GETWORD(p, status, endp);
2008                         GETWORD(p, jobcount, endp);
2009
2010                         if (sep_file && print_proc && dest && parms &&
2011                                         comment) {
2012                                 qfn(qname, priority, start_time, until_time, sep_file, print_proc,
2013                                         dest, parms, comment, status, jobcount);
2014                         }
2015
2016                         if (jobcount) {
2017                                 int j;
2018                                 for (j=0;j<jobcount;j++) {
2019                                         uint16 jid = 0, pos = 0, fsstatus = 0;
2020                                         char ownername[RAP_USERNAME_LEN];
2021                                         char notifyname[RAP_MACHNAME_LEN];
2022                                         char datatype[RAP_DATATYPE_LEN];
2023                                         char *jparms, *jstatus, *jcomment;
2024                                         unsigned int submitted = 0, jsize = 0;
2025
2026                                         GETWORD(p, jid, endp);
2027                                         p += rap_getstringf(p,
2028                                                         ownername,
2029                                                         RAP_USERNAME_LEN,
2030                                                         RAP_USERNAME_LEN,
2031                                                         endp);
2032                                         p++; /* pad byte */
2033                                         p += rap_getstringf(p,
2034                                                         notifyname,
2035                                                         RAP_MACHNAME_LEN,
2036                                                         RAP_MACHNAME_LEN,
2037                                                         endp);
2038                                         p += rap_getstringf(p,
2039                                                         datatype,
2040                                                         RAP_DATATYPE_LEN,
2041                                                         RAP_DATATYPE_LEN,
2042                                                         endp);
2043                                         p += rap_getstringp(frame,
2044                                                         p,
2045                                                         &jparms,
2046                                                         rdata,
2047                                                         converter,
2048                                                         endp);
2049                                         GETWORD(p, pos, endp);
2050                                         GETWORD(p, fsstatus, endp);
2051                                         p += rap_getstringp(frame,
2052                                                         p,
2053                                                         &jstatus,
2054                                                         rdata,
2055                                                         converter,
2056                                                         endp);
2057                                         GETDWORD(p, submitted, endp);
2058                                         GETDWORD(p, jsize, endp);
2059                                         p += rap_getstringp(frame,
2060                                                         p,
2061                                                         &jcomment,
2062                                                         rdata,
2063                                                         converter,
2064                                                         endp);
2065
2066                                         if (jparms && jstatus && jcomment) {
2067                                                 jfn(jid, ownername, notifyname, datatype, jparms, pos, fsstatus,
2068                                                         jstatus, submitted, jsize, jcomment);
2069                                         }
2070                                 }
2071                         }
2072                 }
2073                 TALLOC_FREE(frame);
2074         } else {
2075                 DEBUG(4,("NetPrintQEnum res=%d\n", res));
2076         }
2077
2078   out:
2079
2080         SAFE_FREE(rparam);
2081         SAFE_FREE(rdata);
2082
2083         return res;
2084 }
2085
2086 int cli_NetPrintQGetInfo(struct cli_state *cli, const char *printer,
2087         void (*qfn)(const char*,uint16,uint16,uint16,const char*,const char*,const char*,const char*,const char*,uint16,uint16),
2088         void (*jfn)(uint16,const char*,const char*,const char*,const char*,uint16,uint16,const char*,unsigned int,unsigned int,const char*))
2089 {
2090         char param[WORDSIZE                         /* api number    */
2091                 +sizeof(RAP_NetPrintQGetInfo_REQ) /* req string    */
2092                 +sizeof(RAP_PRINTQ_INFO_L2)       /* return string */
2093                 +RAP_SHARENAME_LEN                /* printer name  */
2094                 +WORDSIZE                         /* info level    */
2095                 +WORDSIZE                         /* buffer size   */
2096                 +sizeof(RAP_SMB_PRINT_JOB_L1)];   /* more ret data */
2097         char *p;
2098         char *rparam = NULL;
2099         char *rdata = NULL;
2100         unsigned int rprcnt, rdrcnt;
2101         int res = -1;
2102
2103         memset(param, '\0',sizeof(param));
2104         p = make_header(param, RAP_WPrintQGetInfo,
2105                 RAP_NetPrintQGetInfo_REQ, RAP_PRINTQ_INFO_L2);
2106         PUTSTRING(p, printer, RAP_SHARENAME_LEN-1);
2107         PUTWORD(p, 2);     /* Info level 2 */
2108         PUTWORD(p,0xFFE0); /* Return buffer size */
2109         PUTSTRING(p, RAP_SMB_PRINT_JOB_L1, 0);
2110
2111         if (cli_api(cli,
2112                         param, PTR_DIFF(p,param),1024,
2113                         NULL, 0, CLI_BUFFER_SIZE,
2114                         &rparam, &rprcnt,
2115                         &rdata, &rdrcnt)) {
2116                 char *endp = rparam + rprcnt;
2117                 res = GETRES(rparam, endp);
2118                 cli->rap_error = res;
2119                 if (res != 0) {
2120                         DEBUG(1,("NetPrintQGetInfo gave error %d\n", res));
2121                 }
2122         }
2123
2124         if (!rdata) {
2125                 DEBUG(4,("NetPrintQGetInfo no data returned\n"));
2126                 goto out;
2127         }
2128
2129         if (res == 0 || res == ERRmoredata) {
2130                 TALLOC_CTX *frame = talloc_stackframe();
2131                 char *endp = rparam + rprcnt;
2132                 int rsize = 0, converter = 0;
2133                 char qname[RAP_SHARENAME_LEN];
2134                 char *sep_file, *print_proc, *dest, *parms, *comment;
2135                 uint16_t jobcount = 0, priority = 0;
2136                 uint16_t start_time = 0, until_time = 0, status = 0;
2137
2138                 p = rparam + WORDSIZE;
2139                 GETWORD(p, converter, endp);
2140                 GETWORD(p, rsize, endp);
2141
2142                 p = rdata;
2143                 endp = rdata + rdrcnt;
2144                 p += rap_getstringf(p,
2145                                 qname,
2146                                 RAP_SHARENAME_LEN,
2147                                 RAP_SHARENAME_LEN,
2148                                 endp);
2149                 p++; /* pad */
2150                 GETWORD(p, priority, endp);
2151                 GETWORD(p, start_time, endp);
2152                 GETWORD(p, until_time, endp);
2153                 p += rap_getstringp(frame,
2154                                 p,
2155                                 &sep_file,
2156                                 rdata,
2157                                 converter,
2158                                 endp);
2159                 p += rap_getstringp(frame,
2160                                 p,
2161                                 &print_proc,
2162                                 rdata,
2163                                 converter,
2164                                 endp);
2165                 p += rap_getstringp(frame,
2166                                 p,
2167                                 &dest,
2168                                 rdata,
2169                                 converter,
2170                                 endp);
2171                 p += rap_getstringp(frame,
2172                                 p,
2173                                 &parms,
2174                                 rdata,
2175                                 converter,
2176                                 endp);
2177                 p += rap_getstringp(frame,
2178                                 p,
2179                                 &comment,
2180                                 rdata,
2181                                 converter,
2182                                 endp);
2183                 GETWORD(p, status, endp);
2184                 GETWORD(p, jobcount, endp);
2185
2186                 if (sep_file && print_proc && dest &&
2187                                 parms && comment) {
2188                         qfn(qname, priority, start_time, until_time, sep_file, print_proc,
2189                                 dest, parms, comment, status, jobcount);
2190                 }
2191                 if (jobcount) {
2192                         int j;
2193                         for (j=0;(j<jobcount)&&(PTR_DIFF(p,rdata)< rsize)&&
2194                                         p<endp;j++) {
2195                                 uint16_t jid = 0, pos = 0, fsstatus = 0;
2196                                 char ownername[RAP_USERNAME_LEN];
2197                                 char notifyname[RAP_MACHNAME_LEN];
2198                                 char datatype[RAP_DATATYPE_LEN];
2199                                 char *jparms, *jstatus, *jcomment;
2200                                 unsigned int submitted = 0, jsize = 0;
2201
2202                                 GETWORD(p, jid, endp);
2203                                 p += rap_getstringf(p,
2204                                                 ownername,
2205                                                 RAP_USERNAME_LEN,
2206                                                 RAP_USERNAME_LEN,
2207                                                 endp);
2208                                 p++; /* pad byte */
2209                                 p += rap_getstringf(p,
2210                                                 notifyname,
2211                                                 RAP_MACHNAME_LEN,
2212                                                 RAP_MACHNAME_LEN,
2213                                                 endp);
2214                                 p += rap_getstringf(p,
2215                                                 datatype,
2216                                                 RAP_DATATYPE_LEN,
2217                                                 RAP_DATATYPE_LEN,
2218                                                 endp);
2219                                 p += rap_getstringp(frame,
2220                                                 p,
2221                                                 &jparms,
2222                                                 rdata,
2223                                                 converter,
2224                                                 endp);
2225                                 GETWORD(p, pos,endp);
2226                                 GETWORD(p, fsstatus,endp);
2227                                 p += rap_getstringp(frame,
2228                                                 p,
2229                                                 &jstatus,
2230                                                 rdata,
2231                                                 converter,
2232                                                 endp);
2233                                 GETDWORD(p, submitted,endp);
2234                                 GETDWORD(p, jsize,endp);
2235                                 p += rap_getstringp(frame,
2236                                                 p,
2237                                                 &jcomment,
2238                                                 rdata,
2239                                                 converter,
2240                                                 endp);
2241
2242                                 if (jparms && jstatus && jcomment) {
2243                                         jfn(jid, ownername, notifyname, datatype, jparms, pos, fsstatus,
2244                                                 jstatus, submitted, jsize, jcomment);
2245                                 }
2246                         }
2247                 }
2248                 TALLOC_FREE(frame);
2249         } else {
2250                 DEBUG(4,("NetPrintQGetInfo res=%d\n", res));
2251         }
2252
2253   out:
2254
2255         SAFE_FREE(rparam);
2256         SAFE_FREE(rdata);
2257
2258         return res;
2259 }
2260
2261 /****************************************************************************
2262  Call a NetServiceEnum - list running services on a different host.
2263 ****************************************************************************/
2264
2265 int cli_RNetServiceEnum(struct cli_state *cli, void (*fn)(const char *, const char *, void *), void *state)
2266 {
2267         char param[WORDSIZE                     /* api number    */
2268                 +sizeof(RAP_NetServiceEnum_REQ) /* parm string   */
2269                 +sizeof(RAP_SERVICE_INFO_L2)    /* return string */
2270                 +WORDSIZE                     /* info level    */
2271                 +WORDSIZE];                   /* buffer size   */
2272         char *p;
2273         char *rparam = NULL;
2274         char *rdata = NULL;
2275         unsigned int rprcnt, rdrcnt;
2276         int res = -1;
2277
2278         memset(param, '\0', sizeof(param));
2279         p = make_header(param, RAP_WServiceEnum,
2280                 RAP_NetServiceEnum_REQ, RAP_SERVICE_INFO_L2);
2281         PUTWORD(p,2); /* Info level 2 */
2282         PUTWORD(p,0xFFE0); /* Return buffer size */
2283
2284         if (cli_api(cli,
2285                         param, PTR_DIFF(p,param),8,
2286                         NULL, 0, 0xFFE0 /* data area size */,
2287                         &rparam, &rprcnt,
2288                         &rdata, &rdrcnt)) {
2289                 char *endp = rparam + rprcnt;
2290                 res = GETRES(rparam, endp);
2291                 cli->rap_error = res;
2292                 if(cli->rap_error == 234) {
2293                         DEBUG(1,("Not all service names were returned (such as those longer than 15 characters)\n"));
2294                 } else if (cli->rap_error != 0) {
2295                         DEBUG(1,("NetServiceEnum gave error %d\n", cli->rap_error));
2296                 }
2297         }
2298
2299         if (!rdata) {
2300                 DEBUG(4,("NetServiceEnum no data returned\n"));
2301                 goto out;
2302         }
2303
2304         if (res == 0 || res == ERRmoredata) {
2305                 char *endp = rparam + rprcnt;
2306                 int i, count = 0;
2307
2308                 p = rparam + WORDSIZE + WORDSIZE; /* skip result and converter */
2309                 GETWORD(p, count,endp);
2310
2311                 endp = rdata + rdrcnt;
2312                 for (i=0,p=rdata;i<count && p < endp;i++) {
2313                         char comment[RAP_SRVCCMNT_LEN];
2314                         char servicename[RAP_SRVCNAME_LEN];
2315
2316                         p += rap_getstringf(p,
2317                                         servicename,
2318                                         RAP_SRVCNAME_LEN,
2319                                         RAP_SRVCNAME_LEN,
2320                                         endp);
2321                         p+=8; /* pass status words */
2322                         p += rap_getstringf(p,
2323                                         comment,
2324                                         RAP_SRVCCMNT_LEN,
2325                                         RAP_SRVCCMNT_LEN,
2326                                         endp);
2327
2328                         if (servicename[0]) {
2329                                 fn(servicename, comment, cli);  /* BB add status too */
2330                         }
2331                 }
2332         } else {
2333                 DEBUG(4,("NetServiceEnum res=%d\n", res));
2334         }
2335
2336   out:
2337
2338         SAFE_FREE(rparam);
2339         SAFE_FREE(rdata);
2340
2341         return res;
2342 }
2343
2344 /****************************************************************************
2345  Call a NetSessionEnum - list workstations with sessions to an SMB server.
2346 ****************************************************************************/
2347
2348 int cli_NetSessionEnum(struct cli_state *cli, void (*fn)(char *, char *, uint16, uint16, uint16, unsigned int, unsigned int, unsigned int, char *))
2349 {
2350         char param[WORDSIZE                       /* api number    */
2351                 +sizeof(RAP_NetSessionEnum_REQ) /* parm string   */
2352                 +sizeof(RAP_SESSION_INFO_L2)    /* return string */
2353                 +WORDSIZE                       /* info level    */
2354                 +WORDSIZE];                     /* buffer size   */
2355         char *p;
2356         char *rparam = NULL;
2357         char *rdata = NULL;
2358         unsigned int rprcnt, rdrcnt;
2359         int res = -1;
2360
2361         memset(param, '\0', sizeof(param));
2362         p = make_header(param, RAP_WsessionEnum,
2363                         RAP_NetSessionEnum_REQ, RAP_SESSION_INFO_L2);
2364         PUTWORD(p,2);    /* Info level 2 */
2365         PUTWORD(p,0xFF); /* Return buffer size */
2366
2367         if (cli_api(cli,
2368                         param, PTR_DIFF(p,param),8,
2369                         NULL, 0, CLI_BUFFER_SIZE,
2370                         &rparam, &rprcnt,
2371                         &rdata, &rdrcnt)) {
2372                 char *endp = rparam + rprcnt;
2373                 res = GETRES(rparam, endp);
2374                 cli->rap_error = res;
2375                 if (res != 0) {
2376                         DEBUG(1,("NetSessionEnum gave error %d\n", res));
2377                 }
2378         }
2379
2380         if (!rdata) {
2381                 DEBUG(4,("NetSesssionEnum no data returned\n"));
2382                 goto out;
2383         }
2384
2385         if (res == 0 || res == ERRmoredata) {
2386                 TALLOC_CTX *frame = talloc_stackframe();
2387                 char *endp = rparam + rprcnt;
2388                 int i, converter = 0, count = 0;
2389
2390                 p = rparam + WORDSIZE;
2391                 GETWORD(p, converter, endp);
2392                 GETWORD(p, count, endp);
2393
2394                 endp = rdata + rdrcnt;
2395                 for (i=0,p=rdata;i<count && p < endp;i++) {
2396                         char *wsname, *username, *clitype_name;
2397                         uint16_t num_conns = 0, num_opens = 0, num_users = 0;
2398                         unsigned int sess_time = 0, idle_time = 0, user_flags = 0;
2399
2400                         p += rap_getstringp(frame,
2401                                         p,
2402                                         &wsname,
2403                                         rdata,
2404                                         converter,
2405                                         endp);
2406                         p += rap_getstringp(frame,
2407                                         p,
2408                                         &username,
2409                                         rdata,
2410                                         converter,
2411                                         endp);
2412                         GETWORD(p, num_conns, endp);
2413                         GETWORD(p, num_opens, endp);
2414                         GETWORD(p, num_users, endp);
2415                         GETDWORD(p, sess_time, endp);
2416                         GETDWORD(p, idle_time, endp);
2417                         GETDWORD(p, user_flags, endp);
2418                         p += rap_getstringp(frame,
2419                                         p,
2420                                         &clitype_name,
2421                                         rdata,
2422                                         converter,
2423                                         endp);
2424
2425                         if (wsname && username && clitype_name) {
2426                                 fn(wsname, username, num_conns, num_opens, num_users, sess_time,
2427                                         idle_time, user_flags, clitype_name);
2428                         }
2429                 }
2430                 TALLOC_FREE(frame);
2431         } else {
2432                 DEBUG(4,("NetSessionEnum res=%d\n", res));
2433         }
2434
2435   out:
2436
2437         SAFE_FREE(rparam);
2438         SAFE_FREE(rdata);
2439
2440         return res;
2441 }
2442
2443 /****************************************************************************
2444  Call a NetSessionGetInfo - get information about other session to an SMB server.
2445 ****************************************************************************/
2446
2447 int cli_NetSessionGetInfo(struct cli_state *cli, const char *workstation,
2448                 void (*fn)(const char *, const char *, uint16, uint16, uint16, unsigned int, unsigned int, unsigned int, const char *))
2449 {
2450         char param[WORDSIZE                          /* api number    */
2451                 +sizeof(RAP_NetSessionGetInfo_REQ) /* req string    */
2452                 +sizeof(RAP_SESSION_INFO_L2)       /* return string */
2453                 +RAP_MACHNAME_LEN                  /* wksta name    */
2454                 +WORDSIZE                          /* info level    */
2455                 +WORDSIZE];                        /* buffer size   */
2456         char *p;
2457         char *rparam = NULL;
2458         char *rdata = NULL;
2459         unsigned int rprcnt, rdrcnt;
2460         char *endp;
2461         int res = -1;
2462
2463         memset(param, '\0', sizeof(param));
2464         p = make_header(param, RAP_WsessionGetInfo,
2465                         RAP_NetSessionGetInfo_REQ, RAP_SESSION_INFO_L2);
2466         PUTSTRING(p, workstation, RAP_MACHNAME_LEN-1);
2467         PUTWORD(p,2); /* Info level 2 */
2468         PUTWORD(p,0xFF); /* Return buffer size */
2469
2470         if (cli_api(cli,
2471                         param, PTR_DIFF(p,param),PTR_DIFF(p,param),
2472                         NULL, 0, CLI_BUFFER_SIZE,
2473                         &rparam, &rprcnt,
2474                         &rdata, &rdrcnt)) {
2475                 endp = rparam + rprcnt;
2476                 res = GETRES(rparam, endp);
2477                 cli->rap_error = res;
2478                 if (cli->rap_error != 0) {
2479                         DEBUG(1,("NetSessionGetInfo gave error %d\n", cli->rap_error));
2480                 }
2481         }
2482
2483         if (!rdata) {
2484                 DEBUG(4,("NetSessionGetInfo no data returned\n"));
2485                 goto out;
2486         }
2487
2488         endp = rparam + rprcnt;
2489         res = GETRES(rparam, endp);
2490
2491         if (res == 0 || res == ERRmoredata) {
2492                 TALLOC_CTX *frame = talloc_stackframe();
2493                 int converter = 0;
2494                 char *wsname, *username, *clitype_name;
2495                 uint16_t num_conns = 0, num_opens = 0, num_users = 0;
2496                 unsigned int sess_time = 0, idle_time = 0, user_flags = 0;
2497
2498                 p = rparam + WORDSIZE;
2499                 GETWORD(p, converter,endp);
2500                 p += WORDSIZE;            /* skip rsize */
2501
2502                 p = rdata;
2503                 endp = rdata + rdrcnt;
2504                 p += rap_getstringp(frame,
2505                                 p,
2506                                 &wsname,
2507                                 rdata,
2508                                 converter,
2509                                 endp);
2510                 p += rap_getstringp(frame,
2511                                 p,
2512                                 &username,
2513                                 rdata,
2514                                 converter,
2515                                 endp);
2516                 GETWORD(p, num_conns, endp);
2517                 GETWORD(p, num_opens, endp);
2518                 GETWORD(p, num_users, endp);
2519                 GETDWORD(p, sess_time, endp);
2520                 GETDWORD(p, idle_time, endp);
2521                 GETDWORD(p, user_flags, endp);
2522                 p += rap_getstringp(frame,
2523                                 p,
2524                                 &clitype_name,
2525                                 rdata,
2526                                 converter,
2527                                 endp);
2528
2529                 if (wsname && username && clitype_name) {
2530                         fn(wsname, username, num_conns, num_opens, num_users, sess_time,
2531                                 idle_time, user_flags, clitype_name);
2532                 }
2533                 TALLOC_FREE(frame);
2534         } else {
2535                 DEBUG(4,("NetSessionGetInfo res=%d\n", res));
2536         }
2537
2538   out:
2539
2540         SAFE_FREE(rparam);
2541         SAFE_FREE(rdata);
2542
2543         return res;
2544 }
2545
2546 /****************************************************************************
2547  Call a NetSessionDel - close a session to an SMB server.
2548 ****************************************************************************/
2549
2550 int cli_NetSessionDel(struct cli_state *cli, const char *workstation)
2551 {
2552         char param[WORDSIZE                      /* api number       */
2553                 +sizeof(RAP_NetSessionDel_REQ) /* req string       */
2554                 +1                             /* no return string */
2555                 +RAP_MACHNAME_LEN              /* workstation name */
2556                 +WORDSIZE];                    /* reserved (0)     */
2557         char *p;
2558         char *rparam = NULL;
2559         char *rdata = NULL;
2560         unsigned int rprcnt, rdrcnt;
2561         int res = -1;
2562
2563         memset(param, '\0', sizeof(param));
2564         p = make_header(param, RAP_WsessionDel, RAP_NetSessionDel_REQ, NULL);
2565         PUTSTRING(p, workstation, RAP_MACHNAME_LEN-1);
2566         PUTWORD(p,0); /* reserved word of 0 */
2567
2568         if (cli_api(cli,
2569                         param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
2570                         NULL, 0, 200,       /* data, length, maxlen */
2571                         &rparam, &rprcnt,   /* return params, length */
2572                         &rdata, &rdrcnt))   /* return data, length */
2573         {
2574                 char *endp = rparam + rprcnt;
2575                 res = GETRES(rparam, endp);
2576                 cli->rap_error = res;
2577
2578                 if (res == 0) {
2579                         /* nothing to do */
2580                 } else {
2581                         DEBUG(4,("NetFileClose2 res=%d\n", res));
2582                 }
2583         } else {
2584                 res = -1;
2585                 DEBUG(4,("NetFileClose2 failed\n"));
2586         }
2587
2588         SAFE_FREE(rparam);
2589         SAFE_FREE(rdata);
2590
2591         return res;
2592 }
2593
2594 int cli_NetConnectionEnum(struct cli_state *cli, const char *qualifier,
2595                         void (*fn)(uint16_t conid, uint16_t contype,
2596                                 uint16_t numopens, uint16_t numusers,
2597                                 uint32_t contime, const char *username,
2598                                 const char *netname))
2599 {
2600         char param[WORDSIZE                          /* api number    */
2601                 +sizeof(RAP_NetConnectionEnum_REQ) /* req string    */
2602                 +sizeof(RAP_CONNECTION_INFO_L1)    /* return string */
2603                 +RAP_MACHNAME_LEN                  /* wksta name    */
2604                 +WORDSIZE                          /* info level    */
2605                 +WORDSIZE];                        /* buffer size   */
2606         char *p;
2607         char *rparam = NULL;
2608         char *rdata = NULL;
2609         unsigned int rprcnt, rdrcnt;
2610         int res = -1;
2611
2612         memset(param, '\0', sizeof(param));
2613         p = make_header(param, RAP_WconnectionEnum,
2614                 RAP_NetConnectionEnum_REQ, RAP_CONNECTION_INFO_L1);
2615         PUTSTRING(p, qualifier, RAP_MACHNAME_LEN-1);/* Workstation name */
2616         PUTWORD(p,1);            /* Info level 1 */
2617         PUTWORD(p,0xFFE0);       /* Return buffer size */
2618
2619         if (cli_api(cli,
2620                         param, PTR_DIFF(p,param),PTR_DIFF(p,param),
2621                         NULL, 0, CLI_BUFFER_SIZE,
2622                         &rparam, &rprcnt,
2623                         &rdata, &rdrcnt)) {
2624                 char *endp = rparam + rprcnt;
2625                 res = GETRES(rparam, endp);
2626                 cli->rap_error = res;
2627                 if (res != 0) {
2628                         DEBUG(1,("NetConnectionEnum gave error %d\n", res));
2629                 }
2630         }
2631
2632         if (!rdata) {
2633                 DEBUG(4,("NetConnectionEnum no data returned\n"));
2634                 goto out;
2635         }
2636
2637         if (res == 0 || res == ERRmoredata) {
2638                 TALLOC_CTX *frame = talloc_stackframe();
2639                 char *endp = rparam + rprcnt;
2640                 int i, converter = 0, count = 0;
2641
2642                 p = rparam + WORDSIZE;
2643                 GETWORD(p, converter, endp);
2644                 GETWORD(p, count, endp);
2645
2646                 endp = rdata + rdrcnt;
2647                 for (i=0,p=rdata;i<count && p < endp;i++) {
2648                         char *netname, *username;
2649                         uint16_t conn_id = 0, conn_type = 0, num_opens = 0, num_users = 0;
2650                         unsigned int conn_time = 0;
2651
2652                         GETWORD(p,conn_id, endp);
2653                         GETWORD(p,conn_type, endp);
2654                         GETWORD(p,num_opens, endp);
2655                         GETWORD(p,num_users, endp);
2656                         GETDWORD(p,conn_time, endp);
2657                         p += rap_getstringp(frame,
2658                                         p,
2659                                         &username,
2660                                         rdata,
2661                                         converter,
2662                                         endp);
2663                         p += rap_getstringp(frame,
2664                                         p,
2665                                         &netname,
2666                                         rdata,
2667                                         converter,
2668                                         endp);
2669
2670                         if (username && netname) {
2671                                 fn(conn_id, conn_type, num_opens, num_users, conn_time,
2672                                         username, netname);
2673                         }
2674                 }
2675                 TALLOC_FREE(frame);
2676         } else {
2677                 DEBUG(4,("NetConnectionEnum res=%d\n", res));
2678         }
2679
2680   out:
2681
2682         SAFE_FREE(rdata);
2683         SAFE_FREE(rparam);
2684         return res;
2685 }