1 /* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */
3 Copyright (C) 2016 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
5 Portions of this code are copyright 2017 to Primary Data Inc.
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.
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.
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/>.
44 #ifdef HAVE_SYS_TYPES_H
45 #include <sys/types.h>
48 #ifdef HAVE_SYS_STAT_H
59 #include <sys/socket.h>
67 #include "sha-private.h"
72 #include "libsmb2-raw.h"
73 #include "libsmb2-private.h"
74 #include "portable-endian.h"
78 #include "krb5-wrapper.h"
82 #define DEFAULT_OUTPUT_BUFFER_LENGTH 512
84 #define DEFAULT_OUTPUT_BUFFER_LENGTH 0xffff
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";
104 #define O_DSYNC 040000
106 #define __O_SYNC 020000000
107 #define O_SYNC (__O_SYNC|O_DSYNC)
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
115 struct connect_data {
123 /* UNC for the share in utf8 as well as ucs2 formats */
125 struct ucs2 *ucs2_unc;
130 struct smb2_dirent_internal {
131 struct smb2_dirent_internal *next;
132 struct smb2dirent dirent;
136 struct smb2dir *next;
139 smb2_file_id file_id;
141 struct smb2_dirent_internal *entries;
142 struct smb2_dirent_internal *current_entry;
151 smb2_file_id file_id;
156 smb2_close_context(struct smb2_context *smb2)
158 if (smb2->fd != -1) {
162 smb2->is_connected = 0;
163 smb2->message_id = 0;
164 smb2->session_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;
171 smb2->session_key_size = 0;
175 send_session_setup_request(struct smb2_context *smb2,
176 struct connect_data *c_data,
177 unsigned char *buf, int len);
180 free_smb2dir(struct smb2_context *smb2, struct smb2dir *dir)
182 SMB2_LIST_REMOVE(&smb2->dirs, dir);
183 while (dir->entries) {
184 struct smb2_dirent_internal *e = dir->entries->next;
186 free(discard_const(dir->entries->dirent.name));
193 void smb2_free_all_dirs(struct smb2_context *smb2)
196 free_smb2dir(smb2, smb2->dirs);
201 smb2_seekdir(struct smb2_context *smb2, struct smb2dir *dir,
204 dir->current_entry = dir->entries;
207 while (dir->current_entry && loc--) {
208 dir->current_entry = dir->current_entry->next;
214 smb2_telldir(struct smb2_context *smb2, struct smb2dir *dir)
220 smb2_rewinddir(struct smb2_context *smb2,
223 dir->current_entry = dir->entries;
228 smb2_readdir(struct smb2_context *smb2,
231 struct smb2dirent *ent;
233 if (dir->current_entry == NULL) {
237 ent = &dir->current_entry->dirent;
238 dir->current_entry = dir->current_entry->next;
245 smb2_closedir(struct smb2_context *smb2, struct smb2dir *dir)
247 free_smb2dir(smb2, dir);
251 decode_dirents(struct smb2_context *smb2, struct smb2dir *dir,
252 struct smb2_iovec *vec)
254 struct smb2_dirent_internal *ent;
255 struct smb2_fileidfulldirectoryinformation fs;
259 struct smb2_iovec tmp_vec;
261 /* Make sure we do not go beyond end of vector */
262 if (offset >= vec->len) {
263 smb2_set_error(smb2, "Malformed query reply.");
267 ent = malloc(sizeof(struct smb2_dirent_internal));
269 smb2_set_error(smb2, "Failed to allocate "
273 memset(ent, 0, sizeof(struct smb2_dirent_internal));
274 SMB2_LIST_ADD(&dir->entries, ent);
277 tmp_vec.buf = &vec->buf[offset];
278 tmp_vec.len = vec->len - offset;
280 smb2_decode_fileidfulldirectoryinformation(smb2, &fs,
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;
288 if (fs.file_attributes & SMB2_FILE_ATTRIBUTE_REPARSE_POINT) {
289 ent->dirent.st.smb2_type = SMB2_TYPE_LINK;
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;
303 offset += fs.next_entry_offset;
304 } while (fs.next_entry_offset);
310 od_close_cb(struct smb2_context *smb2, int status,
311 void *command_data, void *private_data)
313 struct smb2dir *dir = private_data;
315 if (status != SMB2_STATUS_SUCCESS) {
316 dir->cb(smb2, -ENOMEM, NULL, dir->cb_data);
317 free_smb2dir(smb2, dir);
321 dir->current_entry = dir->entries;
324 /* dir will be freed in smb2_closedir() */
325 dir->cb(smb2, 0, dir, dir->cb_data);
329 query_cb(struct smb2_context *smb2, int status,
330 void *command_data, void *private_data)
332 struct smb2dir *dir = private_data;
333 struct smb2_query_directory_reply *rep = command_data;
335 if (status == SMB2_STATUS_SUCCESS) {
336 struct smb2_iovec vec;
337 struct smb2_query_directory_request req;
338 struct smb2_pdu *pdu;
340 vec.buf = rep->output_buffer;
341 vec.len = rep->output_buffer_length;
343 if (decode_dirents(smb2, dir, &vec) < 0) {
344 dir->cb(smb2, -ENOMEM, NULL, dir->cb_data);
345 free_smb2dir(smb2, dir);
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;
353 memcpy(req.file_id, dir->file_id, SMB2_FD_SIZE);
354 req.output_buffer_length = DEFAULT_OUTPUT_BUFFER_LENGTH;
357 pdu = smb2_cmd_query_directory_async(smb2, &req, query_cb, dir);
359 dir->cb(smb2, -ENOMEM, NULL, dir->cb_data);
360 free_smb2dir(smb2, dir);
363 smb2_queue_pdu(smb2, pdu);
368 if (status == SMB2_STATUS_NO_MORE_FILES) {
369 struct smb2_close_request req;
370 struct smb2_pdu *pdu;
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);
377 pdu = smb2_cmd_close_async(smb2, &req, od_close_cb, dir);
379 dir->cb(smb2, -ENOMEM, NULL, dir->cb_data);
380 free_smb2dir(smb2, dir);
383 smb2_queue_pdu(smb2, pdu);
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);
396 opendir_cb(struct smb2_context *smb2, int status,
397 void *command_data, void *private_data)
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;
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);
412 memcpy(dir->file_id, rep->file_id, SMB2_FD_SIZE);
414 memset(&req, 0, sizeof(struct smb2_query_directory_request));
415 req.file_information_class = SMB2_FILE_ID_FULL_DIRECTORY_INFORMATION;
417 memcpy(req.file_id, dir->file_id, SMB2_FD_SIZE);
418 req.output_buffer_length = DEFAULT_OUTPUT_BUFFER_LENGTH;
421 pdu = smb2_cmd_query_directory_async(smb2, &req, query_cb, dir);
423 smb2_set_error(smb2, "Failed to create query command.");
424 dir->cb(smb2, -ENOMEM, NULL, dir->cb_data);
425 free_smb2dir(smb2, dir);
428 smb2_queue_pdu(smb2, pdu);
432 smb2_opendir_async(struct smb2_context *smb2, const char *path,
433 smb2_command_cb cb, void *cb_data)
435 struct smb2_create_request req;
437 struct smb2_pdu *pdu;
443 dir = malloc(sizeof(struct smb2dir));
445 smb2_set_error(smb2, "Failed to allocate smb2dir.");
448 memset(dir, 0, sizeof(struct smb2dir));
449 SMB2_LIST_ADD(&smb2->dirs, dir);
451 dir->cb_data = cb_data;
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;
463 pdu = smb2_cmd_create_async(smb2, &req, opendir_cb, dir);
465 free_smb2dir(smb2, dir);
466 smb2_set_error(smb2, "Failed to create opendir command.");
469 smb2_queue_pdu(smb2, pdu);
475 free_c_data(struct smb2_context *smb2, struct connect_data *c_data)
477 if (c_data->auth_data) {
478 if (smb2->sec == SMB2_SEC_NTLMSSP) {
479 ntlmssp_destroy_context(c_data->auth_data);
483 krb5_free_auth_data(c_data->auth_data);
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));
498 tree_connect_cb(struct smb2_context *smb2, int status,
499 void *command_data, void *private_data)
501 struct connect_data *c_data = private_data;
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);
513 c_data->cb(smb2, 0, NULL, c_data->cb_data);
514 free_c_data(smb2, c_data);
517 void smb2_derive_key(
518 uint8_t *derivation_key,
519 uint32_t derivation_key_len,
523 uint32_t context_len,
524 uint8_t derived_key[SMB2_KEY_SIZE]
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};
532 uint8_t digest[USHAMaxHashSize];
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);
547 session_setup_cb(struct smb2_context *smb2, int status,
548 void *command_data, void *private_data)
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;
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);
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.
574 * Ignore any krb5 errors if the SMB2 layer reported
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);
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,
594 free_c_data(smb2, c_data);
598 if (smb2->sign || smb2->seal) {
599 uint8_t zero_key[SMB2_KEY_SIZE] = {0};
600 int have_valid_session_key = 1;
602 if (smb2->sec == SMB2_SEC_NTLMSSP) {
603 if (ntlmssp_get_session_key(c_data->auth_data,
605 &smb2->session_key_size) < 0) {
606 have_valid_session_key = 0;
611 if (krb5_session_get_session_key(smb2, c_data->auth_data) < 0) {
612 have_valid_session_key = 0;
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;
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);
630 /* Derive the signing key from session key
631 * This is based on negotiated protocol
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,
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,
647 smb2_derive_key(smb2->session_key,
648 smb2->session_key_size,
654 smb2_derive_key(smb2->session_key,
655 smb2->session_key_size,
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);
671 memset(&req, 0, sizeof(struct smb2_tree_connect_request));
673 req.path_length = 2 * c_data->ucs2_unc->len;
674 req.path = c_data->ucs2_unc->val;
676 pdu = smb2_cmd_tree_connect_async(smb2, &req, tree_connect_cb, c_data);
678 smb2_close_context(smb2);
679 c_data->cb(smb2, -ENOMEM, NULL, c_data->cb_data);
680 free_c_data(smb2, c_data);
683 smb2_queue_pdu(smb2, pdu);
686 /* Returns 0 for success and -errno for failure */
688 send_session_setup_request(struct smb2_context *smb2,
689 struct connect_data *c_data,
690 unsigned char *buf, int len)
692 struct smb2_pdu *pdu;
693 struct smb2_session_setup_request req;
695 /* Session setup request. */
696 memset(&req, 0, sizeof(struct smb2_session_setup_request));
697 req.security_mode = smb2->security_mode;
699 if (smb2->sec == SMB2_SEC_NTLMSSP) {
700 if (ntlmssp_generate_blob(smb2, time(NULL), c_data->auth_data,
702 &req.security_buffer,
703 &req.security_buffer_length) < 0) {
704 smb2_close_context(smb2);
710 if (krb5_session_request(smb2, c_data->auth_data,
712 smb2_close_context(smb2);
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);
722 pdu = smb2_cmd_session_setup_async(smb2, &req,
723 session_setup_cb, c_data);
725 smb2_close_context(smb2);
728 smb2_queue_pdu(smb2, pdu);
734 negotiate_cb(struct smb2_context *smb2, int status,
735 void *command_data, void *private_data)
737 struct connect_data *c_data = private_data;
738 struct smb2_negotiate_reply *rep = command_data;
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,
748 free_c_data(smb2, c_data);
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;
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;
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);
776 if (rep->security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) {
784 if (smb2->sec == SMB2_SEC_NTLMSSP) {
785 c_data->auth_data = ntlmssp_init_context(smb2->user,
789 smb2->client_challenge);
793 c_data->auth_data = krb5_negotiate_reply(smb2,
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);
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);
816 connect_cb(struct smb2_context *smb2, int status,
817 void *command_data _U_, void *private_data)
819 struct connect_data *c_data = private_data;
820 struct smb2_negotiate_request req;
821 struct smb2_pdu *pdu;
824 smb2_set_error(smb2, "Socket connect failed with %d",
826 c_data->cb(smb2, -status, NULL, c_data->cb_data);
827 free_c_data(smb2, c_data);
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;
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;
847 case SMB2_VERSION_ANY2:
848 req.dialect_count = 2;
849 req.dialects[0] = SMB2_VERSION_0202;
850 req.dialects[1] = SMB2_VERSION_0210;
852 case SMB2_VERSION_ANY3:
853 req.dialect_count = 2;
854 req.dialects[0] = SMB2_VERSION_0300;
855 req.dialects[1] = SMB2_VERSION_0302;
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;
866 memcpy(req.client_guid, smb2_get_client_guid(smb2), SMB2_GUID_SIZE);
868 if (smb2->sec == SMB2_SEC_UNDEFINED) {
870 smb2->sec = SMB2_SEC_KRB5;
872 smb2->sec = SMB2_SEC_NTLMSSP;
875 pdu = smb2_cmd_negotiate_async(smb2, &req, negotiate_cb, c_data);
877 c_data->cb(smb2, -ENOMEM, NULL, c_data->cb_data);
878 free_c_data(smb2, c_data);
881 smb2_queue_pdu(smb2, pdu);
885 smb2_connect_share_async(struct smb2_context *smb2,
887 const char *share, const char *user,
888 smb2_command_cb cb, void *cb_data)
890 struct connect_data *c_data;
894 free(discard_const(smb2->server));
898 smb2_set_error(smb2, "No server name provided");
901 smb2->server = strdup(server);
904 free(discard_const(smb2->share));
906 smb2->share = strdup(share);
909 smb2_set_user(smb2, user);
912 c_data = malloc(sizeof(struct connect_data));
913 if (c_data == NULL) {
914 smb2_set_error(smb2, "Failed to allocate connect_data");
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)");
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)");
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)");
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.");
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",
952 c_data->cb_data = cb_data;
954 err = smb2_connect_async(smb2, server, connect_cb, c_data);
956 free_c_data(smb2, c_data);
964 free_smb2fh(struct smb2_context *smb2, struct smb2fh *fh)
966 SMB2_LIST_REMOVE(&smb2->fhs, fh);
970 void smb2_free_all_fhs(struct smb2_context *smb2)
973 free_smb2fh(smb2, smb2->fhs);
978 open_cb(struct smb2_context *smb2, int status,
979 void *command_data, void *private_data)
981 struct smb2fh *fh = private_data;
982 struct smb2_create_reply *rep = command_data;
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);
992 memcpy(fh->file_id, rep->file_id, SMB2_FD_SIZE);
993 fh->cb(smb2, 0, fh, fh->cb_data);
997 smb2_open_async(struct smb2_context *smb2, const char *path, int flags,
998 smb2_command_cb cb, void *cb_data)
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;
1008 fh = malloc(sizeof(struct smb2fh));
1010 smb2_set_error(smb2, "Failed to allocate smbfh");
1013 memset(fh, 0, sizeof(struct smb2fh));
1014 SMB2_LIST_ADD(&smb2->fhs, fh);
1017 fh->cb_data = cb_data;
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;
1026 create_disposition = SMB2_FILE_OPEN_IF;
1029 if (flags & O_TRUNC) {
1030 create_disposition = SMB2_FILE_OVERWRITE;
1032 create_disposition = SMB2_FILE_OPEN;
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;
1042 if (flags & O_RDWR || !(flags & O_WRONLY)) {
1043 desired_access |= SMB2_FILE_READ_DATA |
1045 SMB2_FILE_READ_ATTRIBUTES;
1048 /* create options */
1049 create_options |= SMB2_FILE_NON_DIRECTORY_FILE;
1052 if (flags & O_SYNC) {
1053 desired_access |= SMB2_SYNCHRONIZE;
1054 create_options |= SMB2_FILE_NO_INTERMEDIATE_BUFFERING;
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;
1067 pdu = smb2_cmd_create_async(smb2, &req, open_cb, fh);
1069 smb2_set_error(smb2, "Failed to create create command");
1070 free_smb2fh(smb2, fh);
1073 smb2_queue_pdu(smb2, pdu);
1079 close_cb(struct smb2_context *smb2, int status,
1080 void *command_data, void *private_data)
1082 struct smb2fh *fh = private_data;
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);
1092 fh->cb(smb2, 0, NULL, fh->cb_data);
1093 free_smb2fh(smb2, fh);
1097 smb2_close_async(struct smb2_context *smb2, struct smb2fh *fh,
1098 smb2_command_cb cb, void *cb_data)
1100 struct smb2_close_request req;
1101 struct smb2_pdu *pdu;
1104 fh->cb_data = cb_data;
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);
1110 pdu = smb2_cmd_close_async(smb2, &req, close_cb, fh);
1112 smb2_set_error(smb2, "Failed to create close command");
1115 smb2_queue_pdu(smb2, pdu);
1121 fsync_cb(struct smb2_context *smb2, int status,
1122 void *command_data, void *private_data)
1124 struct smb2fh *fh = private_data;
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);
1133 fh->cb(smb2, 0, NULL, fh->cb_data);
1137 smb2_fsync_async(struct smb2_context *smb2, struct smb2fh *fh,
1138 smb2_command_cb cb, void *cb_data)
1140 struct smb2_flush_request req;
1141 struct smb2_pdu *pdu;
1144 fh->cb_data = cb_data;
1146 memset(&req, 0, sizeof(struct smb2_flush_request));
1147 memcpy(req.file_id, fh->file_id, SMB2_FD_SIZE);
1149 pdu = smb2_cmd_flush_async(smb2, &req, fsync_cb, fh);
1151 smb2_set_error(smb2, "Failed to create flush command");
1154 smb2_queue_pdu(smb2, pdu);
1168 read_cb(struct smb2_context *smb2, int status,
1169 void *command_data, void *private_data)
1171 struct rw_data *rd = private_data;
1172 struct smb2_read_reply *rep = command_data;
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);
1182 if (status == SMB2_STATUS_SUCCESS) {
1183 rd->fh->offset = rd->offset + rep->data_length;
1186 rd->cb(smb2, rep->data_length, NULL, rd->cb_data);
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)
1195 struct smb2_read_request req;
1197 struct smb2_pdu *pdu;
1198 int needed_credits = (count - 1) / 65536 + 1;
1200 if (count > smb2->max_read_size) {
1201 count = smb2->max_read_size;
1203 if (smb2->dialect > SMB2_VERSION_0202) {
1204 if (needed_credits > MAX_CREDITS - 16) {
1205 count = (MAX_CREDITS - 16) * 65536;
1207 needed_credits = (count - 1) / 65536 + 1;
1208 if (needed_credits > smb2->credits) {
1209 count = smb2->credits * 65536;
1212 if (count > 65536) {
1217 rd = malloc(sizeof(struct rw_data));
1219 smb2_set_error(smb2, "Failed to allocate rw_data");
1222 memset(rd, 0, sizeof(struct rw_data));
1225 rd->cb_data = cb_data;
1227 rd->offset = offset;
1229 memset(&req, 0, sizeof(struct smb2_read_request));
1232 req.offset = offset;
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;
1239 pdu = smb2_cmd_read_async(smb2, &req, read_cb, rd);
1241 smb2_set_error(smb2, "Failed to create read command");
1245 smb2_queue_pdu(smb2, pdu);
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)
1255 return smb2_pread_async(smb2, fh, buf, count, fh->offset,
1260 write_cb(struct smb2_context *smb2, int status,
1261 void *command_data, void *private_data)
1263 struct rw_data *rd = private_data;
1264 struct smb2_write_reply *rep = command_data;
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);
1274 if (status == SMB2_STATUS_SUCCESS) {
1275 rd->fh->offset = rd->offset + rep->count;
1278 rd->cb(smb2, rep->count, NULL, rd->cb_data);
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)
1287 struct smb2_write_request req;
1289 struct smb2_pdu *pdu;
1290 int needed_credits = (count - 1) / 65536 + 1;
1292 if (count > smb2->max_write_size) {
1293 count = smb2->max_write_size;
1295 if (smb2->dialect > SMB2_VERSION_0202) {
1296 if (needed_credits > MAX_CREDITS - 16) {
1297 count = (MAX_CREDITS - 16) * 65536;
1299 needed_credits = (count - 1) / 65536 + 1;
1300 if (needed_credits > smb2->credits) {
1301 count = smb2->credits * 65536;
1304 if (count > 65536) {
1309 rd = malloc(sizeof(struct rw_data));
1311 smb2_set_error(smb2, "Failed to allocate rw_data");
1314 memset(rd, 0, sizeof(struct rw_data));
1317 rd->cb_data = cb_data;
1319 rd->offset = offset;
1321 memset(&req, 0, sizeof(struct smb2_write_request));
1323 req.offset = offset;
1325 memcpy(req.file_id, fh->file_id, SMB2_FD_SIZE);
1326 req.channel = SMB2_CHANNEL_NONE;
1327 req.remaining_bytes = 0;
1330 pdu = smb2_cmd_write_async(smb2, &req, write_cb, rd);
1332 smb2_set_error(smb2, "Failed to create write command");
1335 smb2_queue_pdu(smb2, pdu);
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)
1345 return smb2_pwrite_async(smb2, fh, buf, count, fh->offset,
1350 smb2_lseek(struct smb2_context *smb2, struct smb2fh *fh,
1351 int64_t offset, int whence, uint64_t *current_offset)
1356 smb2_set_error(smb2, "Lseek() offset would become"
1360 fh->offset = offset;
1361 if (current_offset) {
1362 *current_offset = fh->offset;
1366 if (fh->offset + offset < 0) {
1367 smb2_set_error(smb2, "Lseek() offset would become"
1371 fh->offset += offset;
1372 if (current_offset) {
1373 *current_offset = fh->offset;
1377 smb2_set_error(smb2, "SEEK_END not implemented");
1380 smb2_set_error(smb2, "Invalid whence(%d) for lseek",
1386 struct create_cb_data {
1392 create_cb_2(struct smb2_context *smb2, int status,
1393 void *command_data, void *private_data)
1395 struct create_cb_data *create_data = private_data;
1397 if (status != SMB2_STATUS_SUCCESS) {
1398 create_data->cb(smb2, -nterror_to_errno(status),
1399 NULL, create_data->cb_data);
1404 create_data->cb(smb2, 0, NULL, create_data->cb_data);
1409 create_cb_1(struct smb2_context *smb2, int status,
1410 void *command_data, void *private_data)
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;
1417 if (status != SMB2_STATUS_SUCCESS) {
1418 create_data->cb(smb2, -nterror_to_errno(status),
1419 NULL, create_data->cb_data);
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);
1428 pdu = smb2_cmd_close_async(smb2, &req, create_cb_2, create_data);
1430 create_data->cb(smb2, -ENOMEM, NULL, create_data->cb_data);
1434 smb2_queue_pdu(smb2, pdu);
1438 smb2_unlink_internal(struct smb2_context *smb2, const char *path,
1440 smb2_command_cb cb, void *cb_data)
1442 struct create_cb_data *create_data;
1443 struct smb2_create_request req;
1444 struct smb2_pdu *pdu;
1446 create_data = malloc(sizeof(struct create_cb_data));
1447 if (create_data == NULL) {
1448 smb2_set_error(smb2, "Failed to allocate create_data");
1451 memset(create_data, 0, sizeof(struct create_cb_data));
1453 create_data->cb = cb;
1454 create_data->cb_data = cb_data;
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;
1462 req.file_attributes = SMB2_FILE_ATTRIBUTE_DIRECTORY;
1464 req.file_attributes = SMB2_FILE_ATTRIBUTE_NORMAL;
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;
1472 pdu = smb2_cmd_create_async(smb2, &req, create_cb_1, create_data);
1474 smb2_set_error(smb2, "Failed to create create command");
1477 smb2_queue_pdu(smb2, pdu);
1483 smb2_unlink_async(struct smb2_context *smb2, const char *path,
1484 smb2_command_cb cb, void *cb_data)
1486 return smb2_unlink_internal(smb2, path, 0, cb, cb_data);
1490 smb2_rmdir_async(struct smb2_context *smb2, const char *path,
1491 smb2_command_cb cb, void *cb_data)
1493 return smb2_unlink_internal(smb2, path, 1, cb, cb_data);
1497 smb2_mkdir_async(struct smb2_context *smb2, const char *path,
1498 smb2_command_cb cb, void *cb_data)
1500 struct create_cb_data *create_data;
1501 struct smb2_create_request req;
1502 struct smb2_pdu *pdu;
1504 create_data = malloc(sizeof(struct create_cb_data));
1505 if (create_data == NULL) {
1506 smb2_set_error(smb2, "Failed to allocate create_data");
1509 memset(create_data, 0, sizeof(struct create_cb_data));
1511 create_data->cb = cb;
1512 create_data->cb_data = cb_data;
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;
1524 pdu = smb2_cmd_create_async(smb2, &req, create_cb_1, create_data);
1526 smb2_set_error(smb2, "Failed to create create command");
1529 smb2_queue_pdu(smb2, pdu);
1534 struct stat_cb_data {
1540 uint8_t file_info_class;
1545 fstat_cb_1(struct smb2_context *smb2, int status,
1546 void *command_data, void *private_data)
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;
1553 if (status != SMB2_STATUS_SUCCESS) {
1554 stat_data->cb(smb2, -nterror_to_errno(status),
1555 NULL, stat_data->cb_data);
1560 st->smb2_type = SMB2_TYPE_FILE;
1561 if (fs->basic.file_attributes & SMB2_FILE_ATTRIBUTE_DIRECTORY) {
1562 st->smb2_type = SMB2_TYPE_DIRECTORY;
1564 if (fs->basic.file_attributes & SMB2_FILE_ATTRIBUTE_REPARSE_POINT) {
1565 st->smb2_type = SMB2_TYPE_LINK;
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 *
1573 st->smb2_mtime = fs->basic.last_write_time.tv_sec;
1574 st->smb2_mtime_nsec = fs->basic.last_write_time.tv_usec *
1576 st->smb2_ctime = fs->basic.change_time.tv_sec;
1577 st->smb2_ctime_nsec = fs->basic.change_time.tv_usec *
1579 st->smb2_btime = fs->basic.creation_time.tv_sec;
1580 st->smb2_btime_nsec = fs->basic.creation_time.tv_usec *
1583 smb2_free_data(smb2, fs);
1585 stat_data->cb(smb2, 0, st, stat_data->cb_data);
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)
1594 struct stat_cb_data *stat_data;
1595 struct smb2_query_info_request req;
1596 struct smb2_pdu *pdu;
1598 stat_data = malloc(sizeof(struct stat_cb_data));
1599 if (stat_data == NULL) {
1600 smb2_set_error(smb2, "Failed to allocate stat_data");
1603 memset(stat_data, 0, sizeof(struct stat_cb_data));
1606 stat_data->cb_data = cb_data;
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;
1615 memcpy(req.file_id, fh->file_id, SMB2_FD_SIZE);
1617 pdu = smb2_cmd_query_info_async(smb2, &req, fstat_cb_1, stat_data);
1619 smb2_set_error(smb2, "Failed to create query command");
1623 smb2_queue_pdu(smb2, pdu);
1629 getinfo_cb_3(struct smb2_context *smb2, int status,
1630 void *command_data _U_, void *private_data)
1632 struct stat_cb_data *stat_data = private_data;
1634 if (stat_data->status == SMB2_STATUS_SUCCESS) {
1635 stat_data->status = status;
1638 stat_data->cb(smb2, -nterror_to_errno(stat_data->status),
1639 stat_data->st, stat_data->cb_data);
1644 getinfo_cb_2(struct smb2_context *smb2, int status,
1645 void *command_data, void *private_data)
1647 struct stat_cb_data *stat_data = private_data;
1648 struct smb2_query_info_reply *rep = command_data;
1650 if (stat_data->status == SMB2_STATUS_SUCCESS) {
1651 stat_data->status = status;
1653 if (stat_data->status != SMB2_STATUS_SUCCESS) {
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;
1662 st->smb2_type = SMB2_TYPE_FILE;
1663 if (fs->basic.file_attributes & SMB2_FILE_ATTRIBUTE_DIRECTORY) {
1664 st->smb2_type = SMB2_TYPE_DIRECTORY;
1666 if (fs->basic.file_attributes & SMB2_FILE_ATTRIBUTE_REPARSE_POINT) {
1667 st->smb2_type = SMB2_TYPE_LINK;
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 *
1675 st->smb2_mtime = fs->basic.last_write_time.tv_sec;
1676 st->smb2_mtime_nsec = fs->basic.last_write_time.tv_usec *
1678 st->smb2_ctime = fs->basic.change_time.tv_sec;
1679 st->smb2_ctime_nsec = fs->basic.change_time.tv_usec *
1681 st->smb2_btime = fs->basic.creation_time.tv_sec;
1682 st->smb2_btime_nsec = fs->basic.creation_time.tv_usec *
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;
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;
1697 smb2_free_data(smb2, rep->output_buffer);
1701 getinfo_cb_1(struct smb2_context *smb2, int status,
1702 void *command_data _U_, void *private_data)
1704 struct stat_cb_data *stat_data = private_data;
1706 if (stat_data->status == SMB2_STATUS_SUCCESS) {
1707 stat_data->status = status;
1712 smb2_getinfo_async(struct smb2_context *smb2, const char *path,
1713 uint8_t info_type, uint8_t file_info_class,
1715 smb2_command_cb cb, void *cb_data)
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;
1723 stat_data = malloc(sizeof(struct stat_cb_data));
1724 if (stat_data == NULL) {
1725 smb2_set_error(smb2, "Failed to allocate create_data");
1728 memset(stat_data, 0, sizeof(struct stat_cb_data));
1731 stat_data->cb_data = cb_data;
1732 stat_data->info_type = info_type;
1733 stat_data->file_info_class = file_info_class;
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;
1747 pdu = smb2_cmd_create_async(smb2, &cr_req, getinfo_cb_1, stat_data);
1749 smb2_set_error(smb2, "Failed to create create command");
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;
1761 memcpy(qi_req.file_id, compound_file_id, SMB2_FD_SIZE);
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");
1768 smb2_free_pdu(smb2, pdu);
1771 smb2_add_compound_pdu(smb2, pdu, next_pdu);
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);
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);
1782 smb2_free_pdu(smb2, pdu);
1785 smb2_add_compound_pdu(smb2, pdu, next_pdu);
1787 smb2_queue_pdu(smb2, pdu);
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)
1797 return smb2_getinfo_async(smb2, path,
1799 SMB2_FILE_ALL_INFORMATION,
1804 smb2_statvfs_async(struct smb2_context *smb2, const char *path,
1805 struct smb2_statvfs *statvfs,
1806 smb2_command_cb cb, void *cb_data)
1808 return smb2_getinfo_async(smb2, path,
1809 SMB2_0_INFO_FILESYSTEM,
1810 SMB2_FILE_FS_FULL_SIZE_INFORMATION,
1811 statvfs, cb, cb_data);
1814 struct trunc_cb_data {
1823 trunc_cb_3(struct smb2_context *smb2, int status,
1824 void *command_data _U_, void *private_data)
1826 struct trunc_cb_data *trunc_data = private_data;
1828 if (trunc_data->status == SMB2_STATUS_SUCCESS) {
1829 trunc_data->status = status;
1832 trunc_data->cb(smb2, -nterror_to_errno(trunc_data->status),
1833 NULL, trunc_data->cb_data);
1838 trunc_cb_2(struct smb2_context *smb2, int status,
1839 void *command_data, void *private_data)
1841 struct trunc_cb_data *trunc_data = private_data;
1843 if (trunc_data->status == SMB2_STATUS_SUCCESS) {
1844 trunc_data->status = status;
1849 trunc_cb_1(struct smb2_context *smb2, int status,
1850 void *command_data _U_, void *private_data)
1852 struct trunc_cb_data *trunc_data = private_data;
1854 if (trunc_data->status == SMB2_STATUS_SUCCESS) {
1855 trunc_data->status = status;
1860 smb2_truncate_async(struct smb2_context *smb2, const char *path,
1861 uint64_t length, smb2_command_cb cb, void *cb_data)
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;
1870 trunc_data = malloc(sizeof(struct trunc_cb_data));
1871 if (trunc_data == NULL) {
1872 smb2_set_error(smb2, "Failed to allocate trunc_data");
1875 memset(trunc_data, 0, sizeof(struct trunc_cb_data));
1877 trunc_data->cb = cb;
1878 trunc_data->cb_data = cb_data;
1879 trunc_data->length = length;
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;
1892 pdu = smb2_cmd_create_async(smb2, &cr_req, trunc_cb_1, trunc_data);
1894 smb2_set_error(smb2, "Failed to create create command");
1899 /* SET INFO command */
1900 eofi.end_of_file = length;
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;
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));
1915 smb2_free_pdu(smb2, pdu);
1918 smb2_add_compound_pdu(smb2, pdu, next_pdu);
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);
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);
1929 smb2_free_pdu(smb2, pdu);
1932 smb2_add_compound_pdu(smb2, pdu, next_pdu);
1934 smb2_queue_pdu(smb2, pdu);
1939 struct rename_cb_data {
1946 rename_cb_3(struct smb2_context *smb2, int status,
1947 void *command_data _U_, void *private_data)
1949 struct rename_cb_data *rename_data = private_data;
1951 if (rename_data->status == SMB2_STATUS_SUCCESS) {
1952 rename_data->status = status;
1955 rename_data->cb(smb2, -nterror_to_errno(rename_data->status),
1956 NULL, rename_data->cb_data);
1961 rename_cb_2(struct smb2_context *smb2, int status,
1962 void *command_data _U_, void *private_data)
1964 struct rename_cb_data *rename_data = private_data;
1966 if (rename_data->status == SMB2_STATUS_SUCCESS) {
1967 rename_data->status = status;
1972 rename_cb_1(struct smb2_context *smb2, int status,
1973 void *command_data _U_, void *private_data)
1975 struct rename_cb_data *rename_data = private_data;
1977 if (rename_data->status == SMB2_STATUS_SUCCESS) {
1978 rename_data->status = status;
1983 smb2_rename_async(struct smb2_context *smb2, const char *oldpath,
1984 const char *newpath, smb2_command_cb cb, void *cb_data)
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;
1993 rename_data = malloc(sizeof(struct rename_cb_data));
1994 if (rename_data == NULL) {
1995 smb2_set_error(smb2, "Failed to allocate rename_data");
1998 memset(rename_data, 0, sizeof(struct rename_cb_data));
2000 rename_data->cb = cb;
2001 rename_data->cb_data = cb_data;
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;
2014 pdu = smb2_cmd_create_async(smb2, &cr_req, rename_cb_1, rename_data);
2016 smb2_set_error(smb2, "Failed to create create command");
2021 /* SET INFO command */
2022 rn_info.replace_if_exist = 0;
2023 rn_info.file_name = discard_const(newpath);
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;
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));
2038 smb2_free_pdu(smb2, pdu);
2041 smb2_add_compound_pdu(smb2, pdu, next_pdu);
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);
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);
2052 smb2_free_pdu(smb2, pdu);
2055 smb2_add_compound_pdu(smb2, pdu, next_pdu);
2057 smb2_queue_pdu(smb2, pdu);
2063 ftrunc_cb_1(struct smb2_context *smb2, int status,
2064 void *command_data _U_, void *private_data)
2066 struct create_cb_data *cb_data = private_data;
2068 cb_data->cb(smb2, -nterror_to_errno(status),
2069 NULL, cb_data->cb_data);
2074 smb2_ftruncate_async(struct smb2_context *smb2, struct smb2fh *fh,
2075 uint64_t length, smb2_command_cb cb, void *cb_data)
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;
2082 create_data = malloc(sizeof(struct create_cb_data));
2083 if (create_data == NULL) {
2084 smb2_set_error(smb2, "Failed to allocate create_data");
2087 memset(create_data, 0, sizeof(struct create_cb_data));
2089 create_data->cb = cb;
2090 create_data->cb_data = cb_data;
2092 eofi.end_of_file = length;
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;
2101 pdu = smb2_cmd_set_info_async(smb2, &req, ftrunc_cb_1, create_data);
2103 smb2_set_error(smb2, "Failed to create set info command");
2106 smb2_queue_pdu(smb2, pdu);
2111 struct readlink_cb_data {
2116 struct smb2_reparse_data_buffer *reparse;
2120 readlink_cb_3(struct smb2_context *smb2, int status,
2121 void *command_data _U_, void *private_data)
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>";
2128 switch (rp->reparse_tag) {
2129 case SMB2_REPARSE_TAG_SYMLINK:
2130 target = rp->symlink.subname;
2133 cb_data->cb(smb2, -nterror_to_errno(cb_data->status),
2134 target, cb_data->cb_data);
2135 smb2_free_data(smb2, rp);
2140 readlink_cb_2(struct smb2_context *smb2, int status,
2141 void *command_data, void *private_data)
2143 struct readlink_cb_data *cb_data = private_data;
2144 struct smb2_ioctl_reply *rep = command_data;
2146 if (cb_data->status == SMB2_STATUS_SUCCESS) {
2147 cb_data->status = status;
2149 if (status == SMB2_STATUS_NOT_A_REPARSE_POINT) {
2150 smb2_set_error(smb2, "Not a reparse point");
2152 if (status == SMB2_STATUS_SUCCESS) {
2153 cb_data->reparse = rep->output;
2158 readlink_cb_1(struct smb2_context *smb2, int status,
2159 void *command_data _U_, void *private_data)
2161 struct readlink_cb_data *cb_data = private_data;
2163 if (status != SMB2_STATUS_SUCCESS) {
2164 smb2_set_error(smb2, "%s", nterror_to_str(status));
2166 cb_data->status = status;
2170 smb2_readlink_async(struct smb2_context *smb2, const char *path,
2171 smb2_command_cb cb, void *cb_data)
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;
2179 readlink_data = malloc(sizeof(struct readlink_cb_data));
2180 if (readlink_data == NULL) {
2181 smb2_set_error(smb2, "Failed to allocate readlink_data");
2184 memset(readlink_data, 0, sizeof(struct readlink_cb_data));
2186 readlink_data->cb = cb;
2187 readlink_data->cb_data = cb_data;
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;
2201 pdu = smb2_cmd_create_async(smb2, &cr_req, readlink_cb_1, readlink_data);
2203 smb2_set_error(smb2, "Failed to create create command");
2204 free(readlink_data);
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;
2216 next_pdu = smb2_cmd_ioctl_async(smb2, &io_req, readlink_cb_2,
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);
2224 smb2_add_compound_pdu(smb2, pdu, next_pdu);
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);
2231 next_pdu = smb2_cmd_close_async(smb2, &cl_req, readlink_cb_3,
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);
2239 smb2_add_compound_pdu(smb2, pdu, next_pdu);
2241 smb2_queue_pdu(smb2, pdu);
2246 struct disconnect_data {
2252 disconnect_cb_2(struct smb2_context *smb2, int status,
2253 void *command_data _U_, void *private_data)
2255 struct disconnect_data *dc_data = private_data;
2257 dc_data->cb(smb2, 0, NULL, dc_data->cb_data);
2264 disconnect_cb_1(struct smb2_context *smb2, int status,
2265 void *command_data _U_, void *private_data)
2267 struct disconnect_data *dc_data = private_data;
2268 struct smb2_pdu *pdu;
2270 pdu = smb2_cmd_logoff_async(smb2, disconnect_cb_2, dc_data);
2272 dc_data->cb(smb2, -ENOMEM, NULL, dc_data->cb_data);
2276 smb2_queue_pdu(smb2, pdu);
2280 smb2_disconnect_share_async(struct smb2_context *smb2,
2281 smb2_command_cb cb, void *cb_data)
2283 struct disconnect_data *dc_data;
2284 struct smb2_pdu *pdu;
2286 dc_data = malloc(sizeof(struct disconnect_data));
2287 if (dc_data == NULL) {
2288 smb2_set_error(smb2, "Failed to allocate disconnect_data");
2291 memset(dc_data, 0, sizeof(struct disconnect_data));
2294 dc_data->cb_data = cb_data;
2296 pdu = smb2_cmd_tree_disconnect_async(smb2, disconnect_cb_1, dc_data);
2301 smb2_queue_pdu(smb2, pdu);
2312 echo_cb(struct smb2_context *smb2, int status,
2313 void *command_data _U_, void *private_data)
2315 struct echo_data *cb_data = private_data;
2317 cb_data->cb(smb2, -nterror_to_errno(status),
2318 NULL, cb_data->cb_data);
2323 smb2_echo_async(struct smb2_context *smb2,
2324 smb2_command_cb cb, void *cb_data)
2326 struct echo_data *echo_data;
2327 struct smb2_pdu *pdu;
2329 echo_data = malloc(sizeof(struct echo_data));
2330 if (echo_data == NULL) {
2331 smb2_set_error(smb2, "Failed to allocate echo_data");
2334 memset(echo_data, 0, sizeof(struct echo_data));
2337 echo_data->cb_data = cb_data;
2339 pdu = smb2_cmd_echo_async(smb2, echo_cb, echo_data);
2344 smb2_queue_pdu(smb2, pdu);
2350 smb2_get_max_read_size(struct smb2_context *smb2)
2352 return smb2->max_read_size;
2356 smb2_get_max_write_size(struct smb2_context *smb2)
2358 return smb2->max_write_size;
2362 smb2_get_file_id(struct smb2fh *fh)
2364 return &fh->file_id;
2368 smb2_fh_from_file_id(struct smb2_context *smb2, smb2_file_id *fileid)
2372 fh = malloc(sizeof(struct smb2fh));
2376 memset(fh, 0, sizeof(struct smb2fh));
2377 memcpy(fh->file_id, fileid, SMB2_FD_SIZE);
2378 SMB2_LIST_ADD(&smb2->fhs, fh);