- added some error checking
[abartlet/samba.git/.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, int pipe_name_len,
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   if (pipe_name_len == 0)
38     pipe_name_len = strlen(pipe_name);
39
40   cli_send_trans(cli, SMBtrans, 
41                  pipe_name, pipe_name_len,
42                  0,0,                         /* fid, flags */
43                  setup, setup_count, max_setup_count,
44                  params, param_count, max_param_count,
45                  data, data_count, max_data_count);
46
47   return (cli_receive_trans(cli, SMBtrans, 
48                             rparam, (int *)rparam_count,
49                             rdata, (int *)rdata_count));
50 }
51
52 /****************************************************************************
53 call a remote api
54 ****************************************************************************/
55 BOOL cli_api(struct cli_state *cli,
56              char *param, int prcnt, int mprcnt,
57              char *data, int drcnt, int mdrcnt,
58              char **rparam, int *rprcnt,
59              char **rdata, int *rdrcnt)
60 {
61   cli_send_trans(cli,SMBtrans,
62                  PIPE_LANMAN,strlen(PIPE_LANMAN), /* Name, length */
63                  0,0,                             /* fid, flags */
64                  NULL,0,0,                /* Setup, length, max */
65                  param, prcnt, mprcnt,    /* Params, length, max */
66                  data, drcnt, mdrcnt      /* Data, length, max */ 
67                 );
68
69   return (cli_receive_trans(cli,SMBtrans,
70                             rparam, rprcnt,
71                             rdata, rdrcnt));
72 }
73
74
75 /****************************************************************************
76 perform a NetWkstaUserLogon
77 ****************************************************************************/
78 BOOL cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation)
79 {
80         char *rparam = NULL;
81         char *rdata = NULL;
82         char *p;
83         int rdrcnt,rprcnt;
84         pstring param;
85
86         memset(param, 0, sizeof(param));
87         
88         /* send a SMBtrans command with api NetWkstaUserLogon */
89         p = param;
90         SSVAL(p,0,132); /* api number */
91         p += 2;
92         pstrcpy(p,"OOWb54WrLh");
93         p = skip_string(p,1);
94         pstrcpy(p,"WB21BWDWWDDDDDDDzzzD");
95         p = skip_string(p,1);
96         SSVAL(p,0,1);
97         p += 2;
98         pstrcpy(p,user);
99         strupper(p);
100         p += 21;
101         p++;
102         p += 15;
103         p++; 
104         pstrcpy(p, workstation); 
105         strupper(p);
106         p += 16;
107         SSVAL(p, 0, CLI_BUFFER_SIZE);
108         p += 2;
109         SSVAL(p, 0, CLI_BUFFER_SIZE);
110         p += 2;
111         
112         if (cli_api(cli, 
113                     param, PTR_DIFF(p,param),1024,  /* param, length, max */
114                     NULL, 0, CLI_BUFFER_SIZE,           /* data, length, max */
115                     &rparam, &rprcnt,               /* return params, return size */
116                     &rdata, &rdrcnt                 /* return data, return size */
117                    )) {
118                 cli->rap_error = rparam? SVAL(rparam,0) : -1;
119                 p = rdata;
120                 
121                 if (cli->rap_error == 0) {
122                         DEBUG(4,("NetWkstaUserLogon success\n"));
123                         cli->privileges = SVAL(p, 24);
124                         fstrcpy(cli->eff_name,p+2);
125                 } else {
126                         DEBUG(1,("NetwkstaUserLogon gave error %d\n", cli->rap_error));
127                 }
128         }
129         
130         if (rparam)
131       free(rparam);
132         if (rdata)
133       free(rdata);
134         return (cli->rap_error == 0);
135 }
136
137 /****************************************************************************
138 call a NetShareEnum - try and browse available connections on a host
139 ****************************************************************************/
140 int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, const char *))
141 {
142         char *rparam = NULL;
143         char *rdata = NULL;
144         char *p;
145         int rdrcnt,rprcnt;
146         pstring param;
147         int count = -1;
148
149         /* now send a SMBtrans command with api RNetShareEnum */
150         p = param;
151         SSVAL(p,0,0); /* api number */
152         p += 2;
153         pstrcpy(p,"WrLeh");
154         p = skip_string(p,1);
155         pstrcpy(p,"B13BWz");
156         p = skip_string(p,1);
157         SSVAL(p,0,1);
158         /*
159          * Win2k needs a *smaller* buffer than 0xFFFF here -
160          * it returns "out of server memory" with 0xFFFF !!! JRA.
161          */
162         SSVAL(p,2,0xFFE0);
163         p += 4;
164         
165         if (cli_api(cli, 
166                     param, PTR_DIFF(p,param), 1024,  /* Param, length, maxlen */
167                     NULL, 0, 0xFFE0,            /* data, length, maxlen - Win2k needs a small buffer here too ! */
168                     &rparam, &rprcnt,                /* return params, length */
169                     &rdata, &rdrcnt))                /* return data, length */
170                 {
171                         int res = rparam? SVAL(rparam,0) : -1;
172                         
173                         if (res == 0 || res == ERRmoredata) {
174                                 int converter=SVAL(rparam,2);
175                                 int i;
176                                 
177                                 count=SVAL(rparam,4);
178                                 p = rdata;
179                                 
180                                 for (i=0;i<count;i++,p+=20) {
181                                         char *sname = p;
182                                         int type = SVAL(p,14);
183                                         int comment_offset = IVAL(p,16) & 0xFFFF;
184                                         char *cmnt = comment_offset?(rdata+comment_offset-converter):"";
185                                         dos_to_unix(sname,True);
186                                         dos_to_unix(cmnt,True);
187                                         fn(sname, type, cmnt);
188                                 }
189                         } else {
190                                 DEBUG(4,("NetShareEnum res=%d\n", res));
191                         }      
192                 } else {
193                         DEBUG(4,("NetShareEnum failed\n"));
194                 }
195   
196         if (rparam)
197                 free(rparam);
198         if (rdata)
199                 free(rdata);
200         
201         return count;
202 }
203
204
205 /****************************************************************************
206 call a NetServerEnum for the specified workgroup and servertype mask.
207 This function then calls the specified callback function for each name returned.
208
209 The callback function takes 3 arguments: the machine name, the server type and
210 the comment.
211 ****************************************************************************/
212 BOOL cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
213                        void (*fn)(const char *, uint32, const char *))
214 {
215         char *rparam = NULL;
216         char *rdata = NULL;
217         int rdrcnt,rprcnt;
218         char *p;
219         pstring param;
220         int uLevel = 1;
221         int count = -1;
222   
223         /* send a SMBtrans command with api NetServerEnum */
224         p = param;
225         SSVAL(p,0,0x68); /* api number */
226         p += 2;
227         pstrcpy(p,"WrLehDz");
228         p = skip_string(p,1);
229   
230         pstrcpy(p,"B16BBDz");
231   
232         p = skip_string(p,1);
233         SSVAL(p,0,uLevel);
234         SSVAL(p,2,CLI_BUFFER_SIZE);
235         p += 4;
236         SIVAL(p,0,stype);
237         p += 4;
238         
239         pstrcpy(p, workgroup);
240         p = skip_string(p,1);
241         
242         if (cli_api(cli, 
243                     param, PTR_DIFF(p,param), 8,        /* params, length, max */
244                     NULL, 0, CLI_BUFFER_SIZE,               /* data, length, max */
245                     &rparam, &rprcnt,                   /* return params, return size */
246                     &rdata, &rdrcnt                     /* return data, return size */
247                    )) {
248                 int res = rparam? SVAL(rparam,0) : -1;
249                         
250                 if (res == 0 || res == ERRmoredata) {
251                         int i;
252                         int converter=SVAL(rparam,2);
253
254                         count=SVAL(rparam,4);
255                         p = rdata;
256                                         
257                         for (i = 0;i < count;i++, p += 26) {
258                                 char *sname = p;
259                                 int comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
260                                 char *cmnt = comment_offset?(rdata+comment_offset):"";
261                                 if (comment_offset < 0 || comment_offset > rdrcnt) continue;
262
263                                 stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
264
265                                 dos_to_unix(sname, True);
266                                 dos_to_unix(cmnt, True);
267                                 fn(sname, stype, cmnt);
268                         }
269                 }
270         }
271   
272         if (rparam)
273                 free(rparam);
274         if (rdata)
275                 free(rdata);
276         
277         return(count > 0);
278 }
279
280
281
282 /****************************************************************************
283 Send a SamOEMChangePassword command
284 ****************************************************************************/
285 BOOL cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
286                              const char *old_password)
287 {
288   char param[16+sizeof(fstring)];
289   char data[532];
290   char *p = param;
291   fstring upper_case_old_pw;
292   fstring upper_case_new_pw;
293   unsigned char old_pw_hash[16];
294   unsigned char new_pw_hash[16];
295   int data_len;
296   int param_len = 0;
297   char *rparam = NULL;
298   char *rdata = NULL;
299   int rprcnt, rdrcnt;
300   pstring dos_new_password;
301
302   if (strlen(user) >= sizeof(fstring)-1) {
303     DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
304     return False;
305   }
306
307   SSVAL(p,0,214); /* SamOEMChangePassword command. */
308   p += 2;
309   pstrcpy(p, "zsT");
310   p = skip_string(p,1);
311   pstrcpy(p, "B516B16");
312   p = skip_string(p,1);
313   pstrcpy(p,user);
314   p = skip_string(p,1);
315   SSVAL(p,0,532);
316   p += 2;
317
318   param_len = PTR_DIFF(p,param);
319
320   /*
321    * Get the Lanman hash of the old password, we
322    * use this as the key to make_oem_passwd_hash().
323    */
324   memset(upper_case_old_pw, '\0', sizeof(upper_case_old_pw));
325   fstrcpy(upper_case_old_pw, old_password);
326   unix_to_dos(upper_case_old_pw,True);
327   strupper(upper_case_old_pw);
328   E_P16((uchar *)upper_case_old_pw, old_pw_hash);
329
330   pstrcpy(dos_new_password, new_password);
331   unix_to_dos(dos_new_password, True);
332
333   if (!make_oem_passwd_hash( data, dos_new_password, old_pw_hash, False))
334     return False;
335
336   /* 
337    * Now place the old password hash in the data.
338    */
339   memset(upper_case_new_pw, '\0', sizeof(upper_case_new_pw));
340   fstrcpy(upper_case_new_pw, new_password);
341   unix_to_dos(upper_case_new_pw,True);
342   strupper(upper_case_new_pw);
343
344   E_P16((uchar *)upper_case_new_pw, new_pw_hash);
345
346   E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
347
348   data_len = 532;
349     
350   if (cli_send_trans(cli,SMBtrans,
351                     PIPE_LANMAN,strlen(PIPE_LANMAN),      /* name, length */
352                     0,0,                                  /* fid, flags */
353                     NULL,0,0,                             /* setup, length, max */
354                     param,param_len,2,                    /* param, length, max */
355                     data,data_len,0                       /* data, length, max */
356                    ) == False) {
357     DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
358               user ));
359     return False;
360   }
361
362   if (cli_receive_trans(cli,SMBtrans,
363                        &rparam, &rprcnt,
364                        &rdata, &rdrcnt)) {
365     if (rparam)
366       cli->rap_error = SVAL(rparam,0);
367   }
368
369   if (rparam)
370     free(rparam);
371   if (rdata)
372     free(rdata);
373
374   return (cli->rap_error == 0);
375 }
376
377
378 /****************************************************************************
379 send a qpathinfo call
380 ****************************************************************************/
381 BOOL cli_qpathinfo(struct cli_state *cli, const char *fname, 
382                    time_t *c_time, time_t *a_time, time_t *m_time, 
383                    size_t *size, uint16 *mode)
384 {
385         int data_len = 0;
386         int param_len = 0;
387         uint16 setup = TRANSACT2_QPATHINFO;
388         pstring param;
389         char *rparam=NULL, *rdata=NULL;
390         int count=8;
391         BOOL ret;
392         time_t (*date_fn)(void *);
393
394         param_len = strlen(fname) + 7;
395
396         memset(param, 0, param_len);
397         SSVAL(param, 0, SMB_INFO_STANDARD);
398         pstrcpy(&param[6], fname);
399     unix_to_dos(&param[6],True);
400
401         do {
402                 ret = (cli_send_trans(cli, SMBtrans2, 
403                                       NULL, 0,        /* Name, length */
404                                       -1, 0,          /* fid, flags */
405                                       &setup, 1, 0,   /* setup, length, max */
406                                       param, param_len, 10, /* param, length, max */
407                                       NULL, data_len, cli->max_xmit /* data, length, max */
408                                       ) &&
409                        cli_receive_trans(cli, SMBtrans2, 
410                                          &rparam, &param_len,
411                                          &rdata, &data_len));
412                 if (!ret) {
413                         /* we need to work around a Win95 bug - sometimes
414                            it gives ERRSRV/ERRerror temprarily */
415                         uint8 eclass;
416                         uint32 ecode;
417                         cli_error(cli, &eclass, &ecode, NULL);
418                         if (eclass != ERRSRV || ecode != ERRerror) break;
419                         msleep(100);
420                 }
421         } while (count-- && ret==False);
422
423         if (!ret || !rdata || data_len < 22) {
424                 return False;
425         }
426
427         if (cli->win95) {
428                 date_fn = make_unix_date;
429         } else {
430                 date_fn = make_unix_date2;
431         }
432
433         if (c_time) {
434                 *c_time = date_fn(rdata+0);
435         }
436         if (a_time) {
437                 *a_time = date_fn(rdata+4);
438         }
439         if (m_time) {
440                 *m_time = date_fn(rdata+8);
441         }
442         if (size) {
443                 *size = IVAL(rdata, 12);
444         }
445         if (mode) {
446                 *mode = SVAL(rdata,l1_attrFile);
447         }
448
449         if (rdata) free(rdata);
450         if (rparam) free(rparam);
451         return True;
452 }
453
454 /****************************************************************************
455 send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level
456 ****************************************************************************/
457 BOOL cli_qpathinfo2(struct cli_state *cli, const char *fname, 
458                     time_t *c_time, time_t *a_time, time_t *m_time, 
459                     time_t *w_time, size_t *size, uint16 *mode,
460                     SMB_INO_T *ino)
461 {
462         int data_len = 0;
463         int param_len = 0;
464         uint16 setup = TRANSACT2_QPATHINFO;
465         pstring param;
466         char *rparam=NULL, *rdata=NULL;
467
468         param_len = strlen(fname) + 7;
469
470         memset(param, 0, param_len);
471         SSVAL(param, 0, SMB_QUERY_FILE_ALL_INFO);
472         pstrcpy(&param[6], fname);
473     unix_to_dos(&param[6],True);
474
475         if (!cli_send_trans(cli, SMBtrans2, 
476                             NULL, 0,                      /* name, length */
477                             -1, 0,                        /* fid, flags */
478                             &setup, 1, 0,                 /* setup, length, max */
479                             param, param_len, 10,         /* param, length, max */
480                             NULL, data_len, cli->max_xmit /* data, length, max */
481                            )) {
482                 return False;
483         }
484
485         if (!cli_receive_trans(cli, SMBtrans2,
486                                &rparam, &param_len,
487                                &rdata, &data_len)) {
488                 return False;
489         }
490
491         if (!rdata || data_len < 22) {
492                 return False;
493         }
494
495         if (c_time) {
496                 *c_time = interpret_long_date(rdata+0) - cli->serverzone;
497         }
498         if (a_time) {
499                 *a_time = interpret_long_date(rdata+8) - cli->serverzone;
500         }
501         if (m_time) {
502                 *m_time = interpret_long_date(rdata+16) - cli->serverzone;
503         }
504         if (w_time) {
505                 *w_time = interpret_long_date(rdata+24) - cli->serverzone;
506         }
507         if (mode) {
508                 *mode = SVAL(rdata, 32);
509         }
510         if (size) {
511                 *size = IVAL(rdata, 48);
512         }
513         if (ino) {
514                 *ino = IVAL(rdata, 64);
515         }
516
517         if (rdata) free(rdata);
518         if (rparam) free(rparam);
519         return True;
520 }
521
522
523 /****************************************************************************
524 send a qfileinfo call
525 ****************************************************************************/
526 BOOL cli_qfileinfo(struct cli_state *cli, int fnum, 
527                    uint16 *mode, size_t *size,
528                    time_t *c_time, time_t *a_time, time_t *m_time, 
529                    time_t *w_time, SMB_INO_T *ino)
530 {
531         int data_len = 0;
532         int param_len = 0;
533         uint16 setup = TRANSACT2_QFILEINFO;
534         pstring param;
535         char *rparam=NULL, *rdata=NULL;
536
537         /* if its a win95 server then fail this - win95 totally screws it
538            up */
539         if (cli->win95) return False;
540
541         param_len = 4;
542
543         memset(param, 0, param_len);
544         SSVAL(param, 0, fnum);
545         SSVAL(param, 2, SMB_QUERY_FILE_ALL_INFO);
546
547         if (!cli_send_trans(cli, SMBtrans2, 
548                             NULL, 0,                        /* name, length */
549                             -1, 0,                          /* fid, flags */
550                             &setup, 1, 0,                   /* setup, length, max */
551                             param, param_len, 2,            /* param, length, max */
552                             NULL, data_len, cli->max_xmit   /* data, length, max */
553                            )) {
554                 return False;
555         }
556
557         if (!cli_receive_trans(cli, SMBtrans2,
558                                &rparam, &param_len,
559                                &rdata, &data_len)) {
560                 return False;
561         }
562
563         if (!rdata || data_len < 68) {
564                 return False;
565         }
566
567         if (c_time) {
568                 *c_time = interpret_long_date(rdata+0) - cli->serverzone;
569         }
570         if (a_time) {
571                 *a_time = interpret_long_date(rdata+8) - cli->serverzone;
572         }
573         if (m_time) {
574                 *m_time = interpret_long_date(rdata+16) - cli->serverzone;
575         }
576         if (w_time) {
577                 *w_time = interpret_long_date(rdata+24) - cli->serverzone;
578         }
579         if (mode) {
580                 *mode = SVAL(rdata, 32);
581         }
582         if (size) {
583                 *size = IVAL(rdata, 48);
584         }
585         if (ino) {
586                 *ino = IVAL(rdata, 64);
587         }
588
589         if (rdata) free(rdata);
590         if (rparam) free(rparam);
591         return True;
592 }
593