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