fixed a bug in qpathinfo client code
[metze/samba/wip.git] / source3 / libsmb / clirap.c
1 /* 
2    Unix SMB/CIFS implementation.
3    client RAP calls
4    Copyright (C) Andrew Tridgell 1994-1998
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #define NO_SYSLOG
22
23 #include "includes.h"
24
25
26 /****************************************************************************
27 Call a remote api on an arbitrary pipe.  takes param, data and setup buffers.
28 ****************************************************************************/
29 BOOL cli_api_pipe(struct cli_state *cli, char *pipe_name, 
30                   uint16 *setup, uint32 setup_count, uint32 max_setup_count,
31                   char *params, uint32 param_count, uint32 max_param_count,
32                   char *data, uint32 data_count, uint32 max_data_count,
33                   char **rparam, uint32 *rparam_count,
34                   char **rdata, uint32 *rdata_count)
35 {
36   cli_send_trans(cli, SMBtrans, 
37                  pipe_name, 
38                  0,0,                         /* fid, flags */
39                  setup, setup_count, max_setup_count,
40                  params, param_count, max_param_count,
41                  data, data_count, max_data_count);
42
43   return (cli_receive_trans(cli, SMBtrans, 
44                             rparam, (int *)rparam_count,
45                             rdata, (int *)rdata_count));
46 }
47
48 /****************************************************************************
49 call a remote api
50 ****************************************************************************/
51 BOOL cli_api(struct cli_state *cli,
52              char *param, int prcnt, int mprcnt,
53              char *data, int drcnt, int mdrcnt,
54              char **rparam, int *rprcnt,
55              char **rdata, int *rdrcnt)
56 {
57   cli_send_trans(cli,SMBtrans,
58                  PIPE_LANMAN,             /* Name */
59                  0,0,                     /* fid, flags */
60                  NULL,0,0,                /* Setup, length, max */
61                  param, prcnt, mprcnt,    /* Params, length, max */
62                  data, drcnt, mdrcnt      /* Data, length, max */ 
63                 );
64
65   return (cli_receive_trans(cli,SMBtrans,
66                             rparam, rprcnt,
67                             rdata, rdrcnt));
68 }
69
70
71 /****************************************************************************
72 perform a NetWkstaUserLogon
73 ****************************************************************************/
74 BOOL cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation)
75 {
76         char *rparam = NULL;
77         char *rdata = NULL;
78         char *p;
79         int rdrcnt,rprcnt;
80         pstring param;
81
82         memset(param, 0, sizeof(param));
83         
84         /* send a SMBtrans command with api NetWkstaUserLogon */
85         p = param;
86         SSVAL(p,0,132); /* api number */
87         p += 2;
88         pstrcpy(p,"OOWb54WrLh");
89         p = skip_string(p,1);
90         pstrcpy(p,"WB21BWDWWDDDDDDDzzzD");
91         p = skip_string(p,1);
92         SSVAL(p,0,1);
93         p += 2;
94         pstrcpy(p,user);
95         strupper(p);
96         p += 21;
97         p++;
98         p += 15;
99         p++; 
100         pstrcpy(p, workstation); 
101         strupper(p);
102         p += 16;
103         SSVAL(p, 0, CLI_BUFFER_SIZE);
104         p += 2;
105         SSVAL(p, 0, CLI_BUFFER_SIZE);
106         p += 2;
107         
108         if (cli_api(cli, 
109                     param, PTR_DIFF(p,param),1024,  /* param, length, max */
110                     NULL, 0, CLI_BUFFER_SIZE,           /* data, length, max */
111                     &rparam, &rprcnt,               /* return params, return size */
112                     &rdata, &rdrcnt                 /* return data, return size */
113                    )) {
114                 cli->rap_error = rparam? SVAL(rparam,0) : -1;
115                 p = rdata;
116                 
117                 if (cli->rap_error == 0) {
118                         DEBUG(4,("NetWkstaUserLogon success\n"));
119                         cli->privileges = SVAL(p, 24);
120                         fstrcpy(cli->eff_name,p+2);
121                 } else {
122                         DEBUG(1,("NetwkstaUserLogon gave error %d\n", cli->rap_error));
123                 }
124         }
125         
126         SAFE_FREE(rparam);
127         SAFE_FREE(rdata);
128         return (cli->rap_error == 0);
129 }
130
131 /****************************************************************************
132 call a NetShareEnum - try and browse available connections on a host
133 ****************************************************************************/
134 int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, const char *, void *), void *state)
135 {
136         char *rparam = NULL;
137         char *rdata = NULL;
138         char *p;
139         int rdrcnt,rprcnt;
140         pstring param;
141         int count = -1;
142
143         /* now send a SMBtrans command with api RNetShareEnum */
144         p = param;
145         SSVAL(p,0,0); /* api number */
146         p += 2;
147         pstrcpy(p,"WrLeh");
148         p = skip_string(p,1);
149         pstrcpy(p,"B13BWz");
150         p = skip_string(p,1);
151         SSVAL(p,0,1);
152         /*
153          * Win2k needs a *smaller* buffer than 0xFFFF here -
154          * it returns "out of server memory" with 0xFFFF !!! JRA.
155          */
156         SSVAL(p,2,0xFFE0);
157         p += 4;
158         
159         if (cli_api(cli, 
160                     param, PTR_DIFF(p,param), 1024,  /* Param, length, maxlen */
161                     NULL, 0, 0xFFE0,            /* data, length, maxlen - Win2k needs a small buffer here too ! */
162                     &rparam, &rprcnt,                /* return params, length */
163                     &rdata, &rdrcnt))                /* return data, length */
164                 {
165                         int res = rparam? SVAL(rparam,0) : -1;
166                         
167                         if (res == 0 || res == ERRmoredata) {
168                                 int converter=SVAL(rparam,2);
169                                 int i;
170                                 
171                                 count=SVAL(rparam,4);
172                                 p = rdata;
173                                 
174                                 for (i=0;i<count;i++,p+=20) {
175                                         char *sname = p;
176                                         int type = SVAL(p,14);
177                                         int comment_offset = IVAL(p,16) & 0xFFFF;
178                                         char *cmnt = comment_offset?(rdata+comment_offset-converter):"";
179                                         pstring s1, s2;
180
181                                         pull_ascii_pstring(s1, sname);
182                                         pull_ascii_pstring(s2, cmnt);
183
184                                         fn(s1, type, s2, state);
185                                 }
186                         } else {
187                                 DEBUG(4,("NetShareEnum res=%d\n", res));
188                         }      
189                 } else {
190                         DEBUG(4,("NetShareEnum failed\n"));
191                 }
192   
193         SAFE_FREE(rparam);
194         SAFE_FREE(rdata);
195         
196         return count;
197 }
198
199
200 /****************************************************************************
201 call a NetServerEnum for the specified workgroup and servertype mask.  This
202 function then calls the specified callback function for each name returned.
203
204 The callback function takes 4 arguments: the machine name, the server type,
205 the comment and a state pointer.
206 ****************************************************************************/
207 BOOL cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
208                        void (*fn)(const char *, uint32, const char *, void *),
209                        void *state)
210 {
211         char *rparam = NULL;
212         char *rdata = NULL;
213         int rdrcnt,rprcnt;
214         char *p;
215         pstring param;
216         int uLevel = 1;
217         int count = -1;
218
219         /* send a SMBtrans command with api NetServerEnum */
220         p = param;
221         SSVAL(p,0,0x68); /* api number */
222         p += 2;
223         pstrcpy(p,"WrLehDz");
224         p = skip_string(p,1);
225   
226         pstrcpy(p,"B16BBDz");
227
228         p = skip_string(p,1);
229         SSVAL(p,0,uLevel);
230         SSVAL(p,2,CLI_BUFFER_SIZE);
231         p += 4;
232         SIVAL(p,0,stype);
233         p += 4;
234
235         p += push_pstring(p, workgroup);
236         
237         if (cli_api(cli, 
238                     param, PTR_DIFF(p,param), 8,        /* params, length, max */
239                     NULL, 0, CLI_BUFFER_SIZE,               /* data, length, max */
240                     &rparam, &rprcnt,                   /* return params, return size */
241                     &rdata, &rdrcnt                     /* return data, return size */
242                    )) {
243                 int res = rparam? SVAL(rparam,0) : -1;
244                         
245                 if (res == 0 || res == ERRmoredata) {
246                         int i;
247                         int converter=SVAL(rparam,2);
248
249                         count=SVAL(rparam,4);
250                         p = rdata;
251                                         
252                         for (i = 0;i < count;i++, p += 26) {
253                                 char *sname = p;
254                                 int comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
255                                 char *cmnt = comment_offset?(rdata+comment_offset):"";
256                                 pstring s1, s2;
257
258                                 if (comment_offset < 0 || comment_offset > rdrcnt) continue;
259
260                                 stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
261
262                                 pull_ascii_pstring(s1, sname);
263                                 pull_ascii_pstring(s2, cmnt);
264                                 fn(s1, stype, s2, state);
265                         }
266                 }
267         }
268   
269         SAFE_FREE(rparam);
270         SAFE_FREE(rdata);
271         
272         return(count > 0);
273 }
274
275
276
277 /****************************************************************************
278 Send a SamOEMChangePassword command
279 ****************************************************************************/
280 BOOL cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
281                              const char *old_password)
282 {
283   char param[16+sizeof(fstring)];
284   char data[532];
285   char *p = param;
286   fstring upper_case_old_pw;
287   fstring upper_case_new_pw;
288   unsigned char old_pw_hash[16];
289   unsigned char new_pw_hash[16];
290   int data_len;
291   int param_len = 0;
292   char *rparam = NULL;
293   char *rdata = NULL;
294   int rprcnt, rdrcnt;
295   pstring dos_new_password;
296
297   if (strlen(user) >= sizeof(fstring)-1) {
298     DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
299     return False;
300   }
301
302   SSVAL(p,0,214); /* SamOEMChangePassword command. */
303   p += 2;
304   pstrcpy(p, "zsT");
305   p = skip_string(p,1);
306   pstrcpy(p, "B516B16");
307   p = skip_string(p,1);
308   pstrcpy(p,user);
309   p = skip_string(p,1);
310   SSVAL(p,0,532);
311   p += 2;
312
313   param_len = PTR_DIFF(p,param);
314
315   /*
316    * Get the Lanman hash of the old password, we
317    * use this as the key to make_oem_passwd_hash().
318    */
319   memset(upper_case_old_pw, '\0', sizeof(upper_case_old_pw));
320   clistr_push(cli, upper_case_old_pw, old_password, -1,STR_TERMINATE|STR_UPPER|STR_ASCII);
321   E_P16((uchar *)upper_case_old_pw, old_pw_hash);
322
323   clistr_push(cli, dos_new_password, new_password, -1, STR_TERMINATE|STR_ASCII);
324
325   if (!make_oem_passwd_hash( data, dos_new_password, old_pw_hash, False))
326     return False;
327
328   /* 
329    * Now place the old password hash in the data.
330    */
331   memset(upper_case_new_pw, '\0', sizeof(upper_case_new_pw));
332   clistr_push(cli, upper_case_new_pw, new_password, -1, STR_TERMINATE|STR_UPPER|STR_ASCII);
333
334   E_P16((uchar *)upper_case_new_pw, new_pw_hash);
335
336   E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
337
338   data_len = 532;
339     
340   if (cli_send_trans(cli,SMBtrans,
341                     PIPE_LANMAN,                          /* name */
342                     0,0,                                  /* fid, flags */
343                     NULL,0,0,                             /* setup, length, max */
344                     param,param_len,2,                    /* param, length, max */
345                     data,data_len,0                       /* data, length, max */
346                    ) == False) {
347     DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
348               user ));
349     return False;
350   }
351
352   if (cli_receive_trans(cli,SMBtrans,
353                        &rparam, &rprcnt,
354                        &rdata, &rdrcnt)) {
355     if (rparam)
356       cli->rap_error = SVAL(rparam,0);
357   }
358
359   SAFE_FREE(rparam);
360   SAFE_FREE(rdata);
361
362   return (cli->rap_error == 0);
363 }
364
365
366 /****************************************************************************
367 send a qpathinfo call
368 ****************************************************************************/
369 BOOL cli_qpathinfo(struct cli_state *cli, const char *fname, 
370                    time_t *c_time, time_t *a_time, time_t *m_time, 
371                    size_t *size, uint16 *mode)
372 {
373         int data_len = 0;
374         int param_len = 0;
375         int rparam_len, rdata_len;
376         uint16 setup = TRANSACT2_QPATHINFO;
377         pstring param;
378         char *rparam=NULL, *rdata=NULL;
379         int count=8;
380         BOOL ret;
381         time_t (*date_fn)(void *);
382         char *p;
383
384         p = param;
385         memset(p, 0, 6);
386         SSVAL(p, 0, SMB_INFO_STANDARD);
387         p += 6;
388         p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
389
390         param_len = PTR_DIFF(p, param);
391
392         do {
393                 ret = (cli_send_trans(cli, SMBtrans2, 
394                                       NULL,           /* Name */
395                                       -1, 0,          /* fid, flags */
396                                       &setup, 1, 0,   /* setup, length, max */
397                                       param, param_len, 10, /* param, length, max */
398                                       NULL, data_len, cli->max_xmit /* data, length, max */
399                                       ) &&
400                        cli_receive_trans(cli, SMBtrans2, 
401                                          &rparam, &rparam_len,
402                                          &rdata, &rdata_len));
403                 if (!cli_is_dos_error(cli)) break;
404                 if (!ret) {
405                         /* we need to work around a Win95 bug - sometimes
406                            it gives ERRSRV/ERRerror temprarily */
407                         uint8 eclass;
408                         uint32 ecode;
409                         cli_dos_error(cli, &eclass, &ecode);
410                         if (eclass != ERRSRV || ecode != ERRerror) break;
411                         msleep(100);
412                 }
413         } while (count-- && ret==False);
414
415         if (!ret || !rdata || rdata_len < 22) {
416                 return False;
417         }
418
419         if (cli->win95) {
420                 date_fn = make_unix_date;
421         } else {
422                 date_fn = make_unix_date2;
423         }
424
425         if (c_time) {
426                 *c_time = date_fn(rdata+0);
427         }
428         if (a_time) {
429                 *a_time = date_fn(rdata+4);
430         }
431         if (m_time) {
432                 *m_time = date_fn(rdata+8);
433         }
434         if (size) {
435                 *size = IVAL(rdata, 12);
436         }
437         if (mode) {
438                 *mode = SVAL(rdata,l1_attrFile);
439         }
440
441         SAFE_FREE(rdata);
442         SAFE_FREE(rparam);
443         return True;
444 }
445
446 /****************************************************************************
447 send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level
448 ****************************************************************************/
449 BOOL cli_qpathinfo2(struct cli_state *cli, const char *fname, 
450                     time_t *c_time, time_t *a_time, time_t *m_time, 
451                     time_t *w_time, size_t *size, uint16 *mode,
452                     SMB_INO_T *ino)
453 {
454         int data_len = 0;
455         int param_len = 0;
456         uint16 setup = TRANSACT2_QPATHINFO;
457         pstring param;
458         char *rparam=NULL, *rdata=NULL;
459         char *p;
460
461         p = param;
462         memset(p, 0, 6);
463         SSVAL(p, 0, SMB_QUERY_FILE_ALL_INFO);
464         p += 6;
465         p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
466
467         param_len = PTR_DIFF(p, param);
468
469         if (!cli_send_trans(cli, SMBtrans2, 
470                             NULL,                         /* name */
471                             -1, 0,                        /* fid, flags */
472                             &setup, 1, 0,                 /* setup, length, max */
473                             param, param_len, 10,         /* param, length, max */
474                             NULL, data_len, cli->max_xmit /* data, length, max */
475                            )) {
476                 return False;
477         }
478
479         if (!cli_receive_trans(cli, SMBtrans2,
480                                &rparam, &param_len,
481                                &rdata, &data_len)) {
482                 return False;
483         }
484
485         if (!rdata || data_len < 22) {
486                 return False;
487         }
488
489         if (c_time) {
490                 *c_time = interpret_long_date(rdata+0) - cli->serverzone;
491         }
492         if (a_time) {
493                 *a_time = interpret_long_date(rdata+8) - cli->serverzone;
494         }
495         if (m_time) {
496                 *m_time = interpret_long_date(rdata+16) - cli->serverzone;
497         }
498         if (w_time) {
499                 *w_time = interpret_long_date(rdata+24) - cli->serverzone;
500         }
501         if (mode) {
502                 *mode = SVAL(rdata, 32);
503         }
504         if (size) {
505                 *size = IVAL(rdata, 48);
506         }
507         if (ino) {
508                 *ino = IVAL(rdata, 64);
509         }
510
511         SAFE_FREE(rdata);
512         SAFE_FREE(rparam);
513         return True;
514 }
515
516
517 /****************************************************************************
518 send a qfileinfo call
519 ****************************************************************************/
520 BOOL cli_qfileinfo(struct cli_state *cli, int fnum, 
521                    uint16 *mode, size_t *size,
522                    time_t *c_time, time_t *a_time, time_t *m_time, 
523                    time_t *w_time, SMB_INO_T *ino)
524 {
525         int data_len = 0;
526         int param_len = 0;
527         uint16 setup = TRANSACT2_QFILEINFO;
528         pstring param;
529         char *rparam=NULL, *rdata=NULL;
530
531         /* if its a win95 server then fail this - win95 totally screws it
532            up */
533         if (cli->win95) return False;
534
535         param_len = 4;
536
537         memset(param, 0, param_len);
538         SSVAL(param, 0, fnum);
539         SSVAL(param, 2, SMB_QUERY_FILE_ALL_INFO);
540
541         if (!cli_send_trans(cli, SMBtrans2, 
542                             NULL,                           /* name */
543                             -1, 0,                          /* fid, flags */
544                             &setup, 1, 0,                   /* setup, length, max */
545                             param, param_len, 2,            /* param, length, max */
546                             NULL, data_len, cli->max_xmit   /* data, length, max */
547                            )) {
548                 return False;
549         }
550
551         if (!cli_receive_trans(cli, SMBtrans2,
552                                &rparam, &param_len,
553                                &rdata, &data_len)) {
554                 return False;
555         }
556
557         if (!rdata || data_len < 68) {
558                 return False;
559         }
560
561         if (c_time) {
562                 *c_time = interpret_long_date(rdata+0) - cli->serverzone;
563         }
564         if (a_time) {
565                 *a_time = interpret_long_date(rdata+8) - cli->serverzone;
566         }
567         if (m_time) {
568                 *m_time = interpret_long_date(rdata+16) - cli->serverzone;
569         }
570         if (w_time) {
571                 *w_time = interpret_long_date(rdata+24) - cli->serverzone;
572         }
573         if (mode) {
574                 *mode = SVAL(rdata, 32);
575         }
576         if (size) {
577                 *size = IVAL(rdata, 48);
578         }
579         if (ino) {
580                 *ino = IVAL(rdata, 64);
581         }
582
583         SAFE_FREE(rdata);
584         SAFE_FREE(rparam);
585         return True;
586 }
587
588 /****************************************************************************
589 send a qfileinfo call
590 ****************************************************************************/
591 BOOL cli_qfileinfo_test(struct cli_state *cli, int fnum, int level, char *outdata)
592 {
593         int data_len = 0;
594         int param_len = 0;
595         uint16 setup = TRANSACT2_QFILEINFO;
596         pstring param;
597         char *rparam=NULL, *rdata=NULL;
598
599         /* if its a win95 server then fail this - win95 totally screws it
600            up */
601         if (cli->win95) return False;
602
603         param_len = 4;
604
605         memset(param, 0, param_len);
606         SSVAL(param, 0, fnum);
607         SSVAL(param, 2, level);
608
609         if (!cli_send_trans(cli, SMBtrans2, 
610                             NULL,                           /* name */
611                             -1, 0,                          /* fid, flags */
612                             &setup, 1, 0,                   /* setup, length, max */
613                             param, param_len, 2,            /* param, length, max */
614                             NULL, data_len, cli->max_xmit   /* data, length, max */
615                            )) {
616                 return False;
617         }
618
619         if (!cli_receive_trans(cli, SMBtrans2,
620                                &rparam, &param_len,
621                                &rdata, &data_len)) {
622                 return False;
623         }
624
625         memcpy(outdata, rdata, data_len);
626
627         SAFE_FREE(rdata);
628         SAFE_FREE(rparam);
629         return True;
630 }
631
632
633
634 /****************************************************************************
635 send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call
636 ****************************************************************************/
637 NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstring alt_name)
638 {
639         int data_len = 0;
640         int param_len = 0;
641         uint16 setup = TRANSACT2_QPATHINFO;
642         pstring param;
643         char *rparam=NULL, *rdata=NULL;
644         int count=8;
645         char *p;
646         BOOL ret;
647         int len;
648
649         p = param;
650         memset(p, 0, 6);
651         SSVAL(p, 0, SMB_QUERY_FILE_ALT_NAME_INFO);
652         p += 6;
653         p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
654
655         param_len = PTR_DIFF(p, param);
656
657         do {
658                 ret = (cli_send_trans(cli, SMBtrans2, 
659                                       NULL,           /* Name */
660                                       -1, 0,          /* fid, flags */
661                                       &setup, 1, 0,   /* setup, length, max */
662                                       param, param_len, 10, /* param, length, max */
663                                       NULL, data_len, cli->max_xmit /* data, length, max */
664                                       ) &&
665                        cli_receive_trans(cli, SMBtrans2, 
666                                          &rparam, &param_len,
667                                          &rdata, &data_len));
668                 if (!ret && cli_is_dos_error(cli)) {
669                         /* we need to work around a Win95 bug - sometimes
670                            it gives ERRSRV/ERRerror temprarily */
671                         uint8 eclass;
672                         uint32 ecode;
673                         cli_dos_error(cli, &eclass, &ecode);
674                         if (eclass != ERRSRV || ecode != ERRerror) break;
675                         msleep(100);
676                 }
677         } while (count-- && ret==False);
678
679         if (!ret || !rdata || data_len < 4) {
680                 return NT_STATUS_UNSUCCESSFUL;
681         }
682
683         len = IVAL(rdata, 0);
684
685         if (len > data_len - 4) {
686                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
687         }
688
689         clistr_pull(cli, alt_name, rdata+4, sizeof(fstring), len, 0);
690
691         SAFE_FREE(rdata);
692         SAFE_FREE(rparam);
693
694         return NT_STATUS_OK;
695 }