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