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