45a89c775edbfbb021544d0acfdc0393fcc5e0df
[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 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, 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 = push_skip_string(p);\
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 = push_skip_string(p);\
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 BOOL cli_get_server_name(TALLOC_CTX *mem_ctx, struct cli_state *cli,
1418                          char **servername)
1419 {
1420         char *rparam = NULL;
1421         char *rdata = NULL;
1422         unsigned int rdrcnt,rprcnt;
1423         char *p;
1424         char param[WORDSIZE                       /* api number    */
1425                    +sizeof(RAP_WserverGetInfo_REQ) /* req string    */
1426                    +sizeof(RAP_SERVER_INFO_L1)     /* return string */
1427                    +WORDSIZE                       /* info level    */
1428                    +WORDSIZE];                     /* buffer size   */
1429         BOOL res = False;
1430         fstring tmp;
1431   
1432         /* send a SMBtrans command with api NetServerGetInfo */
1433         p = make_header(param, RAP_WserverGetInfo,
1434                         RAP_WserverGetInfo_REQ, RAP_SERVER_INFO_L1);
1435         PUTWORD(p, 1); /* info level */
1436         PUTWORD(p, CLI_BUFFER_SIZE);
1437         
1438         if (!cli_api(cli, 
1439                      param, PTR_DIFF(p,param), 8, /* params, length, max */
1440                      NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
1441                      &rparam, &rprcnt,         /* return params, return size */
1442                      &rdata, &rdrcnt           /* return data, return size */
1443                     )) {
1444                 goto failed;
1445         }
1446     
1447         if (GETRES(rparam) != 0) {
1448                 goto failed;
1449         }
1450
1451         if (rdrcnt < 16) {
1452                 DEBUG(10, ("invalid data count %d, expected >= 16\n", rdrcnt));
1453                 goto failed;
1454         }
1455
1456         if (pull_ascii(tmp, rdata, sizeof(tmp)-1, 16, STR_TERMINATE) == -1) {
1457                 DEBUG(10, ("pull_ascii failed\n"));
1458                 goto failed;
1459         }
1460
1461         if (!(*servername = talloc_strdup(mem_ctx, tmp))) {
1462                 DEBUG(1, ("talloc_strdup failed\n"));
1463                 goto failed;
1464         }
1465
1466         res = True;
1467
1468  failed:
1469         SAFE_FREE(rparam);
1470         SAFE_FREE(rdata);
1471         return res;
1472 }
1473
1474 /*************************************************************************
1475 *
1476 * Function Name:  cli_ns_check_server_type
1477 *
1478 * PURPOSE:  Remotes a NetServerEnum2 API call to the current server
1479 *           requesting server_info_0 level information of machines
1480 *           matching the given server type. If the returned server
1481 *           list contains the machine name contained in cli->desthost
1482 *           then we conclude the server type checks out. This routine
1483 *           is useful to retrieve list of server's of a certain
1484 *           type when all you have is a null session connection and
1485 *           can't remote API calls such as NetWkstaGetInfo or 
1486 *           NetServerGetInfo.
1487 *
1488 * Dependencies: none
1489 *
1490 * Parameters: 
1491 *             cli       - pointer to cli_state structure
1492 *             workgroup - pointer to string containing domain
1493 *             stype     - server type
1494 *
1495 * Returns:
1496 *             True      - success
1497 *             False     - failure
1498 *
1499 ************************************************************************/
1500 BOOL cli_ns_check_server_type(struct cli_state *cli, char *workgroup, uint32 stype)
1501 {
1502   char *rparam = NULL;
1503   char *rdata = NULL;
1504   unsigned int rdrcnt,rprcnt;
1505   char *p;
1506   char param[WORDSIZE                       /* api number    */
1507             +sizeof(RAP_NetServerEnum2_REQ) /* req string    */
1508             +sizeof(RAP_SERVER_INFO_L0)     /* return string */
1509             +WORDSIZE                       /* info level    */
1510             +WORDSIZE                       /* buffer size   */
1511             +DWORDSIZE                      /* server type   */
1512             +RAP_MACHNAME_LEN];             /* workgroup     */
1513   BOOL found_server = False;
1514   int res = -1;
1515   
1516   /* send a SMBtrans command with api NetServerEnum */
1517   p = make_header(param, RAP_NetServerEnum2,
1518                   RAP_NetServerEnum2_REQ, RAP_SERVER_INFO_L0);
1519   PUTWORD(p, 0); /* info level 0 */
1520   PUTWORD(p, CLI_BUFFER_SIZE);
1521   PUTDWORD(p, stype);
1522   PUTSTRING(p, workgroup, RAP_MACHNAME_LEN);
1523         
1524   if (cli_api(cli, 
1525               param, PTR_DIFF(p,param), 8, /* params, length, max */
1526               NULL, 0, CLI_BUFFER_SIZE,  /* data, length, max */
1527               &rparam, &rprcnt,          /* return params, return size */
1528               &rdata, &rdrcnt            /* return data, return size */
1529               )) {
1530         
1531     res = GETRES(rparam);
1532     cli->rap_error = res;
1533
1534     if (res == 0 || res == ERRmoredata) {
1535       int i, count;
1536
1537       p = rparam + WORDSIZE + WORDSIZE;
1538       GETWORD(p, count);
1539
1540       p = rdata;
1541       for (i = 0;i < count;i++, p += 16) {
1542         char ret_server[RAP_MACHNAME_LEN];
1543
1544         GETSTRINGF(p, ret_server, RAP_MACHNAME_LEN);
1545         if (strequal(ret_server, cli->desthost)) {
1546           found_server = True;
1547           break;
1548         }
1549       }
1550     }
1551     else {
1552       DEBUG(4,("cli_ns_check_server_type: machine %s failed the NetServerEnum call. "
1553                "Error was : %s.\n", cli->desthost, cli_errstr(cli) ));
1554     }
1555   }
1556   
1557   SAFE_FREE(rparam);
1558   SAFE_FREE(rdata);
1559         
1560   return found_server;
1561  }
1562
1563
1564 /****************************************************************************
1565  perform a NetWkstaUserLogoff
1566 ****************************************************************************/
1567 BOOL cli_NetWkstaUserLogoff(struct cli_state *cli,char *user, char *workstation)
1568 {
1569   char *rparam = NULL;
1570   char *rdata = NULL;
1571   char *p;
1572   unsigned int rdrcnt,rprcnt;
1573   char param[WORDSIZE                           /* api number    */
1574             +sizeof(RAP_NetWkstaUserLogoff_REQ) /* req string    */
1575             +sizeof(RAP_USER_LOGOFF_INFO_L1)    /* return string */
1576             +RAP_USERNAME_LEN+1                 /* user name+pad */
1577             +RAP_MACHNAME_LEN                   /* wksta name    */
1578             +WORDSIZE                           /* buffer size   */
1579             +WORDSIZE];                         /* buffer size?  */
1580   fstring upperbuf;
1581   
1582   memset(param, 0, sizeof(param));
1583
1584   /* send a SMBtrans command with api NetWkstaUserLogoff */
1585   p = make_header(param, RAP_WWkstaUserLogoff,
1586                   RAP_NetWkstaUserLogoff_REQ, RAP_USER_LOGOFF_INFO_L1);
1587   PUTDWORD(p, 0); /* Null pointer */
1588   PUTDWORD(p, 0); /* Null pointer */
1589   fstrcpy(upperbuf, user);
1590   strupper_m(upperbuf);
1591   PUTSTRINGF(p, upperbuf, RAP_USERNAME_LEN);
1592   p++; /* strange format, but ok */
1593   fstrcpy(upperbuf, workstation);
1594   strupper_m(upperbuf);
1595   PUTSTRINGF(p, upperbuf, RAP_MACHNAME_LEN);
1596   PUTWORD(p, CLI_BUFFER_SIZE);
1597   PUTWORD(p, CLI_BUFFER_SIZE);
1598   
1599   if (cli_api(cli,
1600               param, PTR_DIFF(p,param),1024,  /* param, length, max */
1601               NULL, 0, CLI_BUFFER_SIZE,       /* data, length, max */
1602               &rparam, &rprcnt,               /* return params, return size */
1603               &rdata, &rdrcnt                 /* return data, return size */
1604               )) {
1605     cli->rap_error = GETRES(rparam);
1606     
1607     if (cli->rap_error != 0) {
1608       DEBUG(4,("NetwkstaUserLogoff gave error %d\n", cli->rap_error));
1609     }
1610   }
1611   
1612   SAFE_FREE(rparam);
1613   SAFE_FREE(rdata);
1614   return (cli->rap_error == 0);
1615 }
1616  
1617 int cli_NetPrintQEnum(struct cli_state *cli,
1618                 void (*qfn)(const char*,uint16,uint16,uint16,const char*,const char*,const char*,const char*,const char*,uint16,uint16),
1619                 void (*jfn)(uint16,const char*,const char*,const char*,const char*,uint16,uint16,const char*,uint,uint,const char*))
1620 {
1621   char param[WORDSIZE                         /* api number    */
1622             +sizeof(RAP_NetPrintQEnum_REQ)    /* req string    */
1623             +sizeof(RAP_PRINTQ_INFO_L2)       /* return string */
1624             +WORDSIZE                         /* info level    */
1625             +WORDSIZE                         /* buffer size   */
1626             +sizeof(RAP_SMB_PRINT_JOB_L1)];   /* more ret data */
1627   char *p;
1628   char *rparam = NULL;
1629   char *rdata = NULL; 
1630   unsigned int rprcnt, rdrcnt;
1631   int res = -1;
1632   
1633
1634   memset(param, '\0',sizeof(param));
1635   p = make_header(param, RAP_WPrintQEnum, 
1636                   RAP_NetPrintQEnum_REQ, RAP_PRINTQ_INFO_L2);
1637   PUTWORD(p,2); /* Info level 2 */
1638   PUTWORD(p,0xFFE0); /* Return buffer size */
1639   PUTSTRING(p, RAP_SMB_PRINT_JOB_L1, 0);
1640
1641   if (cli_api(cli,
1642               param, PTR_DIFF(p,param),1024,
1643               NULL, 0, CLI_BUFFER_SIZE,
1644               &rparam, &rprcnt,
1645               &rdata, &rdrcnt)) {
1646     res = GETRES(rparam);
1647     cli->rap_error = res;
1648     if (res != 0) {
1649       DEBUG(1,("NetPrintQEnum gave error %d\n", res));
1650     }
1651   }
1652
1653   if (rdata) {
1654     if (res == 0 || res == ERRmoredata) {
1655       int i, converter, count;
1656
1657       p = rparam + WORDSIZE;
1658       GETWORD(p, converter);
1659       GETWORD(p, count);
1660
1661       p = rdata;
1662       for (i=0;i<count;i++) {
1663         pstring qname, sep_file, print_proc, dest, parms, comment;
1664         uint16 jobcount, priority, start_time, until_time, status;
1665
1666         GETSTRINGF(p, qname, RAP_SHARENAME_LEN);
1667         p++; /* pad */
1668         GETWORD(p, priority);
1669         GETWORD(p, start_time);
1670         GETWORD(p, until_time);
1671         GETSTRINGP(p, sep_file, rdata, converter);
1672         GETSTRINGP(p, print_proc, rdata, converter);
1673         GETSTRINGP(p, dest, rdata, converter);
1674         GETSTRINGP(p, parms, rdata, converter);
1675         GETSTRINGP(p, parms, comment, converter);
1676         GETWORD(p, status);
1677         GETWORD(p, jobcount);
1678
1679         qfn(qname, priority, start_time, until_time, sep_file, print_proc,
1680             dest, parms, comment, status, jobcount);
1681
1682         if (jobcount) {
1683           int j;
1684           for (j=0;j<jobcount;j++) {
1685             uint16 jid, pos, fsstatus;
1686             pstring ownername, notifyname, datatype, jparms, jstatus, jcomment;
1687             unsigned int submitted, jsize;
1688             
1689             GETWORD(p, jid);
1690             GETSTRINGF(p, ownername, RAP_USERNAME_LEN);
1691             p++; /* pad byte */
1692             GETSTRINGF(p, notifyname, RAP_MACHNAME_LEN);
1693             GETSTRINGF(p, datatype, RAP_DATATYPE_LEN);
1694             GETSTRINGP(p, jparms, rdata, converter);
1695             GETWORD(p, pos);
1696             GETWORD(p, fsstatus);
1697             GETSTRINGP(p, jstatus, rdata, converter);
1698             GETDWORD(p, submitted);
1699             GETDWORD(p, jsize);
1700             GETSTRINGP(p, jcomment, rdata, converter);
1701           
1702             jfn(jid, ownername, notifyname, datatype, jparms, pos, fsstatus,
1703                 jstatus, submitted, jsize, jcomment);
1704           }
1705         }
1706       }
1707     } else {
1708       DEBUG(4,("NetPrintQEnum res=%d\n", res));
1709     }
1710   } else {
1711     DEBUG(4,("NetPrintQEnum no data returned\n"));
1712   }
1713     
1714   SAFE_FREE(rparam);
1715   SAFE_FREE(rdata);
1716
1717   return res;  
1718 }
1719
1720 int cli_NetPrintQGetInfo(struct cli_state *cli, const char *printer,
1721         void (*qfn)(const char*,uint16,uint16,uint16,const char*,const char*,const char*,const char*,const char*,uint16,uint16),
1722         void (*jfn)(uint16,const char*,const char*,const char*,const char*,uint16,uint16,const char*,uint,uint,const char*))
1723 {
1724   char param[WORDSIZE                         /* api number    */
1725             +sizeof(RAP_NetPrintQGetInfo_REQ) /* req string    */
1726             +sizeof(RAP_PRINTQ_INFO_L2)       /* return string */ 
1727             +RAP_SHARENAME_LEN                /* printer name  */
1728             +WORDSIZE                         /* info level    */
1729             +WORDSIZE                         /* buffer size   */
1730             +sizeof(RAP_SMB_PRINT_JOB_L1)];   /* more ret data */
1731   char *p;
1732   char *rparam = NULL;
1733   char *rdata = NULL; 
1734   unsigned int rprcnt, rdrcnt;
1735   int res = -1;
1736   
1737
1738   memset(param, '\0',sizeof(param));
1739   p = make_header(param, RAP_WPrintQGetInfo,
1740                   RAP_NetPrintQGetInfo_REQ, RAP_PRINTQ_INFO_L2);
1741   PUTSTRING(p, printer, RAP_SHARENAME_LEN-1);
1742   PUTWORD(p, 2);     /* Info level 2 */
1743   PUTWORD(p,0xFFE0); /* Return buffer size */
1744   PUTSTRING(p, RAP_SMB_PRINT_JOB_L1, 0);
1745
1746   if (cli_api(cli,
1747               param, PTR_DIFF(p,param),1024,
1748               NULL, 0, CLI_BUFFER_SIZE,
1749               &rparam, &rprcnt,
1750               &rdata, &rdrcnt)) {
1751     res = GETRES(rparam);
1752     cli->rap_error = res;
1753     if (res != 0) {
1754       DEBUG(1,("NetPrintQGetInfo gave error %d\n", res));
1755     }
1756   }
1757
1758   if (rdata) {
1759     if (res == 0 || res == ERRmoredata) {
1760       int rsize, converter;
1761       pstring qname, sep_file, print_proc, dest, parms, comment;
1762       uint16 jobcount, priority, start_time, until_time, status;
1763       
1764       p = rparam + WORDSIZE;
1765       GETWORD(p, converter);
1766       GETWORD(p, rsize);
1767
1768       p = rdata;
1769       GETSTRINGF(p, qname, RAP_SHARENAME_LEN);
1770       p++; /* pad */
1771       GETWORD(p, priority);
1772       GETWORD(p, start_time);
1773       GETWORD(p, until_time);
1774       GETSTRINGP(p, sep_file, rdata, converter);
1775       GETSTRINGP(p, print_proc, rdata, converter);
1776       GETSTRINGP(p, dest, rdata, converter);
1777       GETSTRINGP(p, parms, rdata, converter);
1778       GETSTRINGP(p, comment, rdata, converter);
1779       GETWORD(p, status);
1780       GETWORD(p, jobcount);
1781       qfn(qname, priority, start_time, until_time, sep_file, print_proc,
1782           dest, parms, comment, status, jobcount);
1783       if (jobcount) {
1784         int j;
1785         for (j=0;(j<jobcount)&&(PTR_DIFF(p,rdata)< rsize);j++) {
1786           uint16 jid, pos, fsstatus;
1787           pstring ownername, notifyname, datatype, jparms, jstatus, jcomment;
1788           unsigned int submitted, jsize;
1789
1790           GETWORD(p, jid);
1791           GETSTRINGF(p, ownername, RAP_USERNAME_LEN);
1792           p++; /* pad byte */
1793           GETSTRINGF(p, notifyname, RAP_MACHNAME_LEN);
1794           GETSTRINGF(p, datatype, RAP_DATATYPE_LEN);
1795           GETSTRINGP(p, jparms, rdata, converter);
1796           GETWORD(p, pos);
1797           GETWORD(p, fsstatus);
1798           GETSTRINGP(p, jstatus, rdata, converter);
1799           GETDWORD(p, submitted);
1800           GETDWORD(p, jsize);
1801           GETSTRINGP(p, jcomment, rdata, converter);
1802           
1803           jfn(jid, ownername, notifyname, datatype, jparms, pos, fsstatus,
1804               jstatus, submitted, jsize, jcomment);
1805         }
1806       }
1807     } else {
1808       DEBUG(4,("NetPrintQGetInfo res=%d\n", res));
1809     }
1810   } else {
1811     DEBUG(4,("NetPrintQGetInfo no data returned\n"));
1812   }
1813     
1814   SAFE_FREE(rparam);
1815   SAFE_FREE(rdata);
1816
1817   return res;  
1818 }
1819
1820 /****************************************************************************
1821 call a NetServiceEnum - list running services on a different host
1822 ****************************************************************************/
1823 int cli_RNetServiceEnum(struct cli_state *cli, void (*fn)(const char *, const char *, void *), void *state)
1824 {
1825   char param[WORDSIZE                     /* api number    */
1826             +sizeof(RAP_NetServiceEnum_REQ) /* parm string   */
1827             +sizeof(RAP_SERVICE_INFO_L2)    /* return string */
1828             +WORDSIZE                     /* info level    */
1829             +WORDSIZE];                   /* buffer size   */
1830   char *p;
1831   char *rparam = NULL;
1832   char *rdata = NULL; 
1833   unsigned int rprcnt, rdrcnt;
1834   int res = -1;
1835   
1836   
1837   memset(param, '\0', sizeof(param));
1838   p = make_header(param, RAP_WServiceEnum,
1839                   RAP_NetServiceEnum_REQ, RAP_SERVICE_INFO_L2);
1840   PUTWORD(p,2); /* Info level 2 */  
1841   PUTWORD(p,0xFFE0); /* Return buffer size */
1842
1843   if (cli_api(cli,
1844               param, PTR_DIFF(p,param),8,
1845               NULL, 0, 0xFFE0 /* data area size */,
1846               &rparam, &rprcnt,
1847               &rdata, &rdrcnt)) {
1848     res = GETRES(rparam);
1849     cli->rap_error = res;
1850     if(cli->rap_error == 234) 
1851         DEBUG(1,("Not all service names were returned (such as those longer than 15 characters)\n"));
1852     else if (cli->rap_error != 0) {
1853       DEBUG(1,("NetServiceEnum gave error %d\n", cli->rap_error));
1854     }
1855   }
1856
1857   if (rdata) {
1858     if (res == 0 || res == ERRmoredata) {
1859       int i, count;
1860
1861       p = rparam + WORDSIZE + WORDSIZE; /* skip result and converter */
1862       GETWORD(p, count);
1863
1864       for (i=0,p=rdata;i<count;i++) {
1865             pstring comment;
1866             char servicename[RAP_SRVCNAME_LEN];
1867
1868             GETSTRINGF(p, servicename, RAP_SRVCNAME_LEN);
1869             p+=8; /* pass status words */
1870             GETSTRINGF(p, comment, RAP_SRVCCMNT_LEN);
1871
1872             fn(servicename, comment, cli);  /* BB add status too */
1873       } 
1874     } else {
1875       DEBUG(4,("NetServiceEnum res=%d\n", res));
1876     }
1877   } else {
1878     DEBUG(4,("NetServiceEnum no data returned\n"));
1879   }
1880     
1881   SAFE_FREE(rparam);
1882   SAFE_FREE(rdata);
1883
1884   return res;
1885 }
1886
1887
1888 /****************************************************************************
1889 call a NetSessionEnum - list workstations with sessions to an SMB server
1890 ****************************************************************************/
1891 int cli_NetSessionEnum(struct cli_state *cli, void (*fn)(char *, char *, uint16, uint16, uint16, uint, uint, uint, char *))
1892 {
1893   char param[WORDSIZE                       /* api number    */
1894             +sizeof(RAP_NetSessionEnum_REQ) /* parm string   */
1895             +sizeof(RAP_SESSION_INFO_L2)    /* return string */
1896             +WORDSIZE                       /* info level    */
1897             +WORDSIZE];                     /* buffer size   */
1898   char *p;
1899   char *rparam = NULL;
1900   char *rdata = NULL; 
1901   unsigned int rprcnt, rdrcnt;
1902   int res = -1;
1903   
1904   memset(param, '\0', sizeof(param));
1905   p = make_header(param, RAP_WsessionEnum, 
1906                   RAP_NetSessionEnum_REQ, RAP_SESSION_INFO_L2);
1907   PUTWORD(p,2);    /* Info level 2 */
1908   PUTWORD(p,0xFF); /* Return buffer size */
1909
1910   if (cli_api(cli,
1911               param, PTR_DIFF(p,param),8,
1912               NULL, 0, CLI_BUFFER_SIZE,
1913               &rparam, &rprcnt,
1914               &rdata, &rdrcnt)) {
1915     res = GETRES(rparam);
1916     cli->rap_error = res;
1917     if (res != 0) {
1918       DEBUG(1,("NetSessionEnum gave error %d\n", res));
1919     }
1920   }
1921
1922   if (rdata) {
1923     if (res == 0 || res == ERRmoredata) {
1924       int i, converter, count;
1925       
1926       p = rparam + WORDSIZE;
1927       GETWORD(p, converter);
1928       GETWORD(p, count);
1929
1930       for (i=0,p=rdata;i<count;i++) {
1931         pstring wsname, username, clitype_name;
1932         uint16  num_conns, num_opens, num_users;
1933         unsigned int    sess_time, idle_time, user_flags;
1934
1935         GETSTRINGP(p, wsname, rdata, converter);
1936         GETSTRINGP(p, username, rdata, converter);
1937         GETWORD(p, num_conns);
1938         GETWORD(p, num_opens);
1939         GETWORD(p, num_users);
1940         GETDWORD(p, sess_time);
1941         GETDWORD(p, idle_time);
1942         GETDWORD(p, user_flags);
1943         GETSTRINGP(p, clitype_name, rdata, converter);
1944
1945         fn(wsname, username, num_conns, num_opens, num_users, sess_time,
1946            idle_time, user_flags, clitype_name);
1947       }
1948         
1949     } else {
1950       DEBUG(4,("NetSessionEnum res=%d\n", res));
1951     }
1952   } else {
1953     DEBUG(4,("NetSesssionEnum no data returned\n"));
1954   }
1955     
1956   SAFE_FREE(rparam);
1957   SAFE_FREE(rdata);
1958
1959   return res;
1960 }
1961
1962 /****************************************************************************
1963  Call a NetSessionGetInfo - get information about other session to an SMB server.
1964 ****************************************************************************/
1965
1966 int cli_NetSessionGetInfo(struct cli_state *cli, const char *workstation, void (*fn)(const char *, const char *, uint16, uint16, uint16, uint, uint, uint, const char *))
1967 {
1968   char param[WORDSIZE                          /* api number    */
1969             +sizeof(RAP_NetSessionGetInfo_REQ) /* req string    */
1970             +sizeof(RAP_SESSION_INFO_L2)       /* return string */ 
1971             +RAP_MACHNAME_LEN                  /* wksta name    */
1972             +WORDSIZE                          /* info level    */
1973             +WORDSIZE];                        /* buffer size   */
1974   char *p;
1975   char *rparam = NULL;
1976   char *rdata = NULL; 
1977   unsigned int rprcnt, rdrcnt;
1978   int res = -1;
1979   
1980
1981   memset(param, '\0', sizeof(param));
1982   p = make_header(param, RAP_WsessionGetInfo, 
1983                   RAP_NetSessionGetInfo_REQ, RAP_SESSION_INFO_L2);
1984   PUTSTRING(p, workstation, RAP_MACHNAME_LEN-1);
1985   PUTWORD(p,2); /* Info level 2 */
1986   PUTWORD(p,0xFF); /* Return buffer size */
1987
1988   if (cli_api(cli,
1989               param, PTR_DIFF(p,param),PTR_DIFF(p,param),
1990               NULL, 0, CLI_BUFFER_SIZE,
1991               &rparam, &rprcnt,
1992               &rdata, &rdrcnt)) {
1993     cli->rap_error = SVAL(rparam,0);
1994     if (cli->rap_error != 0) {
1995       DEBUG(1,("NetSessionGetInfo gave error %d\n", cli->rap_error));
1996     }
1997   }
1998
1999   if (rdata) {
2000     res = GETRES(rparam);
2001     
2002     if (res == 0 || res == ERRmoredata) {
2003       int converter;
2004       pstring wsname, username, clitype_name;
2005       uint16  num_conns, num_opens, num_users;
2006       unsigned int    sess_time, idle_time, user_flags;
2007
2008       p = rparam + WORDSIZE;
2009       GETWORD(p, converter);
2010       p += WORDSIZE;            /* skip rsize */
2011
2012       p = rdata;
2013       GETSTRINGP(p, wsname, rdata, converter);
2014       GETSTRINGP(p, username, rdata, converter);
2015       GETWORD(p, num_conns);
2016       GETWORD(p, num_opens);
2017       GETWORD(p, num_users);
2018       GETDWORD(p, sess_time);
2019       GETDWORD(p, idle_time);
2020       GETDWORD(p, user_flags);
2021       GETSTRINGP(p, clitype_name, rdata, converter);
2022       
2023       fn(wsname, username, num_conns, num_opens, num_users, sess_time,
2024          idle_time, user_flags, clitype_name);
2025     } else {
2026       DEBUG(4,("NetSessionGetInfo res=%d\n", res));
2027     }
2028   } else {
2029     DEBUG(4,("NetSessionGetInfo no data returned\n"));
2030   }
2031     
2032   SAFE_FREE(rparam);
2033   SAFE_FREE(rdata);
2034
2035   return res;  
2036 }
2037
2038 /****************************************************************************
2039 call a NetSessionDel - close a session to an SMB server
2040 ****************************************************************************/
2041 int cli_NetSessionDel(struct cli_state *cli, const char *workstation)
2042 {
2043   char param[WORDSIZE                      /* api number       */
2044             +sizeof(RAP_NetSessionDel_REQ) /* req string       */
2045             +1                             /* no return string */
2046             +RAP_MACHNAME_LEN              /* workstation name */
2047             +WORDSIZE];                    /* reserved (0)     */
2048   char *p;
2049   char *rparam = NULL;
2050   char *rdata = NULL;
2051   unsigned int rprcnt, rdrcnt;
2052   int res;
2053
2054   memset(param, '\0', sizeof(param));
2055   p = make_header(param, RAP_WsessionDel, RAP_NetSessionDel_REQ, NULL);
2056   PUTSTRING(p, workstation, RAP_MACHNAME_LEN-1);
2057   PUTWORD(p,0); /* reserved word of 0 */
2058   if (cli_api(cli, 
2059               param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
2060               NULL, 0, 200,       /* data, length, maxlen */
2061               &rparam, &rprcnt,   /* return params, length */
2062               &rdata, &rdrcnt))   /* return data, length */
2063     {
2064       res = GETRES(rparam);
2065       cli->rap_error = res;
2066       
2067       if (res == 0) {
2068         /* nothing to do */             
2069       }
2070       else {
2071         DEBUG(4,("NetFileClose2 res=%d\n", res));
2072       }      
2073     } else {
2074       res = -1;
2075       DEBUG(4,("NetFileClose2 failed\n"));
2076     }
2077   
2078   SAFE_FREE(rparam);
2079   SAFE_FREE(rdata);
2080
2081   return res;
2082 }
2083   
2084
2085 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))
2086 {
2087   char param[WORDSIZE                          /* api number    */
2088             +sizeof(RAP_NetConnectionEnum_REQ) /* req string    */
2089             +sizeof(RAP_CONNECTION_INFO_L1)    /* return string */ 
2090             +RAP_MACHNAME_LEN                  /* wksta name    */
2091             +WORDSIZE                          /* info level    */
2092             +WORDSIZE];                        /* buffer size   */
2093   char *p;
2094   char *rparam = NULL;
2095   char *rdata = NULL; 
2096   unsigned int rprcnt, rdrcnt;
2097   int res = -1;
2098
2099   memset(param, '\0', sizeof(param));
2100   p = make_header(param, RAP_WconnectionEnum,
2101                   RAP_NetConnectionEnum_REQ, RAP_CONNECTION_INFO_L1);
2102   PUTSTRING(p, qualifier, RAP_MACHNAME_LEN-1);/* Workstation name */
2103   PUTWORD(p,1);            /* Info level 1 */
2104   PUTWORD(p,0xFFE0);       /* Return buffer size */
2105
2106   if (cli_api(cli,
2107               param, PTR_DIFF(p,param),PTR_DIFF(p,param),
2108               NULL, 0, CLI_BUFFER_SIZE,
2109               &rparam, &rprcnt,
2110               &rdata, &rdrcnt)) {
2111     res = GETRES(rparam);
2112     cli->rap_error = res;
2113     if (res != 0) {
2114       DEBUG(1,("NetConnectionEnum gave error %d\n", res));
2115     }
2116   }
2117   if (rdata) {
2118     if (res == 0 || res == ERRmoredata) {
2119       int i, converter, count;
2120
2121       p = rparam + WORDSIZE;
2122       GETWORD(p, converter);
2123       GETWORD(p, count);
2124
2125       for (i=0,p=rdata;i<count;i++) {
2126         pstring netname, username;
2127         uint16  conn_id, conn_type, num_opens, num_users;
2128         unsigned int    conn_time;
2129
2130         GETWORD(p,conn_id);
2131         GETWORD(p,conn_type);
2132         GETWORD(p,num_opens);
2133         GETWORD(p,num_users);
2134         GETDWORD(p,conn_time);
2135         GETSTRINGP(p, username, rdata, converter);
2136         GETSTRINGP(p, netname, rdata, converter);
2137
2138         fn(conn_id, conn_type, num_opens, num_users, conn_time,
2139            username, netname);
2140       }
2141         
2142     } else {
2143       DEBUG(4,("NetConnectionEnum res=%d\n", res));
2144     }
2145   } else {
2146     DEBUG(4,("NetConnectionEnum no data returned\n"));
2147   }
2148   SAFE_FREE(rdata);
2149   SAFE_FREE(rparam);
2150   return res;
2151 }