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