s3: Remove some unused code
[garming/samba-autobuild/.git] / source3 / libsmb / clientgen.c
1 /* 
2    Unix SMB/CIFS implementation.
3    SMB client generic functions
4    Copyright (C) Andrew Tridgell 1994-1998
5    Copyright (C) Jeremy Allison 2007.
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 3 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, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22
23 /*******************************************************************
24  Setup the word count and byte count for a client smb message.
25 ********************************************************************/
26
27 int cli_set_message(char *buf,int num_words,int num_bytes,bool zero)
28 {
29         if (zero && (num_words || num_bytes)) {
30                 memset(buf + smb_size,'\0',num_words*2 + num_bytes);
31         }
32         SCVAL(buf,smb_wct,num_words);
33         SSVAL(buf,smb_vwv + num_words*SIZEOFWORD,num_bytes);
34         smb_setlen(buf,smb_size + num_words*2 + num_bytes - 4);
35         return (smb_size + num_words*2 + num_bytes);
36 }
37
38 /****************************************************************************
39  Change the timeout (in milliseconds).
40 ****************************************************************************/
41
42 unsigned int cli_set_timeout(struct cli_state *cli, unsigned int timeout)
43 {
44         unsigned int old_timeout = cli->timeout;
45         cli->timeout = timeout;
46         return old_timeout;
47 }
48
49 /****************************************************************************
50  Change the port number used to call on.
51 ****************************************************************************/
52
53 void cli_set_port(struct cli_state *cli, int port)
54 {
55         cli->port = port;
56 }
57
58 /****************************************************************************
59  convenience routine to find if we negotiated ucs2
60 ****************************************************************************/
61
62 bool cli_ucs2(struct cli_state *cli)
63 {
64         return ((cli->capabilities & CAP_UNICODE) != 0);
65 }
66
67
68 /****************************************************************************
69  Read an smb from a fd ignoring all keepalive packets.
70  The timeout is in milliseconds
71
72  This is exactly the same as receive_smb except that it never returns
73  a session keepalive packet (just as receive_smb used to do).
74  receive_smb was changed to return keepalives as the oplock processing means this call
75  should never go into a blocking read.
76 ****************************************************************************/
77
78 static ssize_t client_receive_smb(struct cli_state *cli, size_t maxlen)
79 {
80         size_t len;
81
82         for(;;) {
83                 NTSTATUS status;
84
85                 set_smb_read_error(&cli->smb_rw_error, SMB_READ_OK);
86
87                 status = receive_smb_raw(cli->fd, cli->inbuf, cli->bufsize,
88                                         cli->timeout, maxlen, &len);
89                 if (!NT_STATUS_IS_OK(status)) {
90                         DEBUG(10,("client_receive_smb failed\n"));
91                         show_msg(cli->inbuf);
92
93                         if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {
94                                 set_smb_read_error(&cli->smb_rw_error,
95                                                    SMB_READ_EOF);
96                                 return -1;
97                         }
98
99                         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
100                                 set_smb_read_error(&cli->smb_rw_error,
101                                                    SMB_READ_TIMEOUT);
102                                 return -1;
103                         }
104
105                         set_smb_read_error(&cli->smb_rw_error, SMB_READ_ERROR);
106                         return -1;
107                 }
108
109                 /*
110                  * I don't believe len can be < 0 with NT_STATUS_OK
111                  * returned above, but this check doesn't hurt. JRA.
112                  */
113
114                 if ((ssize_t)len < 0) {
115                         return len;
116                 }
117
118                 /* Ignore session keepalive packets. */
119                 if(CVAL(cli->inbuf,0) != SMBkeepalive) {
120                         break;
121                 }
122         }
123
124         if (cli_encryption_on(cli)) {
125                 NTSTATUS status = cli_decrypt_message(cli);
126                 if (!NT_STATUS_IS_OK(status)) {
127                         DEBUG(0, ("SMB decryption failed on incoming packet! Error %s\n",
128                                 nt_errstr(status)));
129                         cli->smb_rw_error = SMB_READ_BAD_DECRYPT;
130                         return -1;
131                 }
132         }
133
134         show_msg(cli->inbuf);
135         return len;
136 }
137
138 static bool cli_state_set_seqnum(struct cli_state *cli, uint16_t mid, uint32_t seqnum)
139 {
140         struct cli_state_seqnum *c;
141
142         for (c = cli->seqnum; c; c = c->next) {
143                 if (c->mid == mid) {
144                         c->seqnum = seqnum;
145                         return true;
146                 }
147         }
148
149         c = talloc_zero(cli, struct cli_state_seqnum);
150         if (!c) {
151                 return false;
152         }
153
154         c->mid = mid;
155         c->seqnum = seqnum;
156         c->persistent = false;
157         DLIST_ADD_END(cli->seqnum, c, struct cli_state_seqnum *);
158
159         return true;
160 }
161
162 bool cli_state_seqnum_persistent(struct cli_state *cli,
163                                  uint16_t mid)
164 {
165         struct cli_state_seqnum *c;
166
167         for (c = cli->seqnum; c; c = c->next) {
168                 if (c->mid == mid) {
169                         c->persistent = true;
170                         return true;
171                 }
172         }
173
174         return false;
175 }
176
177 bool cli_state_seqnum_remove(struct cli_state *cli,
178                              uint16_t mid)
179 {
180         struct cli_state_seqnum *c;
181
182         for (c = cli->seqnum; c; c = c->next) {
183                 if (c->mid == mid) {
184                         DLIST_REMOVE(cli->seqnum, c);
185                         TALLOC_FREE(c);
186                         return true;
187                 }
188         }
189
190         return false;
191 }
192
193 static uint32_t cli_state_get_seqnum(struct cli_state *cli, uint16_t mid)
194 {
195         struct cli_state_seqnum *c;
196
197         for (c = cli->seqnum; c; c = c->next) {
198                 if (c->mid == mid) {
199                         uint32_t seqnum = c->seqnum;
200                         if (!c->persistent) {
201                                 DLIST_REMOVE(cli->seqnum, c);
202                                 TALLOC_FREE(c);
203                         }
204                         return seqnum;
205                 }
206         }
207
208         return 0;
209 }
210
211 /****************************************************************************
212  Recv an smb.
213 ****************************************************************************/
214
215 bool cli_receive_smb(struct cli_state *cli)
216 {
217         ssize_t len;
218         uint16_t mid;
219         uint32_t seqnum;
220
221         /* fd == -1 causes segfaults -- Tom (tom@ninja.nl) */
222         if (cli->fd == -1)
223                 return false; 
224
225  again:
226         len = client_receive_smb(cli, 0);
227         
228         if (len > 0) {
229                 /* it might be an oplock break request */
230                 if (!(CVAL(cli->inbuf, smb_flg) & FLAG_REPLY) &&
231                     CVAL(cli->inbuf,smb_com) == SMBlockingX &&
232                     SVAL(cli->inbuf,smb_vwv6) == 0 &&
233                     SVAL(cli->inbuf,smb_vwv7) == 0) {
234                         if (cli->oplock_handler) {
235                                 int fnum = SVAL(cli->inbuf,smb_vwv2);
236                                 unsigned char level = CVAL(cli->inbuf,smb_vwv3+1);
237                                 if (!NT_STATUS_IS_OK(cli->oplock_handler(cli, fnum, level))) {
238                                         return false;
239                                 }
240                         }
241                         /* try to prevent loops */
242                         SCVAL(cli->inbuf,smb_com,0xFF);
243                         goto again;
244                 }
245         }
246
247         /* If the server is not responding, note that now */
248         if (len < 0) {
249                 DEBUG(0, ("Receiving SMB: Server stopped responding\n"));
250                 close(cli->fd);
251                 cli->fd = -1;
252                 return false;
253         }
254
255         mid = SVAL(cli->inbuf,smb_mid);
256         seqnum = cli_state_get_seqnum(cli, mid);
257
258         if (!cli_check_sign_mac(cli, cli->inbuf, seqnum+1)) {
259                 /*
260                  * If we get a signature failure in sessionsetup, then
261                  * the server sometimes just reflects the sent signature
262                  * back to us. Detect this and allow the upper layer to
263                  * retrieve the correct Windows error message.
264                  */
265                 if (CVAL(cli->outbuf,smb_com) == SMBsesssetupX &&
266                         (smb_len(cli->inbuf) > (smb_ss_field + 8 - 4)) &&
267                         (SVAL(cli->inbuf,smb_flg2) & FLAGS2_SMB_SECURITY_SIGNATURES) &&
268                         memcmp(&cli->outbuf[smb_ss_field],&cli->inbuf[smb_ss_field],8) == 0 &&
269                         cli_is_error(cli)) {
270
271                         /*
272                          * Reflected signature on login error. 
273                          * Set bad sig but don't close fd.
274                          */
275                         cli->smb_rw_error = SMB_READ_BAD_SIG;
276                         return true;
277                 }
278
279                 DEBUG(0, ("SMB Signature verification failed on incoming packet!\n"));
280                 cli->smb_rw_error = SMB_READ_BAD_SIG;
281                 close(cli->fd);
282                 cli->fd = -1;
283                 return false;
284         };
285         return true;
286 }
287
288 static ssize_t write_socket(int fd, const char *buf, size_t len)
289 {
290         ssize_t ret=0;
291
292         DEBUG(6,("write_socket(%d,%d)\n",fd,(int)len));
293         ret = write_data(fd,buf,len);
294
295         DEBUG(6,("write_socket(%d,%d) wrote %d\n",fd,(int)len,(int)ret));
296         if(ret <= 0)
297                 DEBUG(0,("write_socket: Error writing %d bytes to socket %d: ERRNO = %s\n",
298                         (int)len, fd, strerror(errno) ));
299
300         return(ret);
301 }
302
303 /****************************************************************************
304  Send an smb to a fd.
305 ****************************************************************************/
306
307 bool cli_send_smb(struct cli_state *cli)
308 {
309         size_t len;
310         size_t nwritten=0;
311         ssize_t ret;
312         char *buf_out = cli->outbuf;
313         bool enc_on = cli_encryption_on(cli);
314         uint32_t seqnum;
315
316         /* fd == -1 causes segfaults -- Tom (tom@ninja.nl) */
317         if (cli->fd == -1)
318                 return false;
319
320         cli_calculate_sign_mac(cli, cli->outbuf, &seqnum);
321
322         if (!cli_state_set_seqnum(cli, cli->mid, seqnum)) {
323                 DEBUG(0,("Failed to store mid[%u]/seqnum[%u]\n",
324                         (unsigned int)cli->mid,
325                         (unsigned int)seqnum));
326                 return false;
327         }
328
329         if (enc_on) {
330                 NTSTATUS status = cli_encrypt_message(cli, cli->outbuf,
331                                                       &buf_out);
332                 if (!NT_STATUS_IS_OK(status)) {
333                         close(cli->fd);
334                         cli->fd = -1;
335                         cli->smb_rw_error = SMB_WRITE_ERROR;
336                         DEBUG(0,("Error in encrypting client message. Error %s\n",
337                                 nt_errstr(status) ));
338                         return false;
339                 }
340         }
341
342         len = smb_len(buf_out) + 4;
343
344         while (nwritten < len) {
345                 ret = write_socket(cli->fd,buf_out+nwritten,len - nwritten);
346                 if (ret <= 0) {
347                         if (enc_on) {
348                                 cli_free_enc_buffer(cli, buf_out);
349                         }
350                         close(cli->fd);
351                         cli->fd = -1;
352                         cli->smb_rw_error = SMB_WRITE_ERROR;
353                         DEBUG(0,("Error writing %d bytes to client. %d (%s)\n",
354                                 (int)len,(int)ret, strerror(errno) ));
355                         return false;
356                 }
357                 nwritten += ret;
358         }
359
360         if (enc_on) {
361                 cli_free_enc_buffer(cli, buf_out);
362         }
363
364         /* Increment the mid so we can tell between responses. */
365         cli->mid++;
366         if (!cli->mid)
367                 cli->mid++;
368         return true;
369 }
370
371 /****************************************************************************
372  Send a "direct" writeX smb to a fd.
373 ****************************************************************************/
374
375 bool cli_send_smb_direct_writeX(struct cli_state *cli,
376                                 const char *p,
377                                 size_t extradata)
378 {
379         /* First length to send is the offset to the data. */
380         size_t len = SVAL(cli->outbuf,smb_vwv11) + 4;
381         size_t nwritten=0;
382         struct iovec iov[2];
383
384         /* fd == -1 causes segfaults -- Tom (tom@ninja.nl) */
385         if (cli->fd == -1) {
386                 return false;
387         }
388
389         if (client_is_signing_on(cli)) {
390                 DEBUG(0,("cli_send_smb_large: cannot send signed packet.\n"));
391                 return false;
392         }
393
394         iov[0].iov_base = (void *)cli->outbuf;
395         iov[0].iov_len = len;
396         iov[1].iov_base = CONST_DISCARD(void *, p);
397         iov[1].iov_len = extradata;
398
399         nwritten = write_data_iov(cli->fd, iov, 2);
400         if (nwritten < (len + extradata)) {
401                 close(cli->fd);
402                 cli->fd = -1;
403                 cli->smb_rw_error = SMB_WRITE_ERROR;
404                 DEBUG(0,("Error writing %d bytes to client. (%s)\n",
405                          (int)(len+extradata), strerror(errno)));
406                 return false;
407         }
408
409         /* Increment the mid so we can tell between responses. */
410         cli->mid++;
411         if (!cli->mid)
412                 cli->mid++;
413         return true;
414 }
415
416 /****************************************************************************
417  Setup basics in a outgoing packet.
418 ****************************************************************************/
419
420 void cli_setup_packet_buf(struct cli_state *cli, char *buf)
421 {
422         uint16 flags2;
423         cli->rap_error = 0;
424         SIVAL(buf,smb_rcls,0);
425         SSVAL(buf,smb_pid,cli->pid);
426         memset(buf+smb_pidhigh, 0, 12);
427         SSVAL(buf,smb_uid,cli->vuid);
428         SSVAL(buf,smb_mid,cli->mid);
429
430         if (cli->protocol <= PROTOCOL_CORE) {
431                 return;
432         }
433
434         if (cli->case_sensitive) {
435                 SCVAL(buf,smb_flg,0x0);
436         } else {
437                 /* Default setting, case insensitive. */
438                 SCVAL(buf,smb_flg,0x8);
439         }
440         flags2 = FLAGS2_LONG_PATH_COMPONENTS;
441         if (cli->capabilities & CAP_UNICODE)
442                 flags2 |= FLAGS2_UNICODE_STRINGS;
443         if ((cli->capabilities & CAP_DFS) && cli->dfsroot)
444                 flags2 |= FLAGS2_DFS_PATHNAMES;
445         if (cli->capabilities & CAP_STATUS32)
446                 flags2 |= FLAGS2_32_BIT_ERROR_CODES;
447         if (cli->use_spnego)
448                 flags2 |= FLAGS2_EXTENDED_SECURITY;
449         SSVAL(buf,smb_flg2, flags2);
450 }
451
452 void cli_setup_packet(struct cli_state *cli)
453 {
454         cli_setup_packet_buf(cli, cli->outbuf);
455 }
456
457 /****************************************************************************
458  Setup the bcc length of the packet from a pointer to the end of the data.
459 ****************************************************************************/
460
461 void cli_setup_bcc(struct cli_state *cli, void *p)
462 {
463         set_message_bcc(cli->outbuf, PTR_DIFF(p, smb_buf(cli->outbuf)));
464 }
465
466 /****************************************************************************
467  Initialize Domain, user or password.
468 ****************************************************************************/
469
470 NTSTATUS cli_set_domain(struct cli_state *cli, const char *domain)
471 {
472         TALLOC_FREE(cli->domain);
473         cli->domain = talloc_strdup(cli, domain ? domain : "");
474         if (cli->domain == NULL) {
475                 return NT_STATUS_NO_MEMORY;
476         }
477         return NT_STATUS_OK;
478 }
479
480 NTSTATUS cli_set_username(struct cli_state *cli, const char *username)
481 {
482         TALLOC_FREE(cli->user_name);
483         cli->user_name = talloc_strdup(cli, username ? username : "");
484         if (cli->user_name == NULL) {
485                 return NT_STATUS_NO_MEMORY;
486         }
487         return NT_STATUS_OK;
488 }
489
490 NTSTATUS cli_set_password(struct cli_state *cli, const char *password)
491 {
492         TALLOC_FREE(cli->password);
493
494         /* Password can be NULL. */
495         if (password) {
496                 cli->password = talloc_strdup(cli, password);
497                 if (cli->password == NULL) {
498                         return NT_STATUS_NO_MEMORY;
499                 }
500         } else {
501                 /* Use zero NTLMSSP hashes and session key. */
502                 cli->password = NULL;
503         }
504
505         return NT_STATUS_OK;
506 }
507
508 /****************************************************************************
509  Initialise credentials of a client structure.
510 ****************************************************************************/
511
512 NTSTATUS cli_init_creds(struct cli_state *cli, const char *username, const char *domain, const char *password)
513 {
514         NTSTATUS status = cli_set_username(cli, username);
515         if (!NT_STATUS_IS_OK(status)) {
516                 return status;
517         }
518         status = cli_set_domain(cli, domain);
519         if (!NT_STATUS_IS_OK(status)) {
520                 return status;
521         }
522         DEBUG(10,("cli_init_creds: user %s domain %s\n", cli->user_name, cli->domain));
523
524         return cli_set_password(cli, password);
525 }
526
527 /****************************************************************************
528  Initialise a client structure. Always returns a talloc'ed struct.
529  Set the signing state (used from the command line).
530 ****************************************************************************/
531
532 struct cli_state *cli_initialise_ex(int signing_state)
533 {
534         struct cli_state *cli = NULL;
535         bool allow_smb_signing = false;
536         bool mandatory_signing = false;
537
538         /* Check the effective uid - make sure we are not setuid */
539         if (is_setuid_root()) {
540                 DEBUG(0,("libsmb based programs must *NOT* be setuid root.\n"));
541                 return NULL;
542         }
543
544         cli = TALLOC_ZERO_P(NULL, struct cli_state);
545         if (!cli) {
546                 return NULL;
547         }
548
549         cli->dfs_mountpoint = talloc_strdup(cli, "");
550         if (!cli->dfs_mountpoint) {
551                 goto error;
552         }
553         cli->port = 0;
554         cli->fd = -1;
555         cli->cnum = -1;
556         cli->pid = (uint16)sys_getpid();
557         cli->mid = 1;
558         cli->vuid = UID_FIELD_INVALID;
559         cli->protocol = PROTOCOL_NT1;
560         cli->timeout = 20000; /* Timeout is in milliseconds. */
561         cli->bufsize = CLI_BUFFER_SIZE+4;
562         cli->max_xmit = cli->bufsize;
563         cli->outbuf = (char *)SMB_MALLOC(cli->bufsize+SAFETY_MARGIN);
564         cli->seqnum = 0;
565         cli->inbuf = (char *)SMB_MALLOC(cli->bufsize+SAFETY_MARGIN);
566         cli->oplock_handler = cli_oplock_ack;
567         cli->case_sensitive = false;
568         cli->smb_rw_error = SMB_READ_OK;
569
570         cli->use_spnego = lp_client_use_spnego();
571
572         cli->capabilities = CAP_UNICODE | CAP_STATUS32 | CAP_DFS;
573
574         /* Set the CLI_FORCE_DOSERR environment variable to test
575            client routines using DOS errors instead of STATUS32
576            ones.  This intended only as a temporary hack. */    
577         if (getenv("CLI_FORCE_DOSERR"))
578                 cli->force_dos_errors = true;
579
580         if (lp_client_signing()) {
581                 allow_smb_signing = true;
582         }
583
584         if (lp_client_signing() == Required) {
585                 mandatory_signing = true;
586         }
587
588         if (signing_state != Undefined) {
589                 allow_smb_signing = true;
590         }
591
592         if (signing_state == false) {
593                 allow_smb_signing = false;
594                 mandatory_signing = false;
595         }
596
597         if (signing_state == Required) {
598                 mandatory_signing = true;
599         }
600
601         if (!cli->outbuf || !cli->inbuf)
602                 goto error;
603
604         memset(cli->outbuf, 0, cli->bufsize);
605         memset(cli->inbuf, 0, cli->bufsize);
606
607
608 #if defined(DEVELOPER)
609         /* just because we over-allocate, doesn't mean it's right to use it */
610         clobber_region(FUNCTION_MACRO, __LINE__, cli->outbuf+cli->bufsize, SAFETY_MARGIN);
611         clobber_region(FUNCTION_MACRO, __LINE__, cli->inbuf+cli->bufsize, SAFETY_MARGIN);
612 #endif
613
614         /* initialise signing */
615         cli->signing_state = smb_signing_init(cli,
616                                               allow_smb_signing,
617                                               mandatory_signing);
618         if (!cli->signing_state) {
619                 goto error;
620         }
621
622         cli->outgoing = tevent_queue_create(cli, "cli_outgoing");
623         if (cli->outgoing == NULL) {
624                 goto error;
625         }
626         cli->pending = NULL;
627
628         cli->initialised = 1;
629
630         return cli;
631
632         /* Clean up after malloc() error */
633
634  error:
635
636         SAFE_FREE(cli->inbuf);
637         SAFE_FREE(cli->outbuf);
638         TALLOC_FREE(cli);
639         return NULL;
640 }
641
642 struct cli_state *cli_initialise(void)
643 {
644         return cli_initialise_ex(Undefined);
645 }
646
647 /****************************************************************************
648  Close all pipes open on this session.
649 ****************************************************************************/
650
651 void cli_nt_pipes_close(struct cli_state *cli)
652 {
653         while (cli->pipe_list != NULL) {
654                 /*
655                  * No TALLOC_FREE here!
656                  */
657                 talloc_free(cli->pipe_list);
658         }
659 }
660
661 /****************************************************************************
662  Shutdown a client structure.
663 ****************************************************************************/
664
665 static void _cli_shutdown(struct cli_state *cli)
666 {
667         cli_nt_pipes_close(cli);
668
669         /*
670          * tell our peer to free his resources.  Wihtout this, when an
671          * application attempts to do a graceful shutdown and calls
672          * smbc_free_context() to clean up all connections, some connections
673          * can remain active on the peer end, until some (long) timeout period
674          * later.  This tree disconnect forces the peer to clean up, since the
675          * connection will be going away.
676          *
677          * Also, do not do tree disconnect when cli->smb_rw_error is SMB_DO_NOT_DO_TDIS
678          * the only user for this so far is smbmount which passes opened connection
679          * down to kernel's smbfs module.
680          */
681         if ( (cli->cnum != (uint16)-1) && (cli->smb_rw_error != SMB_DO_NOT_DO_TDIS ) ) {
682                 cli_tdis(cli);
683         }
684         
685         SAFE_FREE(cli->outbuf);
686         SAFE_FREE(cli->inbuf);
687
688         data_blob_free(&cli->secblob);
689         data_blob_free(&cli->user_session_key);
690
691         if (cli->fd != -1) {
692                 close(cli->fd);
693         }
694         cli->fd = -1;
695         cli->smb_rw_error = SMB_READ_OK;
696
697         /*
698          * Need to free pending first, they remove themselves
699          */
700         while (cli->pending) {
701                 talloc_free(cli->pending[0]);
702         }
703         TALLOC_FREE(cli);
704 }
705
706 void cli_shutdown(struct cli_state *cli)
707 {
708         struct cli_state *cli_head;
709         if (cli == NULL) {
710                 return;
711         }
712         DLIST_HEAD(cli, cli_head);
713         if (cli_head == cli) {
714                 /*
715                  * head of a DFS list, shutdown all subsidiary DFS
716                  * connections.
717                  */
718                 struct cli_state *p, *next;
719
720                 for (p = cli_head->next; p; p = next) {
721                         next = p->next;
722                         DLIST_REMOVE(cli_head, p);
723                         _cli_shutdown(p);
724                 }
725         } else {
726                 DLIST_REMOVE(cli_head, cli);
727         }
728
729         _cli_shutdown(cli);
730 }
731
732 /****************************************************************************
733  Set socket options on a open connection.
734 ****************************************************************************/
735
736 void cli_sockopt(struct cli_state *cli, const char *options)
737 {
738         set_socket_options(cli->fd, options);
739 }
740
741 /****************************************************************************
742  Set the PID to use for smb messages. Return the old pid.
743 ****************************************************************************/
744
745 uint16 cli_setpid(struct cli_state *cli, uint16 pid)
746 {
747         uint16 ret = cli->pid;
748         cli->pid = pid;
749         return ret;
750 }
751
752 /****************************************************************************
753  Set the case sensitivity flag on the packets. Returns old state.
754 ****************************************************************************/
755
756 bool cli_set_case_sensitive(struct cli_state *cli, bool case_sensitive)
757 {
758         bool ret = cli->case_sensitive;
759         cli->case_sensitive = case_sensitive;
760         return ret;
761 }
762
763 /****************************************************************************
764 Send a keepalive packet to the server
765 ****************************************************************************/
766
767 bool cli_send_keepalive(struct cli_state *cli)
768 {
769         if (cli->fd == -1) {
770                 DEBUG(3, ("cli_send_keepalive: fd == -1\n"));
771                 return false;
772         }
773         if (!send_keepalive(cli->fd)) {
774                 close(cli->fd);
775                 cli->fd = -1;
776                 DEBUG(0,("Error sending keepalive packet to client.\n"));
777                 return false;
778         }
779         return true;
780 }
781
782 struct cli_echo_state {
783         uint16_t vwv[1];
784         DATA_BLOB data;
785         int num_echos;
786 };
787
788 static void cli_echo_done(struct tevent_req *subreq);
789
790 struct tevent_req *cli_echo_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
791                                  struct cli_state *cli, uint16_t num_echos,
792                                  DATA_BLOB data)
793 {
794         struct tevent_req *req, *subreq;
795         struct cli_echo_state *state;
796
797         req = tevent_req_create(mem_ctx, &state, struct cli_echo_state);
798         if (req == NULL) {
799                 return NULL;
800         }
801         SSVAL(state->vwv, 0, num_echos);
802         state->data = data;
803         state->num_echos = num_echos;
804
805         subreq = cli_smb_send(state, ev, cli, SMBecho, 0, 1, state->vwv,
806                               data.length, data.data);
807         if (subreq == NULL) {
808                 goto fail;
809         }
810         tevent_req_set_callback(subreq, cli_echo_done, req);
811         return req;
812  fail:
813         TALLOC_FREE(req);
814         return NULL;
815 }
816
817 static void cli_echo_done(struct tevent_req *subreq)
818 {
819         struct tevent_req *req = tevent_req_callback_data(
820                 subreq, struct tevent_req);
821         struct cli_echo_state *state = tevent_req_data(
822                 req, struct cli_echo_state);
823         NTSTATUS status;
824         uint32_t num_bytes;
825         uint8_t *bytes;
826         uint8_t *inbuf;
827
828         status = cli_smb_recv(subreq, state, &inbuf, 0, NULL, NULL,
829                               &num_bytes, &bytes);
830         if (!NT_STATUS_IS_OK(status)) {
831                 tevent_req_nterror(req, status);
832                 return;
833         }
834         if ((num_bytes != state->data.length)
835             || (memcmp(bytes, state->data.data, num_bytes) != 0)) {
836                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
837                 return;
838         }
839
840         state->num_echos -=1;
841         if (state->num_echos == 0) {
842                 tevent_req_done(req);
843                 return;
844         }
845
846         if (!cli_smb_req_set_pending(subreq)) {
847                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
848                 return;
849         }
850 }
851
852 /**
853  * Get the result out from an echo request
854  * @param[in] req       The async_req from cli_echo_send
855  * @retval Did the server reply correctly?
856  */
857
858 NTSTATUS cli_echo_recv(struct tevent_req *req)
859 {
860         return tevent_req_simple_recv_ntstatus(req);
861 }
862
863 /**
864  * @brief Send/Receive SMBEcho requests
865  * @param[in] mem_ctx   The memory context to put the async_req on
866  * @param[in] ev        The event context that will call us back
867  * @param[in] cli       The connection to send the echo to
868  * @param[in] num_echos How many times do we want to get the reply?
869  * @param[in] data      The data we want to get back
870  * @retval Did the server reply correctly?
871  */
872
873 NTSTATUS cli_echo(struct cli_state *cli, uint16_t num_echos, DATA_BLOB data)
874 {
875         TALLOC_CTX *frame = talloc_stackframe();
876         struct event_context *ev;
877         struct tevent_req *req;
878         NTSTATUS status = NT_STATUS_OK;
879
880         if (cli_has_async_calls(cli)) {
881                 /*
882                  * Can't use sync call while an async call is in flight
883                  */
884                 status = NT_STATUS_INVALID_PARAMETER;
885                 goto fail;
886         }
887
888         ev = event_context_init(frame);
889         if (ev == NULL) {
890                 status = NT_STATUS_NO_MEMORY;
891                 goto fail;
892         }
893
894         req = cli_echo_send(frame, ev, cli, num_echos, data);
895         if (req == NULL) {
896                 status = NT_STATUS_NO_MEMORY;
897                 goto fail;
898         }
899
900         if (!tevent_req_poll(req, ev)) {
901                 status = map_nt_error_from_unix(errno);
902                 goto fail;
903         }
904
905         status = cli_echo_recv(req);
906  fail:
907         TALLOC_FREE(frame);
908         if (!NT_STATUS_IS_OK(status)) {
909                 cli_set_error(cli, status);
910         }
911         return status;
912 }
913
914 /**
915  * Is the SMB command able to hold an AND_X successor
916  * @param[in] cmd       The SMB command in question
917  * @retval Can we add a chained request after "cmd"?
918  */
919 bool is_andx_req(uint8_t cmd)
920 {
921         switch (cmd) {
922         case SMBtconX:
923         case SMBlockingX:
924         case SMBopenX:
925         case SMBreadX:
926         case SMBwriteX:
927         case SMBsesssetupX:
928         case SMBulogoffX:
929         case SMBntcreateX:
930                 return true;
931                 break;
932         default:
933                 break;
934         }
935
936         return false;
937 }
938
939 NTSTATUS cli_smb(TALLOC_CTX *mem_ctx, struct cli_state *cli,
940                  uint8_t smb_command, uint8_t additional_flags,
941                  uint8_t wct, uint16_t *vwv,
942                  uint32_t num_bytes, const uint8_t *bytes,
943                  struct tevent_req **result_parent,
944                  uint8_t min_wct, uint8_t *pwct, uint16_t **pvwv,
945                  uint32_t *pnum_bytes, uint8_t **pbytes)
946 {
947         struct tevent_context *ev;
948         struct tevent_req *req = NULL;
949         NTSTATUS status = NT_STATUS_NO_MEMORY;
950
951         if (cli_has_async_calls(cli)) {
952                 return NT_STATUS_INVALID_PARAMETER;
953         }
954         ev = tevent_context_init(mem_ctx);
955         if (ev == NULL) {
956                 goto fail;
957         }
958         req = cli_smb_send(mem_ctx, ev, cli, smb_command, additional_flags,
959                            wct, vwv, num_bytes, bytes);
960         if (req == NULL) {
961                 goto fail;
962         }
963         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
964                 goto fail;
965         }
966         status = cli_smb_recv(req, NULL, NULL, min_wct, pwct, pvwv,
967                               pnum_bytes, pbytes);
968 fail:
969         TALLOC_FREE(ev);
970         if (NT_STATUS_IS_OK(status)) {
971                 *result_parent = req;
972         }
973         return status;
974 }