root/source4/auth/ntlmssp/ntlmssp_client.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ntlmssp_client_initial
  2. ntlmssp_client_challenge
  3. gensec_ntlmssp_client_start

   1 /* 
   2    Unix SMB/Netbios implementation.
   3    Version 3.0
   4    handle NLTMSSP, client server side parsing
   5 
   6    Copyright (C) Andrew Tridgell      2001
   7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2001-2005
   8    Copyright (C) Stefan Metzmacher 2005
   9 
  10    This program is free software; you can redistribute it and/or modify
  11    it under the terms of the GNU General Public License as published by
  12    the Free Software Foundation; either version 3 of the License, or
  13    (at your option) any later version.
  14    
  15    This program is distributed in the hope that it will be useful,
  16    but WITHOUT ANY WARRANTY; without even the implied warranty of
  17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18    GNU General Public License for more details.
  19    
  20    You should have received a copy of the GNU General Public License
  21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  22 */
  23 
  24 #include "includes.h"
  25 #include "auth/ntlmssp/ntlmssp.h"
  26 #include "auth/ntlmssp/msrpc_parse.h"
  27 #include "../lib/crypto/crypto.h"
  28 #include "libcli/auth/libcli_auth.h"
  29 #include "auth/credentials/credentials.h"
  30 #include "auth/gensec/gensec.h"
  31 #include "param/param.h"
  32 
  33 /*********************************************************************
  34  Client side NTLMSSP
  35 *********************************************************************/
  36 
  37 /**
  38  * Next state function for the Initial packet
  39  * 
  40  * @param ntlmssp_state NTLMSSP State
  41  * @param out_mem_ctx The DATA_BLOB *out will be allocated on this context
  42  * @param in A NULL data blob (input ignored)
  43  * @param out The initial negotiate request to the server, as an talloc()ed DATA_BLOB, on out_mem_ctx
  44  * @return Errors or NT_STATUS_OK. 
  45  */
  46 
  47 NTSTATUS ntlmssp_client_initial(struct gensec_security *gensec_security, 
     /* [<][>][^][v][top][bottom][index][help] */
  48                                 TALLOC_CTX *out_mem_ctx, 
  49                                 DATA_BLOB in, DATA_BLOB *out) 
  50 {
  51         struct gensec_ntlmssp_state *gensec_ntlmssp_state = (struct gensec_ntlmssp_state *)gensec_security->private_data;
  52         const char *domain = gensec_ntlmssp_state->domain;
  53         const char *workstation = cli_credentials_get_workstation(gensec_security->credentials);
  54 
  55         /* These don't really matter in the initial packet, so don't panic if they are not set */
  56         if (!domain) {
  57                 domain = "";
  58         }
  59 
  60         if (!workstation) {
  61                 workstation = "";
  62         }
  63 
  64         if (gensec_ntlmssp_state->unicode) {
  65                 gensec_ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE;
  66         } else {
  67                 gensec_ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_OEM;
  68         }
  69         
  70         if (gensec_ntlmssp_state->use_ntlmv2) {
  71                 gensec_ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2;
  72         }
  73 
  74         /* generate the ntlmssp negotiate packet */
  75         msrpc_gen(out_mem_ctx, 
  76                   out, "CddAA",
  77                   "NTLMSSP",
  78                   NTLMSSP_NEGOTIATE,
  79                   gensec_ntlmssp_state->neg_flags,
  80                   domain, 
  81                   workstation);
  82 
  83         gensec_ntlmssp_state->expected_state = NTLMSSP_CHALLENGE;
  84 
  85         return NT_STATUS_MORE_PROCESSING_REQUIRED;
  86 }
  87 
  88 /**
  89  * Next state function for the Challenge Packet.  Generate an auth packet.
  90  * 
  91  * @param gensec_security GENSEC state
  92  * @param out_mem_ctx Memory context for *out
  93  * @param in The server challnege, as a DATA_BLOB.  reply.data must be NULL
  94  * @param out The next request (auth packet) to the server, as an allocated DATA_BLOB, on the out_mem_ctx context
  95  * @return Errors or NT_STATUS_OK. 
  96  */
  97 
  98 NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security, 
     /* [<][>][^][v][top][bottom][index][help] */
  99                                   TALLOC_CTX *out_mem_ctx,
 100                                   const DATA_BLOB in, DATA_BLOB *out) 
 101 {
 102         struct gensec_ntlmssp_state *gensec_ntlmssp_state = (struct gensec_ntlmssp_state *)gensec_security->private_data;
 103         uint32_t chal_flags, ntlmssp_command, unkn1, unkn2;
 104         DATA_BLOB server_domain_blob;
 105         DATA_BLOB challenge_blob;
 106         DATA_BLOB target_info = data_blob(NULL, 0);
 107         char *server_domain;
 108         const char *chal_parse_string;
 109         const char *auth_gen_string;
 110         DATA_BLOB lm_response = data_blob(NULL, 0);
 111         DATA_BLOB nt_response = data_blob(NULL, 0);
 112         DATA_BLOB session_key = data_blob(NULL, 0);
 113         DATA_BLOB lm_session_key = data_blob(NULL, 0);
 114         DATA_BLOB encrypted_session_key = data_blob(NULL, 0);
 115         NTSTATUS nt_status;
 116         int flags = 0;
 117         const char *user, *domain;
 118 
 119         TALLOC_CTX *mem_ctx = talloc_new(out_mem_ctx);
 120         if (!mem_ctx) {
 121                 return NT_STATUS_NO_MEMORY;
 122         }
 123 
 124         if (!msrpc_parse(mem_ctx,
 125                          &in, "CdBd",
 126                          "NTLMSSP",
 127                          &ntlmssp_command, 
 128                          &server_domain_blob,
 129                          &chal_flags)) {
 130                 DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#1)\n"));
 131                 dump_data(2, in.data, in.length);
 132                 talloc_free(mem_ctx);
 133 
 134                 return NT_STATUS_INVALID_PARAMETER;
 135         }
 136         
 137         data_blob_free(&server_domain_blob);
 138 
 139         DEBUG(3, ("Got challenge flags:\n"));
 140         debug_ntlmssp_flags(chal_flags);
 141 
 142         ntlmssp_handle_neg_flags(gensec_ntlmssp_state, chal_flags, gensec_ntlmssp_state->allow_lm_key);
 143 
 144         if (gensec_ntlmssp_state->unicode) {
 145                 if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) {
 146                         chal_parse_string = "CdUdbddB";
 147                 } else {
 148                         chal_parse_string = "CdUdbdd";
 149                 }
 150                 auth_gen_string = "CdBBUUUBd";
 151         } else {
 152                 if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) {
 153                         chal_parse_string = "CdAdbddB";
 154                 } else {
 155                         chal_parse_string = "CdAdbdd";
 156                 }
 157 
 158                 auth_gen_string = "CdBBAAABd";
 159         }
 160 
 161         if (!msrpc_parse(mem_ctx,
 162                          &in, chal_parse_string,
 163                          "NTLMSSP",
 164                          &ntlmssp_command, 
 165                          &server_domain,
 166                          &chal_flags,
 167                          &challenge_blob, 8,
 168                          &unkn1, &unkn2,
 169                          &target_info)) {
 170                 DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#2)\n"));
 171                 dump_data(2, in.data, in.length);
 172                 talloc_free(mem_ctx);
 173                 return NT_STATUS_INVALID_PARAMETER;
 174         }
 175 
 176         gensec_ntlmssp_state->server_domain = server_domain;
 177 
 178         if (challenge_blob.length != 8) {
 179                 talloc_free(mem_ctx);
 180                 return NT_STATUS_INVALID_PARAMETER;
 181         }
 182 
 183         cli_credentials_get_ntlm_username_domain(gensec_security->credentials, mem_ctx, 
 184                                                  &user, &domain);
 185 
 186         if (gensec_ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
 187                 flags |= CLI_CRED_NTLM2;
 188         }
 189         if (gensec_ntlmssp_state->use_ntlmv2) {
 190                 flags |= CLI_CRED_NTLMv2_AUTH;
 191         }
 192         if (gensec_ntlmssp_state->use_nt_response) {
 193                 flags |= CLI_CRED_NTLM_AUTH;
 194         }
 195         if (lp_client_lanman_auth(gensec_security->settings->lp_ctx)) {
 196                 flags |= CLI_CRED_LANMAN_AUTH;
 197         }
 198 
 199         nt_status = cli_credentials_get_ntlm_response(gensec_security->credentials, mem_ctx, 
 200                                                       &flags, challenge_blob, target_info,
 201                                                       &lm_response, &nt_response, 
 202                                                       &lm_session_key, &session_key);
 203 
 204         if (!NT_STATUS_IS_OK(nt_status)) {
 205                 return nt_status;
 206         }
 207         
 208         if (!(flags & CLI_CRED_LANMAN_AUTH)) {
 209                 /* LM Key is still possible, just silly.  Fortunetly
 210                  * we require command line options to end up here */
 211                 /* gensec_ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; */
 212         }
 213 
 214         if (!(flags & CLI_CRED_NTLM2)) {
 215                 /* NTLM2 is incompatible... */
 216                 gensec_ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
 217         }
 218         
 219         if ((gensec_ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) 
 220             && lp_client_lanman_auth(gensec_security->settings->lp_ctx) && lm_session_key.length == 16) {
 221                 DATA_BLOB new_session_key = data_blob_talloc(mem_ctx, NULL, 16);
 222                 if (lm_response.length == 24) {
 223                         SMBsesskeygen_lm_sess_key(lm_session_key.data, lm_response.data, 
 224                                                   new_session_key.data);
 225                 } else {
 226                         static const uint8_t zeros[24];
 227                         SMBsesskeygen_lm_sess_key(lm_session_key.data, zeros,
 228                                                   new_session_key.data);
 229                 }
 230                 session_key = new_session_key;
 231                 dump_data_pw("LM session key\n", session_key.data, session_key.length);
 232         }
 233 
 234 
 235         /* Key exchange encryptes a new client-generated session key with
 236            the password-derived key */
 237         if (gensec_ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
 238                 /* Make up a new session key */
 239                 uint8_t client_session_key[16];
 240                 generate_secret_buffer(client_session_key, sizeof(client_session_key));
 241 
 242                 /* Encrypt the new session key with the old one */
 243                 encrypted_session_key = data_blob_talloc(gensec_ntlmssp_state, 
 244                                                          client_session_key, sizeof(client_session_key));
 245                 dump_data_pw("KEY_EXCH session key:\n", encrypted_session_key.data, encrypted_session_key.length);
 246                 arcfour_crypt(encrypted_session_key.data, session_key.data, encrypted_session_key.length);
 247                 dump_data_pw("KEY_EXCH session key (enc):\n", encrypted_session_key.data, encrypted_session_key.length);
 248 
 249                 /* Mark the new session key as the 'real' session key */
 250                 session_key = data_blob_talloc(mem_ctx, client_session_key, sizeof(client_session_key));
 251         }
 252 
 253         DEBUG(3, ("NTLMSSP: Set final flags:\n"));
 254         debug_ntlmssp_flags(gensec_ntlmssp_state->neg_flags);
 255 
 256         /* this generates the actual auth packet */
 257         if (!msrpc_gen(mem_ctx, 
 258                        out, auth_gen_string, 
 259                        "NTLMSSP", 
 260                        NTLMSSP_AUTH, 
 261                        lm_response.data, lm_response.length,
 262                        nt_response.data, nt_response.length,
 263                        domain, 
 264                        user, 
 265                        cli_credentials_get_workstation(gensec_security->credentials),
 266                        encrypted_session_key.data, encrypted_session_key.length,
 267                        gensec_ntlmssp_state->neg_flags)) {
 268                 talloc_free(mem_ctx);
 269                 return NT_STATUS_NO_MEMORY;
 270         }
 271 
 272         gensec_ntlmssp_state->session_key = session_key;
 273         talloc_steal(gensec_ntlmssp_state, session_key.data);
 274 
 275         talloc_steal(out_mem_ctx, out->data);
 276 
 277         gensec_ntlmssp_state->chal = challenge_blob;
 278         gensec_ntlmssp_state->lm_resp = lm_response;
 279         talloc_steal(gensec_ntlmssp_state->lm_resp.data, lm_response.data);
 280         gensec_ntlmssp_state->nt_resp = nt_response;
 281         talloc_steal(gensec_ntlmssp_state->nt_resp.data, nt_response.data);
 282 
 283         gensec_ntlmssp_state->expected_state = NTLMSSP_DONE;
 284 
 285         if (gensec_security->want_features & (GENSEC_FEATURE_SIGN|GENSEC_FEATURE_SEAL)) {
 286                 nt_status = ntlmssp_sign_init(gensec_ntlmssp_state);
 287                 if (!NT_STATUS_IS_OK(nt_status)) {
 288                         DEBUG(1, ("Could not setup NTLMSSP signing/sealing system (error was: %s)\n", 
 289                                   nt_errstr(nt_status)));
 290                         talloc_free(mem_ctx);
 291                         return nt_status;
 292                 }
 293         }
 294 
 295         talloc_free(mem_ctx);
 296         return NT_STATUS_OK;
 297 }
 298 
 299 NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security)
     /* [<][>][^][v][top][bottom][index][help] */
 300 {
 301         struct gensec_ntlmssp_state *gensec_ntlmssp_state;
 302         NTSTATUS nt_status;
 303 
 304         nt_status = gensec_ntlmssp_start(gensec_security);
 305         NT_STATUS_NOT_OK_RETURN(nt_status);
 306 
 307         gensec_ntlmssp_state = (struct gensec_ntlmssp_state *)gensec_security->private_data;
 308 
 309         gensec_ntlmssp_state->role = NTLMSSP_CLIENT;
 310 
 311         gensec_ntlmssp_state->domain = lp_workgroup(gensec_security->settings->lp_ctx);
 312 
 313         gensec_ntlmssp_state->unicode = gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "unicode", true);
 314 
 315         gensec_ntlmssp_state->use_nt_response = gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "send_nt_reponse", true);
 316 
 317         gensec_ntlmssp_state->allow_lm_key = (lp_client_lanman_auth(gensec_security->settings->lp_ctx) 
 318                                               && (gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "allow_lm_key", false)
 319                                                   || gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "lm_key", false)));
 320 
 321         gensec_ntlmssp_state->use_ntlmv2 = lp_client_ntlmv2_auth(gensec_security->settings->lp_ctx);
 322 
 323         gensec_ntlmssp_state->expected_state = NTLMSSP_INITIAL;
 324 
 325         gensec_ntlmssp_state->neg_flags = 
 326                 NTLMSSP_NEGOTIATE_NTLM |
 327                 NTLMSSP_REQUEST_TARGET;
 328 
 329         if (gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "128bit", true)) {
 330                 gensec_ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_128;               
 331         }
 332 
 333         if (gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "56bit", false)) {
 334                 gensec_ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_56;                
 335         }
 336 
 337         if (gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "lm_key", false)) {
 338                 gensec_ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_LM_KEY;
 339         }
 340 
 341         if (gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "keyexchange", true)) {
 342                 gensec_ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_KEY_EXCH;          
 343         }
 344 
 345         if (gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "alwayssign", true)) {
 346                 gensec_ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;               
 347         }
 348 
 349         if (gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "ntlm2", true)) {
 350                 gensec_ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2;             
 351         } else {
 352                 /* apparently we can't do ntlmv2 if we don't do ntlm2 */
 353                 gensec_ntlmssp_state->use_ntlmv2 = false;
 354         }
 355 
 356         if (gensec_security->want_features & GENSEC_FEATURE_SESSION_KEY) {
 357                 /*
 358                  * We need to set this to allow a later SetPassword
 359                  * via the SAMR pipe to succeed. Strange.... We could
 360                  * also add  NTLMSSP_NEGOTIATE_SEAL here. JRA.
 361                  * 
 362                  * Without this, Windows will not create the master key
 363                  * that it thinks is only used for NTLMSSP signing and 
 364                  * sealing.  (It is actually pulled out and used directly) 
 365                  */
 366                 gensec_ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
 367         }
 368         if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
 369                 gensec_ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
 370         }
 371         if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
 372                 gensec_ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL;
 373         }
 374 
 375         gensec_security->private_data = gensec_ntlmssp_state;
 376 
 377         return NT_STATUS_OK;
 378 }
 379 

/* [<][>][^][v][top][bottom][index][help] */