fb433c9d73e144f1ec9768617fe6253c62f84471
[libsmb2.git] / lib / libsmb2.c
1 /* -*-  mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil;  -*- */
2 /*
3    Copyright (C) 2016 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
4
5    Portions of this code are copyright 2017 to Primary Data Inc.
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU Lesser General Public License as published by
9    the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
16
17    You should have received a copy of the GNU Lesser General Public License
18    along with this program; if not, see <http://www.gnu.org/licenses/>.
19 */
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #ifndef _GNU_SOURCE
25 #define _GNU_SOURCE
26 #endif
27
28 #ifdef HAVE_STDINT_H
29 #include <stdint.h>
30 #endif
31
32 #ifdef HAVE_STDLIB_H
33 #include <stdlib.h>
34 #endif
35
36 #ifdef HAVE_STRING_H
37 #include <string.h>
38 #endif
39
40 #ifdef STDC_HEADERS
41 #include <stddef.h>
42 #endif
43
44 #ifdef HAVE_SYS_TYPES_H
45 #include <sys/types.h>
46 #endif
47
48 #ifdef HAVE_SYS_STAT_H
49 #include <sys/stat.h>
50 #endif
51
52 #ifdef HAVE_UNISTD_H
53 #include <unistd.h>
54 #endif
55
56 #include <errno.h>
57 #include <fcntl.h>
58 #include <stdio.h>
59 #include <sys/socket.h>
60 #include <time.h>
61
62 #ifdef _WIN32
63 #include "asprintf.h"
64 #endif
65
66 #include "sha.h"
67 #include "sha-private.h"
68
69 #include "slist.h"
70 #include "smb2.h"
71 #include "libsmb2.h"
72 #include "libsmb2-raw.h"
73 #include "libsmb2-private.h"
74 #include "portable-endian.h"
75 #include "ntlmssp.h"
76
77 #ifdef HAVE_LIBKRB5
78 #include "krb5-wrapper.h"
79 #endif
80
81 #ifdef ESP_PLATFORM
82 #define DEFAULT_OUTPUT_BUFFER_LENGTH 512
83 #else
84 #define DEFAULT_OUTPUT_BUFFER_LENGTH 0xffff
85 #endif
86
87 /* strings used to derive SMB signing and encryption keys */
88 static const char SMB2AESCMAC[] = "SMB2AESCMAC";
89 static const char SmbSign[] = "SmbSign";
90 static const char SMB2AESCCM[] = "SMB2AESCCM";
91 static const char ServerOut[] = "ServerOut";
92 static const char ServerIn[] = "ServerIn ";
93 /* The following strings will be used for deriving other keys
94 static const char SMB2APP[] = "SMB2APP";
95 static const char SmbRpc[] = "SmbRpc";
96 static const char SMBSigningKey[] = "SMBSigningKey";
97 static const char SMBAppKey[] = "SMBAppKey";
98 static const char SMBS2CCipherKey[] = "SMBS2CCipherKey";
99 static const char SMBC2SCipherKey[] = "SMBC2SCipherKey";
100 */
101
102 #ifndef O_SYNC
103 #ifndef O_DSYNC
104 #define O_DSYNC         040000
105 #endif // !O_DSYNC
106 #define __O_SYNC        020000000
107 #define O_SYNC          (__O_SYNC|O_DSYNC)
108 #endif // !O_SYNC
109
110 const smb2_file_id compound_file_id = {
111         0xff, 0xff, 0xff, 0xff,  0xff, 0xff, 0xff, 0xff,
112         0xff, 0xff, 0xff, 0xff,  0xff, 0xff, 0xff, 0xff
113 };
114
115 struct connect_data {
116         smb2_command_cb cb;
117         void *cb_data;
118
119         const char *server;
120         const char *share;
121         const char *user;
122
123         /* UNC for the share in utf8 as well as ucs2 formats */
124         char *utf8_unc;
125         struct ucs2 *ucs2_unc;
126
127         void *auth_data;
128 };
129
130 struct smb2_dirent_internal {
131         struct smb2_dirent_internal *next;
132         struct smb2dirent dirent;
133 };
134
135 struct smb2dir {
136         struct smb2dir *next;
137         smb2_command_cb cb;
138         void *cb_data;
139         smb2_file_id file_id;
140
141         struct smb2_dirent_internal *entries;
142         struct smb2_dirent_internal *current_entry;
143         int index;
144 };
145
146 struct smb2fh {
147         struct smb2fh *next;
148         smb2_command_cb cb;
149         void *cb_data;
150
151         smb2_file_id file_id;
152         int64_t offset;
153 };
154
155 static void
156 smb2_close_context(struct smb2_context *smb2)
157 {
158         if (smb2->fd != -1) {
159                 close(smb2->fd);
160                 smb2->fd = -1;
161         }
162         smb2->is_connected = 0;
163         smb2->message_id = 0;
164         smb2->session_id = 0;
165         smb2->tree_id = 0;
166         memset(smb2->signing_key, 0, SMB2_KEY_SIZE);
167         if (smb2->session_key) {
168                 free(smb2->session_key);
169                 smb2->session_key = NULL;
170         }
171         smb2->session_key_size = 0;
172 }
173
174 static int
175 send_session_setup_request(struct smb2_context *smb2,
176                            struct connect_data *c_data,
177                            unsigned char *buf, int len);
178
179 static void
180 free_smb2dir(struct smb2_context *smb2, struct smb2dir *dir)
181 {
182         SMB2_LIST_REMOVE(&smb2->dirs, dir);
183         while (dir->entries) {
184                 struct smb2_dirent_internal *e = dir->entries->next;
185
186                 free(discard_const(dir->entries->dirent.name));
187                 free(dir->entries);
188                 dir->entries = e;
189         }
190         free(dir);
191 }
192
193 void smb2_free_all_dirs(struct smb2_context *smb2)
194 {
195         while (smb2->dirs) {
196                 free_smb2dir(smb2, smb2->dirs);
197         }
198 }
199
200 void
201 smb2_seekdir(struct smb2_context *smb2, struct smb2dir *dir,
202                   long loc)
203 {
204         dir->current_entry = dir->entries;
205         dir->index = 0;
206
207         while (dir->current_entry && loc--) {
208                 dir->current_entry = dir->current_entry->next;
209                 dir->index++;
210         }
211 }
212
213 long
214 smb2_telldir(struct smb2_context *smb2, struct smb2dir *dir)
215 {
216         return dir->index;
217 }
218
219 void
220 smb2_rewinddir(struct smb2_context *smb2,
221                     struct smb2dir *dir)
222 {
223         dir->current_entry = dir->entries;
224         dir->index = 0;
225 }
226
227 struct smb2dirent *
228 smb2_readdir(struct smb2_context *smb2,
229              struct smb2dir *dir)
230 {
231         struct smb2dirent *ent;
232
233         if (dir->current_entry == NULL) {
234                 return NULL;
235         }
236
237         ent = &dir->current_entry->dirent;
238         dir->current_entry = dir->current_entry->next;
239         dir->index++;
240
241         return ent;
242 }
243
244 void
245 smb2_closedir(struct smb2_context *smb2, struct smb2dir *dir)
246 {
247         free_smb2dir(smb2, dir);
248 }
249
250 static int
251 decode_dirents(struct smb2_context *smb2, struct smb2dir *dir,
252                struct smb2_iovec *vec)
253 {
254         struct smb2_dirent_internal *ent;
255         struct smb2_fileidfulldirectoryinformation fs;
256         uint32_t offset = 0;
257
258         do {
259                 struct smb2_iovec tmp_vec;
260
261                 /* Make sure we do not go beyond end of vector */
262                 if (offset >= vec->len) {
263                         smb2_set_error(smb2, "Malformed query reply.");
264                         return -1;
265                 }
266                 
267                 ent = malloc(sizeof(struct smb2_dirent_internal));
268                 if (ent == NULL) {
269                         smb2_set_error(smb2, "Failed to allocate "
270                                        "dirent_internal");
271                         return -1;
272                 }
273                 memset(ent, 0, sizeof(struct smb2_dirent_internal));
274                 SMB2_LIST_ADD(&dir->entries, ent);
275
276
277                 tmp_vec.buf = &vec->buf[offset];
278                 tmp_vec.len = vec->len - offset;
279
280                 smb2_decode_fileidfulldirectoryinformation(smb2, &fs,
281                                                            &tmp_vec);
282                 /* steal the name */
283                 ent->dirent.name = fs.name;
284                 ent->dirent.st.smb2_type = SMB2_TYPE_FILE;
285                 if (fs.file_attributes & SMB2_FILE_ATTRIBUTE_DIRECTORY) {
286                         ent->dirent.st.smb2_type = SMB2_TYPE_DIRECTORY;
287                 }
288                 if (fs.file_attributes & SMB2_FILE_ATTRIBUTE_REPARSE_POINT) {
289                         ent->dirent.st.smb2_type = SMB2_TYPE_LINK;
290                 }
291                 ent->dirent.st.smb2_nlink = 0;
292                 ent->dirent.st.smb2_ino = fs.file_id;
293                 ent->dirent.st.smb2_size = fs.end_of_file;
294                 ent->dirent.st.smb2_atime = fs.last_access_time.tv_sec;
295                 ent->dirent.st.smb2_atime_nsec = fs.last_access_time.tv_usec * 1000;
296                 ent->dirent.st.smb2_mtime = fs.last_write_time.tv_sec;
297                 ent->dirent.st.smb2_mtime_nsec = fs.last_write_time.tv_usec * 1000;
298                 ent->dirent.st.smb2_ctime = fs.change_time.tv_sec;
299                 ent->dirent.st.smb2_ctime_nsec = fs.change_time.tv_usec * 1000;
300                 ent->dirent.st.smb2_btime = fs.creation_time.tv_sec;
301                 ent->dirent.st.smb2_btime_nsec = fs.creation_time.tv_usec * 1000;
302
303                 offset += fs.next_entry_offset;
304         } while (fs.next_entry_offset);
305         
306         return 0;
307 }
308
309 static void
310 od_close_cb(struct smb2_context *smb2, int status,
311          void *command_data, void *private_data)
312 {
313         struct smb2dir *dir = private_data;
314
315         if (status != SMB2_STATUS_SUCCESS) {
316                 dir->cb(smb2, -ENOMEM, NULL, dir->cb_data);
317                 free_smb2dir(smb2, dir);
318                 return;
319         }
320
321         dir->current_entry = dir->entries;
322         dir->index = 0;
323
324         /* dir will be freed in smb2_closedir() */
325         dir->cb(smb2, 0, dir, dir->cb_data);
326 }
327
328 static void
329 query_cb(struct smb2_context *smb2, int status,
330          void *command_data, void *private_data)
331 {
332         struct smb2dir *dir = private_data;
333         struct smb2_query_directory_reply *rep = command_data;
334
335         if (status == SMB2_STATUS_SUCCESS) {
336                 struct smb2_iovec vec;
337                 struct smb2_query_directory_request req;
338                 struct smb2_pdu *pdu;
339
340                 vec.buf = rep->output_buffer;
341                 vec.len = rep->output_buffer_length;
342
343                 if (decode_dirents(smb2, dir, &vec) < 0) {
344                         dir->cb(smb2, -ENOMEM, NULL, dir->cb_data);
345                         free_smb2dir(smb2, dir);
346                         return;
347                 }
348
349                 /* We need to get more data */
350                 memset(&req, 0, sizeof(struct smb2_query_directory_request));
351                 req.file_information_class = SMB2_FILE_ID_FULL_DIRECTORY_INFORMATION;
352                 req.flags = 0;
353                 memcpy(req.file_id, dir->file_id, SMB2_FD_SIZE);
354                 req.output_buffer_length = DEFAULT_OUTPUT_BUFFER_LENGTH;
355                 req.name = "*";
356
357                 pdu = smb2_cmd_query_directory_async(smb2, &req, query_cb, dir);
358                 if (pdu == NULL) {
359                         dir->cb(smb2, -ENOMEM, NULL, dir->cb_data);
360                         free_smb2dir(smb2, dir);
361                         return;
362                 }
363                 smb2_queue_pdu(smb2, pdu);
364
365                 return;
366         }
367
368         if (status == SMB2_STATUS_NO_MORE_FILES) {
369                 struct smb2_close_request req;
370                 struct smb2_pdu *pdu;
371
372                 /* We have all the data */
373                 memset(&req, 0, sizeof(struct smb2_close_request));
374                 req.flags = SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB;
375                 memcpy(req.file_id, dir->file_id, SMB2_FD_SIZE);
376
377                 pdu = smb2_cmd_close_async(smb2, &req, od_close_cb, dir);
378                 if (pdu == NULL) {
379                         dir->cb(smb2, -ENOMEM, NULL, dir->cb_data);
380                         free_smb2dir(smb2, dir);
381                         return;
382                 }
383                 smb2_queue_pdu(smb2, pdu);
384
385                 return;
386         }
387
388         smb2_set_error(smb2, "Query directory failed with (0x%08x) %s. %s",
389                        status, nterror_to_str(status),
390                        smb2_get_error(smb2));
391         dir->cb(smb2, -nterror_to_errno(status), NULL, dir->cb_data);
392         free_smb2dir(smb2, dir);
393 }
394
395 static void
396 opendir_cb(struct smb2_context *smb2, int status,
397            void *command_data, void *private_data)
398 {
399         struct smb2dir *dir = private_data;
400         struct smb2_create_reply *rep = command_data;
401         struct smb2_query_directory_request req;
402         struct smb2_pdu *pdu;
403
404         if (status != SMB2_STATUS_SUCCESS) {
405                 smb2_set_error(smb2, "Opendir failed with (0x%08x) %s.",
406                                status, nterror_to_str(status));
407                 dir->cb(smb2, -nterror_to_errno(status), NULL, dir->cb_data);
408                 free_smb2dir(smb2, dir);
409                 return;
410         }
411
412         memcpy(dir->file_id, rep->file_id, SMB2_FD_SIZE);
413         
414         memset(&req, 0, sizeof(struct smb2_query_directory_request));
415         req.file_information_class = SMB2_FILE_ID_FULL_DIRECTORY_INFORMATION;
416         req.flags = 0;
417         memcpy(req.file_id, dir->file_id, SMB2_FD_SIZE);
418         req.output_buffer_length = DEFAULT_OUTPUT_BUFFER_LENGTH;
419         req.name = "*";
420
421         pdu = smb2_cmd_query_directory_async(smb2, &req, query_cb, dir);
422         if (pdu == NULL) {
423                 smb2_set_error(smb2, "Failed to create query command.");
424                 dir->cb(smb2, -ENOMEM, NULL, dir->cb_data);
425                 free_smb2dir(smb2, dir);
426                 return;
427         }
428         smb2_queue_pdu(smb2, pdu);
429 }
430
431 int
432 smb2_opendir_async(struct smb2_context *smb2, const char *path,
433                    smb2_command_cb cb, void *cb_data)
434 {
435         struct smb2_create_request req;
436         struct smb2dir *dir;
437         struct smb2_pdu *pdu;
438
439         if (path == NULL) {
440                 path = "";
441         }
442
443         dir = malloc(sizeof(struct smb2dir));
444         if (dir == NULL) {
445                 smb2_set_error(smb2, "Failed to allocate smb2dir.");
446                 return -1;
447         }
448         memset(dir, 0, sizeof(struct smb2dir));
449         SMB2_LIST_ADD(&smb2->dirs, dir);
450         dir->cb = cb;
451         dir->cb_data = cb_data;
452
453         memset(&req, 0, sizeof(struct smb2_create_request));
454         req.requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
455         req.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
456         req.desired_access = SMB2_FILE_LIST_DIRECTORY | SMB2_FILE_READ_ATTRIBUTES;
457         req.file_attributes = SMB2_FILE_ATTRIBUTE_DIRECTORY;
458         req.share_access = SMB2_FILE_SHARE_READ | SMB2_FILE_SHARE_WRITE;
459         req.create_disposition = SMB2_FILE_OPEN;
460         req.create_options = SMB2_FILE_DIRECTORY_FILE;
461         req.name = path;
462
463         pdu = smb2_cmd_create_async(smb2, &req, opendir_cb, dir);
464         if (pdu == NULL) {
465                 free_smb2dir(smb2, dir);
466                 smb2_set_error(smb2, "Failed to create opendir command.");
467                 return -1;
468         }
469         smb2_queue_pdu(smb2, pdu);
470         
471         return 0;
472 }
473
474 static void
475 free_c_data(struct smb2_context *smb2, struct connect_data *c_data)
476 {
477         if (c_data->auth_data) {
478                 if (smb2->sec == SMB2_SEC_NTLMSSP) {
479                         ntlmssp_destroy_context(c_data->auth_data);
480                 }
481 #ifdef HAVE_LIBKRB5
482                 else {
483                         krb5_free_auth_data(c_data->auth_data);
484                 }
485 #endif
486         }
487
488         free(c_data->utf8_unc);
489         free(c_data->ucs2_unc);
490         free(discard_const(c_data->server));
491         free(discard_const(c_data->share));
492         free(discard_const(c_data->user));
493         free(c_data);
494 }
495
496
497 static void
498 tree_connect_cb(struct smb2_context *smb2, int status,
499                 void *command_data, void *private_data)
500 {
501         struct connect_data *c_data = private_data;
502
503         if (status != SMB2_STATUS_SUCCESS) {
504                 smb2_close_context(smb2);
505                 smb2_set_error(smb2, "Session setup failed with (0x%08x) %s. %s",
506                                status, nterror_to_str(status),
507                                smb2_get_error(smb2));
508                 c_data->cb(smb2, -nterror_to_errno(status), NULL, c_data->cb_data);
509                 free_c_data(smb2, c_data);
510                 return;
511         }
512
513         c_data->cb(smb2, 0, NULL, c_data->cb_data);
514         free_c_data(smb2, c_data);
515 }
516
517 void smb2_derive_key(
518     uint8_t     *derivation_key,
519     uint32_t    derivation_key_len,
520     const char  *label,
521     uint32_t    label_len,
522     const char  *context,
523     uint32_t    context_len,
524     uint8_t     derived_key[SMB2_KEY_SIZE]
525     )
526 {
527         unsigned char nul = 0;
528         const uint32_t counter = htobe32(1);
529         const uint32_t keylen = htobe32(SMB2_KEY_SIZE * 8);
530         uint8_t input_key[SMB2_KEY_SIZE] = {0};
531         HMACContext ctx;
532         uint8_t digest[USHAMaxHashSize];
533
534         memcpy(input_key, derivation_key, MIN(sizeof(input_key),
535                                               derivation_key_len));
536         hmacReset(&ctx, SHA256, input_key, sizeof(input_key));
537         hmacInput(&ctx, (unsigned char *)&counter, sizeof(counter));
538         hmacInput(&ctx, (unsigned char *)label, label_len);
539         hmacInput(&ctx, &nul, 1);
540         hmacInput(&ctx, (unsigned char *)context, context_len);
541         hmacInput(&ctx, (unsigned char *)&keylen, sizeof(keylen));
542         hmacResult(&ctx, digest);
543         memcpy(derived_key, digest, SMB2_KEY_SIZE);
544 }
545
546 static void
547 session_setup_cb(struct smb2_context *smb2, int status,
548                  void *command_data, void *private_data)
549 {
550         struct connect_data *c_data = private_data;
551         struct smb2_session_setup_reply *rep = command_data;
552         struct smb2_tree_connect_request req;
553         struct smb2_pdu *pdu;
554         int ret;
555
556         if (status == SMB2_STATUS_MORE_PROCESSING_REQUIRED) {
557                 if ((ret = send_session_setup_request(
558                                 smb2, c_data, rep->security_buffer,
559                                 rep->security_buffer_length)) < 0) {
560                         smb2_close_context(smb2);
561                         c_data->cb(smb2, ret, NULL, c_data->cb_data);
562                         free_c_data(smb2, c_data);
563                         return;
564                 }
565                 return;
566 #ifdef HAVE_LIBKRB5
567         } else if (smb2->sec == SMB2_SEC_KRB5) {
568                 /* For NTLM the status will be
569                  * SMB2_STATUS_MORE_PROCESSING_REQUIRED and a second call to
570                  * gss_init_sec_context will complete the gss session.
571                  * But for krb5 a second call to gss_init_sec_context is
572                  * required if GSS_C_MUTUAL_FLAG is set.
573                  *
574                  * Ignore any krb5 errors if the SMB2 layer reported
575                  * success.
576                  */
577                 if (krb5_session_request(smb2, c_data->auth_data,
578                                          rep->security_buffer,
579                                          rep->security_buffer_length) < 0 &&
580                     status != SMB2_STATUS_SUCCESS) {
581                         c_data->cb(smb2, -1, NULL, c_data->cb_data);
582                         free_c_data(smb2, c_data);
583                         return;
584                 }
585 #endif
586         }
587
588         if (status != SMB2_STATUS_SUCCESS) {
589                 smb2_close_context(smb2);
590                 smb2_set_error(smb2, "Session setup failed with (0x%08x) %s",
591                                status, nterror_to_str(status));
592                 c_data->cb(smb2, -nterror_to_errno(status), NULL,
593                            c_data->cb_data);
594                 free_c_data(smb2, c_data);
595                 return;
596         }
597
598         if (smb2->sign || smb2->seal) {
599                 uint8_t zero_key[SMB2_KEY_SIZE] = {0};
600                 int have_valid_session_key = 1;
601
602                 if (smb2->sec == SMB2_SEC_NTLMSSP) {
603                         if (ntlmssp_get_session_key(c_data->auth_data,
604                                                     &smb2->session_key,
605                                                     &smb2->session_key_size) < 0) {
606                                 have_valid_session_key = 0;
607                         }
608                 }
609 #ifdef HAVE_LIBKRB5
610                 else {
611                         if (krb5_session_get_session_key(smb2, c_data->auth_data) < 0) {
612                                 have_valid_session_key = 0;
613                         }
614                 }
615 #endif
616                 /* check if the session key is proper */
617                 if (smb2->session_key == NULL || memcmp(smb2->session_key, zero_key, SMB2_KEY_SIZE) == 0) {
618                         have_valid_session_key = 0;
619                 }
620                 if (have_valid_session_key == 0) {
621                         smb2_close_context(smb2);
622                         smb2_set_error(smb2, "Signing required by server. Session "
623                                        "Key is not available %s",
624                                        smb2_get_error(smb2));
625                         c_data->cb(smb2, -1, NULL, c_data->cb_data);
626                         free_c_data(smb2, c_data);
627                         return;
628                 }
629
630                 /* Derive the signing key from session key
631                  * This is based on negotiated protocol
632                  */
633                 if (smb2->dialect == SMB2_VERSION_0202 ||
634                     smb2->dialect == SMB2_VERSION_0210) {
635                         /* For SMB2 session key is the signing key */
636                         memcpy(smb2->signing_key,
637                                smb2->session_key,
638                                MIN(smb2->session_key_size, SMB2_KEY_SIZE));
639                 } else if (smb2->dialect <= SMB2_VERSION_0302) {
640                         smb2_derive_key(smb2->session_key,
641                                         smb2->session_key_size,
642                                         SMB2AESCMAC,
643                                         sizeof(SMB2AESCMAC),
644                                         SmbSign,
645                                         sizeof(SmbSign),
646                                         smb2->signing_key);
647                         smb2_derive_key(smb2->session_key,
648                                         smb2->session_key_size,
649                                         SMB2AESCCM,
650                                         sizeof(SMB2AESCCM),
651                                         ServerIn,
652                                         sizeof(ServerIn),
653                                         smb2->serverin_key);
654                         smb2_derive_key(smb2->session_key,
655                                         smb2->session_key_size,
656                                         SMB2AESCCM,
657                                         sizeof(SMB2AESCCM),
658                                         ServerOut,
659                                         sizeof(ServerOut),
660                                         smb2->serverout_key);
661                 } else if (smb2->dialect > SMB2_VERSION_0302) {
662                         smb2_close_context(smb2);
663                         smb2_set_error(smb2, "Signing/Encryption Required. "
664                                              "Not yet implemented for SMB3.1");
665                         c_data->cb(smb2, -EINVAL, NULL, c_data->cb_data);
666                         free_c_data(smb2, c_data);
667                         return;
668                 }
669         }
670
671         memset(&req, 0, sizeof(struct smb2_tree_connect_request));
672         req.flags       = 0;
673         req.path_length = 2 * c_data->ucs2_unc->len;
674         req.path        = c_data->ucs2_unc->val;
675
676         pdu = smb2_cmd_tree_connect_async(smb2, &req, tree_connect_cb, c_data);
677         if (pdu == NULL) {
678                 smb2_close_context(smb2);
679                 c_data->cb(smb2, -ENOMEM, NULL, c_data->cb_data);
680                 free_c_data(smb2, c_data);
681                 return;
682         }
683         smb2_queue_pdu(smb2, pdu);
684 }
685
686 /* Returns 0 for success and -errno for failure */
687 static int
688 send_session_setup_request(struct smb2_context *smb2,
689                            struct connect_data *c_data,
690                            unsigned char *buf, int len)
691 {
692         struct smb2_pdu *pdu;
693         struct smb2_session_setup_request req;
694
695         /* Session setup request. */
696         memset(&req, 0, sizeof(struct smb2_session_setup_request));
697         req.security_mode = smb2->security_mode;
698
699         if (smb2->sec == SMB2_SEC_NTLMSSP) {
700                 if (ntlmssp_generate_blob(smb2, time(NULL), c_data->auth_data,
701                                           buf, len,
702                                           &req.security_buffer,
703                                           &req.security_buffer_length) < 0) {
704                         smb2_close_context(smb2);
705                         return -1;
706                 }
707         }
708 #ifdef HAVE_LIBKRB5
709         else {
710                 if (krb5_session_request(smb2, c_data->auth_data,
711                                          buf, len) < 0) {
712                         smb2_close_context(smb2);
713                         return -1;
714                 }
715                 req.security_buffer_length =
716                         krb5_get_output_token_length(c_data->auth_data);
717                 req.security_buffer =
718                         krb5_get_output_token_buffer(c_data->auth_data);
719         }
720 #endif
721
722         pdu = smb2_cmd_session_setup_async(smb2, &req,
723                                            session_setup_cb, c_data);
724         if (pdu == NULL) {
725                 smb2_close_context(smb2);
726                 return -ENOMEM;
727         }
728         smb2_queue_pdu(smb2, pdu);
729
730         return 0;
731 }
732
733 static void
734 negotiate_cb(struct smb2_context *smb2, int status,
735              void *command_data, void *private_data)
736 {
737         struct connect_data *c_data = private_data;
738         struct smb2_negotiate_reply *rep = command_data;
739         int ret;
740
741         if (status != SMB2_STATUS_SUCCESS) {
742                 smb2_close_context(smb2);
743                 smb2_set_error(smb2, "Negotiate failed with (0x%08x) %s. %s",
744                                status, nterror_to_str(status),
745                                smb2_get_error(smb2));
746                 c_data->cb(smb2, -nterror_to_errno(status), NULL,
747                            c_data->cb_data);
748                 free_c_data(smb2, c_data);
749                 return;
750         }
751
752         /* update the context with the server capabilities */
753         if (rep->dialect_revision > SMB2_VERSION_0202) {
754                 if (rep->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU) {
755                         smb2->supports_multi_credit = 1;
756                 }
757         }
758
759         smb2->max_transact_size = rep->max_transact_size;
760         smb2->max_read_size     = rep->max_read_size;
761         smb2->max_write_size    = rep->max_write_size;
762         smb2->dialect           = rep->dialect_revision;
763
764         if (smb2->seal && (smb2->dialect == SMB2_VERSION_0300 ||
765                            smb2->dialect == SMB2_VERSION_0302)) {
766                 if(!(rep->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION)) {
767                         smb2_set_error(smb2, "Encryption requested but server "
768                                        "does not support encryption.");
769                         smb2_close_context(smb2);
770                         c_data->cb(smb2, -ENOMEM, NULL, c_data->cb_data);
771                         free_c_data(smb2, c_data);
772                         return;
773                 }
774         }
775
776         if (rep->security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) {
777                 smb2->sign = 1;
778         }
779
780         if (smb2->seal) {
781                 smb2->sign = 0;
782         }
783
784         if (smb2->sec == SMB2_SEC_NTLMSSP) {
785                 c_data->auth_data = ntlmssp_init_context(smb2->user,
786                                                          smb2->password,
787                                                          smb2->domain,
788                                                          smb2->workstation,
789                                                          smb2->client_challenge);
790         }
791 #ifdef HAVE_LIBKRB5
792         else {
793                 c_data->auth_data = krb5_negotiate_reply(smb2,
794                                                          c_data->server,
795                                                          smb2->domain,
796                                                          c_data->user,
797                                                          smb2->password);
798         }
799 #endif
800         if (c_data->auth_data == NULL) {
801                 smb2_close_context(smb2);
802                 c_data->cb(smb2, -ENOMEM, NULL, c_data->cb_data);
803                 free_c_data(smb2, c_data);
804                 return;
805         }
806
807         if ((ret = send_session_setup_request(smb2, c_data, NULL, 0)) < 0) {
808                 smb2_close_context(smb2);
809                 c_data->cb(smb2, ret, NULL, c_data->cb_data);
810                 free_c_data(smb2, c_data);
811                 return;
812         }
813 }
814
815 static void
816 connect_cb(struct smb2_context *smb2, int status,
817            void *command_data _U_, void *private_data)
818 {
819         struct connect_data *c_data = private_data;
820         struct smb2_negotiate_request req;
821         struct smb2_pdu *pdu;
822
823         if (status != 0) {
824                 smb2_set_error(smb2, "Socket connect failed with %d",
825                                status);
826                 c_data->cb(smb2, -status, NULL, c_data->cb_data);
827                 free_c_data(smb2, c_data);
828                 return;
829         }
830
831         memset(&req, 0, sizeof(struct smb2_negotiate_request));
832         req.capabilities = SMB2_GLOBAL_CAP_LARGE_MTU;
833         if (smb2->seal && (smb2->version == SMB2_VERSION_ANY3 ||
834                            smb2->version == SMB2_VERSION_0300 ||
835                            smb2->version == SMB2_VERSION_0302)) {
836                 req.capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION;
837         }
838         req.security_mode = smb2->security_mode;
839         switch (smb2->version) {
840         case SMB2_VERSION_ANY:
841                 req.dialect_count = 4;
842                 req.dialects[0] = SMB2_VERSION_0202;
843                 req.dialects[1] = SMB2_VERSION_0210;
844                 req.dialects[2] = SMB2_VERSION_0300;
845                 req.dialects[3] = SMB2_VERSION_0302;
846                 break;
847         case SMB2_VERSION_ANY2:
848                 req.dialect_count = 2;
849                 req.dialects[0] = SMB2_VERSION_0202;
850                 req.dialects[1] = SMB2_VERSION_0210;
851                 break;
852         case SMB2_VERSION_ANY3:
853                 req.dialect_count = 2;
854                 req.dialects[0] = SMB2_VERSION_0300;
855                 req.dialects[1] = SMB2_VERSION_0302;
856                 break;
857         case SMB2_VERSION_0202:
858         case SMB2_VERSION_0210:
859         case SMB2_VERSION_0300:
860         case SMB2_VERSION_0302:
861                 req.dialect_count = 1;
862                 req.dialects[0] = smb2->version;
863                 break;
864         }
865
866         memcpy(req.client_guid, smb2_get_client_guid(smb2), SMB2_GUID_SIZE);
867
868         if (smb2->sec == SMB2_SEC_UNDEFINED) {
869 #ifdef HAVE_LIBKRB5
870                 smb2->sec = SMB2_SEC_KRB5;
871 #else
872                 smb2->sec = SMB2_SEC_NTLMSSP;
873 #endif
874         }
875         pdu = smb2_cmd_negotiate_async(smb2, &req, negotiate_cb, c_data);
876         if (pdu == NULL) {
877                 c_data->cb(smb2, -ENOMEM, NULL, c_data->cb_data);
878                 free_c_data(smb2, c_data);
879                 return;
880         }
881         smb2_queue_pdu(smb2, pdu);
882 }
883
884 int
885 smb2_connect_share_async(struct smb2_context *smb2,
886                          const char *server,
887                          const char *share, const char *user,
888                          smb2_command_cb cb, void *cb_data)
889 {
890         struct connect_data *c_data;
891         int err;
892
893         if (smb2->server) {
894                 free(discard_const(smb2->server));
895                 smb2->server = NULL;
896         }
897         if (!server) {
898                 smb2_set_error(smb2, "No server name provided");
899                 return -EINVAL;
900         }
901         smb2->server = strdup(server);
902
903         if (smb2->share) {
904                 free(discard_const(smb2->share));
905         }
906         smb2->share = strdup(share);
907
908         if (user) {
909                 smb2_set_user(smb2, user);
910         }
911
912         c_data = malloc(sizeof(struct connect_data));
913         if (c_data == NULL) {
914                 smb2_set_error(smb2, "Failed to allocate connect_data");
915                 return -ENOMEM;
916         }
917         memset(c_data, 0, sizeof(struct connect_data));
918         c_data->server = strdup(smb2->server);
919         if (c_data->server == NULL) {
920                 free_c_data(smb2, c_data);
921                 smb2_set_error(smb2, "Failed to strdup(server)");
922                 return -ENOMEM;
923         }
924         c_data->share = strdup(smb2->share);
925         if (c_data->share == NULL) {
926                 free_c_data(smb2, c_data);
927                 smb2_set_error(smb2, "Failed to strdup(share)");
928                 return -ENOMEM;
929         }
930         c_data->user = strdup(smb2->user);
931         if (c_data->user == NULL) {
932                 free_c_data(smb2, c_data);
933                 smb2_set_error(smb2, "Failed to strdup(user)");
934                 return -ENOMEM;
935         }
936         if (asprintf(&c_data->utf8_unc, "\\\\%s\\%s", c_data->server,
937                      c_data->share) < 0) {
938                 free_c_data(smb2, c_data);
939                 smb2_set_error(smb2, "Failed to allocate unc string.");
940                 return -ENOMEM;
941         }
942
943         c_data->ucs2_unc = utf8_to_ucs2(c_data->utf8_unc);
944         if (c_data->ucs2_unc == NULL) {
945                 free_c_data(smb2, c_data);
946                 smb2_set_error(smb2, "Count not convert UNC:[%s] into UCS2",
947                                c_data->utf8_unc);
948                 return -ENOMEM;
949         }
950
951         c_data->cb = cb;
952         c_data->cb_data = cb_data;
953
954         err = smb2_connect_async(smb2, server, connect_cb, c_data);
955         if (err != 0) {
956                 free_c_data(smb2, c_data);
957                 return err;
958         }
959
960         return 0;
961 }
962
963 static void
964 free_smb2fh(struct smb2_context *smb2, struct smb2fh *fh)
965 {
966         SMB2_LIST_REMOVE(&smb2->fhs, fh);
967         free(fh);
968 }
969
970 void smb2_free_all_fhs(struct smb2_context *smb2)
971 {
972         while (smb2->fhs) {
973                 free_smb2fh(smb2, smb2->fhs);
974         }
975 }
976
977 static void
978 open_cb(struct smb2_context *smb2, int status,
979         void *command_data, void *private_data)
980 {
981         struct smb2fh *fh = private_data;
982         struct smb2_create_reply *rep = command_data;
983
984         if (status != SMB2_STATUS_SUCCESS) {
985                 smb2_set_error(smb2, "Open failed with (0x%08x) %s.",
986                                status, nterror_to_str(status));
987                 fh->cb(smb2, -nterror_to_errno(status), NULL, fh->cb_data);
988                 free_smb2fh(smb2, fh);
989                 return;
990         }
991
992         memcpy(fh->file_id, rep->file_id, SMB2_FD_SIZE);
993         fh->cb(smb2, 0, fh, fh->cb_data);
994 }
995
996 int
997 smb2_open_async(struct smb2_context *smb2, const char *path, int flags,
998                 smb2_command_cb cb, void *cb_data)
999 {
1000         struct smb2fh *fh;
1001         struct smb2_create_request req;
1002         struct smb2_pdu *pdu;
1003         uint32_t desired_access = 0;
1004         uint32_t create_disposition = 0;
1005         uint32_t create_options = 0;
1006         uint32_t file_attributes = 0;
1007
1008         fh = malloc(sizeof(struct smb2fh));
1009         if (fh == NULL) {
1010                 smb2_set_error(smb2, "Failed to allocate smbfh");
1011                 return -ENOMEM;
1012         }
1013         memset(fh, 0, sizeof(struct smb2fh));
1014         SMB2_LIST_ADD(&smb2->fhs, fh);
1015
1016         fh->cb = cb;
1017         fh->cb_data = cb_data;
1018
1019         /* Create disposition */
1020         if (flags & O_CREAT) {
1021                 if (flags & O_EXCL) {
1022                         create_disposition = SMB2_FILE_CREATE;
1023                 } else if(flags & O_TRUNC) {
1024                         create_disposition = SMB2_FILE_OVERWRITE_IF;
1025                 } else {
1026                         create_disposition = SMB2_FILE_OPEN_IF;
1027                 }
1028         } else {
1029                 if (flags & O_TRUNC) {
1030                         create_disposition = SMB2_FILE_OVERWRITE;
1031                 } else {
1032                         create_disposition = SMB2_FILE_OPEN;
1033                 }
1034         }
1035
1036         /* desired access */
1037         if (flags & (O_RDWR | O_WRONLY)) {
1038                 desired_access |= SMB2_FILE_WRITE_DATA |
1039                         SMB2_FILE_WRITE_EA |
1040                         SMB2_FILE_WRITE_ATTRIBUTES;
1041         }
1042         if (flags & O_RDWR || !(flags & O_WRONLY)) {
1043                 desired_access |= SMB2_FILE_READ_DATA |
1044                         SMB2_FILE_READ_EA |
1045                         SMB2_FILE_READ_ATTRIBUTES;
1046         }
1047
1048         /* create options */
1049         create_options |= SMB2_FILE_NON_DIRECTORY_FILE;
1050
1051
1052         if (flags & O_SYNC) {
1053                 desired_access |= SMB2_SYNCHRONIZE;
1054                 create_options |= SMB2_FILE_NO_INTERMEDIATE_BUFFERING;
1055         }
1056
1057         memset(&req, 0, sizeof(struct smb2_create_request));
1058         req.requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
1059         req.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
1060         req.desired_access = desired_access;
1061         req.file_attributes = file_attributes;
1062         req.share_access = SMB2_FILE_SHARE_READ | SMB2_FILE_SHARE_WRITE;
1063         req.create_disposition = create_disposition;
1064         req.create_options = create_options;
1065         req.name = path;
1066
1067         pdu = smb2_cmd_create_async(smb2, &req, open_cb, fh);
1068         if (pdu == NULL) {
1069                 smb2_set_error(smb2, "Failed to create create command");
1070                 free_smb2fh(smb2, fh);
1071                 return -ENOMEM;
1072         }
1073         smb2_queue_pdu(smb2, pdu);
1074
1075         return 0;
1076 }
1077
1078 static void
1079 close_cb(struct smb2_context *smb2, int status,
1080          void *command_data, void *private_data)
1081 {
1082         struct smb2fh *fh = private_data;
1083
1084         if (status != SMB2_STATUS_SUCCESS) {
1085                 smb2_set_error(smb2, "Close failed with (0x%08x) %s",
1086                                status, nterror_to_str(status));
1087                 fh->cb(smb2, -nterror_to_errno(status), NULL, fh->cb_data);
1088                 free_smb2fh(smb2, fh);
1089                 return;
1090         }
1091
1092         fh->cb(smb2, 0, NULL, fh->cb_data);
1093         free_smb2fh(smb2, fh);
1094 }
1095         
1096 int
1097 smb2_close_async(struct smb2_context *smb2, struct smb2fh *fh,
1098                  smb2_command_cb cb, void *cb_data)
1099 {
1100         struct smb2_close_request req;
1101         struct smb2_pdu *pdu;
1102
1103         fh->cb = cb;
1104         fh->cb_data = cb_data;
1105
1106         memset(&req, 0, sizeof(struct smb2_close_request));
1107         req.flags = SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB;
1108         memcpy(req.file_id, fh->file_id, SMB2_FD_SIZE);
1109
1110         pdu = smb2_cmd_close_async(smb2, &req, close_cb, fh);
1111         if (pdu == NULL) {
1112                 smb2_set_error(smb2, "Failed to create close command");
1113                 return -ENOMEM;
1114         }
1115         smb2_queue_pdu(smb2, pdu);
1116
1117         return 0;
1118 }
1119
1120 static void
1121 fsync_cb(struct smb2_context *smb2, int status,
1122          void *command_data, void *private_data)
1123 {
1124         struct smb2fh *fh = private_data;
1125
1126         if (status != SMB2_STATUS_SUCCESS) {
1127                 smb2_set_error(smb2, "Flush failed with (0x%08x) %s",
1128                                status, nterror_to_str(status));
1129                 fh->cb(smb2, -nterror_to_errno(status), NULL, fh->cb_data);
1130                 return;
1131         }
1132
1133         fh->cb(smb2, 0, NULL, fh->cb_data);
1134 }
1135
1136 int
1137 smb2_fsync_async(struct smb2_context *smb2, struct smb2fh *fh,
1138                  smb2_command_cb cb, void *cb_data)
1139 {
1140         struct smb2_flush_request req;
1141         struct smb2_pdu *pdu;
1142
1143         fh->cb = cb;
1144         fh->cb_data = cb_data;
1145
1146         memset(&req, 0, sizeof(struct smb2_flush_request));
1147         memcpy(req.file_id, fh->file_id, SMB2_FD_SIZE);
1148
1149         pdu = smb2_cmd_flush_async(smb2, &req, fsync_cb, fh);
1150         if (pdu == NULL) {
1151                 smb2_set_error(smb2, "Failed to create flush command");
1152                 return -ENOMEM;
1153         }
1154         smb2_queue_pdu(smb2, pdu);
1155
1156         return 0;
1157 }
1158
1159 struct rw_data {
1160         smb2_command_cb cb;
1161         void *cb_data;
1162
1163         struct smb2fh *fh;
1164         uint64_t offset;
1165 };
1166
1167 static void
1168 read_cb(struct smb2_context *smb2, int status,
1169       void *command_data, void *private_data)
1170 {
1171         struct rw_data *rd = private_data;
1172         struct smb2_read_reply *rep = command_data;
1173
1174         if (status && status != SMB2_STATUS_END_OF_FILE) {
1175                 smb2_set_error(smb2, "Read/Write failed with (0x%08x) %s",
1176                                status, nterror_to_str(status));
1177                 rd->cb(smb2, -nterror_to_errno(status), NULL, rd->cb_data);
1178                 free(rd);
1179                 return;
1180         }
1181
1182         if (status == SMB2_STATUS_SUCCESS) {
1183                 rd->fh->offset = rd->offset + rep->data_length;
1184         }
1185
1186         rd->cb(smb2, rep->data_length, NULL, rd->cb_data);
1187         free(rd);
1188 }
1189
1190 int
1191 smb2_pread_async(struct smb2_context *smb2, struct smb2fh *fh,
1192                  uint8_t *buf, uint32_t count, uint64_t offset,
1193                  smb2_command_cb cb, void *cb_data)
1194 {
1195         struct smb2_read_request req;
1196         struct rw_data *rd;
1197         struct smb2_pdu *pdu;
1198         int needed_credits = (count - 1) / 65536 + 1;
1199
1200         if (count > smb2->max_read_size) {
1201                 count = smb2->max_read_size;
1202         }
1203         if (smb2->dialect > SMB2_VERSION_0202) {
1204                 if (needed_credits > MAX_CREDITS - 16) {
1205                         count =  (MAX_CREDITS - 16) * 65536;
1206                 }
1207                 needed_credits = (count - 1) / 65536 + 1;
1208                 if (needed_credits > smb2->credits) {
1209                         count = smb2->credits * 65536;
1210                 }
1211         } else {
1212                 if (count > 65536) {
1213                         count = 65536;
1214                 }
1215         }
1216
1217         rd = malloc(sizeof(struct rw_data));
1218         if (rd == NULL) {
1219                 smb2_set_error(smb2, "Failed to allocate rw_data");
1220                 return -ENOMEM;
1221         }
1222         memset(rd, 0, sizeof(struct rw_data));
1223                 
1224         rd->cb = cb;
1225         rd->cb_data = cb_data;
1226         rd->fh = fh;
1227         rd->offset = offset;
1228
1229         memset(&req, 0, sizeof(struct smb2_read_request));
1230         req.flags = 0;
1231         req.length = count;
1232         req.offset = offset;
1233         req.buf = buf;
1234         memcpy(req.file_id, fh->file_id, SMB2_FD_SIZE);
1235         req.minimum_count = 0;
1236         req.channel = SMB2_CHANNEL_NONE;
1237         req.remaining_bytes = 0;
1238
1239         pdu = smb2_cmd_read_async(smb2, &req, read_cb, rd);
1240         if (pdu == NULL) {
1241                 smb2_set_error(smb2, "Failed to create read command");
1242                 return -1;
1243         }
1244
1245         smb2_queue_pdu(smb2, pdu);
1246
1247         return 0;
1248 }        
1249
1250 int
1251 smb2_read_async(struct smb2_context *smb2, struct smb2fh *fh,
1252                 uint8_t *buf, uint32_t count,
1253                 smb2_command_cb cb, void *cb_data)
1254 {
1255         return smb2_pread_async(smb2, fh, buf, count, fh->offset,
1256                                 cb, cb_data);
1257 }
1258
1259 static void
1260 write_cb(struct smb2_context *smb2, int status,
1261       void *command_data, void *private_data)
1262 {
1263         struct rw_data *rd = private_data;
1264         struct smb2_write_reply *rep = command_data;
1265
1266         if (status && status != SMB2_STATUS_END_OF_FILE) {
1267                 smb2_set_error(smb2, "Read/Write failed with (0x%08x) %s",
1268                                status, nterror_to_str(status));
1269                 rd->cb(smb2, -nterror_to_errno(status), NULL, rd->cb_data);
1270                 free(rd);
1271                 return;
1272         }
1273
1274         if (status == SMB2_STATUS_SUCCESS) {
1275                 rd->fh->offset = rd->offset + rep->count;
1276         }
1277
1278         rd->cb(smb2, rep->count, NULL, rd->cb_data);
1279         free(rd);
1280 }
1281
1282 int
1283 smb2_pwrite_async(struct smb2_context *smb2, struct smb2fh *fh,
1284                   uint8_t *buf, uint32_t count, uint64_t offset,
1285                   smb2_command_cb cb, void *cb_data)
1286 {
1287         struct smb2_write_request req;
1288         struct rw_data *rd;
1289         struct smb2_pdu *pdu;
1290         int needed_credits = (count - 1) / 65536 + 1;
1291
1292         if (count > smb2->max_write_size) {
1293                 count = smb2->max_write_size;
1294         }
1295         if (smb2->dialect > SMB2_VERSION_0202) {
1296                 if (needed_credits > MAX_CREDITS - 16) {
1297                         count =  (MAX_CREDITS - 16) * 65536;
1298                 }
1299                 needed_credits = (count - 1) / 65536 + 1;
1300                 if (needed_credits > smb2->credits) {
1301                         count = smb2->credits * 65536;
1302                 }
1303         } else {
1304                 if (count > 65536) {
1305                         count = 65536;
1306                 }
1307         }
1308
1309         rd = malloc(sizeof(struct rw_data));
1310         if (rd == NULL) {
1311                 smb2_set_error(smb2, "Failed to allocate rw_data");
1312                 return -ENOMEM;
1313         }
1314         memset(rd, 0, sizeof(struct rw_data));
1315                 
1316         rd->cb = cb;
1317         rd->cb_data = cb_data;
1318         rd->fh = fh;
1319         rd->offset = offset;
1320
1321         memset(&req, 0, sizeof(struct smb2_write_request));
1322         req.length = count;
1323         req.offset = offset;
1324         req.buf = buf;
1325         memcpy(req.file_id, fh->file_id, SMB2_FD_SIZE);
1326         req.channel = SMB2_CHANNEL_NONE;
1327         req.remaining_bytes = 0;
1328         req.flags = 0;
1329
1330         pdu = smb2_cmd_write_async(smb2, &req, write_cb, rd);
1331         if (pdu == NULL) {
1332                 smb2_set_error(smb2, "Failed to create write command");
1333                 return -ENOMEM;
1334         }
1335         smb2_queue_pdu(smb2, pdu);
1336
1337         return 0;
1338 }        
1339
1340 int
1341 smb2_write_async(struct smb2_context *smb2, struct smb2fh *fh,
1342                  uint8_t *buf, uint32_t count,
1343                  smb2_command_cb cb, void *cb_data)
1344 {
1345         return smb2_pwrite_async(smb2, fh, buf, count, fh->offset,
1346                                  cb, cb_data);
1347 }
1348
1349 int64_t
1350 smb2_lseek(struct smb2_context *smb2, struct smb2fh *fh,
1351            int64_t offset, int whence, uint64_t *current_offset)
1352 {
1353         switch(whence) {
1354         case SEEK_SET:
1355                 if (offset < 0) {
1356                         smb2_set_error(smb2, "Lseek() offset would become"
1357                                        "negative");
1358                         return -EINVAL;
1359                 }
1360                 fh->offset = offset;
1361                 if (current_offset) {
1362                         *current_offset = fh->offset;
1363                 }
1364                 return fh->offset;
1365         case SEEK_CUR:
1366                 if (fh->offset + offset < 0) {
1367                         smb2_set_error(smb2, "Lseek() offset would become"
1368                                        "negative");
1369                         return -EINVAL;
1370                 }
1371                 fh->offset += offset;
1372                 if (current_offset) {
1373                         *current_offset = fh->offset;
1374                 }
1375                 return fh->offset;
1376         case SEEK_END:
1377                 smb2_set_error(smb2, "SEEK_END not implemented");
1378                 return -EINVAL;
1379         default:
1380                 smb2_set_error(smb2, "Invalid whence(%d) for lseek",
1381                                whence);
1382                 return -EINVAL;
1383         }
1384 }
1385
1386 struct create_cb_data {
1387         smb2_command_cb cb;
1388         void *cb_data;
1389 };
1390
1391 static void
1392 create_cb_2(struct smb2_context *smb2, int status,
1393             void *command_data, void *private_data)
1394 {
1395         struct create_cb_data *create_data = private_data;
1396
1397         if (status != SMB2_STATUS_SUCCESS) {
1398                 create_data->cb(smb2, -nterror_to_errno(status),
1399                        NULL, create_data->cb_data);
1400                 free(create_data);
1401                 return;
1402         }
1403
1404         create_data->cb(smb2, 0, NULL, create_data->cb_data);
1405         free(create_data);
1406 }
1407
1408 static void
1409 create_cb_1(struct smb2_context *smb2, int status,
1410             void *command_data, void *private_data)
1411 {
1412         struct create_cb_data *create_data = private_data;
1413         struct smb2_create_reply *rep = command_data;
1414         struct smb2_close_request req;
1415         struct smb2_pdu *pdu;
1416
1417         if (status != SMB2_STATUS_SUCCESS) {
1418                 create_data->cb(smb2, -nterror_to_errno(status),
1419                        NULL, create_data->cb_data);
1420                 free(create_data);
1421                 return;
1422         }
1423
1424         memset(&req, 0, sizeof(struct smb2_close_request));
1425         req.flags = SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB;
1426         memcpy(req.file_id, rep->file_id, SMB2_FD_SIZE);
1427
1428         pdu = smb2_cmd_close_async(smb2, &req, create_cb_2, create_data);
1429         if (pdu == NULL) {
1430                 create_data->cb(smb2, -ENOMEM, NULL, create_data->cb_data);
1431                 free(create_data);
1432                 return;
1433         }
1434         smb2_queue_pdu(smb2, pdu);
1435 }
1436
1437 static int
1438 smb2_unlink_internal(struct smb2_context *smb2, const char *path,
1439                      int is_dir,
1440                      smb2_command_cb cb, void *cb_data)
1441 {
1442         struct create_cb_data *create_data;
1443         struct smb2_create_request req;
1444         struct smb2_pdu *pdu;
1445
1446         create_data = malloc(sizeof(struct create_cb_data));
1447         if (create_data == NULL) {
1448                 smb2_set_error(smb2, "Failed to allocate create_data");
1449                 return -ENOMEM;
1450         }
1451         memset(create_data, 0, sizeof(struct create_cb_data));
1452
1453         create_data->cb = cb;
1454         create_data->cb_data = cb_data;
1455
1456
1457         memset(&req, 0, sizeof(struct smb2_create_request));
1458         req.requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
1459         req.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
1460         req.desired_access = SMB2_DELETE;
1461         if (is_dir) {
1462                 req.file_attributes = SMB2_FILE_ATTRIBUTE_DIRECTORY;
1463         } else {
1464                 req.file_attributes = SMB2_FILE_ATTRIBUTE_NORMAL;
1465         }
1466         req.share_access = SMB2_FILE_SHARE_READ | SMB2_FILE_SHARE_WRITE |
1467                 SMB2_FILE_SHARE_DELETE;
1468         req.create_disposition = SMB2_FILE_OPEN;
1469         req.create_options = SMB2_FILE_DELETE_ON_CLOSE;
1470         req.name = path;
1471
1472         pdu = smb2_cmd_create_async(smb2, &req, create_cb_1, create_data);
1473         if (pdu == NULL) {
1474                 smb2_set_error(smb2, "Failed to create create command");
1475                 return -ENOMEM;
1476         }
1477         smb2_queue_pdu(smb2, pdu);
1478
1479         return 0;
1480 }
1481
1482 int
1483 smb2_unlink_async(struct smb2_context *smb2, const char *path,
1484                   smb2_command_cb cb, void *cb_data)
1485 {
1486         return smb2_unlink_internal(smb2, path, 0, cb, cb_data);
1487 }
1488
1489 int
1490 smb2_rmdir_async(struct smb2_context *smb2, const char *path,
1491                  smb2_command_cb cb, void *cb_data)
1492 {
1493         return smb2_unlink_internal(smb2, path, 1, cb, cb_data);
1494 }
1495
1496 int
1497 smb2_mkdir_async(struct smb2_context *smb2, const char *path,
1498                  smb2_command_cb cb, void *cb_data)
1499 {
1500         struct create_cb_data *create_data;
1501         struct smb2_create_request req;
1502         struct smb2_pdu *pdu;
1503
1504         create_data = malloc(sizeof(struct create_cb_data));
1505         if (create_data == NULL) {
1506                 smb2_set_error(smb2, "Failed to allocate create_data");
1507                 return -ENOMEM;
1508         }
1509         memset(create_data, 0, sizeof(struct create_cb_data));
1510
1511         create_data->cb = cb;
1512         create_data->cb_data = cb_data;
1513
1514         memset(&req, 0, sizeof(struct smb2_create_request));
1515         req.requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
1516         req.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
1517         req.desired_access = SMB2_FILE_READ_ATTRIBUTES;
1518         req.file_attributes = SMB2_FILE_ATTRIBUTE_DIRECTORY;
1519         req.share_access = SMB2_FILE_SHARE_READ | SMB2_FILE_SHARE_WRITE;
1520         req.create_disposition = SMB2_FILE_CREATE;
1521         req.create_options = SMB2_FILE_DIRECTORY_FILE;
1522         req.name = path;
1523
1524         pdu = smb2_cmd_create_async(smb2, &req, create_cb_1, create_data);
1525         if (pdu == NULL) {
1526                 smb2_set_error(smb2, "Failed to create create command");
1527                 return -ENOMEM;
1528         }
1529         smb2_queue_pdu(smb2, pdu);
1530
1531         return 0;
1532 }
1533
1534 struct stat_cb_data {
1535         smb2_command_cb cb;
1536         void *cb_data;
1537
1538         uint32_t status;
1539         uint8_t info_type;
1540         uint8_t file_info_class;
1541         void *st;
1542 };
1543
1544 static void
1545 fstat_cb_1(struct smb2_context *smb2, int status,
1546            void *command_data, void *private_data)
1547 {
1548         struct stat_cb_data *stat_data = private_data;
1549         struct smb2_query_info_reply *rep = command_data;
1550         struct smb2_file_all_info *fs = rep->output_buffer;
1551         struct smb2_stat_64 *st = stat_data->st;
1552
1553         if (status != SMB2_STATUS_SUCCESS) {
1554                 stat_data->cb(smb2, -nterror_to_errno(status),
1555                        NULL, stat_data->cb_data);
1556                 free(stat_data);
1557                 return;
1558         }
1559
1560         st->smb2_type = SMB2_TYPE_FILE;
1561         if (fs->basic.file_attributes & SMB2_FILE_ATTRIBUTE_DIRECTORY) {
1562                 st->smb2_type = SMB2_TYPE_DIRECTORY;
1563         }
1564         if (fs->basic.file_attributes & SMB2_FILE_ATTRIBUTE_REPARSE_POINT) {
1565                 st->smb2_type = SMB2_TYPE_LINK;
1566         }
1567         st->smb2_nlink      = fs->standard.number_of_links;
1568         st->smb2_ino        = fs->index_number;
1569         st->smb2_size       = fs->standard.end_of_file;
1570         st->smb2_atime      = fs->basic.last_access_time.tv_sec;
1571         st->smb2_atime_nsec = fs->basic.last_access_time.tv_usec *
1572                 1000;
1573         st->smb2_mtime      = fs->basic.last_write_time.tv_sec;
1574         st->smb2_mtime_nsec = fs->basic.last_write_time.tv_usec *
1575                 1000;
1576         st->smb2_ctime      = fs->basic.change_time.tv_sec;
1577         st->smb2_ctime_nsec = fs->basic.change_time.tv_usec *
1578                 1000;
1579         st->smb2_btime      = fs->basic.creation_time.tv_sec;
1580         st->smb2_btime_nsec = fs->basic.creation_time.tv_usec *
1581                 1000;
1582
1583         smb2_free_data(smb2, fs);
1584
1585         stat_data->cb(smb2, 0, st, stat_data->cb_data);
1586         free(stat_data);
1587 }
1588
1589 int
1590 smb2_fstat_async(struct smb2_context *smb2, struct smb2fh *fh,
1591                  struct smb2_stat_64 *st,
1592                  smb2_command_cb cb, void *cb_data)
1593 {
1594         struct stat_cb_data *stat_data;
1595         struct smb2_query_info_request req;
1596         struct smb2_pdu *pdu;
1597
1598         stat_data = malloc(sizeof(struct stat_cb_data));
1599         if (stat_data == NULL) {
1600                 smb2_set_error(smb2, "Failed to allocate stat_data");
1601                 return -ENOMEM;
1602         }
1603         memset(stat_data, 0, sizeof(struct stat_cb_data));
1604
1605         stat_data->cb = cb;
1606         stat_data->cb_data = cb_data;
1607         stat_data->st = st;
1608
1609         memset(&req, 0, sizeof(struct smb2_query_info_request));
1610         req.info_type = SMB2_0_INFO_FILE;
1611         req.file_info_class = SMB2_FILE_ALL_INFORMATION;
1612         req.output_buffer_length = DEFAULT_OUTPUT_BUFFER_LENGTH;
1613         req.additional_information = 0;
1614         req.flags = 0;
1615         memcpy(req.file_id, fh->file_id, SMB2_FD_SIZE);
1616
1617         pdu = smb2_cmd_query_info_async(smb2, &req, fstat_cb_1, stat_data);
1618         if (pdu == NULL) {
1619                 smb2_set_error(smb2, "Failed to create query command");
1620                 free(stat_data);
1621                 return -ENOMEM;
1622         }
1623         smb2_queue_pdu(smb2, pdu);
1624
1625         return 0;
1626 }
1627
1628 static void
1629 getinfo_cb_3(struct smb2_context *smb2, int status,
1630              void *command_data _U_, void *private_data)
1631 {
1632         struct stat_cb_data *stat_data = private_data;
1633
1634         if (stat_data->status == SMB2_STATUS_SUCCESS) {
1635                 stat_data->status = status;
1636         }
1637
1638         stat_data->cb(smb2, -nterror_to_errno(stat_data->status),
1639                       stat_data->st, stat_data->cb_data);
1640         free(stat_data);
1641 }
1642
1643 static void
1644 getinfo_cb_2(struct smb2_context *smb2, int status,
1645              void *command_data, void *private_data)
1646 {
1647         struct stat_cb_data *stat_data = private_data;
1648         struct smb2_query_info_reply *rep = command_data;
1649
1650         if (stat_data->status == SMB2_STATUS_SUCCESS) {
1651                 stat_data->status = status;
1652         }
1653         if (stat_data->status != SMB2_STATUS_SUCCESS) {
1654                 return;
1655         }
1656
1657         if (stat_data->info_type == SMB2_0_INFO_FILE &&
1658             stat_data->file_info_class == SMB2_FILE_ALL_INFORMATION) {
1659                 struct smb2_stat_64 *st = stat_data->st;
1660                 struct smb2_file_all_info *fs = rep->output_buffer;
1661
1662                 st->smb2_type = SMB2_TYPE_FILE;
1663                 if (fs->basic.file_attributes & SMB2_FILE_ATTRIBUTE_DIRECTORY) {
1664                         st->smb2_type = SMB2_TYPE_DIRECTORY;
1665                 }
1666                 if (fs->basic.file_attributes & SMB2_FILE_ATTRIBUTE_REPARSE_POINT) {
1667                         st->smb2_type = SMB2_TYPE_LINK;
1668                 }
1669                 st->smb2_nlink      = fs->standard.number_of_links;
1670                 st->smb2_ino        = fs->index_number;
1671                 st->smb2_size       = fs->standard.end_of_file;
1672                 st->smb2_atime      = fs->basic.last_access_time.tv_sec;
1673                 st->smb2_atime_nsec = fs->basic.last_access_time.tv_usec *
1674                         1000;
1675                 st->smb2_mtime      = fs->basic.last_write_time.tv_sec;
1676                 st->smb2_mtime_nsec = fs->basic.last_write_time.tv_usec *
1677                         1000;
1678                 st->smb2_ctime      = fs->basic.change_time.tv_sec;
1679                 st->smb2_ctime_nsec = fs->basic.change_time.tv_usec *
1680                         1000;
1681                 st->smb2_btime      = fs->basic.creation_time.tv_sec;
1682                 st->smb2_btime_nsec = fs->basic.creation_time.tv_usec *
1683                         1000;
1684         } else if (stat_data->info_type == SMB2_0_INFO_FILESYSTEM &&
1685                    stat_data->file_info_class == SMB2_FILE_FS_FULL_SIZE_INFORMATION) {
1686                 struct smb2_statvfs *statvfs = stat_data->st;
1687                 struct smb2_file_fs_full_size_info *vfs = rep->output_buffer;
1688
1689                 memset(statvfs, 0, sizeof(struct smb2_statvfs));
1690                 statvfs->f_bsize = statvfs->f_frsize =
1691                         vfs->bytes_per_sector *
1692                         vfs->sectors_per_allocation_unit;
1693                 statvfs->f_blocks = vfs->total_allocation_units;
1694                 statvfs->f_bfree = statvfs->f_bavail =
1695                         vfs->caller_available_allocation_units;
1696         }
1697         smb2_free_data(smb2, rep->output_buffer);
1698 }
1699
1700 static void
1701 getinfo_cb_1(struct smb2_context *smb2, int status,
1702              void *command_data _U_, void *private_data)
1703 {
1704         struct stat_cb_data *stat_data = private_data;
1705
1706         if (stat_data->status == SMB2_STATUS_SUCCESS) {
1707                 stat_data->status = status;
1708         }
1709 }
1710
1711 static int
1712 smb2_getinfo_async(struct smb2_context *smb2, const char *path,
1713                    uint8_t info_type, uint8_t file_info_class,
1714                    void *st,
1715                    smb2_command_cb cb, void *cb_data)
1716 {
1717         struct stat_cb_data *stat_data;
1718         struct smb2_create_request cr_req;
1719         struct smb2_query_info_request qi_req;
1720         struct smb2_close_request cl_req;
1721         struct smb2_pdu *pdu, *next_pdu;
1722
1723         stat_data = malloc(sizeof(struct stat_cb_data));
1724         if (stat_data == NULL) {
1725                 smb2_set_error(smb2, "Failed to allocate create_data");
1726                 return -1;
1727         }
1728         memset(stat_data, 0, sizeof(struct stat_cb_data));
1729
1730         stat_data->cb = cb;
1731         stat_data->cb_data = cb_data;
1732         stat_data->info_type = info_type;
1733         stat_data->file_info_class = file_info_class;
1734         stat_data->st = st;
1735
1736         /* CREATE command */
1737         memset(&cr_req, 0, sizeof(struct smb2_create_request));
1738         cr_req.requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
1739         cr_req.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
1740         cr_req.desired_access = SMB2_FILE_READ_ATTRIBUTES | SMB2_FILE_READ_EA;
1741         cr_req.file_attributes = 0;
1742         cr_req.share_access = SMB2_FILE_SHARE_READ | SMB2_FILE_SHARE_WRITE;
1743         cr_req.create_disposition = SMB2_FILE_OPEN;
1744         cr_req.create_options = 0;
1745         cr_req.name = path;
1746
1747         pdu = smb2_cmd_create_async(smb2, &cr_req, getinfo_cb_1, stat_data);
1748         if (pdu == NULL) {
1749                 smb2_set_error(smb2, "Failed to create create command");
1750                 free(stat_data);
1751                 return -1;
1752         }
1753
1754         /* QUERY INFO command */
1755         memset(&qi_req, 0, sizeof(struct smb2_query_info_request));
1756         qi_req.info_type = info_type;
1757         qi_req.file_info_class = file_info_class;
1758         qi_req.output_buffer_length = DEFAULT_OUTPUT_BUFFER_LENGTH;
1759         qi_req.additional_information = 0;
1760         qi_req.flags = 0;
1761         memcpy(qi_req.file_id, compound_file_id, SMB2_FD_SIZE);
1762
1763         next_pdu = smb2_cmd_query_info_async(smb2, &qi_req,
1764                                              getinfo_cb_2, stat_data);
1765         if (next_pdu == NULL) {
1766                 smb2_set_error(smb2, "Failed to create query command");
1767                 free(stat_data);
1768                 smb2_free_pdu(smb2, pdu);
1769                 return -1;
1770         }
1771         smb2_add_compound_pdu(smb2, pdu, next_pdu);
1772
1773         /* CLOSE command */
1774         memset(&cl_req, 0, sizeof(struct smb2_close_request));
1775         cl_req.flags = SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB;
1776         memcpy(cl_req.file_id, compound_file_id, SMB2_FD_SIZE);
1777
1778         next_pdu = smb2_cmd_close_async(smb2, &cl_req, getinfo_cb_3, stat_data);
1779         if (next_pdu == NULL) {
1780                 stat_data->cb(smb2, -ENOMEM, NULL, stat_data->cb_data);
1781                 free(stat_data);
1782                 smb2_free_pdu(smb2, pdu);
1783                 return -1;
1784         }
1785         smb2_add_compound_pdu(smb2, pdu, next_pdu);
1786
1787         smb2_queue_pdu(smb2, pdu);
1788
1789         return 0;
1790 }
1791
1792 int
1793 smb2_stat_async(struct smb2_context *smb2, const char *path,
1794                 struct smb2_stat_64 *st,
1795                 smb2_command_cb cb, void *cb_data)
1796 {
1797         return smb2_getinfo_async(smb2, path,
1798                                   SMB2_0_INFO_FILE,
1799                                   SMB2_FILE_ALL_INFORMATION,
1800                                   st, cb, cb_data);
1801 }
1802
1803 int
1804 smb2_statvfs_async(struct smb2_context *smb2, const char *path,
1805                    struct smb2_statvfs *statvfs,
1806                    smb2_command_cb cb, void *cb_data)
1807 {
1808         return smb2_getinfo_async(smb2, path,
1809                                   SMB2_0_INFO_FILESYSTEM,
1810                                   SMB2_FILE_FS_FULL_SIZE_INFORMATION,
1811                                   statvfs, cb, cb_data);
1812 }
1813
1814 struct trunc_cb_data {
1815         smb2_command_cb cb;
1816         void *cb_data;
1817
1818         uint32_t status;
1819         uint64_t length;
1820 };
1821
1822 static void
1823 trunc_cb_3(struct smb2_context *smb2, int status,
1824            void *command_data _U_, void *private_data)
1825 {
1826         struct trunc_cb_data *trunc_data = private_data;
1827
1828         if (trunc_data->status == SMB2_STATUS_SUCCESS) {
1829                 trunc_data->status = status;
1830         }
1831
1832         trunc_data->cb(smb2, -nterror_to_errno(trunc_data->status),
1833                        NULL, trunc_data->cb_data);
1834         free(trunc_data);
1835 }
1836
1837 static void
1838 trunc_cb_2(struct smb2_context *smb2, int status,
1839            void *command_data, void *private_data)
1840 {
1841         struct trunc_cb_data *trunc_data = private_data;
1842
1843         if (trunc_data->status == SMB2_STATUS_SUCCESS) {
1844                 trunc_data->status = status;
1845         }
1846 }
1847
1848 static void
1849 trunc_cb_1(struct smb2_context *smb2, int status,
1850            void *command_data _U_, void *private_data)
1851 {
1852         struct trunc_cb_data *trunc_data = private_data;
1853
1854         if (trunc_data->status == SMB2_STATUS_SUCCESS) {
1855                 trunc_data->status = status;
1856         }
1857 }
1858
1859 int
1860 smb2_truncate_async(struct smb2_context *smb2, const char *path,
1861                     uint64_t length, smb2_command_cb cb, void *cb_data)
1862 {
1863         struct trunc_cb_data *trunc_data;
1864         struct smb2_create_request cr_req;
1865         struct smb2_set_info_request si_req;
1866         struct smb2_close_request cl_req;
1867         struct smb2_pdu *pdu, *next_pdu;
1868         struct smb2_file_end_of_file_info eofi;
1869
1870         trunc_data = malloc(sizeof(struct trunc_cb_data));
1871         if (trunc_data == NULL) {
1872                 smb2_set_error(smb2, "Failed to allocate trunc_data");
1873                 return -1;
1874         }
1875         memset(trunc_data, 0, sizeof(struct trunc_cb_data));
1876
1877         trunc_data->cb = cb;
1878         trunc_data->cb_data = cb_data;
1879         trunc_data->length = length;
1880
1881         /* CREATE command */
1882         memset(&cr_req, 0, sizeof(struct smb2_create_request));
1883         cr_req.requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
1884         cr_req.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
1885         cr_req.desired_access = SMB2_GENERIC_WRITE;
1886         cr_req.file_attributes = 0;
1887         cr_req.share_access = SMB2_FILE_SHARE_READ | SMB2_FILE_SHARE_WRITE;
1888         cr_req.create_disposition = SMB2_FILE_OPEN;
1889         cr_req.create_options = 0;
1890         cr_req.name = path;
1891
1892         pdu = smb2_cmd_create_async(smb2, &cr_req, trunc_cb_1, trunc_data);
1893         if (pdu == NULL) {
1894                 smb2_set_error(smb2, "Failed to create create command");
1895                 free(trunc_data);
1896                 return -1;
1897         }
1898
1899         /* SET INFO command */
1900         eofi.end_of_file = length;
1901
1902         memset(&si_req, 0, sizeof(struct smb2_set_info_request));
1903         si_req.info_type = SMB2_0_INFO_FILE;
1904         si_req.file_info_class = SMB2_FILE_END_OF_FILE_INFORMATION;
1905         si_req.additional_information = 0;
1906         memcpy(si_req.file_id, compound_file_id, SMB2_FD_SIZE);
1907         si_req.input_data = &eofi;
1908
1909         next_pdu = smb2_cmd_set_info_async(smb2, &si_req,
1910                                            trunc_cb_2, trunc_data);
1911         if (next_pdu == NULL) {
1912                 smb2_set_error(smb2, "Failed to create set command. %s",
1913                                smb2_get_error(smb2));
1914                 free(trunc_data);
1915                 smb2_free_pdu(smb2, pdu);
1916                 return -1;
1917         }
1918         smb2_add_compound_pdu(smb2, pdu, next_pdu);
1919
1920         /* CLOSE command */
1921         memset(&cl_req, 0, sizeof(struct smb2_close_request));
1922         cl_req.flags = SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB;
1923         memcpy(cl_req.file_id, compound_file_id, SMB2_FD_SIZE);
1924
1925         next_pdu = smb2_cmd_close_async(smb2, &cl_req, trunc_cb_3, trunc_data);
1926         if (next_pdu == NULL) {
1927                 trunc_data->cb(smb2, -ENOMEM, NULL, trunc_data->cb_data);
1928                 free(trunc_data);
1929                 smb2_free_pdu(smb2, pdu);
1930                 return -1;
1931         }
1932         smb2_add_compound_pdu(smb2, pdu, next_pdu);
1933
1934         smb2_queue_pdu(smb2, pdu);
1935
1936         return 0;
1937 }
1938
1939 struct rename_cb_data {
1940         smb2_command_cb cb;
1941         void *cb_data;
1942         uint32_t status;
1943 };
1944
1945 static void
1946 rename_cb_3(struct smb2_context *smb2, int status,
1947            void *command_data _U_, void *private_data)
1948 {
1949         struct rename_cb_data *rename_data = private_data;
1950
1951         if (rename_data->status == SMB2_STATUS_SUCCESS) {
1952                 rename_data->status = status;
1953         }
1954
1955         rename_data->cb(smb2, -nterror_to_errno(rename_data->status),
1956                         NULL, rename_data->cb_data);
1957         free(rename_data);
1958 }
1959
1960 static void
1961 rename_cb_2(struct smb2_context *smb2, int status,
1962            void *command_data _U_, void *private_data)
1963 {
1964         struct rename_cb_data *rename_data = private_data;
1965
1966         if (rename_data->status == SMB2_STATUS_SUCCESS) {
1967                 rename_data->status = status;
1968         }
1969 }
1970
1971 static void
1972 rename_cb_1(struct smb2_context *smb2, int status,
1973            void *command_data _U_, void *private_data)
1974 {
1975         struct rename_cb_data *rename_data = private_data;
1976
1977         if (rename_data->status == SMB2_STATUS_SUCCESS) {
1978                 rename_data->status = status;
1979         }
1980 }
1981
1982 int
1983 smb2_rename_async(struct smb2_context *smb2, const char *oldpath,
1984                   const char *newpath, smb2_command_cb cb, void *cb_data)
1985 {
1986         struct rename_cb_data *rename_data;
1987         struct smb2_create_request cr_req;
1988         struct smb2_set_info_request si_req;
1989         struct smb2_close_request cl_req;
1990         struct smb2_pdu *pdu, *next_pdu;
1991         struct smb2_file_rename_info rn_info;
1992
1993         rename_data = malloc(sizeof(struct rename_cb_data));
1994         if (rename_data == NULL) {
1995                 smb2_set_error(smb2, "Failed to allocate rename_data");
1996                 return -1;
1997         }
1998         memset(rename_data, 0, sizeof(struct rename_cb_data));
1999
2000         rename_data->cb = cb;
2001         rename_data->cb_data = cb_data;
2002
2003         /* CREATE command */
2004         memset(&cr_req, 0, sizeof(struct smb2_create_request));
2005         cr_req.requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
2006         cr_req.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
2007         cr_req.desired_access = SMB2_GENERIC_READ  | SMB2_FILE_READ_ATTRIBUTES | SMB2_DELETE;
2008         cr_req.file_attributes = 0;
2009         cr_req.share_access = SMB2_FILE_SHARE_READ | SMB2_FILE_SHARE_WRITE | SMB2_FILE_SHARE_DELETE;
2010         cr_req.create_disposition = SMB2_FILE_OPEN;
2011         cr_req.create_options = 0;
2012         cr_req.name = oldpath;
2013
2014         pdu = smb2_cmd_create_async(smb2, &cr_req, rename_cb_1, rename_data);
2015         if (pdu == NULL) {
2016                 smb2_set_error(smb2, "Failed to create create command");
2017                 free(rename_data);
2018                 return -1;
2019         }
2020
2021         /* SET INFO command */
2022         rn_info.replace_if_exist = 0;
2023         rn_info.file_name = discard_const(newpath);
2024
2025         memset(&si_req, 0, sizeof(struct smb2_set_info_request));
2026         si_req.info_type = SMB2_0_INFO_FILE;
2027         si_req.file_info_class = SMB2_FILE_RENAME_INFORMATION;
2028         si_req.additional_information = 0;
2029         memcpy(si_req.file_id, compound_file_id, SMB2_FD_SIZE);
2030         si_req.input_data = &rn_info;
2031
2032         next_pdu = smb2_cmd_set_info_async(smb2, &si_req,
2033                                            rename_cb_2, rename_data);
2034         if (next_pdu == NULL) {
2035                 smb2_set_error(smb2, "Failed to create set command. %s",
2036                                smb2_get_error(smb2));
2037                 free(rename_data);
2038                 smb2_free_pdu(smb2, pdu);
2039                 return -1;
2040         }
2041         smb2_add_compound_pdu(smb2, pdu, next_pdu);
2042
2043         /* CLOSE command */
2044         memset(&cl_req, 0, sizeof(struct smb2_close_request));
2045         cl_req.flags = SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB;
2046         memcpy(cl_req.file_id, compound_file_id, SMB2_FD_SIZE);
2047
2048         next_pdu = smb2_cmd_close_async(smb2, &cl_req, rename_cb_3, rename_data);
2049         if (next_pdu == NULL) {
2050                 rename_data->cb(smb2, -ENOMEM, NULL, rename_data->cb_data);
2051                 free(rename_data);
2052                 smb2_free_pdu(smb2, pdu);
2053                 return -1;
2054         }
2055         smb2_add_compound_pdu(smb2, pdu, next_pdu);
2056
2057         smb2_queue_pdu(smb2, pdu);
2058
2059         return 0;
2060 }
2061
2062 static void
2063 ftrunc_cb_1(struct smb2_context *smb2, int status,
2064             void *command_data _U_, void *private_data)
2065 {
2066         struct create_cb_data *cb_data = private_data;
2067
2068         cb_data->cb(smb2, -nterror_to_errno(status),
2069                     NULL, cb_data->cb_data);
2070         free(cb_data);
2071 }
2072
2073 int
2074 smb2_ftruncate_async(struct smb2_context *smb2, struct smb2fh *fh,
2075                      uint64_t length, smb2_command_cb cb, void *cb_data)
2076 {
2077         struct create_cb_data *create_data;
2078         struct smb2_set_info_request req;
2079         struct smb2_file_end_of_file_info eofi;
2080         struct smb2_pdu *pdu;
2081
2082         create_data = malloc(sizeof(struct create_cb_data));
2083         if (create_data == NULL) {
2084                 smb2_set_error(smb2, "Failed to allocate create_data");
2085                 return -ENOMEM;
2086         }
2087         memset(create_data, 0, sizeof(struct create_cb_data));
2088
2089         create_data->cb = cb;
2090         create_data->cb_data = cb_data;
2091
2092         eofi.end_of_file = length;
2093
2094         memset(&req, 0, sizeof(struct smb2_set_info_request));
2095         req.info_type = SMB2_0_INFO_FILE;
2096         req.file_info_class = SMB2_FILE_END_OF_FILE_INFORMATION;
2097         req.additional_information = 0;
2098         memcpy(req.file_id, fh->file_id, SMB2_FD_SIZE);
2099         req.input_data = &eofi;
2100
2101         pdu = smb2_cmd_set_info_async(smb2, &req, ftrunc_cb_1, create_data);
2102         if (pdu == NULL) {
2103                 smb2_set_error(smb2, "Failed to create set info command");
2104                 return -ENOMEM;
2105         }
2106         smb2_queue_pdu(smb2, pdu);
2107
2108         return 0;
2109 }
2110
2111 struct readlink_cb_data {
2112         smb2_command_cb cb;
2113         void *cb_data;
2114
2115         uint32_t status;
2116         struct smb2_reparse_data_buffer *reparse;
2117 };
2118
2119 static void
2120 readlink_cb_3(struct smb2_context *smb2, int status,
2121             void *command_data _U_, void *private_data)
2122 {
2123         struct readlink_cb_data *cb_data = private_data;
2124         struct smb2_reparse_data_buffer *rp = cb_data->reparse;
2125         char *target = "<unknown reparse point type>";
2126
2127         if (rp) {
2128                 switch (rp->reparse_tag) {
2129                 case SMB2_REPARSE_TAG_SYMLINK:
2130                         target = rp->symlink.subname;
2131                 }
2132         }
2133         cb_data->cb(smb2, -nterror_to_errno(cb_data->status),
2134                     target, cb_data->cb_data);
2135         smb2_free_data(smb2, rp);
2136         free(cb_data);
2137 }
2138
2139 static void
2140 readlink_cb_2(struct smb2_context *smb2, int status,
2141             void *command_data, void *private_data)
2142 {
2143         struct readlink_cb_data *cb_data = private_data;
2144         struct smb2_ioctl_reply *rep = command_data;
2145
2146         if (cb_data->status == SMB2_STATUS_SUCCESS) {
2147                 cb_data->status = status;
2148         }
2149         if (status == SMB2_STATUS_NOT_A_REPARSE_POINT) {
2150                 smb2_set_error(smb2, "Not a reparse point");
2151         }
2152         if (status == SMB2_STATUS_SUCCESS) {
2153                 cb_data->reparse = rep->output;
2154         }
2155 }
2156
2157 static void
2158 readlink_cb_1(struct smb2_context *smb2, int status,
2159             void *command_data _U_, void *private_data)
2160 {
2161         struct readlink_cb_data *cb_data = private_data;
2162
2163         if (status != SMB2_STATUS_SUCCESS) {
2164                 smb2_set_error(smb2, "%s", nterror_to_str(status));
2165         }
2166         cb_data->status = status;
2167 }
2168
2169 int
2170 smb2_readlink_async(struct smb2_context *smb2, const char *path,
2171                     smb2_command_cb cb, void *cb_data)
2172 {
2173         struct readlink_cb_data *readlink_data;
2174         struct smb2_create_request cr_req;
2175         struct smb2_ioctl_request io_req;
2176         struct smb2_close_request cl_req;
2177         struct smb2_pdu *pdu, *next_pdu;
2178
2179         readlink_data = malloc(sizeof(struct readlink_cb_data));
2180         if (readlink_data == NULL) {
2181                 smb2_set_error(smb2, "Failed to allocate readlink_data");
2182                 return -1;
2183         }
2184         memset(readlink_data, 0, sizeof(struct readlink_cb_data));
2185
2186         readlink_data->cb = cb;
2187         readlink_data->cb_data = cb_data;
2188
2189         /* CREATE command */
2190         memset(&cr_req, 0, sizeof(struct smb2_create_request));
2191         cr_req.requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
2192         cr_req.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
2193         cr_req.desired_access = SMB2_FILE_READ_ATTRIBUTES;
2194         cr_req.file_attributes = 0;
2195         cr_req.share_access = SMB2_FILE_SHARE_READ | SMB2_FILE_SHARE_WRITE |
2196                 SMB2_FILE_SHARE_DELETE;
2197         cr_req.create_disposition = SMB2_FILE_OPEN;
2198         cr_req.create_options = SMB2_FILE_OPEN_REPARSE_POINT;
2199         cr_req.name = path;
2200
2201         pdu = smb2_cmd_create_async(smb2, &cr_req, readlink_cb_1, readlink_data);
2202         if (pdu == NULL) {
2203                 smb2_set_error(smb2, "Failed to create create command");
2204                 free(readlink_data);
2205                 return -1;
2206         }
2207
2208         /* IOCTL command */
2209         memset(&io_req, 0, sizeof(struct smb2_ioctl_request));
2210         io_req.ctl_code = SMB2_FSCTL_GET_REPARSE_POINT;
2211         memcpy(io_req.file_id, compound_file_id, SMB2_FD_SIZE);
2212         io_req.input_count = 0;
2213         io_req.input = NULL;
2214         io_req.flags = SMB2_0_IOCTL_IS_FSCTL;
2215
2216         next_pdu = smb2_cmd_ioctl_async(smb2, &io_req, readlink_cb_2,
2217                                         readlink_data);
2218         if (next_pdu == NULL) {
2219                 readlink_data->cb(smb2, -ENOMEM, NULL, readlink_data->cb_data);
2220                 free(readlink_data);
2221                 smb2_free_pdu(smb2, pdu);
2222                 return -1;
2223         }
2224         smb2_add_compound_pdu(smb2, pdu, next_pdu);
2225
2226         /* CLOSE command */
2227         memset(&cl_req, 0, sizeof(struct smb2_close_request));
2228         cl_req.flags = SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB;
2229         memcpy(cl_req.file_id, compound_file_id, SMB2_FD_SIZE);
2230
2231         next_pdu = smb2_cmd_close_async(smb2, &cl_req, readlink_cb_3,
2232                                         readlink_data);
2233         if (next_pdu == NULL) {
2234                 readlink_data->cb(smb2, -ENOMEM, NULL, readlink_data->cb_data);
2235                 free(readlink_data);
2236                 smb2_free_pdu(smb2, pdu);
2237                 return -1;
2238         }
2239         smb2_add_compound_pdu(smb2, pdu, next_pdu);
2240
2241         smb2_queue_pdu(smb2, pdu);
2242
2243         return 0;
2244 }
2245
2246 struct disconnect_data {
2247         smb2_command_cb cb;
2248         void *cb_data;
2249 };
2250
2251 static void
2252 disconnect_cb_2(struct smb2_context *smb2, int status,
2253            void *command_data _U_, void *private_data)
2254 {
2255         struct disconnect_data *dc_data = private_data;
2256
2257         dc_data->cb(smb2, 0, NULL, dc_data->cb_data);
2258         free(dc_data);
2259         close(smb2->fd);
2260         smb2->fd = -1;
2261 }
2262
2263 static void
2264 disconnect_cb_1(struct smb2_context *smb2, int status,
2265            void *command_data _U_, void *private_data)
2266 {
2267         struct disconnect_data *dc_data = private_data;
2268         struct smb2_pdu *pdu;
2269
2270         pdu = smb2_cmd_logoff_async(smb2, disconnect_cb_2, dc_data);
2271         if (pdu == NULL) {
2272                 dc_data->cb(smb2, -ENOMEM, NULL, dc_data->cb_data);
2273                 free(dc_data);
2274                 return;
2275         }
2276         smb2_queue_pdu(smb2, pdu);
2277 }
2278
2279 int
2280 smb2_disconnect_share_async(struct smb2_context *smb2,
2281                             smb2_command_cb cb, void *cb_data)
2282 {
2283         struct disconnect_data *dc_data;
2284         struct smb2_pdu *pdu;
2285
2286         dc_data = malloc(sizeof(struct disconnect_data));
2287         if (dc_data == NULL) {
2288                 smb2_set_error(smb2, "Failed to allocate disconnect_data");
2289                 return -ENOMEM;
2290         }
2291         memset(dc_data, 0, sizeof(struct disconnect_data));
2292
2293         dc_data->cb = cb;
2294         dc_data->cb_data = cb_data;
2295
2296         pdu = smb2_cmd_tree_disconnect_async(smb2, disconnect_cb_1, dc_data);
2297         if (pdu == NULL) {
2298                 free(dc_data);
2299                 return -ENOMEM;
2300         }
2301         smb2_queue_pdu(smb2, pdu);
2302
2303         return 0;
2304 }
2305
2306 struct echo_data {
2307         smb2_command_cb cb;
2308         void *cb_data;
2309 };
2310
2311 static void
2312 echo_cb(struct smb2_context *smb2, int status,
2313            void *command_data _U_, void *private_data)
2314 {
2315         struct echo_data *cb_data = private_data;
2316
2317         cb_data->cb(smb2, -nterror_to_errno(status),
2318                     NULL, cb_data->cb_data);
2319         free(cb_data);
2320 }
2321
2322 int
2323 smb2_echo_async(struct smb2_context *smb2,
2324                 smb2_command_cb cb, void *cb_data)
2325 {
2326         struct echo_data *echo_data;
2327         struct smb2_pdu *pdu;
2328
2329         echo_data = malloc(sizeof(struct echo_data));
2330         if (echo_data == NULL) {
2331                 smb2_set_error(smb2, "Failed to allocate echo_data");
2332                 return -ENOMEM;
2333         }
2334         memset(echo_data, 0, sizeof(struct echo_data));
2335
2336         echo_data->cb = cb;
2337         echo_data->cb_data = cb_data;
2338
2339         pdu = smb2_cmd_echo_async(smb2, echo_cb, echo_data);
2340         if (pdu == NULL) {
2341                 free(echo_data);
2342                 return -ENOMEM;
2343         }
2344         smb2_queue_pdu(smb2, pdu);
2345
2346         return 0;
2347 }
2348         
2349 uint32_t
2350 smb2_get_max_read_size(struct smb2_context *smb2)
2351 {
2352         return smb2->max_read_size;
2353 }
2354
2355 uint32_t
2356 smb2_get_max_write_size(struct smb2_context *smb2)
2357 {
2358         return smb2->max_write_size;
2359 }
2360
2361 smb2_file_id *
2362 smb2_get_file_id(struct smb2fh *fh)
2363 {
2364         return &fh->file_id;
2365 }
2366
2367 struct smb2fh *
2368 smb2_fh_from_file_id(struct smb2_context *smb2, smb2_file_id *fileid)
2369 {
2370         struct smb2fh *fh;
2371
2372         fh = malloc(sizeof(struct smb2fh));
2373         if (fh == NULL) {
2374                 return NULL;
2375         }
2376         memset(fh, 0, sizeof(struct smb2fh));
2377         memcpy(fh->file_id, fileid, SMB2_FD_SIZE);
2378         SMB2_LIST_ADD(&smb2->fhs, fh);
2379
2380         return fh;
2381 }