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