ssize_t smb_fread(smb_session *s, smb_fd fd, void *buf, size_t buf_size) { smb_file *file; smb_message *req_msg, resp_msg; smb_read_req req; smb_read_resp *resp; size_t max_read; int res; assert(s != NULL && buf != NULL); if (!fd) return (-1); if ((file = smb_session_file_get(s, fd)) == NULL) return (-1); req_msg = smb_message_new(SMB_CMD_READ); if (!req_msg) return (-1); req_msg->packet->header.tid = file->tid; max_read = 0xffff; max_read = max_read < buf_size ? max_read : buf_size; SMB_MSG_INIT_PKT_ANDX(req); req.wct = 12; req.fid = file->fid; req.offset = file->readp; req.max_count = max_read; req.min_count = max_read; req.max_count_high = 0; req.remaining = 0; req.offset_high = 0; req.bct = 0; SMB_MSG_PUT_PKT(req_msg, req); res = smb_session_send_msg(s, req_msg); smb_message_destroy(req_msg); if (!res) return (-1); if (!smb_session_recv_msg(s, &resp_msg)) return (-1); if (resp_msg.packet->header.status != NT_STATUS_SUCCESS) return (-1); resp = (smb_read_resp *)resp_msg.packet->payload; memcpy(buf, resp->file, resp->data_len); smb_fseek(s, fd, resp->data_len, SEEK_CUR); return (resp->data_len); }
smb_fd smb_fopen(smb_session *s, smb_tid tid, const char *path, uint32_t o_flags) { smb_share *share; smb_file *file; smb_message *req_msg, resp_msg; smb_create_req req; smb_create_resp *resp; size_t path_len; int res; char *utf_path; assert(s != NULL && path != NULL); if ((share = smb_session_share_get(s, tid)) == NULL) return (0); path_len = smb_to_utf16(path, strlen(path) + 1, &utf_path); if (path_len == 0) return (0); req_msg = smb_message_new(SMB_CMD_CREATE); if (!req_msg) { free(utf_path); return (0); } // Set SMB Headers req_msg->packet->header.tid = tid; // Create AndX Params SMB_MSG_INIT_PKT_ANDX(req); req.wct = 24; req.flags = 0; req.root_fid = 0; req.access_mask = o_flags; req.alloc_size = 0; req.file_attr = 0; req.share_access = SMB_SHARE_READ | SMB_SHARE_WRITE; req.disposition = 1; // 1 = Open and file if doesn't exist req.create_opts = 0; // We dont't support create req.impersonation = 2; // ????? req.security_flags = 0; // ??? req.path_length = path_len; req.bct = path_len + 1; SMB_MSG_PUT_PKT(req_msg, req); // Create AndX 'Body' smb_message_put8(req_msg, 0); // Align beginning of path smb_message_append(req_msg, utf_path, path_len); free(utf_path); // smb_message_put16(req_msg, 0); // ?? res = smb_session_send_msg(s, req_msg); smb_message_destroy(req_msg); if (!res) return (0); if (!smb_session_recv_msg(s, &resp_msg)) return (0); if (resp_msg.packet->header.status != NT_STATUS_SUCCESS) return (0); resp = (smb_create_resp *)resp_msg.packet->payload; file = calloc(1, sizeof(smb_file)); if (!file) return (0); file->fid = resp->fid; file->tid = tid; file->created = resp->created; file->accessed = resp->accessed; file->written = resp->written; file->changed = resp->changed; file->alloc_size = resp->alloc_size; file->size = resp->size; file->attr = resp->attr; file->is_dir = resp->is_dir; smb_session_file_add(s, tid, file); // XXX Check return return (SMB_FD(tid, file->fid)); }
static int auth(smb_session *s, const char *domain, const char *user, const char *password) { smb_message *msg = NULL, resp; smb_session_xsec_req req; smb_buffer ntlm; ASN1_TYPE token; int res, der_size = 512; char der[512], err_desc[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; msg = smb_message_new(SMB_CMD_SETUP); if (!msg) return DSM_ERROR_GENERIC; // this struct will be set at the end when we know the payload size SMB_MSG_ADVANCE_PKT(msg, smb_session_xsec_req); asn1_create_element(s->spnego_asn1, "SPNEGO.NegotiationToken", &token); // Select a response message type res = asn1_write_value(token, "", "negTokenResp", 1); if (res != ASN1_SUCCESS) goto error; // Delete all optionnal field except 'ResponseToken' res = asn1_write_value(token, "negTokenResp.negResult", NULL, 0); if (res != ASN1_SUCCESS) goto error; res = asn1_write_value(token, "negTokenResp.supportedMech", NULL, 0); if (res != ASN1_SUCCESS) goto error; res = asn1_write_value(token, "negTokenResp.mechListMIC", NULL, 0); if (res != ASN1_SUCCESS) goto error; smb_ntlmssp_response(s->srv.challenge, s->srv.ts - 4200, domain, domain, user, password, &s->xsec_target, &ntlm); res = asn1_write_value(token, "negTokenResp.responseToken", ntlm.data, ntlm.size); smb_buffer_free(&ntlm); if (res != ASN1_SUCCESS) goto error; res = asn1_der_coding(token, "", der, &der_size, err_desc); if (res != ASN1_SUCCESS) { smb_message_destroy(msg); BDSM_dbg("Encoding error: %s", err_desc); return DSM_ERROR_GENERIC; } smb_message_append(msg, der, der_size); if (msg->cursor % 2) smb_message_put8(msg, 0); smb_message_put_utf16(msg, SMB_OS, strlen(SMB_OS)); smb_message_put16(msg, 0); smb_message_put_utf16(msg, SMB_LANMAN, strlen(SMB_LANMAN)); smb_message_put16(msg, 0); smb_message_put16(msg, 0); // Empty PDC name SMB_MSG_INIT_PKT_ANDX(req); req.wct = 12; req.max_buffer = SMB_SESSION_MAX_BUFFER; req.mpx_count = 16; // XXX ? req.vc_count = 1; req.caps = s->srv.caps; // XXX caps & our_caps_mask req.session_key = s->srv.session_key; req.xsec_blob_size = der_size; req.payload_size = msg->cursor - sizeof(smb_session_xsec_req); SMB_MSG_INSERT_PKT(msg, 0, req); asn1_delete_structure(&token); if (!smb_session_send_msg(s, msg)) { smb_message_destroy(msg); BDSM_dbg("Unable to send Session Setup AndX (NTLMSSP_AUTH) message\n"); return DSM_ERROR_NETWORK; } smb_message_destroy(msg); if (smb_session_recv_msg(s, &resp) == 0) return DSM_ERROR_NETWORK; if (!smb_session_check_nt_status(s, &resp)) return DSM_ERROR_NT; else { smb_session_xsec_resp *r = (smb_session_xsec_resp *)resp.packet->payload; if (r->action & 0x0001) s->guest = true; s->srv.uid = resp.packet->header.uid; s->logged = true; return DSM_SUCCESS; } error: asn1_display_error("smb_session_login auth()", res); smb_message_destroy(msg); return DSM_ERROR_GENERIC; }
static int negotiate(smb_session *s, const char *domain) { smb_message *msg = NULL; smb_session_xsec_req req; smb_buffer ntlm; ASN1_TYPE token; int res, der_size = 128; char der[128], err_desc[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; msg = smb_message_new(SMB_CMD_SETUP); if (!msg) return DSM_ERROR_GENERIC; // this struct will be set at the end when we know the payload size SMB_MSG_ADVANCE_PKT(msg, smb_session_xsec_req); asn1_create_element(s->spnego_asn1, "SPNEGO.GSSAPIContextToken", &token); res = asn1_write_value(token, "thisMech", spnego_oid, 1); if (res != ASN1_SUCCESS) goto error; res = asn1_write_value(token, "spnego", "negTokenInit", 1); if (res != ASN1_SUCCESS) goto error; res = asn1_write_value(token, "spnego.negTokenInit.mechTypes", "NEW", 1); if (res != ASN1_SUCCESS) goto error; res = asn1_write_value(token, "spnego.negTokenInit.mechTypes.?1", ntlmssp_oid, 1); if (res != ASN1_SUCCESS) goto error; res = asn1_write_value(token, "spnego.negTokenInit.reqFlags", NULL, 0); if (res != ASN1_SUCCESS) goto error; res = asn1_write_value(token, "spnego.negTokenInit.mechListMIC", NULL, 0); if (res != ASN1_SUCCESS) goto error; smb_ntlmssp_negotiate(domain, domain, &ntlm); res = asn1_write_value(token, "spnego.negTokenInit.mechToken", ntlm.data, ntlm.size); smb_buffer_free(&ntlm); if (res != ASN1_SUCCESS) goto error; res = asn1_der_coding(token, "", der, &der_size, err_desc); if (res != ASN1_SUCCESS) { smb_message_destroy(msg); BDSM_dbg("Encoding error: %s", err_desc); return DSM_ERROR_GENERIC; } smb_message_append(msg, der, der_size); smb_message_put_utf16(msg, SMB_OS, strlen(SMB_OS)); smb_message_put16(msg, 0); smb_message_put_utf16(msg, SMB_LANMAN, strlen(SMB_LANMAN)); smb_message_put16(msg, 0); smb_message_put16(msg, 0); SMB_MSG_INIT_PKT_ANDX(req); req.wct = 12; req.max_buffer = SMB_SESSION_MAX_BUFFER; req.mpx_count = 16; req.vc_count = 1; req.caps = s->srv.caps; req.session_key = s->srv.session_key; req.xsec_blob_size = der_size; req.payload_size = msg->cursor - sizeof(smb_session_xsec_req); SMB_MSG_INSERT_PKT(msg, 0, req); asn1_delete_structure(&token); if (!smb_session_send_msg(s, msg)) { smb_message_destroy(msg); BDSM_dbg("Unable to send Session Setup AndX (NTLMSSP_NEGOTIATE) message\n"); return DSM_ERROR_NETWORK; } smb_message_destroy(msg); return DSM_SUCCESS; error: asn1_display_error("smb_session_login negotiate()", res); smb_message_destroy(msg); return DSM_ERROR_GENERIC; }
int smb_tree_connect(smb_session *s, const char *name, smb_tid *tid) { smb_tree_connect_req req; smb_tree_connect_resp *resp; smb_message resp_msg; smb_message *req_msg; smb_share *share; size_t path_len, utf_path_len; char *path, *utf_path; assert(s != NULL && name != NULL && tid != NULL); if( s != NULL && name != NULL && tid != NULL ) { req_msg = smb_message_new(SMB_CMD_TREE_CONNECT); if (!req_msg) return DSM_ERROR_GENERIC; // Build \\SERVER\Share path from name path_len = strlen(name) + strlen(s->srv.name) + 4; path = alloca(path_len); snprintf(path, path_len, "\\\\%s\\%s", s->srv.name, name); utf_path_len = smb_to_utf16(path, strlen(path) + 1, &utf_path); // Packet headers req_msg->packet->header.tid = 0xffff; // Behavior of libsmbclient smb_message_set_andx_members(req_msg); // Packet payload SMB_MSG_INIT_PKT_ANDX(req); req.wct = 4; req.flags = 0x0c; // (??) req.passwd_len = 1; // Null byte req.bct = utf_path_len + 6 + 1; SMB_MSG_PUT_PKT(req_msg, req); smb_message_put8(req_msg, 0); // Ze null byte password; smb_message_append(req_msg, utf_path, utf_path_len); free(utf_path); smb_message_append(req_msg, "?????", strlen("?????") + 1); if (!smb_session_send_msg(s, req_msg)) { smb_message_destroy(req_msg); return DSM_ERROR_NETWORK; } smb_message_destroy(req_msg); if (!smb_session_recv_msg(s, &resp_msg)) return DSM_ERROR_NETWORK; if (!smb_session_check_nt_status(s, &resp_msg)) return DSM_ERROR_NT; resp = (smb_tree_connect_resp *)resp_msg.packet->payload; share = calloc(1, sizeof(smb_share)); if (!share) return DSM_ERROR_GENERIC; share->tid = resp_msg.packet->header.tid; share->opts = resp->opt_support; share->rights = resp->max_rights; share->guest_rights = resp->guest_rights; smb_session_share_add(s, share); *tid = share->tid; return 0; } return DSM_ERROR_GENERIC; }