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
131static 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****************************************************************************/
151int 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****************************************************************************/
203int 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/****************************************************************************
265call a NetGroupEnum - try and list user groups on a different host
266****************************************************************************/
267int 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
332int 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
391int 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
448int 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
503int 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****************************************************************************/
562int 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****************************************************************************/
614int 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/****************************************************************************
699call a NetUserEnum - try and list users on a different host
700****************************************************************************/
701int 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****************************************************************************/
774int 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/****************************************************************************
817call a NetFileGetInfo - get information about server file opened from other
818     workstation
819****************************************************************************/
820int 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****************************************************************************/
898int 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****************************************************************************/
970int 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****************************************************************************/
1041int 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************************************************************************/
1105BOOL 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************************************************************************/
1185BOOL 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************************************************************************/
1250BOOL 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************************************************************************/
1317BOOL 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****************************************************************************/
1385BOOL 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
1435int 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
1538int 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/****************************************************************************
1639call a NetServiceEnum - list running services on a different host
1640****************************************************************************/
1641int 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/****************************************************************************
1708call a NetSessionEnum - list workstations with sessions to an SMB server
1709****************************************************************************/
1710int 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
1785int 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/****************************************************************************
1858call a NetSessionDel - close a session to an SMB server
1859****************************************************************************/
1860int 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
1904int 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}
1971