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