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