123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366 |
- /*****************************************************************************
- * __________________ _________ _____ _____ .__ ._.
- * \______ \______ \ / _____/ / \ / _ \ |__| ____ | |
- * | | _/| | \ \_____ \ / \ / \ / /_\ \| _/ __ \ | |
- * | | \| ` \/ / Y \ / | | \ ___/ \|
- * |______ /_______ /_______ \____|__ / /\ \____|__ |__|\___ | __
- * \/ \/ \/ \/ )/ \/ \/ \/
- *
- * This file is part of liBDSM. Copyright © 2014-2015 VideoLabs SAS
- *
- * Author: Julien 'Lta' BALLET <contact@lta.io>
- *
- * liBDSM is released under LGPLv2.1 (or later) and is also available
- * under a commercial license.
- *****************************************************************************
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
- *****************************************************************************/
- #include "config.h"
- #include "compat.h"
- #include <stdlib.h>
- #include <string.h>
- #include <stdio.h>
- #include <assert.h>
- #include "bdsm_debug.h"
- #include "smb_session.h"
- #include "smb_session_msg.h"
- #include "smb_fd.h"
- #include "smb_ntlm.h"
- #include "smb_spnego.h"
- #include "smb_transport.h"
- static int smb_negotiate(smb_session *s);
- smb_session *smb_session_new()
- {
- smb_session *s;
- s = calloc(1, sizeof(smb_session));
- if (!s)
- return NULL;
- s->guest = false;
- // Explicitly sets pointer to NULL, insted of 0
- s->spnego_asn1 = NULL;
- s->transport.session = NULL;
- s->shares = NULL;
- s->creds.domain = NULL;
- s->creds.login = NULL;
- s->creds.password = NULL;
- smb_buffer_init(&s->xsec_target, NULL, 0);
- // Until we know more, assume server supports everything.
- // s->c
- return s;
- }
- void smb_session_destroy(smb_session *s)
- {
- assert(s != NULL);
- smb_session_share_clear(s);
- // FIXME Free smb_share and smb_file
- if (s->transport.session != NULL)
- {
- s->transport.destroy(s->transport.session);
- s->transport.session = NULL;
- }
- if (s->spnego_asn1 != NULL)
- asn1_delete_structure(&s->spnego_asn1);
- smb_buffer_free(&s->xsec_target);
- // Free stored credentials.
- free(s->creds.domain);
- free(s->creds.login);
- free(s->creds.password);
- free(s);
- }
- void smb_session_set_creds(smb_session *s, const char *domain,
- const char *login, const char *password)
- {
- assert(s != NULL);
- if (domain != NULL)
- {
- if (s->creds.domain != NULL)
- free(s->creds.domain);
- s->creds.domain = strndup(domain, SMB_CREDS_MAXLEN);
- }
- if (login != NULL)
- {
- if (s->creds.login != NULL)
- free(s->creds.login);
- s->creds.login = strndup(login, SMB_CREDS_MAXLEN);
- }
- if (password != NULL)
- {
- if (s->creds.password != NULL)
- free(s->creds.password);
- s->creds.password = strndup(password, SMB_CREDS_MAXLEN);
- }
- }
- int smb_session_connect(smb_session *s, const char *name,
- uint32_t ip, int transport)
- {
- assert(s != NULL && name != NULL);
- if (s->transport.session != NULL)
- s->transport.destroy(s->transport.session);
- switch (transport)
- {
- case SMB_TRANSPORT_TCP:
- smb_transport_tcp(&s->transport);
- break;
- case SMB_TRANSPORT_NBT:
- smb_transport_nbt(&s->transport);
- break;
- default:
- return DSM_ERROR_GENERIC;
- }
- if ((s->transport.session = s->transport.new(SMB_DEFAULT_BUFSIZE)) == NULL)
- return DSM_ERROR_GENERIC;
- if (!s->transport.connect(ip, s->transport.session, name))
- return DSM_ERROR_NETWORK;
- memcpy(s->srv.name, name, strlen(name) + 1);
- return smb_negotiate(s);
- }
- static int smb_negotiate(smb_session *s)
- {
- const char *dialects[] = SMB_DIALECTS;
- smb_message *msg = NULL;
- smb_message answer;
- smb_nego_resp *nego;
- uint16_t *p_payload_size;
- assert(s != NULL);
- msg = smb_message_new(SMB_CMD_NEGOTIATE);
- if (!msg)
- return DSM_ERROR_GENERIC;
- smb_message_put8(msg, 0); // wct
- smb_message_put16(msg, 0); // bct, will be updated later
- for (unsigned i = 0; dialects[i] != NULL; i++)
- smb_message_append(msg, dialects[i], strlen(dialects[i]) + 1);
- p_payload_size = (uint16_t *)(msg->packet->payload + 1);
- *p_payload_size = msg->cursor - 3;
- if (!smb_session_send_msg(s, msg))
- {
- smb_message_destroy(msg);
- return DSM_ERROR_NETWORK;
- }
- smb_message_destroy(msg);
- if (!smb_session_recv_msg(s, &answer))
- return DSM_ERROR_NETWORK;
- nego = (smb_nego_resp *)answer.packet->payload;
- if (!smb_session_check_nt_status(s, &answer))
- return DSM_ERROR_NT;
- if (nego->wct != 0x11)
- return DSM_ERROR_NETWORK;
- s->srv.dialect = nego->dialect_index;
- s->srv.security_mode = nego->security_mode;
- s->srv.caps = nego->caps;
- s->srv.ts = nego->ts;
- s->srv.session_key = nego->session_key;
- // Copy SPNEGO supported mechanisms token for later usage (login_gss())
- if (smb_session_supports(s, SMB_SESSION_XSEC))
- BDSM_dbg("Server is supporting extended security\n");
- else
- s->srv.challenge = nego->challenge;
- return DSM_SUCCESS;
- }
- static int smb_session_login_ntlm(smb_session *s, const char *domain,
- const char *user, const char *password)
- {
- smb_message answer;
- smb_message *msg = NULL;
- smb_session_req req;
- uint8_t *ntlm2 = NULL;
- smb_ntlmh hash_v2;
- uint64_t user_challenge;
- assert(s != NULL);
- 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_req);
- user_challenge = smb_ntlm_generate_challenge();
- // LM2 Response
- smb_ntlm2_hash(user, password, domain, hash_v2);
- ntlm2 = smb_lm2_response(hash_v2, s->srv.challenge, user_challenge);
- smb_message_append(msg, ntlm2, 16 + 8);
- free(ntlm2);
- if (msg->cursor / 2) // Padding !
- smb_message_put8(msg, 0);
- smb_message_put_utf16(msg, user, strlen(user));
- smb_message_put16(msg, 0);
- smb_message_put_utf16(msg, domain, strlen(domain));
- smb_message_put16(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_MSG_INIT_PKT_ANDX(req);
- req.wct = 13;
- req.max_buffer = SMB_SESSION_MAX_BUFFER;
- req.mpx_count = 16; // XXX ?
- req.vc_count = 1;
- //req.session_key = s->srv.session_key; // XXX Useless on the wire?
- req.caps = s->srv.caps; // XXX caps & our_caps_mask
- req.oem_pass_len = 16 + SMB_LM2_BLOB_SIZE;
- req.uni_pass_len = 0; //16 + blob_size; //SMB_NTLM2_BLOB_SIZE;
- req.payload_size = msg->cursor - sizeof(smb_session_req);
- SMB_MSG_INSERT_PKT(msg, 0, req);
- if (!smb_session_send_msg(s, msg))
- {
- smb_message_destroy(msg);
- BDSM_dbg("Unable to send Session Setup AndX message\n");
- return DSM_ERROR_NETWORK;
- }
- smb_message_destroy(msg);
- if (smb_session_recv_msg(s, &answer) == 0)
- {
- BDSM_dbg("Unable to get Session Setup AndX reply\n");
- return DSM_ERROR_NETWORK;
- }
- smb_session_resp *r = (smb_session_resp *)answer.packet->payload;
- if (!smb_session_check_nt_status(s, &answer))
- {
- BDSM_dbg("Session Setup AndX : failure.\n");
- return DSM_ERROR_NT;
- }
- if (r->action & 0x0001)
- s->guest = true;
- s->srv.uid = answer.packet->header.uid;
- s->logged = true;
- return DSM_SUCCESS;
- }
- int smb_session_login(smb_session *s)
- {
- assert(s != NULL);
- if (s->creds.domain == NULL
- || s->creds.login == NULL
- || s->creds.password == NULL)
- return DSM_ERROR_GENERIC;
- if (smb_session_supports(s, SMB_SESSION_XSEC))
- return (smb_session_login_spnego(s, s->creds.domain, s->creds.login,
- s->creds.password));
- else
- return (smb_session_login_ntlm(s, s->creds.domain, s->creds.login,
- s->creds.password));
- }
- int smb_session_is_guest(smb_session *s)
- {
- assert(s != NULL);
- // We're not logged in yet.
- if (s->logged != true)
- return -1;
- // We're logged in as guest
- if (s->guest)
- return 1;
- // We're logged in as regular user
- return 0;
- }
- const char *smb_session_server_name(smb_session *s)
- {
- assert(s != NULL);
- return s->srv.name;
- }
- int smb_session_supports(smb_session *s, int what)
- {
- assert(s != NULL);
- switch (what)
- {
- case SMB_SESSION_XSEC:
- return s->srv.caps & SMB_CAPS_XSEC;
- default:
- return 0;
- }
- }
- uint32_t smb_session_get_nt_status(smb_session *s)
- {
- assert(s != NULL);
- return s->nt_status;
- }
- bool smb_session_check_nt_status(smb_session *s, smb_message *msg)
- {
- assert(s != NULL && msg != NULL);
- if (msg->packet->header.status != NT_STATUS_SUCCESS)
- {
- s->nt_status = msg->packet->header.status;
- return false;
- }
- return true;
- }
|