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