libcli/smb: add smb1cli_session_setup_nt1_send/recv()
authorStefan Metzmacher <metze@samba.org>
Tue, 25 Oct 2016 13:40:59 +0000 (15:40 +0200)
committerAndreas Schneider <asn@cryptomilk.org>
Tue, 15 Nov 2016 10:00:26 +0000 (11:00 +0100)
This does a session setup for the NT1 protocol (without CAP_EXTENDED_SECURITY).

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
libcli/smb/smb1cli_session.c
libcli/smb/smbXcli_base.h

index 1f6779a6d31b70e7710d6b8b472207920582eb45..c2ed267797a74099ca10a5e081909a37ebfa98f0 100644 (file)
@@ -257,3 +257,311 @@ NTSTATUS smb1cli_session_setup_lm21_recv(struct tevent_req *req,
        tevent_req_received(req);
        return NT_STATUS_OK;
 }
+
+struct smb1cli_session_setup_nt1_state {
+       struct smbXcli_session *session;
+       uint16_t vwv[13];
+       struct iovec *recv_iov;
+       uint8_t *inbuf;
+       uint16_t out_session_id;
+       uint16_t out_action;
+       char *out_native_os;
+       char *out_native_lm;
+       char *out_primary_domain;
+};
+
+static void smb1cli_session_setup_nt1_done(struct tevent_req *subreq);
+
+struct tevent_req *smb1cli_session_setup_nt1_send(TALLOC_CTX *mem_ctx,
+                               struct tevent_context *ev,
+                               struct smbXcli_conn *conn,
+                               uint32_t timeout_msec,
+                               uint32_t pid,
+                               struct smbXcli_session *session,
+                               uint16_t in_buf_size,
+                               uint16_t in_mpx_max,
+                               uint16_t in_vc_num,
+                               uint32_t in_sess_key,
+                               const char *in_user,
+                               const char *in_domain,
+                               const DATA_BLOB in_apassword,
+                               const DATA_BLOB in_upassword,
+                               uint32_t in_capabilities,
+                               const char *in_native_os,
+                               const char *in_native_lm)
+{
+       struct tevent_req *req = NULL;
+       struct smb1cli_session_setup_nt1_state *state = NULL;
+       struct tevent_req *subreq = NULL;
+       uint16_t *vwv = NULL;
+       uint8_t *bytes = NULL;
+       size_t align_upassword = 0;
+       size_t apassword_ofs = 0;
+       size_t upassword_ofs = 0;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct smb1cli_session_setup_nt1_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       state->session = session;
+       vwv = state->vwv;
+
+       if (in_user == NULL) {
+               tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+               return tevent_req_post(req, ev);
+       }
+
+       if (in_domain == NULL) {
+               tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+               return tevent_req_post(req, ev);
+       }
+
+       if (in_apassword.length > UINT16_MAX) {
+               tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+               return tevent_req_post(req, ev);
+       }
+
+       if (in_upassword.length > UINT16_MAX) {
+               tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+               return tevent_req_post(req, ev);
+       }
+
+       if (in_native_os == NULL && in_native_lm != NULL) {
+               tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+               return tevent_req_post(req, ev);
+       }
+
+       SCVAL(vwv+0,  0, 0xff);
+       SCVAL(vwv+0,  1, 0);
+       SSVAL(vwv+1,  0, 0);
+       SSVAL(vwv+2,  0, in_buf_size);
+       SSVAL(vwv+3,  0, in_mpx_max);
+       SSVAL(vwv+4,  0, in_vc_num);
+       SIVAL(vwv+5,  0, in_sess_key);
+       SSVAL(vwv+7,  0, in_apassword.length);
+       SSVAL(vwv+8,  0, in_upassword.length);
+       SSVAL(vwv+9,  0, 0); /* reserved */
+       SSVAL(vwv+10, 0, 0); /* reserved */
+       SIVAL(vwv+11, 0, in_capabilities);
+
+       if (in_apassword.length == 0 && in_upassword.length > 0) {
+               /*
+                * This is plaintext auth with a unicode password,
+                * we need to align the buffer.
+                *
+                * This is what smbclient and Windows XP send as
+                * a client. And what smbd expects.
+                *
+                * But it doesn't follow [MS-CIFS] (v20160714)
+                * 2.2.4.53.1 SMB_COM_SESSION_SETUP_ANDX Request:
+                *
+                * ...
+                *
+                *  If SMB_FLAGS2_UNICODE is set (1), the value of OEMPasswordLen
+                *  MUST be 0x0000 and the password MUST be encoded using
+                *  UTF-16LE Unicode. Padding MUST NOT be added to
+                *  align this plaintext Unicode string to a word boundary.
+                *
+                * ...
+                */
+               uint16_t security_mode = smb1cli_conn_server_security_mode(conn);
+
+               if (!(security_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)) {
+                       align_upassword = 1;
+               }
+       }
+
+       bytes = talloc_array(state, uint8_t,
+                            in_apassword.length +
+                            align_upassword +
+                            in_upassword.length);
+       if (tevent_req_nomem(bytes, req)) {
+               return tevent_req_post(req, ev);
+       }
+       if (in_apassword.length != 0) {
+               memcpy(bytes + apassword_ofs,
+                      in_apassword.data,
+                      in_apassword.length);
+               upassword_ofs += in_apassword.length;
+       }
+       if (align_upassword != 0) {
+               memset(bytes + upassword_ofs, 0, align_upassword);
+               upassword_ofs += align_upassword;
+       }
+       if (in_upassword.length != 0) {
+               memcpy(bytes + upassword_ofs,
+                      in_upassword.data,
+                      in_upassword.length);
+       }
+
+       bytes = smb_bytes_push_str(bytes,
+                                  smbXcli_conn_use_unicode(conn),
+                                  in_user, strlen(in_user)+1,
+                                  NULL);
+       bytes = smb_bytes_push_str(bytes,
+                                  smbXcli_conn_use_unicode(conn),
+                                  in_domain, strlen(in_domain)+1,
+                                  NULL);
+       if (in_native_os != NULL) {
+               bytes = smb_bytes_push_str(bytes,
+                                          smbXcli_conn_use_unicode(conn),
+                                          in_native_os, strlen(in_native_os)+1,
+                                          NULL);
+       }
+       if (in_native_lm != NULL) {
+               bytes = smb_bytes_push_str(bytes,
+                                          smbXcli_conn_use_unicode(conn),
+                                          in_native_lm, strlen(in_native_lm)+1,
+                                          NULL);
+       }
+       if (tevent_req_nomem(bytes, req)) {
+               return tevent_req_post(req, ev);
+       }
+
+       subreq = smb1cli_req_send(state, ev, conn,
+                                 SMBsesssetupX,
+                                 0, /*  additional_flags */
+                                 0, /*  clear_flags */
+                                 0, /*  additional_flags2 */
+                                 0, /*  clear_flags2 */
+                                 timeout_msec,
+                                 pid,
+                                 NULL, /* tcon */
+                                 session,
+                                 13, /* wct */
+                                 vwv,
+                                 talloc_get_size(bytes),
+                                 bytes);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, smb1cli_session_setup_nt1_done, req);
+
+       return req;
+}
+
+static void smb1cli_session_setup_nt1_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req =
+               tevent_req_callback_data(subreq,
+               struct tevent_req);
+       struct smb1cli_session_setup_nt1_state *state =
+               tevent_req_data(req,
+               struct smb1cli_session_setup_nt1_state);
+       NTSTATUS status;
+       uint8_t *inhdr = NULL;
+       uint8_t wct;
+       uint16_t *vwv = NULL;
+       uint32_t num_bytes;
+       uint8_t *bytes = NULL;
+       const uint8_t *p = NULL;
+       size_t ret = 0;
+       uint16_t flags2;
+       bool use_unicode = false;
+       struct smb1cli_req_expected_response expected[] = {
+       {
+               .status = NT_STATUS_OK,
+               .wct    = 3,
+       },
+       };
+
+       status = smb1cli_req_recv(subreq, state,
+                                 &state->recv_iov,
+                                 &inhdr,
+                                 &wct,
+                                 &vwv,
+                                 NULL, /* pvwv_offset */
+                                 &num_bytes,
+                                 &bytes,
+                                 NULL, /* pbytes_offset */
+                                 &state->inbuf,
+                                 expected, ARRAY_SIZE(expected));
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+
+       flags2 = SVAL(inhdr, HDR_FLG2);
+       if (flags2 & FLAGS2_UNICODE_STRINGS) {
+               use_unicode = true;
+       }
+
+       state->out_session_id = SVAL(inhdr, HDR_UID);
+       state->out_action = SVAL(vwv+2, 0);
+
+       p = bytes;
+
+       status = smb_bytes_pull_str(state, &state->out_native_os,
+                                   use_unicode, p,
+                                   bytes+num_bytes-p, &ret);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+       p += ret;
+
+       status = smb_bytes_pull_str(state, &state->out_native_lm,
+                                   use_unicode, p,
+                                   bytes+num_bytes-p, &ret);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+       p += ret;
+
+       status = smb_bytes_pull_str(state, &state->out_primary_domain,
+                                   use_unicode, p,
+                                   bytes+num_bytes-p, &ret);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+       p += ret;
+
+       smb1cli_session_set_id(state->session, state->out_session_id);
+       smb1cli_session_set_action(state->session, state->out_action);
+
+       tevent_req_done(req);
+}
+
+NTSTATUS smb1cli_session_setup_nt1_recv(struct tevent_req *req,
+                                       TALLOC_CTX *mem_ctx,
+                                       struct iovec **precv_iov,
+                                       const uint8_t **precv_inbuf,
+                                       char **out_native_os,
+                                       char **out_native_lm,
+                                       char **out_primary_domain)
+{
+       struct smb1cli_session_setup_nt1_state *state =
+               tevent_req_data(req,
+               struct smb1cli_session_setup_nt1_state);
+       NTSTATUS status;
+       struct iovec *recv_iov = NULL;
+
+       if (tevent_req_is_nterror(req, &status)) {
+               tevent_req_received(req);
+               return status;
+       }
+
+       recv_iov = talloc_move(mem_ctx, &state->recv_iov);
+       if (precv_iov != NULL) {
+               *precv_iov = recv_iov;
+       }
+       if (precv_inbuf != NULL) {
+               *precv_inbuf = state->inbuf;
+       }
+
+       if (out_native_os != NULL) {
+               *out_native_os = talloc_move(mem_ctx, &state->out_native_os);
+       }
+
+       if (out_native_lm != NULL) {
+               *out_native_lm = talloc_move(mem_ctx, &state->out_native_lm);
+       }
+
+       if (out_primary_domain != NULL) {
+               *out_primary_domain = talloc_move(mem_ctx,
+                                                 &state->out_primary_domain);
+       }
+
+       tevent_req_received(req);
+       return NT_STATUS_OK;
+}
index c1a9c70161137ed5d63ffee795ed90cff8cced22..ad4272171edcab2064139ccfec9de4db916a6922 100644 (file)
@@ -220,6 +220,30 @@ NTSTATUS smb1cli_session_setup_lm21_recv(struct tevent_req *req,
                                         TALLOC_CTX *mem_ctx,
                                         char **out_native_os,
                                         char **out_native_lm);
+struct tevent_req *smb1cli_session_setup_nt1_send(TALLOC_CTX *mem_ctx,
+                               struct tevent_context *ev,
+                               struct smbXcli_conn *conn,
+                               uint32_t timeout_msec,
+                               uint32_t pid,
+                               struct smbXcli_session *session,
+                               uint16_t in_buf_size,
+                               uint16_t in_mpx_max,
+                               uint16_t in_vc_num,
+                               uint32_t in_sess_key,
+                               const char *in_user,
+                               const char *in_domain,
+                               const DATA_BLOB in_apassword,
+                               const DATA_BLOB in_upassword,
+                               uint32_t in_capabilities,
+                               const char *in_native_os,
+                               const char *in_native_lm);
+NTSTATUS smb1cli_session_setup_nt1_recv(struct tevent_req *req,
+                                       TALLOC_CTX *mem_ctx,
+                                       struct iovec **precv_iov,
+                                       const uint8_t **precv_inbuf,
+                                       char **out_native_os,
+                                       char **out_native_lm,
+                                       char **out_primary_domain);
 
 struct tevent_req *smb1cli_ntcreatex_send(TALLOC_CTX *mem_ctx,
                                          struct tevent_context *ev,