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