r6392: - Fixes bug 2564: when smbc_opendir() was called with a file rather than
[samba.git] / source / 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                     
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 2 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, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 /*****************************************************/
24 /*                                                   */
25 /*   Additional RAP functionality                    */
26 /*                                                   */
27 /*   RAP is the original SMB RPC, documented         */
28 /*   by Microsoft and X/Open in the 1990s and        */
29 /*   supported by most SMB/CIFS servers although     */
30 /*   it is unlikely that any one implementation      */
31 /*   supports all RAP command codes since some       */
32 /*   are quite obsolete and a few are specific       */
33 /*   to a particular network operating system        */
34 /*                                                   */ 
35 /*   Although it has largely been replaced           */ 
36 /*   for complex remote admistration and management  */
37 /*   (of servers) by the relatively newer            */
38 /*   DCE/RPC based remote API (which better handles  */
39 /*   large >64K data structures), there are many     */
40 /*   important administrative and resource location  */
41 /*   tasks and user tasks (e.g. password change)     */
42 /*   that are performed via RAP.                     */
43 /*                                                   */
44 /*   Although a few of the RAP calls are implemented */
45 /*   in the Samba client library already (clirap.c)  */
46 /*   the new ones are in clirap2.c for easy patching */
47 /*   and integration and a corresponding header      */
48 /*   file, rap.h, has been created.                  */
49 /*                                                   */
50 /*   This is based on data from the CIFS spec        */
51 /*   and the LAN Server and LAN Manager              */
52 /*   Programming Reference books and published       */
53 /*   RAP document and CIFS forum postings and        */
54 /*   lots of trial and error                         */
55 /*                                                   */
56 /*   Function names changed from API_ (as they are   */
57 /*   in the CIFS specification) to RAP_ in order     */
58 /*   to avoid confusion with other API calls         */
59 /*   sent via DCE RPC                                */
60 /*                                                   */
61 /*****************************************************/
62
63 /*****************************************************/
64 /*                                                   */
65 /* cifsrap.c already includes support for:           */
66 /*                                                   */
67 /* WshareEnum ( API number 0, level 1)               */
68 /* NetServerEnum2 (API num 104, level 1)             */
69 /* WWkstaUserLogon (132)                             */
70 /* SamOEMchgPasswordUser2_P (214)                    */
71 /*                                                   */
72 /* cifsprint.c already includes support for:         */
73 /*                                                   */
74 /* WPrintJobEnum (API num 76, level 2)               */
75 /* WPrintJobDel  (API num 81)                        */
76 /*                                                   */
77 /*****************************************************/ 
78
79 #define NO_SYSLOG
80
81 #include "includes.h" 
82
83 #define WORDSIZE 2
84 #define DWORDSIZE 4
85
86 #define PUTBYTE(p,b) do {SCVAL(p,0,b); p++;} while(0)
87 #define GETBYTE(p,b) do {b = CVAL(p,0); p++;} while(0)
88 #define PUTWORD(p,w) do {SSVAL(p,0,w); p += WORDSIZE;} while(0)
89 #define GETWORD(p,w) do {w = SVAL(p,0); p += WORDSIZE;} while(0)
90 #define PUTDWORD(p,d) do {SIVAL(p,0,d); p += DWORDSIZE;} while(0)
91 #define GETDWORD(p,d) do {d = IVAL(p,0); p += DWORDSIZE;} while(0)
92 #define GETRES(p) p ? SVAL(p,0) : -1
93 /* put string s at p with max len n and increment p past string */
94 #define PUTSTRING(p,s,n) do {\
95   push_ascii(p,s?s:"",n?n:256,STR_TERMINATE);\
96   p = skip_string(p,1);\
97   } while(0)
98 /* put string s and p, using fixed len l, and increment p by l */
99 #define PUTSTRINGF(p,s,l) do {\
100   push_ascii(p,s?s:"",l,STR_TERMINATE);\
101   p += l;\
102   } while (0)
103 /* put string pointer at p, supplying offset o from rdata r, store   */
104 /* dword offset at p, increment p by 4 and o by length of s.  This   */
105 /* means on the first call, you must calc the offset yourself!       */
106 #define PUTSTRINGP(p,s,r,o) do {\
107   if (s) {\
108     push_ascii(r+o,s,strlen(s)+1,STR_TERMINATE);\
109     PUTDWORD(p,o);\
110     o += strlen(s) + 1;\
111   } else PUTDWORD(p,0);\
112   }while(0);
113 /* get asciiz string s from p, increment p past string */
114 #define GETSTRING(p,s) do {\
115   pull_ascii_pstring(s,p);\
116   p = skip_string(p,1);\
117   } while(0)
118 /* get fixed length l string s from p, increment p by l */
119 #define GETSTRINGF(p,s,l) do {\
120   pull_ascii_pstring(s,p);\
121   p += l;\
122   } while(0)
123 /* get string s from offset (obtained at p) from rdata r - converter c */
124 #define GETSTRINGP(p,s,r,c) do {\
125   uint32 off;\
126   GETDWORD(p,off);\
127   off &= 0x0000FFFF; /* mask the obsolete segment number from the offset */ \
128   pull_ascii_pstring(s, off?(r+off-c):"");\
129   } while(0)
130
131 static char *make_header(char *param, uint16 apinum, const char *reqfmt, const char *datafmt)
132 {
133   PUTWORD(param,apinum);
134   if (reqfmt) 
135     PUTSTRING(param,reqfmt,0);
136   else 
137     *param++ = (char) 0;
138
139   if (datafmt)
140     PUTSTRING(param,datafmt,0);
141   else
142     *param++ = (char) 0;
143
144   return param;
145 }
146     
147
148 /****************************************************************************
149  call a NetGroupDelete - delete user group from remote server
150 ****************************************************************************/
151 int cli_NetGroupDelete(struct cli_state *cli, const char *group_name )
152 {
153   char *rparam = NULL;
154   char *rdata = NULL;
155   char *p;
156   unsigned int rdrcnt,rprcnt;
157   int res;
158   char param[WORDSIZE                    /* api number    */
159             +sizeof(RAP_NetGroupDel_REQ) /* parm string   */
160             +1                           /* no ret string */
161             +RAP_GROUPNAME_LEN           /* group to del  */
162             +WORDSIZE];                  /* reserved word */
163
164   /* now send a SMBtrans command with api GroupDel */
165   p = make_header(param, RAP_WGroupDel, RAP_NetGroupDel_REQ, NULL);  
166   PUTSTRING(p, group_name, RAP_GROUPNAME_LEN);
167   PUTWORD(p,0);  /* reserved word MBZ on input */
168                  
169   if (cli_api(cli, 
170               param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
171               NULL, 0, 200,       /* data, length, maxlen */
172               &rparam, &rprcnt,   /* return params, length */
173               &rdata, &rdrcnt))   /* return data, length */
174     {
175       res = GETRES(rparam);
176                         
177       if (res == 0) {
178         /* nothing to do */             
179       }
180       else if ((res == 5) || (res == 65)) {
181           DEBUG(1, ("Access Denied\n"));
182       }
183       else if (res == 2220) {
184          DEBUG (1, ("Group does not exist\n"));
185       }
186       else {
187         DEBUG(4,("NetGroupDelete res=%d\n", res));
188       }      
189     } else {
190       res = -1;
191       DEBUG(4,("NetGroupDelete failed\n"));
192     }
193   
194   SAFE_FREE(rparam);
195   SAFE_FREE(rdata);
196   
197   return res;
198 }
199
200 /****************************************************************************
201  call a NetGroupAdd - add user group to remote server
202 ****************************************************************************/
203 int cli_NetGroupAdd(struct cli_state *cli, RAP_GROUP_INFO_1 * grinfo )
204 {
205   char *rparam = NULL;
206   char *rdata = NULL;
207   char *p;
208   unsigned int rdrcnt,rprcnt;
209   int res;
210   char param[WORDSIZE                    /* api number    */
211             +sizeof(RAP_NetGroupAdd_REQ) /* req string    */
212             +sizeof(RAP_GROUP_INFO_L1)   /* return string */
213             +WORDSIZE                    /* info level    */
214             +WORDSIZE];                  /* reserved word */
215
216   char data[1024];
217     
218   /* offset into data of free format strings.  Will be updated */
219   /* by PUTSTRINGP macro and end up with total data length.    */
220   int soffset = RAP_GROUPNAME_LEN + 1 + DWORDSIZE; 
221
222   /* now send a SMBtrans command with api WGroupAdd */
223   
224   p = make_header(param, RAP_WGroupAdd,
225                   RAP_NetGroupAdd_REQ, RAP_GROUP_INFO_L1); 
226   PUTWORD(p, 1); /* info level */
227   PUTWORD(p, 0); /* reserved word 0 */
228   
229   p = data;
230   PUTSTRINGF(p, grinfo->group_name, RAP_GROUPNAME_LEN);
231   PUTBYTE(p, 0); /* pad byte 0 */
232   PUTSTRINGP(p, grinfo->comment, data, soffset);
233   
234   if (cli_api(cli, 
235               param, sizeof(param), 1024, /* Param, length, maxlen */
236               data, soffset, sizeof(data), /* data, length, maxlen */
237               &rparam, &rprcnt,   /* return params, length */
238               &rdata, &rdrcnt))   /* return data, length */
239     {
240       res = GETRES(rparam);
241       
242       if (res == 0) {
243         /* nothing to do */             
244       } else if ((res == 5) || (res == 65)) {
245         DEBUG(1, ("Access Denied\n"));
246       }
247       else if (res == 2223) {
248         DEBUG (1, ("Group already exists\n"));
249       }
250       else {
251         DEBUG(4,("NetGroupAdd res=%d\n", res));
252       }
253     } else {
254       res = -1;
255       DEBUG(4,("NetGroupAdd failed\n"));
256     }
257   
258   SAFE_FREE(rparam);
259   SAFE_FREE(rdata);
260
261   return res;
262 }
263
264 /****************************************************************************
265 call a NetGroupEnum - try and list user groups on a different host
266 ****************************************************************************/
267 int cli_RNetGroupEnum(struct cli_state *cli, void (*fn)(const char *, const char *, void *), void *state)
268 {
269   char param[WORDSIZE                     /* api number    */
270             +sizeof(RAP_NetGroupEnum_REQ) /* parm string   */
271             +sizeof(RAP_GROUP_INFO_L1)    /* return string */
272             +WORDSIZE                     /* info level    */
273             +WORDSIZE];                   /* buffer size   */
274   char *p;
275   char *rparam = NULL;
276   char *rdata = NULL; 
277   unsigned int rprcnt, rdrcnt;
278   int res = -1;
279   
280   
281   memset(param, '\0', sizeof(param));
282   p = make_header(param, RAP_WGroupEnum,
283                   RAP_NetGroupEnum_REQ, RAP_GROUP_INFO_L1);
284   PUTWORD(p,1); /* Info level 1 */  /* add level 0 */
285   PUTWORD(p,0xFFE0); /* Return buffer size */
286
287   if (cli_api(cli,
288               param, PTR_DIFF(p,param),8,
289               NULL, 0, 0xFFE0 /* data area size */,
290               &rparam, &rprcnt,
291               &rdata, &rdrcnt)) {
292     res = GETRES(rparam);
293     cli->rap_error = res;
294     if(cli->rap_error == 234) 
295         DEBUG(1,("Not all group names were returned (such as those longer than 21 characters)\n"));
296     else if (cli->rap_error != 0) {
297       DEBUG(1,("NetGroupEnum gave error %d\n", cli->rap_error));
298     }
299   }
300
301   if (rdata) {
302     if (res == 0 || res == ERRmoredata) {
303       int i, converter, count;
304
305       p = rparam + WORDSIZE; /* skip result */
306       GETWORD(p, converter);
307       GETWORD(p, count);
308
309       for (i=0,p=rdata;i<count;i++) {
310             pstring comment;
311             char groupname[RAP_GROUPNAME_LEN];
312
313             GETSTRINGF(p, groupname, RAP_GROUPNAME_LEN);
314             p++; /* pad byte */
315             GETSTRINGP(p, comment, rdata, converter);
316
317             fn(groupname, comment, cli);
318       } 
319     } else {
320       DEBUG(4,("NetGroupEnum res=%d\n", res));
321     }
322   } else {
323     DEBUG(4,("NetGroupEnum no data returned\n"));
324   }
325     
326   SAFE_FREE(rparam);
327   SAFE_FREE(rdata);
328
329   return res;
330 }
331
332 int cli_RNetGroupEnum0(struct cli_state *cli,
333                        void (*fn)(const char *, void *),
334                        void *state)
335 {
336   char param[WORDSIZE                     /* api number    */
337             +sizeof(RAP_NetGroupEnum_REQ) /* parm string   */
338             +sizeof(RAP_GROUP_INFO_L0)    /* return string */
339             +WORDSIZE                     /* info level    */
340             +WORDSIZE];                   /* buffer size   */
341   char *p;
342   char *rparam = NULL;
343   char *rdata = NULL; 
344   unsigned int rprcnt, rdrcnt;
345   int res = -1;
346   
347   
348   memset(param, '\0', sizeof(param));
349   p = make_header(param, RAP_WGroupEnum,
350                   RAP_NetGroupEnum_REQ, RAP_GROUP_INFO_L0);
351   PUTWORD(p,0); /* Info level 0 */ /* Hmmm. I *very* much suspect this
352                                       is the resume count, at least
353                                       that's what smbd believes... */
354   PUTWORD(p,0xFFE0); /* Return buffer size */
355
356   if (cli_api(cli,
357               param, PTR_DIFF(p,param),8,
358               NULL, 0, 0xFFE0 /* data area size */,
359               &rparam, &rprcnt,
360               &rdata, &rdrcnt)) {
361     res = GETRES(rparam);
362     cli->rap_error = res;
363     if(cli->rap_error == 234) 
364         DEBUG(1,("Not all group names were returned (such as those longer than 21 characters)\n"));
365     else if (cli->rap_error != 0) {
366       DEBUG(1,("NetGroupEnum gave error %d\n", cli->rap_error));
367     }
368   }
369
370   if (rdata) {
371     if (res == 0 || res == ERRmoredata) {
372       int i, count;
373
374       p = rparam + WORDSIZE + WORDSIZE; /* skip result and converter */
375       GETWORD(p, count);
376
377       for (i=0,p=rdata;i<count;i++) {
378             char groupname[RAP_GROUPNAME_LEN];
379             GETSTRINGF(p, groupname, RAP_GROUPNAME_LEN);
380             fn(groupname, cli);
381       } 
382     } else {
383       DEBUG(4,("NetGroupEnum res=%d\n", res));
384     }
385   } else {
386     DEBUG(4,("NetGroupEnum no data returned\n"));
387   }
388     
389   SAFE_FREE(rparam);
390   SAFE_FREE(rdata);
391
392   return res;
393 }
394
395 int cli_NetGroupDelUser(struct cli_state * cli, const char *group_name, const char *user_name)
396 {
397   char *rparam = NULL;
398   char *rdata = NULL;
399   char *p;
400   unsigned int rdrcnt,rprcnt;
401   int res;
402   char param[WORDSIZE                        /* api number    */
403             +sizeof(RAP_NetGroupDelUser_REQ) /* parm string   */
404             +1                               /* no ret string */
405             +RAP_GROUPNAME_LEN               /* group name    */
406             +RAP_USERNAME_LEN];              /* user to del   */
407
408   /* now send a SMBtrans command with api GroupMemberAdd */
409   p = make_header(param, RAP_WGroupDelUser, RAP_NetGroupDelUser_REQ, NULL);
410   PUTSTRING(p,group_name,RAP_GROUPNAME_LEN);
411   PUTSTRING(p,user_name,RAP_USERNAME_LEN);
412
413   if (cli_api(cli, 
414               param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
415               NULL, 0, 200,       /* data, length, maxlen */
416               &rparam, &rprcnt,   /* return params, length */
417               &rdata, &rdrcnt))   /* return data, length */
418     {
419       res = GETRES(rparam);
420       
421       switch(res) {
422         case 0:
423           break;
424         case 5:
425         case 65:
426           DEBUG(1, ("Access Denied\n"));
427           break;
428         case 50:
429           DEBUG(1, ("Not supported by server\n"));
430           break;
431         case 2220:
432           DEBUG(1, ("Group does not exist\n"));
433           break;
434         case 2221:
435           DEBUG(1, ("User does not exist\n"));
436           break;
437         case 2237:
438           DEBUG(1, ("User is not in group\n"));
439           break;
440         default:
441           DEBUG(4,("NetGroupDelUser res=%d\n", res));
442       }
443     } else {
444       res = -1;
445       DEBUG(4,("NetGroupDelUser failed\n"));
446     }
447   
448   SAFE_FREE(rparam);
449   SAFE_FREE(rdata);
450         
451   return res; 
452 }
453
454 int cli_NetGroupAddUser(struct cli_state * cli, const char *group_name, const char *user_name)
455 {
456   char *rparam = NULL;
457   char *rdata = NULL;
458   char *p;
459   unsigned int rdrcnt,rprcnt;
460   int res;
461   char param[WORDSIZE                        /* api number    */
462             +sizeof(RAP_NetGroupAddUser_REQ) /* parm string   */
463             +1                               /* no ret string */
464             +RAP_GROUPNAME_LEN               /* group name    */
465             +RAP_USERNAME_LEN];              /* user to add   */
466
467   /* now send a SMBtrans command with api GroupMemberAdd */
468   p = make_header(param, RAP_WGroupAddUser, RAP_NetGroupAddUser_REQ, NULL);
469   PUTSTRING(p,group_name,RAP_GROUPNAME_LEN);
470   PUTSTRING(p,user_name,RAP_USERNAME_LEN);
471
472   if (cli_api(cli, 
473               param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
474               NULL, 0, 200,       /* data, length, maxlen */
475               &rparam, &rprcnt,   /* return params, length */
476               &rdata, &rdrcnt))   /* return data, length */
477     {
478       res = GETRES(rparam);
479       
480       switch(res) {
481         case 0:
482           break;
483         case 5:
484         case 65:
485           DEBUG(1, ("Access Denied\n"));
486           break;
487         case 50:
488           DEBUG(1, ("Not supported by server\n"));
489           break;
490         case 2220:
491           DEBUG(1, ("Group does not exist\n"));
492           break;
493         case 2221:
494           DEBUG(1, ("User does not exist\n"));
495           break;
496         default:
497           DEBUG(4,("NetGroupAddUser res=%d\n", res));
498       }
499     } else {
500       res = -1;
501       DEBUG(4,("NetGroupAddUser failed\n"));
502     }
503   
504   SAFE_FREE(rparam);
505   SAFE_FREE(rdata);
506         
507   return res;
508 }
509
510
511 int cli_NetGroupGetUsers(struct cli_state * cli, const char *group_name, void (*fn)(const char *, void *), void *state )
512 {
513   char *rparam = NULL;
514   char *rdata = NULL;
515   char *p;
516   unsigned int rdrcnt,rprcnt;
517   int res = -1;
518   char param[WORDSIZE                        /* api number    */
519             +sizeof(RAP_NetGroupGetUsers_REQ)/* parm string   */
520             +sizeof(RAP_GROUP_USERS_INFO_0)  /* return string */
521             +RAP_GROUPNAME_LEN               /* group name    */
522             +WORDSIZE                        /* info level    */
523             +WORDSIZE];                      /* buffer size   */
524
525   /* now send a SMBtrans command with api GroupGetUsers */
526   p = make_header(param, RAP_WGroupGetUsers,
527                   RAP_NetGroupGetUsers_REQ, RAP_GROUP_USERS_INFO_0);
528   PUTSTRING(p,group_name,RAP_GROUPNAME_LEN-1);
529   PUTWORD(p,0); /* info level 0 */
530   PUTWORD(p,0xFFE0); /* return buffer size */
531
532   if (cli_api(cli,
533               param, PTR_DIFF(p,param),PTR_DIFF(p,param),
534               NULL, 0, CLI_BUFFER_SIZE,
535               &rparam, &rprcnt,
536               &rdata, &rdrcnt)) {
537     res = GETRES(rparam);
538     cli->rap_error = res;
539     if (res != 0) {
540       DEBUG(1,("NetGroupGetUsers gave error %d\n", res));
541     }
542   }
543   if (rdata) {
544     if (res == 0 || res == ERRmoredata) {
545       int i, count;
546       fstring username;
547       p = rparam + WORDSIZE + WORDSIZE;
548       GETWORD(p, count);
549
550       for (i=0,p=rdata; i<count; i++) {
551         GETSTRINGF(p, username, RAP_USERNAME_LEN);
552         fn(username, state);
553       }
554     } else {
555       DEBUG(4,("NetGroupGetUsers res=%d\n", res));
556     }
557   } else {
558     DEBUG(4,("NetGroupGetUsers no data returned\n"));
559   }
560   SAFE_FREE(rdata);
561   SAFE_FREE(rparam);
562   return res;
563 }
564
565 int cli_NetUserGetGroups(struct cli_state * cli, const char *user_name, void (*fn)(const char *, void *), void *state )
566 {
567   char *rparam = NULL;
568   char *rdata = NULL;
569   char *p;
570   unsigned int rdrcnt,rprcnt;
571   int res = -1;
572   char param[WORDSIZE                        /* api number    */
573             +sizeof(RAP_NetUserGetGroups_REQ)/* parm string   */
574             +sizeof(RAP_GROUP_USERS_INFO_0)  /* return string */
575             +RAP_USERNAME_LEN               /* user name    */
576             +WORDSIZE                        /* info level    */
577             +WORDSIZE];                      /* buffer size   */
578
579   /* now send a SMBtrans command with api GroupGetUsers */
580   p = make_header(param, RAP_WUserGetGroups,
581                   RAP_NetUserGetGroups_REQ, RAP_GROUP_USERS_INFO_0);
582   PUTSTRING(p,user_name,RAP_USERNAME_LEN-1);
583   PUTWORD(p,0); /* info level 0 */
584   PUTWORD(p,0xFFE0); /* return buffer size */
585
586   if (cli_api(cli,
587               param, PTR_DIFF(p,param),PTR_DIFF(p,param),
588               NULL, 0, CLI_BUFFER_SIZE,
589               &rparam, &rprcnt,
590               &rdata, &rdrcnt)) {
591     res = GETRES(rparam);
592     cli->rap_error = res;
593     if (res != 0) {
594       DEBUG(1,("NetUserGetGroups gave error %d\n", res));
595     }
596   }
597   if (rdata) {
598     if (res == 0 || res == ERRmoredata) {
599       int i, count;
600       fstring groupname;
601       p = rparam + WORDSIZE + WORDSIZE;
602       GETWORD(p, count);
603
604       for (i=0,p=rdata; i<count; i++) {
605         GETSTRINGF(p, groupname, RAP_USERNAME_LEN);
606             fn(groupname, state);
607       }
608     } else {
609       DEBUG(4,("NetUserGetGroups res=%d\n", res));
610     }
611   } else {
612     DEBUG(4,("NetUserGetGroups no data returned\n"));
613   }
614   SAFE_FREE(rdata);
615   SAFE_FREE(rparam);
616   return res;
617 }
618
619
620 /****************************************************************************
621  call a NetUserDelete - delete user from remote server
622 ****************************************************************************/
623 int cli_NetUserDelete(struct cli_state *cli, const char * user_name )
624 {
625   char *rparam = NULL;
626   char *rdata = NULL;
627   char *p;
628   unsigned int rdrcnt,rprcnt;
629   int res;
630   char param[WORDSIZE                    /* api number    */
631             +sizeof(RAP_NetGroupDel_REQ) /* parm string   */
632             +1                           /* no ret string */
633             +RAP_USERNAME_LEN            /* user to del   */
634             +WORDSIZE];                  /* reserved word */
635
636   /* now send a SMBtrans command with api UserDel */
637   p = make_header(param, RAP_WUserDel, RAP_NetGroupDel_REQ, NULL);  
638   PUTSTRING(p, user_name, RAP_USERNAME_LEN);
639   PUTWORD(p,0);  /* reserved word MBZ on input */
640                  
641   if (cli_api(cli, 
642               param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
643               NULL, 0, 200,       /* data, length, maxlen */
644               &rparam, &rprcnt,   /* return params, length */
645               &rdata, &rdrcnt))   /* return data, length */
646     {
647       res = GETRES(rparam);
648       
649       if (res == 0) {
650         /* nothing to do */             
651       }
652       else if ((res == 5) || (res == 65)) {
653          DEBUG(1, ("Access Denied\n"));
654       }
655       else if (res == 2221) {
656          DEBUG (1, ("User does not exist\n"));
657       }
658       else {
659           DEBUG(4,("NetUserDelete res=%d\n", res));
660       }      
661     } else {
662       res = -1;
663       DEBUG(4,("NetUserDelete failed\n"));
664     }
665   
666   SAFE_FREE(rparam);
667   SAFE_FREE(rdata);
668         
669   return res;
670 }
671
672 /****************************************************************************
673  call a NetUserAdd - add user to remote server
674 ****************************************************************************/
675 int cli_NetUserAdd(struct cli_state *cli, RAP_USER_INFO_1 * userinfo )
676 {
677    
678
679
680   char *rparam = NULL;
681   char *rdata = NULL;
682   char *p;                                          
683   unsigned int rdrcnt,rprcnt;
684   int res;
685   char param[WORDSIZE                    /* api number    */
686             +sizeof(RAP_NetUserAdd2_REQ) /* req string    */
687             +sizeof(RAP_USER_INFO_L1)    /* data string   */
688             +WORDSIZE                    /* info level    */
689             +WORDSIZE                    /* buffer length */
690             +WORDSIZE];                  /* reserved      */
691  
692   char data[1024];
693   /* offset into data of free format strings.  Will be updated */
694   /* by PUTSTRINGP macro and end up with total data length.    */
695   int soffset=RAP_USERNAME_LEN+1 /* user name + pad */
696     + RAP_UPASSWD_LEN            /* password        */
697     + DWORDSIZE                  /* password age    */
698     + WORDSIZE                   /* privilege       */
699     + DWORDSIZE                  /* home dir ptr    */
700     + DWORDSIZE                  /* comment ptr     */
701     + WORDSIZE                   /* flags           */
702     + DWORDSIZE;                 /* login script ptr*/
703
704   /* now send a SMBtrans command with api NetUserAdd */
705   p = make_header(param, RAP_WUserAdd2,
706                   RAP_NetUserAdd2_REQ, RAP_USER_INFO_L1);
707   PUTWORD(p, 1); /* info level */
708
709   PUTWORD(p, 0); /* pwencrypt */
710   if(userinfo->passwrd)
711     PUTWORD(p,MIN(strlen(userinfo->passwrd), RAP_UPASSWD_LEN));
712   else
713     PUTWORD(p, 0); /* password length */
714
715   p = data;
716   memset(data, '\0', soffset);
717
718   PUTSTRINGF(p, userinfo->user_name, RAP_USERNAME_LEN);
719   PUTBYTE(p, 0); /* pad byte 0 */
720   PUTSTRINGF(p, userinfo->passwrd, RAP_UPASSWD_LEN);
721   PUTDWORD(p, 0); /* pw age - n.a. on user add */
722   PUTWORD(p, userinfo->priv);
723   PUTSTRINGP(p, userinfo->home_dir, data, soffset);
724   PUTSTRINGP(p, userinfo->comment, data, soffset);
725   PUTWORD(p, userinfo->userflags);
726   PUTSTRINGP(p, userinfo->logon_script, data, soffset);
727
728   if (cli_api(cli, 
729               param, sizeof(param), 1024, /* Param, length, maxlen */
730               data, soffset, sizeof(data), /* data, length, maxlen */
731               &rparam, &rprcnt,   /* return params, length */
732               &rdata, &rdrcnt))   /* return data, length */
733     {
734       res = GETRES(rparam);
735       
736       if (res == 0) {
737         /* nothing to do */             
738       }       
739       else if ((res == 5) || (res == 65)) {
740         DEBUG(1, ("Access Denied\n"));
741       }
742       else if (res == 2224) {
743         DEBUG (1, ("User already exists\n"));
744       }
745       else {
746             DEBUG(4,("NetUserAdd res=%d\n", res));
747       }
748     } else {
749       res = -1;
750       DEBUG(4,("NetUserAdd failed\n"));
751     }
752   
753   SAFE_FREE(rparam);
754   SAFE_FREE(rdata);
755
756   return res;
757 }
758
759 /****************************************************************************
760 call a NetUserEnum - try and list users on a different host
761 ****************************************************************************/
762 int cli_RNetUserEnum(struct cli_state *cli, void (*fn)(const char *, const char *, const char *, const char *, void *), void *state)
763 {
764   char param[WORDSIZE                 /* api number    */
765             +sizeof(RAP_NetUserEnum_REQ) /* parm string   */
766             +sizeof(RAP_USER_INFO_L1)    /* return string */
767             +WORDSIZE                 /* info level    */
768             +WORDSIZE];               /* buffer size   */
769   char *p;
770   char *rparam = NULL;
771   char *rdata = NULL; 
772   unsigned int rprcnt, rdrcnt;
773   int res = -1;
774   
775
776   memset(param, '\0', sizeof(param));
777   p = make_header(param, RAP_WUserEnum,
778                   RAP_NetUserEnum_REQ, RAP_USER_INFO_L1);
779   PUTWORD(p,1); /* Info level 1 */
780   PUTWORD(p,0xFF00); /* Return buffer size */
781
782 /* BB Fix handling of large numbers of users to be returned */
783   if (cli_api(cli,
784               param, PTR_DIFF(p,param),8,
785               NULL, 0, CLI_BUFFER_SIZE,
786               &rparam, &rprcnt,
787               &rdata, &rdrcnt)) {
788     res = GETRES(rparam);
789     cli->rap_error = res;
790     if (cli->rap_error != 0) {
791       DEBUG(1,("NetUserEnum gave error %d\n", cli->rap_error));
792     }
793   }
794   if (rdata) {
795     if (res == 0 || res == ERRmoredata) {
796       int i, converter, count;
797       char username[RAP_USERNAME_LEN];
798       char userpw[RAP_UPASSWD_LEN];
799       pstring comment, homedir, logonscript;
800
801       p = rparam + WORDSIZE; /* skip result */
802       GETWORD(p, converter);
803       GETWORD(p, count);
804
805       for (i=0,p=rdata;i<count;i++) {
806         GETSTRINGF(p, username, RAP_USERNAME_LEN);
807         p++; /* pad byte */
808         GETSTRINGF(p, userpw, RAP_UPASSWD_LEN);
809         p += DWORDSIZE; /* skip password age */
810         p += WORDSIZE;  /* skip priv: 0=guest, 1=user, 2=admin */
811         GETSTRINGP(p, homedir, rdata, converter);
812         GETSTRINGP(p, comment, rdata, converter);
813         p += WORDSIZE;  /* skip flags */
814         GETSTRINGP(p, logonscript, rdata, converter);
815
816         fn(username, comment, homedir, logonscript, cli);
817       }
818     } else {
819       DEBUG(4,("NetUserEnum res=%d\n", res));
820     }
821   } else {
822     DEBUG(4,("NetUserEnum no data returned\n"));
823   }
824     
825   SAFE_FREE(rparam);
826   SAFE_FREE(rdata);
827
828   return res;
829 }
830
831 int cli_RNetUserEnum0(struct cli_state *cli,
832                       void (*fn)(const char *, void *),
833                       void *state)
834 {
835   char param[WORDSIZE                 /* api number    */
836             +sizeof(RAP_NetUserEnum_REQ) /* parm string   */
837             +sizeof(RAP_USER_INFO_L0)    /* return string */
838             +WORDSIZE                 /* info level    */
839             +WORDSIZE];               /* buffer size   */
840   char *p;
841   char *rparam = NULL;
842   char *rdata = NULL; 
843   unsigned int rprcnt, rdrcnt;
844   int res = -1;
845   
846
847   memset(param, '\0', sizeof(param));
848   p = make_header(param, RAP_WUserEnum,
849                   RAP_NetUserEnum_REQ, RAP_USER_INFO_L0);
850   PUTWORD(p,0); /* Info level 1 */
851   PUTWORD(p,0xFF00); /* Return buffer size */
852
853 /* BB Fix handling of large numbers of users to be returned */
854   if (cli_api(cli,
855               param, PTR_DIFF(p,param),8,
856               NULL, 0, CLI_BUFFER_SIZE,
857               &rparam, &rprcnt,
858               &rdata, &rdrcnt)) {
859     res = GETRES(rparam);
860     cli->rap_error = res;
861     if (cli->rap_error != 0) {
862       DEBUG(1,("NetUserEnum gave error %d\n", cli->rap_error));
863     }
864   }
865   if (rdata) {
866     if (res == 0 || res == ERRmoredata) {
867       int i, count;
868       char username[RAP_USERNAME_LEN];
869
870       p = rparam + WORDSIZE + WORDSIZE; /* skip result and converter */
871       GETWORD(p, count);
872
873       for (i=0,p=rdata;i<count;i++) {
874         GETSTRINGF(p, username, RAP_USERNAME_LEN);
875         fn(username, cli);
876       }
877     } else {
878       DEBUG(4,("NetUserEnum res=%d\n", res));
879     }
880   } else {
881     DEBUG(4,("NetUserEnum no data returned\n"));
882   }
883     
884   SAFE_FREE(rparam);
885   SAFE_FREE(rdata);
886
887   return res;
888 }
889
890 /****************************************************************************
891  call a NetFileClose2 - close open file on another session to server
892 ****************************************************************************/
893 int cli_NetFileClose(struct cli_state *cli, uint32 file_id )
894 {
895   char *rparam = NULL;
896   char *rdata = NULL;
897   char *p;
898   unsigned int rdrcnt,rprcnt;
899   char param[WORDSIZE                    /* api number    */
900             +sizeof(RAP_WFileClose2_REQ) /* req string    */
901             +1                           /* no ret string */
902             +DWORDSIZE];                 /* file ID          */
903   int res = -1;
904
905   /* now send a SMBtrans command with api RNetShareEnum */
906   p = make_header(param, RAP_WFileClose2, RAP_WFileClose2_REQ, NULL);
907   PUTDWORD(p, file_id);  
908                  
909   if (cli_api(cli, 
910               param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
911               NULL, 0, 200,       /* data, length, maxlen */
912               &rparam, &rprcnt,   /* return params, length */
913               &rdata, &rdrcnt))   /* return data, length */
914     {
915       res = GETRES(rparam);
916       
917       if (res == 0) {
918         /* nothing to do */             
919       } else if (res == 2314){
920          DEBUG(1, ("NetFileClose2 - attempt to close non-existant file open instance\n"));
921       } else {
922         DEBUG(4,("NetFileClose2 res=%d\n", res));
923       }      
924     } else {
925       res = -1;
926       DEBUG(4,("NetFileClose2 failed\n"));
927     }
928   
929   SAFE_FREE(rparam);
930   SAFE_FREE(rdata);
931   
932   return res;
933 }
934
935 /****************************************************************************
936 call a NetFileGetInfo - get information about server file opened from other
937      workstation
938 ****************************************************************************/
939 int cli_NetFileGetInfo(struct cli_state *cli, uint32 file_id, void (*fn)(const char *, const char *, uint16, uint16, uint32))
940 {
941   char *rparam = NULL;
942   char *rdata = NULL;
943   char *p;
944   unsigned int rdrcnt,rprcnt;
945   int res;
946   char param[WORDSIZE                      /* api number      */
947             +sizeof(RAP_WFileGetInfo2_REQ) /* req string      */
948             +sizeof(RAP_FILE_INFO_L3)      /* return string   */
949             +DWORDSIZE                     /* file ID          */
950             +WORDSIZE                      /* info level      */
951             +WORDSIZE];                    /* buffer size     */
952
953   /* now send a SMBtrans command with api RNetShareEnum */
954   p = make_header(param, RAP_WFileGetInfo2,
955                   RAP_WFileGetInfo2_REQ, RAP_FILE_INFO_L3); 
956   PUTDWORD(p, file_id);
957   PUTWORD(p, 3);  /* info level */
958   PUTWORD(p, 0x1000);   /* buffer size */ 
959   if (cli_api(cli, 
960               param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
961               NULL, 0, 0x1000,  /* data, length, maxlen */
962               &rparam, &rprcnt,               /* return params, length */
963               &rdata, &rdrcnt))               /* return data, length */
964     {
965       res = GETRES(rparam);
966       if (res == 0 || res == ERRmoredata) {
967         int converter,id, perms, locks;
968         pstring fpath, fuser;
969           
970         p = rparam + WORDSIZE; /* skip result */
971         GETWORD(p, converter);
972
973         p = rdata;
974         GETDWORD(p, id);
975         GETWORD(p, perms);
976         GETWORD(p, locks);
977         GETSTRINGP(p, fpath, rdata, converter);
978         GETSTRINGP(p, fuser, rdata, converter);
979         
980         fn(fpath, fuser, perms, locks, id);
981       } else {
982         DEBUG(4,("NetFileGetInfo2 res=%d\n", res));
983       }      
984     } else {
985       res = -1;
986       DEBUG(4,("NetFileGetInfo2 failed\n"));
987     }
988   
989   SAFE_FREE(rparam);
990   SAFE_FREE(rdata);
991   
992   return res;
993 }
994
995 /****************************************************************************
996 * Call a NetFileEnum2 - list open files on an SMB server
997
998 * PURPOSE:  Remotes a NetFileEnum API call to the current server or target 
999 *           server listing the files open via the network (and their
1000 *           corresponding open instance ids)
1001 *          
1002 * Dependencies: none
1003 *
1004 * Parameters: 
1005 *             cli    - pointer to cli_state structure
1006 *             user   - if present, return only files opened by this remote user
1007 *             base_path - if present, return only files opened below this 
1008 *                         base path
1009 *             fn     - display function to invoke for each entry in the result
1010 *                        
1011 *
1012 * Returns:
1013 *             True      - success
1014 *             False     - failure
1015 *
1016 ****************************************************************************/
1017 int cli_NetFileEnum(struct cli_state *cli, char * user, char * base_path, void (*fn)(const char *, const char *, uint16, uint16, uint32))
1018 {
1019   char *rparam = NULL;
1020   char *rdata = NULL;
1021   char *p;
1022   unsigned int rdrcnt,rprcnt;
1023   char param[WORDSIZE                   /* api number      */
1024             +sizeof(RAP_WFileEnum2_REQ) /* req string      */
1025             +sizeof(RAP_FILE_INFO_L3)   /* return string   */
1026             +256                        /* base path (opt) */
1027             +RAP_USERNAME_LEN           /* user name (opt) */
1028             +WORDSIZE                   /* info level      */
1029             +WORDSIZE                   /* buffer size     */
1030             +DWORDSIZE                  /* resume key ?    */
1031             +DWORDSIZE];                /* resume key ?    */
1032   int count = -1;
1033
1034   /* now send a SMBtrans command with api RNetShareEnum */
1035   p = make_header(param, RAP_WFileEnum2,
1036                   RAP_WFileEnum2_REQ, RAP_FILE_INFO_L3); 
1037
1038   PUTSTRING(p, base_path, 256);
1039   PUTSTRING(p, user, RAP_USERNAME_LEN);
1040   PUTWORD(p, 3); /* info level */
1041   PUTWORD(p, 0xFF00);  /* buffer size */ 
1042   PUTDWORD(p, 0);  /* zero out the resume key */
1043   PUTDWORD(p, 0);  /* or is this one the resume key? */
1044                  
1045   if (cli_api(cli, 
1046               param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
1047               NULL, 0, 0xFF00,  /* data, length, maxlen */
1048               &rparam, &rprcnt,               /* return params, length */
1049               &rdata, &rdrcnt))               /* return data, length */
1050     {
1051       int res = GETRES(rparam);
1052       
1053       if (res == 0 || res == ERRmoredata) {
1054         int converter, i;
1055
1056         p = rparam + WORDSIZE; /* skip result */
1057         GETWORD(p, converter);
1058         GETWORD(p, count);
1059         
1060         p = rdata;
1061         for (i=0; i<count; i++) {
1062           int id, perms, locks;
1063           pstring fpath, fuser;
1064           
1065           GETDWORD(p, id);
1066           GETWORD(p, perms);
1067           GETWORD(p, locks);
1068           GETSTRINGP(p, fpath, rdata, converter);
1069           GETSTRINGP(p, fuser, rdata, converter);
1070
1071           fn(fpath, fuser, perms, locks, id);
1072         }  /* BB fix ERRmoredata case to send resume request */
1073       } else {
1074         DEBUG(4,("NetFileEnum2 res=%d\n", res));
1075       }      
1076     } else {
1077       DEBUG(4,("NetFileEnum2 failed\n"));
1078     }
1079   
1080   SAFE_FREE(rparam);
1081   SAFE_FREE(rdata);
1082   
1083   return count;
1084 }
1085
1086 /****************************************************************************
1087  call a NetShareAdd - share/export directory on remote server
1088 ****************************************************************************/
1089 int cli_NetShareAdd(struct cli_state *cli, RAP_SHARE_INFO_2 * sinfo )
1090 {
1091   char *rparam = NULL;
1092   char *rdata = NULL;
1093   char *p;
1094   unsigned int rdrcnt,rprcnt;
1095   int res;
1096   char param[WORDSIZE                  /* api number    */
1097             +sizeof(RAP_WShareAdd_REQ) /* req string    */
1098             +sizeof(RAP_SHARE_INFO_L2) /* return string */
1099             +WORDSIZE                  /* info level    */
1100             +WORDSIZE];                /* reserved word */
1101   char data[1024];
1102   /* offset to free format string section following fixed length data.  */
1103   /* will be updated by PUTSTRINGP macro and will end up with total len */
1104   int soffset = RAP_SHARENAME_LEN + 1 /* share name + pad   */
1105     + WORDSIZE                        /* share type    */
1106     + DWORDSIZE                       /* comment pointer */
1107     + WORDSIZE                        /* permissions */
1108     + WORDSIZE                        /* max users */
1109     + WORDSIZE                        /* active users */
1110     + DWORDSIZE                       /* share path */
1111     + RAP_SPASSWD_LEN + 1;            /* share password + pad */
1112
1113   memset(param,'\0',sizeof(param));
1114   /* now send a SMBtrans command with api RNetShareAdd */
1115   p = make_header(param, RAP_WshareAdd,
1116                   RAP_WShareAdd_REQ, RAP_SHARE_INFO_L2); 
1117   PUTWORD(p, 2); /* info level */
1118   PUTWORD(p, 0); /* reserved word 0 */
1119
1120   p = data;
1121   PUTSTRINGF(p, sinfo->share_name, RAP_SHARENAME_LEN);
1122   PUTBYTE(p, 0); /* pad byte 0 */
1123
1124   PUTWORD(p, sinfo->share_type);
1125   PUTSTRINGP(p, sinfo->comment, data, soffset);
1126   PUTWORD(p, sinfo->perms);
1127   PUTWORD(p, sinfo->maximum_users);
1128   PUTWORD(p, sinfo->active_users);
1129   PUTSTRINGP(p, sinfo->path, data, soffset);
1130   PUTSTRINGF(p, sinfo->password, RAP_SPASSWD_LEN);
1131   SCVAL(p,-1,0x0A); /* required 0x0A at end of password */
1132   
1133   if (cli_api(cli, 
1134               param, sizeof(param), 1024, /* Param, length, maxlen */
1135               data, soffset, sizeof(data), /* data, length, maxlen */
1136               &rparam, &rprcnt,   /* return params, length */
1137               &rdata, &rdrcnt))   /* return data, length */
1138     {
1139       res = rparam? SVAL(rparam,0) : -1;
1140                         
1141       if (res == 0) {
1142         /* nothing to do */             
1143       }
1144       else {
1145         DEBUG(4,("NetShareAdd res=%d\n", res));
1146       }      
1147     } else {
1148       res = -1;
1149       DEBUG(4,("NetShareAdd failed\n"));
1150     }
1151   
1152   SAFE_FREE(rparam);
1153   SAFE_FREE(rdata);
1154   
1155   return res;
1156 }
1157 /****************************************************************************
1158  call a NetShareDelete - unshare exported directory on remote server
1159 ****************************************************************************/
1160 int cli_NetShareDelete(struct cli_state *cli, const char * share_name )
1161 {
1162   char *rparam = NULL;
1163   char *rdata = NULL;
1164   char *p;
1165   unsigned int rdrcnt,rprcnt;
1166   int res;
1167   char param[WORDSIZE                  /* api number    */
1168             +sizeof(RAP_WShareDel_REQ) /* req string    */
1169             +1                         /* no ret string */
1170             +RAP_SHARENAME_LEN         /* share to del  */
1171             +WORDSIZE];                /* reserved word */
1172             
1173
1174   /* now send a SMBtrans command with api RNetShareDelete */
1175   p = make_header(param, RAP_WshareDel, RAP_WShareDel_REQ, NULL);
1176   PUTSTRING(p,share_name,RAP_SHARENAME_LEN);
1177   PUTWORD(p,0);  /* reserved word MBZ on input */
1178                  
1179   if (cli_api(cli, 
1180               param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
1181               NULL, 0, 200,       /* data, length, maxlen */
1182               &rparam, &rprcnt,   /* return params, length */
1183               &rdata, &rdrcnt))   /* return data, length */
1184     {
1185       res = GETRES(rparam);
1186                         
1187       if (res == 0) {
1188         /* nothing to do */             
1189       }
1190       else {
1191         DEBUG(4,("NetShareDelete res=%d\n", res));
1192       }      
1193     } else {
1194       res = -1;
1195       DEBUG(4,("NetShareDelete failed\n"));
1196     }
1197   
1198   SAFE_FREE(rparam);
1199   SAFE_FREE(rdata);
1200         
1201   return res;
1202 }
1203 /*************************************************************************
1204 *
1205 * Function Name:  cli_get_pdc_name
1206 *
1207 * PURPOSE:  Remotes a NetServerEnum API call to the current server
1208 *           requesting the name of a server matching the server
1209 *           type of SV_TYPE_DOMAIN_CTRL (PDC).
1210 *
1211 * Dependencies: none
1212 *
1213 * Parameters: 
1214 *             cli       - pointer to cli_state structure
1215 *             workgroup - pointer to string containing name of domain
1216 *             pdc_name  - pointer to string that will contain PDC name
1217 *                         on successful return
1218 *
1219 * Returns:
1220 *             True      - success
1221 *             False     - failure
1222 *
1223 ************************************************************************/
1224 BOOL cli_get_pdc_name(struct cli_state *cli, char *workgroup, char *pdc_name)
1225 {
1226   char *rparam = NULL;
1227   char *rdata = NULL;
1228   unsigned int rdrcnt,rprcnt;
1229   char *p;
1230   char param[WORDSIZE                       /* api number    */
1231             +sizeof(RAP_NetServerEnum2_REQ) /* req string    */
1232             +sizeof(RAP_SERVER_INFO_L1)     /* return string */
1233             +WORDSIZE                       /* info level    */
1234             +WORDSIZE                       /* buffer size   */
1235             +DWORDSIZE                      /* server type   */
1236             +RAP_MACHNAME_LEN];             /* workgroup     */
1237   int count = -1;
1238   
1239   *pdc_name = '\0';
1240
1241   /* send a SMBtrans command with api NetServerEnum */
1242   p = make_header(param, RAP_NetServerEnum2,
1243                   RAP_NetServerEnum2_REQ, RAP_SERVER_INFO_L1);
1244   PUTWORD(p, 1); /* info level */
1245   PUTWORD(p, CLI_BUFFER_SIZE);
1246   PUTDWORD(p, SV_TYPE_DOMAIN_CTRL);
1247   PUTSTRING(p, workgroup, RAP_MACHNAME_LEN);
1248         
1249   if (cli_api(cli, 
1250               param, PTR_DIFF(p,param), 8,        /* params, length, max */
1251               NULL, 0, CLI_BUFFER_SIZE,               /* data, length, max */
1252               &rparam, &rprcnt,                   /* return params, return size */
1253               &rdata, &rdrcnt                     /* return data, return size */
1254               )) {
1255     cli->rap_error = GETRES(rparam);
1256                         
1257         /*
1258          * We only really care to copy a name if the
1259          * API succeeded and we got back a name.
1260          */
1261     if (cli->rap_error == 0) {
1262       p = rparam + WORDSIZE + WORDSIZE; /* skip result and converter */
1263       GETWORD(p, count);
1264       p = rdata;
1265       
1266       if (count > 0)
1267         GETSTRING(p, pdc_name);
1268     }
1269     else {
1270         DEBUG(4,("cli_get_pdc_name: machine %s failed the NetServerEnum call. "
1271                  "Error was : %s.\n", cli->desthost, cli_errstr(cli) ));
1272     }
1273   }
1274   
1275   SAFE_FREE(rparam);
1276   SAFE_FREE(rdata);
1277   
1278   return(count > 0);
1279 }
1280
1281
1282 /*************************************************************************
1283 *
1284 * Function Name:  cli_get_server_domain
1285 *
1286 * PURPOSE:  Remotes a NetWkstaGetInfo API call to the current server
1287 *           requesting wksta_info_10 level information to determine
1288 *           the domain the server belongs to. On success, this
1289 *           routine sets the server_domain field in the cli_state structure
1290 *           to the server's domain name.
1291 *
1292 * Dependencies: none
1293 *
1294 * Parameters: 
1295 *             cli       - pointer to cli_state structure
1296 *
1297 * Returns:
1298 *             True      - success
1299 *             False     - failure
1300 *
1301 * Origins:  samba 2.0.6 source/libsmb/clientgen.c cli_NetServerEnum()
1302 *
1303 ************************************************************************/
1304 BOOL cli_get_server_domain(struct cli_state *cli)
1305 {
1306   char *rparam = NULL;
1307   char *rdata = NULL;
1308   unsigned int rdrcnt,rprcnt;
1309   char *p;
1310   char param[WORDSIZE                      /* api number    */
1311             +sizeof(RAP_WWkstaGetInfo_REQ) /* req string    */
1312             +sizeof(RAP_WKSTA_INFO_L10)    /* return string */
1313             +WORDSIZE                      /* info level    */
1314             +WORDSIZE];                    /* buffer size   */
1315   int res = -1;
1316   
1317   /* send a SMBtrans command with api NetWkstaGetInfo */
1318   p = make_header(param, RAP_WWkstaGetInfo,
1319                   RAP_WWkstaGetInfo_REQ, RAP_WKSTA_INFO_L10);
1320   PUTWORD(p, 10); /* info level */
1321   PUTWORD(p, CLI_BUFFER_SIZE);
1322         
1323   if (cli_api(cli, param, PTR_DIFF(p,param), 8, /* params, length, max */
1324               NULL, 0, CLI_BUFFER_SIZE,         /* data, length, max */
1325               &rparam, &rprcnt,         /* return params, return size */
1326               &rdata, &rdrcnt)) {       /* return data, return size */
1327     res = GETRES(rparam);
1328     p = rdata;          
1329     
1330     if (res == 0) {
1331       int converter;
1332
1333       p = rparam + WORDSIZE;
1334       GETWORD(p, converter);
1335       
1336       p = rdata + DWORDSIZE + DWORDSIZE; /* skip computer & user names */
1337       GETSTRINGP(p, cli->server_domain, rdata, converter);
1338     }
1339   }
1340   
1341   SAFE_FREE(rparam);
1342   SAFE_FREE(rdata);
1343   
1344   return(res == 0);
1345 }
1346
1347
1348 /*************************************************************************
1349 *
1350 * Function Name:  cli_get_server_type
1351 *
1352 * PURPOSE:  Remotes a NetServerGetInfo API call to the current server
1353 *           requesting server_info_1 level information to retrieve
1354 *           the server type.
1355 *
1356 * Dependencies: none
1357 *
1358 * Parameters: 
1359 *             cli       - pointer to cli_state structure
1360 *             pstype    - pointer to uint32 to contain returned server type
1361 *
1362 * Returns:
1363 *             True      - success
1364 *             False     - failure
1365 *
1366 * Origins:  samba 2.0.6 source/libsmb/clientgen.c cli_NetServerEnum()
1367 *
1368 ************************************************************************/
1369 BOOL cli_get_server_type(struct cli_state *cli, uint32 *pstype)
1370 {
1371   char *rparam = NULL;
1372   char *rdata = NULL;
1373   unsigned int rdrcnt,rprcnt;
1374   char *p;
1375   char param[WORDSIZE                       /* api number    */
1376             +sizeof(RAP_WserverGetInfo_REQ) /* req string    */
1377             +sizeof(RAP_SERVER_INFO_L1)     /* return string */
1378             +WORDSIZE                       /* info level    */
1379             +WORDSIZE];                     /* buffer size   */
1380   int res = -1;
1381   
1382   /* send a SMBtrans command with api NetServerGetInfo */
1383   p = make_header(param, RAP_WserverGetInfo,
1384                   RAP_WserverGetInfo_REQ, RAP_SERVER_INFO_L1);
1385   PUTWORD(p, 1); /* info level */
1386   PUTWORD(p, CLI_BUFFER_SIZE);
1387         
1388   if (cli_api(cli, 
1389               param, PTR_DIFF(p,param), 8, /* params, length, max */
1390               NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
1391               &rparam, &rprcnt,         /* return params, return size */
1392               &rdata, &rdrcnt           /* return data, return size */
1393               )) {
1394     
1395     res = GETRES(rparam);
1396     
1397     if (res == 0 || res == ERRmoredata) {
1398       p = rdata;                                        
1399       *pstype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
1400     }
1401   }
1402   
1403   SAFE_FREE(rparam);
1404   SAFE_FREE(rdata);
1405   
1406   return(res == 0 || res == ERRmoredata);
1407 }
1408
1409
1410 /*************************************************************************
1411 *
1412 * Function Name:  cli_ns_check_server_type
1413 *
1414 * PURPOSE:  Remotes a NetServerEnum2 API call to the current server
1415 *           requesting server_info_0 level information of machines
1416 *           matching the given server type. If the returned server
1417 *           list contains the machine name contained in cli->desthost
1418 *           then we conclude the server type checks out. This routine
1419 *           is useful to retrieve list of server's of a certain
1420 *           type when all you have is a null session connection and
1421 *           can't remote API calls such as NetWkstaGetInfo or 
1422 *           NetServerGetInfo.
1423 *
1424 * Dependencies: none
1425 *
1426 * Parameters: 
1427 *             cli       - pointer to cli_state structure
1428 *             workgroup - pointer to string containing domain
1429 *             stype     - server type
1430 *
1431 * Returns:
1432 *             True      - success
1433 *             False     - failure
1434 *
1435 ************************************************************************/
1436 BOOL cli_ns_check_server_type(struct cli_state *cli, char *workgroup, uint32 stype)
1437 {
1438   char *rparam = NULL;
1439   char *rdata = NULL;
1440   unsigned int rdrcnt,rprcnt;
1441   char *p;
1442   char param[WORDSIZE                       /* api number    */
1443             +sizeof(RAP_NetServerEnum2_REQ) /* req string    */
1444             +sizeof(RAP_SERVER_INFO_L0)     /* return string */
1445             +WORDSIZE                       /* info level    */
1446             +WORDSIZE                       /* buffer size   */
1447             +DWORDSIZE                      /* server type   */
1448             +RAP_MACHNAME_LEN];             /* workgroup     */
1449   BOOL found_server = False;
1450   int res = -1;
1451   
1452   /* send a SMBtrans command with api NetServerEnum */
1453   p = make_header(param, RAP_NetServerEnum2,
1454                   RAP_NetServerEnum2_REQ, RAP_SERVER_INFO_L0);
1455   PUTWORD(p, 0); /* info level 0 */
1456   PUTWORD(p, CLI_BUFFER_SIZE);
1457   PUTDWORD(p, stype);
1458   PUTSTRING(p, workgroup, RAP_MACHNAME_LEN);
1459         
1460   if (cli_api(cli, 
1461               param, PTR_DIFF(p,param), 8, /* params, length, max */
1462               NULL, 0, CLI_BUFFER_SIZE,  /* data, length, max */
1463               &rparam, &rprcnt,          /* return params, return size */
1464               &rdata, &rdrcnt            /* return data, return size */
1465               )) {
1466         
1467     res = GETRES(rparam);
1468     cli->rap_error = res;
1469
1470     if (res == 0 || res == ERRmoredata) {
1471       int i, count;
1472
1473       p = rparam + WORDSIZE + WORDSIZE;
1474       GETWORD(p, count);
1475
1476       p = rdata;
1477       for (i = 0;i < count;i++, p += 16) {
1478         char ret_server[RAP_MACHNAME_LEN];
1479
1480         GETSTRINGF(p, ret_server, RAP_MACHNAME_LEN);
1481         if (strequal(ret_server, cli->desthost)) {
1482           found_server = True;
1483           break;
1484         }
1485       }
1486     }
1487     else {
1488       DEBUG(4,("cli_ns_check_server_type: machine %s failed the NetServerEnum call. "
1489                "Error was : %s.\n", cli->desthost, cli_errstr(cli) ));
1490     }
1491   }
1492   
1493   SAFE_FREE(rparam);
1494   SAFE_FREE(rdata);
1495         
1496   return found_server;
1497  }
1498
1499
1500 /****************************************************************************
1501  perform a NetWkstaUserLogoff
1502 ****************************************************************************/
1503 BOOL cli_NetWkstaUserLogoff(struct cli_state *cli,char *user, char *workstation)
1504 {
1505   char *rparam = NULL;
1506   char *rdata = NULL;
1507   char *p;
1508   unsigned int rdrcnt,rprcnt;
1509   char param[WORDSIZE                           /* api number    */
1510             +sizeof(RAP_NetWkstaUserLogoff_REQ) /* req string    */
1511             +sizeof(RAP_USER_LOGOFF_INFO_L1)    /* return string */
1512             +RAP_USERNAME_LEN+1                 /* user name+pad */
1513             +RAP_MACHNAME_LEN                   /* wksta name    */
1514             +WORDSIZE                           /* buffer size   */
1515             +WORDSIZE];                         /* buffer size?  */
1516   fstring upperbuf;
1517   
1518   memset(param, 0, sizeof(param));
1519
1520   /* send a SMBtrans command with api NetWkstaUserLogoff */
1521   p = make_header(param, RAP_WWkstaUserLogoff,
1522                   RAP_NetWkstaUserLogoff_REQ, RAP_USER_LOGOFF_INFO_L1);
1523   PUTDWORD(p, 0); /* Null pointer */
1524   PUTDWORD(p, 0); /* Null pointer */
1525   fstrcpy(upperbuf, user);
1526   strupper_m(upperbuf);
1527   PUTSTRINGF(p, upperbuf, RAP_USERNAME_LEN);
1528   p++; /* strange format, but ok */
1529   fstrcpy(upperbuf, workstation);
1530   strupper_m(upperbuf);
1531   PUTSTRINGF(p, upperbuf, RAP_MACHNAME_LEN);
1532   PUTWORD(p, CLI_BUFFER_SIZE);
1533   PUTWORD(p, CLI_BUFFER_SIZE);
1534   
1535   if (cli_api(cli,
1536               param, PTR_DIFF(p,param),1024,  /* param, length, max */
1537               NULL, 0, CLI_BUFFER_SIZE,       /* data, length, max */
1538               &rparam, &rprcnt,               /* return params, return size */
1539               &rdata, &rdrcnt                 /* return data, return size */
1540               )) {
1541     cli->rap_error = GETRES(rparam);
1542     
1543     if (cli->rap_error != 0) {
1544       DEBUG(4,("NetwkstaUserLogoff gave error %d\n", cli->rap_error));
1545     }
1546   }
1547   
1548   SAFE_FREE(rparam);
1549   SAFE_FREE(rdata);
1550   return (cli->rap_error == 0);
1551 }
1552  
1553 int cli_NetPrintQEnum(struct cli_state *cli,
1554                 void (*qfn)(const char*,uint16,uint16,uint16,const char*,const char*,const char*,const char*,const char*,uint16,uint16),
1555                 void (*jfn)(uint16,const char*,const char*,const char*,const char*,uint16,uint16,const char*,uint,uint,const char*))
1556 {
1557   char param[WORDSIZE                         /* api number    */
1558             +sizeof(RAP_NetPrintQEnum_REQ)    /* req string    */
1559             +sizeof(RAP_PRINTQ_INFO_L2)       /* return string */
1560             +WORDSIZE                         /* info level    */
1561             +WORDSIZE                         /* buffer size   */
1562             +sizeof(RAP_SMB_PRINT_JOB_L1)];   /* more ret data */
1563   char *p;
1564   char *rparam = NULL;
1565   char *rdata = NULL; 
1566   unsigned int rprcnt, rdrcnt;
1567   int res = -1;
1568   
1569
1570   memset(param, '\0',sizeof(param));
1571   p = make_header(param, RAP_WPrintQEnum, 
1572                   RAP_NetPrintQEnum_REQ, RAP_PRINTQ_INFO_L2);
1573   PUTWORD(p,2); /* Info level 2 */
1574   PUTWORD(p,0xFFE0); /* Return buffer size */
1575   PUTSTRING(p, RAP_SMB_PRINT_JOB_L1, 0);
1576
1577   if (cli_api(cli,
1578               param, PTR_DIFF(p,param),1024,
1579               NULL, 0, CLI_BUFFER_SIZE,
1580               &rparam, &rprcnt,
1581               &rdata, &rdrcnt)) {
1582     res = GETRES(rparam);
1583     cli->rap_error = res;
1584     if (res != 0) {
1585       DEBUG(1,("NetPrintQEnum gave error %d\n", res));
1586     }
1587   }
1588
1589   if (rdata) {
1590     if (res == 0 || res == ERRmoredata) {
1591       int i, converter, count;
1592
1593       p = rparam + WORDSIZE;
1594       GETWORD(p, converter);
1595       GETWORD(p, count);
1596
1597       p = rdata;
1598       for (i=0;i<count;i++) {
1599         pstring qname, sep_file, print_proc, dest, parms, comment;
1600         uint16 jobcount, priority, start_time, until_time, status;
1601
1602         GETSTRINGF(p, qname, RAP_SHARENAME_LEN);
1603         p++; /* pad */
1604         GETWORD(p, priority);
1605         GETWORD(p, start_time);
1606         GETWORD(p, until_time);
1607         GETSTRINGP(p, sep_file, rdata, converter);
1608         GETSTRINGP(p, print_proc, rdata, converter);
1609         GETSTRINGP(p, dest, rdata, converter);
1610         GETSTRINGP(p, parms, rdata, converter);
1611         GETSTRINGP(p, parms, comment, converter);
1612         GETWORD(p, status);
1613         GETWORD(p, jobcount);
1614
1615         qfn(qname, priority, start_time, until_time, sep_file, print_proc,
1616             dest, parms, comment, status, jobcount);
1617
1618         if (jobcount) {
1619           int j;
1620           for (j=0;j<jobcount;j++) {
1621             uint16 jid, pos, fsstatus;
1622             pstring ownername, notifyname, datatype, jparms, jstatus, jcomment;
1623             unsigned int submitted, jsize;
1624             
1625             GETWORD(p, jid);
1626             GETSTRINGF(p, ownername, RAP_USERNAME_LEN);
1627             p++; /* pad byte */
1628             GETSTRINGF(p, notifyname, RAP_MACHNAME_LEN);
1629             GETSTRINGF(p, datatype, RAP_DATATYPE_LEN);
1630             GETSTRINGP(p, jparms, rdata, converter);
1631             GETWORD(p, pos);
1632             GETWORD(p, fsstatus);
1633             GETSTRINGP(p, jstatus, rdata, converter);
1634             GETDWORD(p, submitted);
1635             GETDWORD(p, jsize);
1636             GETSTRINGP(p, jcomment, rdata, converter);
1637           
1638             jfn(jid, ownername, notifyname, datatype, jparms, pos, fsstatus,
1639                 jstatus, submitted, jsize, jcomment);
1640           }
1641         }
1642       }
1643     } else {
1644       DEBUG(4,("NetPrintQEnum res=%d\n", res));
1645     }
1646   } else {
1647     DEBUG(4,("NetPrintQEnum no data returned\n"));
1648   }
1649     
1650   SAFE_FREE(rparam);
1651   SAFE_FREE(rdata);
1652
1653   return res;  
1654 }
1655
1656 int cli_NetPrintQGetInfo(struct cli_state *cli, const char *printer,
1657         void (*qfn)(const char*,uint16,uint16,uint16,const char*,const char*,const char*,const char*,const char*,uint16,uint16),
1658         void (*jfn)(uint16,const char*,const char*,const char*,const char*,uint16,uint16,const char*,uint,uint,const char*))
1659 {
1660   char param[WORDSIZE                         /* api number    */
1661             +sizeof(RAP_NetPrintQGetInfo_REQ) /* req string    */
1662             +sizeof(RAP_PRINTQ_INFO_L2)       /* return string */ 
1663             +RAP_SHARENAME_LEN                /* printer name  */
1664             +WORDSIZE                         /* info level    */
1665             +WORDSIZE                         /* buffer size   */
1666             +sizeof(RAP_SMB_PRINT_JOB_L1)];   /* more ret data */
1667   char *p;
1668   char *rparam = NULL;
1669   char *rdata = NULL; 
1670   unsigned int rprcnt, rdrcnt;
1671   int res = -1;
1672   
1673
1674   memset(param, '\0',sizeof(param));
1675   p = make_header(param, RAP_WPrintQGetInfo,
1676                   RAP_NetPrintQGetInfo_REQ, RAP_PRINTQ_INFO_L2);
1677   PUTSTRING(p, printer, RAP_SHARENAME_LEN-1);
1678   PUTWORD(p, 2);     /* Info level 2 */
1679   PUTWORD(p,0xFFE0); /* Return buffer size */
1680   PUTSTRING(p, RAP_SMB_PRINT_JOB_L1, 0);
1681
1682   if (cli_api(cli,
1683               param, PTR_DIFF(p,param),1024,
1684               NULL, 0, CLI_BUFFER_SIZE,
1685               &rparam, &rprcnt,
1686               &rdata, &rdrcnt)) {
1687     res = GETRES(rparam);
1688     cli->rap_error = res;
1689     if (res != 0) {
1690       DEBUG(1,("NetPrintQGetInfo gave error %d\n", res));
1691     }
1692   }
1693
1694   if (rdata) {
1695     if (res == 0 || res == ERRmoredata) {
1696       int rsize, converter;
1697       pstring qname, sep_file, print_proc, dest, parms, comment;
1698       uint16 jobcount, priority, start_time, until_time, status;
1699       
1700       p = rparam + WORDSIZE;
1701       GETWORD(p, converter);
1702       GETWORD(p, rsize);
1703
1704       p = rdata;
1705       GETSTRINGF(p, qname, RAP_SHARENAME_LEN);
1706       p++; /* pad */
1707       GETWORD(p, priority);
1708       GETWORD(p, start_time);
1709       GETWORD(p, until_time);
1710       GETSTRINGP(p, sep_file, rdata, converter);
1711       GETSTRINGP(p, print_proc, rdata, converter);
1712       GETSTRINGP(p, dest, rdata, converter);
1713       GETSTRINGP(p, parms, rdata, converter);
1714       GETSTRINGP(p, comment, rdata, converter);
1715       GETWORD(p, status);
1716       GETWORD(p, jobcount);
1717       qfn(qname, priority, start_time, until_time, sep_file, print_proc,
1718           dest, parms, comment, status, jobcount);
1719       if (jobcount) {
1720         int j;
1721         for (j=0;(j<jobcount)&&(PTR_DIFF(p,rdata)< rsize);j++) {
1722           uint16 jid, pos, fsstatus;
1723           pstring ownername, notifyname, datatype, jparms, jstatus, jcomment;
1724           unsigned int submitted, jsize;
1725
1726           GETWORD(p, jid);
1727           GETSTRINGF(p, ownername, RAP_USERNAME_LEN);
1728           p++; /* pad byte */
1729           GETSTRINGF(p, notifyname, RAP_MACHNAME_LEN);
1730           GETSTRINGF(p, datatype, RAP_DATATYPE_LEN);
1731           GETSTRINGP(p, jparms, rdata, converter);
1732           GETWORD(p, pos);
1733           GETWORD(p, fsstatus);
1734           GETSTRINGP(p, jstatus, rdata, converter);
1735           GETDWORD(p, submitted);
1736           GETDWORD(p, jsize);
1737           GETSTRINGP(p, jcomment, rdata, converter);
1738           
1739           jfn(jid, ownername, notifyname, datatype, jparms, pos, fsstatus,
1740               jstatus, submitted, jsize, jcomment);
1741         }
1742       }
1743     } else {
1744       DEBUG(4,("NetPrintQGetInfo res=%d\n", res));
1745     }
1746   } else {
1747     DEBUG(4,("NetPrintQGetInfo no data returned\n"));
1748   }
1749     
1750   SAFE_FREE(rparam);
1751   SAFE_FREE(rdata);
1752
1753   return res;  
1754 }
1755
1756 /****************************************************************************
1757 call a NetServiceEnum - list running services on a different host
1758 ****************************************************************************/
1759 int cli_RNetServiceEnum(struct cli_state *cli, void (*fn)(const char *, const char *, void *), void *state)
1760 {
1761   char param[WORDSIZE                     /* api number    */
1762             +sizeof(RAP_NetServiceEnum_REQ) /* parm string   */
1763             +sizeof(RAP_SERVICE_INFO_L2)    /* return string */
1764             +WORDSIZE                     /* info level    */
1765             +WORDSIZE];                   /* buffer size   */
1766   char *p;
1767   char *rparam = NULL;
1768   char *rdata = NULL; 
1769   unsigned int rprcnt, rdrcnt;
1770   int res = -1;
1771   
1772   
1773   memset(param, '\0', sizeof(param));
1774   p = make_header(param, RAP_WServiceEnum,
1775                   RAP_NetServiceEnum_REQ, RAP_SERVICE_INFO_L2);
1776   PUTWORD(p,2); /* Info level 2 */  
1777   PUTWORD(p,0xFFE0); /* Return buffer size */
1778
1779   if (cli_api(cli,
1780               param, PTR_DIFF(p,param),8,
1781               NULL, 0, 0xFFE0 /* data area size */,
1782               &rparam, &rprcnt,
1783               &rdata, &rdrcnt)) {
1784     res = GETRES(rparam);
1785     cli->rap_error = res;
1786     if(cli->rap_error == 234) 
1787         DEBUG(1,("Not all service names were returned (such as those longer than 15 characters)\n"));
1788     else if (cli->rap_error != 0) {
1789       DEBUG(1,("NetServiceEnum gave error %d\n", cli->rap_error));
1790     }
1791   }
1792
1793   if (rdata) {
1794     if (res == 0 || res == ERRmoredata) {
1795       int i, count;
1796
1797       p = rparam + WORDSIZE + WORDSIZE; /* skip result and converter */
1798       GETWORD(p, count);
1799
1800       for (i=0,p=rdata;i<count;i++) {
1801             pstring comment;
1802             char servicename[RAP_SRVCNAME_LEN];
1803
1804             GETSTRINGF(p, servicename, RAP_SRVCNAME_LEN);
1805             p+=8; /* pass status words */
1806             GETSTRINGF(p, comment, RAP_SRVCCMNT_LEN);
1807
1808             fn(servicename, comment, cli);  /* BB add status too */
1809       } 
1810     } else {
1811       DEBUG(4,("NetServiceEnum res=%d\n", res));
1812     }
1813   } else {
1814     DEBUG(4,("NetServiceEnum no data returned\n"));
1815   }
1816     
1817   SAFE_FREE(rparam);
1818   SAFE_FREE(rdata);
1819
1820   return res;
1821 }
1822
1823
1824 /****************************************************************************
1825 call a NetSessionEnum - list workstations with sessions to an SMB server
1826 ****************************************************************************/
1827 int cli_NetSessionEnum(struct cli_state *cli, void (*fn)(char *, char *, uint16, uint16, uint16, uint, uint, uint, char *))
1828 {
1829   char param[WORDSIZE                       /* api number    */
1830             +sizeof(RAP_NetSessionEnum_REQ) /* parm string   */
1831             +sizeof(RAP_SESSION_INFO_L2)    /* return string */
1832             +WORDSIZE                       /* info level    */
1833             +WORDSIZE];                     /* buffer size   */
1834   char *p;
1835   char *rparam = NULL;
1836   char *rdata = NULL; 
1837   unsigned int rprcnt, rdrcnt;
1838   int res = -1;
1839   
1840   memset(param, '\0', sizeof(param));
1841   p = make_header(param, RAP_WsessionEnum, 
1842                   RAP_NetSessionEnum_REQ, RAP_SESSION_INFO_L2);
1843   PUTWORD(p,2);    /* Info level 2 */
1844   PUTWORD(p,0xFF); /* Return buffer size */
1845
1846   if (cli_api(cli,
1847               param, PTR_DIFF(p,param),8,
1848               NULL, 0, CLI_BUFFER_SIZE,
1849               &rparam, &rprcnt,
1850               &rdata, &rdrcnt)) {
1851     res = GETRES(rparam);
1852     cli->rap_error = res;
1853     if (res != 0) {
1854       DEBUG(1,("NetSessionEnum gave error %d\n", res));
1855     }
1856   }
1857
1858   if (rdata) {
1859     if (res == 0 || res == ERRmoredata) {
1860       int i, converter, count;
1861       
1862       p = rparam + WORDSIZE;
1863       GETWORD(p, converter);
1864       GETWORD(p, count);
1865
1866       for (i=0,p=rdata;i<count;i++) {
1867         pstring wsname, username, clitype_name;
1868         uint16  num_conns, num_opens, num_users;
1869         unsigned int    sess_time, idle_time, user_flags;
1870
1871         GETSTRINGP(p, wsname, rdata, converter);
1872         GETSTRINGP(p, username, rdata, converter);
1873         GETWORD(p, num_conns);
1874         GETWORD(p, num_opens);
1875         GETWORD(p, num_users);
1876         GETDWORD(p, sess_time);
1877         GETDWORD(p, idle_time);
1878         GETDWORD(p, user_flags);
1879         GETSTRINGP(p, clitype_name, rdata, converter);
1880
1881         fn(wsname, username, num_conns, num_opens, num_users, sess_time,
1882            idle_time, user_flags, clitype_name);
1883       }
1884         
1885     } else {
1886       DEBUG(4,("NetSessionEnum res=%d\n", res));
1887     }
1888   } else {
1889     DEBUG(4,("NetSesssionEnum no data returned\n"));
1890   }
1891     
1892   SAFE_FREE(rparam);
1893   SAFE_FREE(rdata);
1894
1895   return res;
1896 }
1897
1898 /****************************************************************************
1899  Call a NetSessionGetInfo - get information about other session to an SMB server.
1900 ****************************************************************************/
1901
1902 int cli_NetSessionGetInfo(struct cli_state *cli, const char *workstation, void (*fn)(const char *, const char *, uint16, uint16, uint16, uint, uint, uint, const char *))
1903 {
1904   char param[WORDSIZE                          /* api number    */
1905             +sizeof(RAP_NetSessionGetInfo_REQ) /* req string    */
1906             +sizeof(RAP_SESSION_INFO_L2)       /* return string */ 
1907             +RAP_MACHNAME_LEN                  /* wksta name    */
1908             +WORDSIZE                          /* info level    */
1909             +WORDSIZE];                        /* buffer size   */
1910   char *p;
1911   char *rparam = NULL;
1912   char *rdata = NULL; 
1913   unsigned int rprcnt, rdrcnt;
1914   int res = -1;
1915   
1916
1917   memset(param, '\0', sizeof(param));
1918   p = make_header(param, RAP_WsessionGetInfo, 
1919                   RAP_NetSessionGetInfo_REQ, RAP_SESSION_INFO_L2);
1920   PUTSTRING(p, workstation, RAP_MACHNAME_LEN-1);
1921   PUTWORD(p,2); /* Info level 2 */
1922   PUTWORD(p,0xFF); /* Return buffer size */
1923
1924   if (cli_api(cli,
1925               param, PTR_DIFF(p,param),PTR_DIFF(p,param),
1926               NULL, 0, CLI_BUFFER_SIZE,
1927               &rparam, &rprcnt,
1928               &rdata, &rdrcnt)) {
1929     cli->rap_error = SVAL(rparam,0);
1930     if (cli->rap_error != 0) {
1931       DEBUG(1,("NetSessionGetInfo gave error %d\n", cli->rap_error));
1932     }
1933   }
1934
1935   if (rdata) {
1936     res = GETRES(rparam);
1937     
1938     if (res == 0 || res == ERRmoredata) {
1939       int converter;
1940       pstring wsname, username, clitype_name;
1941       uint16  num_conns, num_opens, num_users;
1942       unsigned int    sess_time, idle_time, user_flags;
1943
1944       p = rparam + WORDSIZE;
1945       GETWORD(p, converter);
1946       p += WORDSIZE;            /* skip rsize */
1947
1948       p = rdata;
1949       GETSTRINGP(p, wsname, rdata, converter);
1950       GETSTRINGP(p, username, rdata, converter);
1951       GETWORD(p, num_conns);
1952       GETWORD(p, num_opens);
1953       GETWORD(p, num_users);
1954       GETDWORD(p, sess_time);
1955       GETDWORD(p, idle_time);
1956       GETDWORD(p, user_flags);
1957       GETSTRINGP(p, clitype_name, rdata, converter);
1958       
1959       fn(wsname, username, num_conns, num_opens, num_users, sess_time,
1960          idle_time, user_flags, clitype_name);
1961     } else {
1962       DEBUG(4,("NetSessionGetInfo res=%d\n", res));
1963     }
1964   } else {
1965     DEBUG(4,("NetSessionGetInfo no data returned\n"));
1966   }
1967     
1968   SAFE_FREE(rparam);
1969   SAFE_FREE(rdata);
1970
1971   return res;  
1972 }
1973
1974 /****************************************************************************
1975 call a NetSessionDel - close a session to an SMB server
1976 ****************************************************************************/
1977 int cli_NetSessionDel(struct cli_state *cli, const char *workstation)
1978 {
1979   char param[WORDSIZE                      /* api number       */
1980             +sizeof(RAP_NetSessionDel_REQ) /* req string       */
1981             +1                             /* no return string */
1982             +RAP_MACHNAME_LEN              /* workstation name */
1983             +WORDSIZE];                    /* reserved (0)     */
1984   char *p;
1985   char *rparam = NULL;
1986   char *rdata = NULL;
1987   unsigned int rprcnt, rdrcnt;
1988   int res;
1989
1990   memset(param, '\0', sizeof(param));
1991   p = make_header(param, RAP_WsessionDel, RAP_NetSessionDel_REQ, NULL);
1992   PUTSTRING(p, workstation, RAP_MACHNAME_LEN-1);
1993   PUTWORD(p,0); /* reserved word of 0 */
1994   if (cli_api(cli, 
1995               param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
1996               NULL, 0, 200,       /* data, length, maxlen */
1997               &rparam, &rprcnt,   /* return params, length */
1998               &rdata, &rdrcnt))   /* return data, length */
1999     {
2000       res = GETRES(rparam);
2001       cli->rap_error = res;
2002       
2003       if (res == 0) {
2004         /* nothing to do */             
2005       }
2006       else {
2007         DEBUG(4,("NetFileClose2 res=%d\n", res));
2008       }      
2009     } else {
2010       res = -1;
2011       DEBUG(4,("NetFileClose2 failed\n"));
2012     }
2013   
2014   SAFE_FREE(rparam);
2015   SAFE_FREE(rdata);
2016
2017   return res;
2018 }
2019   
2020
2021 int cli_NetConnectionEnum(struct cli_state *cli, const char *qualifier, void (*fn)(uint16 conid, uint16 contype, uint16 numopens, uint16 numusers, uint32 contime, const char *username, const char *netname))
2022 {
2023   char param[WORDSIZE                          /* api number    */
2024             +sizeof(RAP_NetConnectionEnum_REQ) /* req string    */
2025             +sizeof(RAP_CONNECTION_INFO_L1)    /* return string */ 
2026             +RAP_MACHNAME_LEN                  /* wksta name    */
2027             +WORDSIZE                          /* info level    */
2028             +WORDSIZE];                        /* buffer size   */
2029   char *p;
2030   char *rparam = NULL;
2031   char *rdata = NULL; 
2032   unsigned int rprcnt, rdrcnt;
2033   int res = -1;
2034
2035   memset(param, '\0', sizeof(param));
2036   p = make_header(param, RAP_WconnectionEnum,
2037                   RAP_NetConnectionEnum_REQ, RAP_CONNECTION_INFO_L1);
2038   PUTSTRING(p, qualifier, RAP_MACHNAME_LEN-1);/* Workstation name */
2039   PUTWORD(p,1);            /* Info level 1 */
2040   PUTWORD(p,0xFFE0);       /* Return buffer size */
2041
2042   if (cli_api(cli,
2043               param, PTR_DIFF(p,param),PTR_DIFF(p,param),
2044               NULL, 0, CLI_BUFFER_SIZE,
2045               &rparam, &rprcnt,
2046               &rdata, &rdrcnt)) {
2047     res = GETRES(rparam);
2048     cli->rap_error = res;
2049     if (res != 0) {
2050       DEBUG(1,("NetConnectionEnum gave error %d\n", res));
2051     }
2052   }
2053   if (rdata) {
2054     if (res == 0 || res == ERRmoredata) {
2055       int i, converter, count;
2056
2057       p = rparam + WORDSIZE;
2058       GETWORD(p, converter);
2059       GETWORD(p, count);
2060
2061       for (i=0,p=rdata;i<count;i++) {
2062         pstring netname, username;
2063         uint16  conn_id, conn_type, num_opens, num_users;
2064         unsigned int    conn_time;
2065
2066         GETWORD(p,conn_id);
2067         GETWORD(p,conn_type);
2068         GETWORD(p,num_opens);
2069         GETWORD(p,num_users);
2070         GETDWORD(p,conn_time);
2071         GETSTRINGP(p, username, rdata, converter);
2072         GETSTRINGP(p, netname, rdata, converter);
2073
2074         fn(conn_id, conn_type, num_opens, num_users, conn_time,
2075            username, netname);
2076       }
2077         
2078     } else {
2079       DEBUG(4,("NetConnectionEnum res=%d\n", res));
2080     }
2081   } else {
2082     DEBUG(4,("NetConnectionEnum no data returned\n"));
2083   }
2084   SAFE_FREE(rdata);
2085   SAFE_FREE(rparam);
2086   return res;
2087 }