1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  25  */
  26 
  27 /*
  28  * NETR challenge/response client functions.
  29  *
  30  * NT_STATUS_INVALID_PARAMETER
  31  * NT_STATUS_NO_TRUST_SAM_ACCOUNT
  32  * NT_STATUS_ACCESS_DENIED
  33  */
  34 
  35 #include <stdio.h>
  36 #include <stdlib.h>
  37 #include <strings.h>
  38 #include <unistd.h>
  39 #include <ctype.h>
  40 #include <security/cryptoki.h>
  41 #include <security/pkcs11.h>
  42 
  43 #include <smbsrv/libsmb.h>
  44 #include <smbsrv/libsmbns.h>
  45 #include <smbsrv/libmlsvc.h>
  46 #include <smbsrv/ndl/netlogon.ndl>
  47 #include <smbsrv/smbinfo.h>
  48 #include <smbsrv/netrauth.h>
  49 
  50 #define NETR_SESSKEY_ZEROBUF_SZ         4
  51 /* The DES algorithm uses a 56-bit encryption key. */
  52 #define NETR_DESKEY_LEN                 7
  53 
  54 int netr_setup_authenticator(netr_info_t *, struct netr_authenticator *,
  55     struct netr_authenticator *);
  56 DWORD netr_validate_chain(netr_info_t *, struct netr_authenticator *);
  57 
  58 static int netr_server_req_challenge(mlsvc_handle_t *, netr_info_t *);
  59 static int netr_server_authenticate2(mlsvc_handle_t *, netr_info_t *);
  60 static int netr_gen_password(BYTE *, BYTE *, BYTE *);
  61 
  62 /*
  63  * Shared with netr_logon.c
  64  */
  65 netr_info_t netr_global_info;
  66 
  67 /*
  68  * netlogon_auth
  69  *
  70  * This is the core of the NETLOGON authentication protocol.
  71  * Do the challenge response authentication.
  72  *
  73  * Prior to calling this function, an anonymous session to the NETLOGON
  74  * pipe on a domain controller(server) should have already been opened.
  75  *
  76  * Upon a successful NETLOGON credential chain establishment, the
  77  * netlogon sequence number will be set to match the kpasswd sequence
  78  * number.
  79  *
  80  */
  81 DWORD
  82 netlogon_auth(char *server, mlsvc_handle_t *netr_handle, DWORD flags)
  83 {
  84         netr_info_t *netr_info;
  85         int rc;
  86         DWORD leout_rc[2];
  87 
  88         netr_info = &netr_global_info;
  89         bzero(netr_info, sizeof (netr_info_t));
  90 
  91         netr_info->flags |= flags;
  92 
  93         rc = smb_getnetbiosname(netr_info->hostname, NETBIOS_NAME_SZ);
  94         if (rc != 0)
  95                 return (NT_STATUS_UNSUCCESSFUL);
  96 
  97         /* server is our DC.  Note: normally an FQDN. */
  98         (void) snprintf(netr_info->server, sizeof (netr_info->server),
  99             "\\\\%s", server);
 100 
 101         LE_OUT32(&leout_rc[0], random());
 102         LE_OUT32(&leout_rc[1], random());
 103         (void) memcpy(&netr_info->client_challenge, leout_rc,
 104             sizeof (struct netr_credential));
 105 
 106         if ((rc = netr_server_req_challenge(netr_handle, netr_info)) == 0) {
 107                 rc = netr_server_authenticate2(netr_handle, netr_info);
 108                 if (rc == 0) {
 109                         /*
 110                          * TODO: (later)  When joining a domain using a
 111                          * pre-created machine account, should do:
 112                          * netr_server_password_set(&netr_handle, netr_info);
 113                          * Nexenta issue 11960
 114                          */
 115                         smb_update_netlogon_seqnum();
 116                         netr_info->flags |= NETR_FLG_VALID;
 117 
 118                 }
 119         }
 120 
 121         return ((rc) ? NT_STATUS_UNSUCCESSFUL : NT_STATUS_SUCCESS);
 122 }
 123 
 124 /*
 125  * netr_open
 126  *
 127  * Open an anonymous session to the NETLOGON pipe on a domain controller
 128  * and bind to the NETR RPC interface.
 129  *
 130  * We store the remote server information, which is used to drive Windows
 131  * version specific behavior.
 132  *
 133  * Returns 0 or NT status
 134  */
 135 DWORD
 136 netr_open(char *server, char *domain, mlsvc_handle_t *netr_handle)
 137 {
 138         char user[SMB_USERNAME_MAXLEN];
 139         DWORD status;
 140 
 141         smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
 142 
 143         status = ndr_rpc_bind(netr_handle, server, domain, user, "NETR");
 144 
 145         return (status);
 146 }
 147 
 148 /*
 149  * netr_close
 150  *
 151  * Close a NETLOGON pipe and free the RPC context.
 152  */
 153 int
 154 netr_close(mlsvc_handle_t *netr_handle)
 155 {
 156         ndr_rpc_unbind(netr_handle);
 157         return (0);
 158 }
 159 
 160 /*
 161  * netr_server_req_challenge
 162  */
 163 static int
 164 netr_server_req_challenge(mlsvc_handle_t *netr_handle, netr_info_t *netr_info)
 165 {
 166         struct netr_ServerReqChallenge arg;
 167         int opnum;
 168 
 169         bzero(&arg, sizeof (struct netr_ServerReqChallenge));
 170         opnum = NETR_OPNUM_ServerReqChallenge;
 171 
 172         arg.servername = (unsigned char *)netr_info->server;
 173         arg.hostname = (unsigned char *)netr_info->hostname;
 174 
 175         (void) memcpy(&arg.client_challenge, &netr_info->client_challenge,
 176             sizeof (struct netr_credential));
 177 
 178         if (ndr_rpc_call(netr_handle, opnum, &arg) != 0)
 179                 return (-1);
 180 
 181         if (arg.status != 0) {
 182                 ndr_rpc_status(netr_handle, opnum, arg.status);
 183                 ndr_rpc_release(netr_handle);
 184                 return (-1);
 185         }
 186 
 187         (void) memcpy(&netr_info->server_challenge, &arg.server_challenge,
 188             sizeof (struct netr_credential));
 189 
 190         ndr_rpc_release(netr_handle);
 191         return (0);
 192 }
 193 
 194 uint32_t netr_server_auth2_flags =
 195     NETR_NEGOTIATE_BASE_FLAGS |
 196     NETR_NEGOTIATE_STRONGKEY_FLAG;
 197 
 198 /*
 199  * netr_server_authenticate2
 200  */
 201 static int
 202 netr_server_authenticate2(mlsvc_handle_t *netr_handle, netr_info_t *netr_info)
 203 {
 204         struct netr_ServerAuthenticate2 arg;
 205         /* sizeof netr_info->hostname, + 1 for the '$' */
 206         char account_name[(NETBIOS_NAME_SZ * 2) + 1];
 207         int opnum;
 208         int rc;
 209 
 210         bzero(&arg, sizeof (struct netr_ServerAuthenticate2));
 211         opnum = NETR_OPNUM_ServerAuthenticate2;
 212 
 213         (void) snprintf(account_name, sizeof (account_name), "%s$",
 214             netr_info->hostname);
 215 
 216         smb_tracef("server=[%s] account_name=[%s] hostname=[%s]\n",
 217             netr_info->server, account_name, netr_info->hostname);
 218 
 219         arg.servername = (unsigned char *)netr_info->server;
 220         arg.account_name = (unsigned char *)account_name;
 221         arg.account_type = NETR_WKSTA_TRUST_ACCOUNT_TYPE;
 222         arg.hostname = (unsigned char *)netr_info->hostname;
 223         arg.negotiate_flags = netr_server_auth2_flags;
 224 
 225         if (arg.negotiate_flags & NETR_NEGOTIATE_STRONGKEY_FLAG) {
 226                 if (netr_gen_skey128(netr_info) != SMBAUTH_SUCCESS)
 227                         return (-1);
 228         } else {
 229                 if (netr_gen_skey64(netr_info) != SMBAUTH_SUCCESS)
 230                         return (-1);
 231         }
 232 
 233         if (netr_gen_credentials(netr_info->session_key.key,
 234             &netr_info->client_challenge, 0,
 235             &netr_info->client_credential) != SMBAUTH_SUCCESS) {
 236                 return (-1);
 237         }
 238 
 239         if (netr_gen_credentials(netr_info->session_key.key,
 240             &netr_info->server_challenge, 0,
 241             &netr_info->server_credential) != SMBAUTH_SUCCESS) {
 242                 return (-1);
 243         }
 244 
 245         (void) memcpy(&arg.client_credential, &netr_info->client_credential,
 246             sizeof (struct netr_credential));
 247 
 248         if (ndr_rpc_call(netr_handle, opnum, &arg) != 0)
 249                 return (-1);
 250 
 251         if (arg.status != 0) {
 252                 ndr_rpc_status(netr_handle, opnum, arg.status);
 253                 ndr_rpc_release(netr_handle);
 254                 return (-1);
 255         }
 256 
 257         rc = memcmp(&netr_info->server_credential, &arg.server_credential,
 258             sizeof (struct netr_credential));
 259 
 260         ndr_rpc_release(netr_handle);
 261         return (rc);
 262 }
 263 
 264 /*
 265  * netr_gen_skey128
 266  *
 267  * Generate a 128-bit session key from the client and server challenges.
 268  * See "Session-Key Computation" section of MS-NRPC document.
 269  */
 270 int
 271 netr_gen_skey128(netr_info_t *netr_info)
 272 {
 273         unsigned char ntlmhash[SMBAUTH_HASH_SZ];
 274         int rc = SMBAUTH_FAILURE;
 275         CK_RV rv;
 276         CK_MECHANISM mechanism;
 277         CK_SESSION_HANDLE hSession;
 278         CK_ULONG diglen = MD_DIGEST_LEN;
 279         unsigned char md5digest[MD_DIGEST_LEN];
 280         unsigned char zerobuf[NETR_SESSKEY_ZEROBUF_SZ];
 281 
 282         bzero(ntlmhash, SMBAUTH_HASH_SZ);
 283         /*
 284          * We should check (netr_info->flags & NETR_FLG_INIT) and use
 285          * the appropriate password but it isn't working yet.  So we
 286          * always use the default one for now.
 287          */
 288         bzero(netr_info->password, sizeof (netr_info->password));
 289         rc = smb_config_getstr(SMB_CI_MACHINE_PASSWD,
 290             (char *)netr_info->password, sizeof (netr_info->password));
 291 
 292         if ((rc != SMBD_SMF_OK) || *netr_info->password == '\0') {
 293                 return (SMBAUTH_FAILURE);
 294         }
 295 
 296         rc = smb_auth_ntlm_hash((char *)netr_info->password, ntlmhash);
 297         if (rc != SMBAUTH_SUCCESS)
 298                 return (SMBAUTH_FAILURE);
 299 
 300         bzero(zerobuf, NETR_SESSKEY_ZEROBUF_SZ);
 301 
 302         mechanism.mechanism = CKM_MD5;
 303         mechanism.pParameter = 0;
 304         mechanism.ulParameterLen = 0;
 305 
 306         rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession);
 307         if (rv != CKR_OK)
 308                 return (SMBAUTH_FAILURE);
 309 
 310         rv = C_DigestInit(hSession, &mechanism);
 311         if (rv != CKR_OK)
 312                 goto cleanup;
 313 
 314         rv = C_DigestUpdate(hSession, (CK_BYTE_PTR)zerobuf,
 315             NETR_SESSKEY_ZEROBUF_SZ);
 316         if (rv != CKR_OK)
 317                 goto cleanup;
 318 
 319         rv = C_DigestUpdate(hSession,
 320             (CK_BYTE_PTR)netr_info->client_challenge.data, NETR_CRED_DATA_SZ);
 321         if (rv != CKR_OK)
 322                 goto cleanup;
 323 
 324         rv = C_DigestUpdate(hSession,
 325             (CK_BYTE_PTR)netr_info->server_challenge.data, NETR_CRED_DATA_SZ);
 326         if (rv != CKR_OK)
 327                 goto cleanup;
 328 
 329         rv = C_DigestFinal(hSession, (CK_BYTE_PTR)md5digest, &diglen);
 330         if (rv != CKR_OK)
 331                 goto cleanup;
 332 
 333         rc = smb_auth_hmac_md5(md5digest, diglen, ntlmhash, SMBAUTH_HASH_SZ,
 334             netr_info->session_key.key);
 335 
 336         netr_info->session_key.len = NETR_SESSKEY128_SZ;
 337 cleanup:
 338         (void) C_CloseSession(hSession);
 339         return (rc);
 340 
 341 }
 342 /*
 343  * netr_gen_skey64
 344  *
 345  * Generate a 64-bit session key from the client and server challenges.
 346  * See "Session-Key Computation" section of MS-NRPC document.
 347  *
 348  * The algorithm is a two stage hash. For the first hash, the input is
 349  * the combination of the client and server challenges, the key is
 350  * the first 7 bytes of the password. The initial password is formed
 351  * using the NT password hash on the local hostname in lower case.
 352  * The result is stored in a temporary buffer.
 353  *
 354  *              input:  challenge
 355  *              key:    passwd lower 7 bytes
 356  *              output: intermediate result
 357  *
 358  * For the second hash, the input is the result of the first hash and
 359  * the key is the last 7 bytes of the password.
 360  *
 361  *              input:  result of first hash
 362  *              key:    passwd upper 7 bytes
 363  *              output: session_key
 364  *
 365  * The final output should be the session key.
 366  *
 367  *              FYI: smb_auth_DES(output, key, input)
 368  *
 369  * If any difficulties occur using the cryptographic framework, the
 370  * function returns SMBAUTH_FAILURE.  Otherwise SMBAUTH_SUCCESS is
 371  * returned.
 372  */
 373 int
 374 netr_gen_skey64(netr_info_t *netr_info)
 375 {
 376         unsigned char md4hash[32];
 377         unsigned char buffer[8];
 378         DWORD data[2];
 379         DWORD *client_challenge;
 380         DWORD *server_challenge;
 381         int rc;
 382         DWORD le_data[2];
 383 
 384         client_challenge = (DWORD *)(uintptr_t)&netr_info->client_challenge;
 385         server_challenge = (DWORD *)(uintptr_t)&netr_info->server_challenge;
 386         bzero(md4hash, 32);
 387 
 388         /*
 389          * We should check (netr_info->flags & NETR_FLG_INIT) and use
 390          * the appropriate password but it isn't working yet.  So we
 391          * always use the default one for now.
 392          */
 393         bzero(netr_info->password, sizeof (netr_info->password));
 394         rc = smb_config_getstr(SMB_CI_MACHINE_PASSWD,
 395             (char *)netr_info->password, sizeof (netr_info->password));
 396 
 397         if ((rc != SMBD_SMF_OK) || *netr_info->password == '\0') {
 398                 return (SMBAUTH_FAILURE);
 399         }
 400 
 401         rc = smb_auth_ntlm_hash((char *)netr_info->password, md4hash);
 402 
 403         if (rc != SMBAUTH_SUCCESS)
 404                 return (SMBAUTH_FAILURE);
 405 
 406         data[0] = LE_IN32(&client_challenge[0]) + LE_IN32(&server_challenge[0]);
 407         data[1] = LE_IN32(&client_challenge[1]) + LE_IN32(&server_challenge[1]);
 408         LE_OUT32(&le_data[0], data[0]);
 409         LE_OUT32(&le_data[1], data[1]);
 410         rc = smb_auth_DES(buffer, 8, md4hash, NETR_DESKEY_LEN,
 411             (unsigned char *)le_data, 8);
 412 
 413         if (rc != SMBAUTH_SUCCESS)
 414                 return (rc);
 415 
 416         netr_info->session_key.len = NETR_SESSKEY64_SZ;
 417         rc = smb_auth_DES(netr_info->session_key.key,
 418             netr_info->session_key.len, &md4hash[9], NETR_DESKEY_LEN, buffer,
 419             8);
 420 
 421         return (rc);
 422 }
 423 
 424 /*
 425  * netr_gen_credentials
 426  *
 427  * Generate a set of credentials from a challenge and a session key.
 428  * The algorithm is a two stage hash. For the first hash, the
 429  * timestamp is added to the challenge and the result is stored in a
 430  * temporary buffer:
 431  *
 432  *              input:  challenge (including timestamp)
 433  *              key:    session_key
 434  *              output: intermediate result
 435  *
 436  * For the second hash, the input is the result of the first hash and
 437  * a strange partial key is used:
 438  *
 439  *              input:  result of first hash
 440  *              key:    funny partial key
 441  *              output: credentiails
 442  *
 443  * The final output should be an encrypted set of credentials.
 444  *
 445  *              FYI: smb_auth_DES(output, key, input)
 446  *
 447  * If any difficulties occur using the cryptographic framework, the
 448  * function returns SMBAUTH_FAILURE.  Otherwise SMBAUTH_SUCCESS is
 449  * returned.
 450  */
 451 int
 452 netr_gen_credentials(BYTE *session_key, netr_cred_t *challenge,
 453     DWORD timestamp, netr_cred_t *out_cred)
 454 {
 455         unsigned char buffer[8];
 456         DWORD data[2];
 457         DWORD le_data[2];
 458         DWORD *p;
 459         int rc;
 460 
 461         p = (DWORD *)(uintptr_t)challenge;
 462         data[0] = LE_IN32(&p[0]) + timestamp;
 463         data[1] = LE_IN32(&p[1]);
 464 
 465         LE_OUT32(&le_data[0], data[0]);
 466         LE_OUT32(&le_data[1], data[1]);
 467 
 468         if (smb_auth_DES(buffer, 8, session_key, NETR_DESKEY_LEN,
 469             (unsigned char *)le_data, 8) != SMBAUTH_SUCCESS)
 470                 return (SMBAUTH_FAILURE);
 471 
 472         rc = smb_auth_DES(out_cred->data, 8, &session_key[NETR_DESKEY_LEN],
 473             NETR_DESKEY_LEN, buffer, 8);
 474 
 475         return (rc);
 476 }
 477 
 478 /*
 479  * netr_server_password_set
 480  *
 481  * Attempt to change the trust account password for this system.
 482  *
 483  * Note that this call may legitimately fail if the registry on the
 484  * domain controller has been setup to deny attempts to change the
 485  * trust account password. In this case we should just continue to
 486  * use the original password.
 487  *
 488  * Possible status values:
 489  *      NT_STATUS_ACCESS_DENIED
 490  */
 491 int
 492 netr_server_password_set(mlsvc_handle_t *netr_handle, netr_info_t *netr_info)
 493 {
 494         struct netr_PasswordSet  arg;
 495         int opnum;
 496         BYTE new_password[NETR_OWF_PASSWORD_SZ];
 497         char account_name[NETBIOS_NAME_SZ * 2];
 498 
 499         bzero(&arg, sizeof (struct netr_PasswordSet));
 500         opnum = NETR_OPNUM_ServerPasswordSet;
 501 
 502         (void) snprintf(account_name, sizeof (account_name), "%s$",
 503             netr_info->hostname);
 504 
 505         arg.servername = (unsigned char *)netr_info->server;
 506         arg.account_name = (unsigned char *)account_name;
 507         arg.sec_chan_type = NETR_WKSTA_TRUST_ACCOUNT_TYPE;
 508         arg.hostname = (unsigned char *)netr_info->hostname;
 509 
 510         /*
 511          * Set up the client side authenticator.
 512          */
 513         if (netr_setup_authenticator(netr_info, &arg.auth, 0) !=
 514             SMBAUTH_SUCCESS) {
 515                 return (-1);
 516         }
 517 
 518         /*
 519          * Generate a new password from the old password.
 520          */
 521         if (netr_gen_password(netr_info->session_key.key,
 522             netr_info->password, new_password) == SMBAUTH_FAILURE) {
 523                 return (-1);
 524         }
 525 
 526         (void) memcpy(&arg.owf_password, &new_password,
 527             NETR_OWF_PASSWORD_SZ);
 528 
 529         if (ndr_rpc_call(netr_handle, opnum, &arg) != 0)
 530                 return (-1);
 531 
 532         if (arg.status != 0) {
 533                 ndr_rpc_status(netr_handle, opnum, arg.status);
 534                 ndr_rpc_release(netr_handle);
 535                 return (-1);
 536         }
 537 
 538         /*
 539          * Check the returned credentials.  The server returns the new
 540          * client credential rather than the new server credentiali,
 541          * as documented elsewhere.
 542          *
 543          * Generate the new seed for the credential chain.  Increment
 544          * the timestamp and add it to the client challenge.  Then we
 545          * need to copy the challenge to the credential field in
 546          * preparation for the next cycle.
 547          */
 548         if (netr_validate_chain(netr_info, &arg.auth) == 0) {
 549                 /*
 550                  * Save the new password.
 551                  */
 552                 (void) memcpy(netr_info->password, new_password,
 553                     NETR_OWF_PASSWORD_SZ);
 554         }
 555 
 556         ndr_rpc_release(netr_handle);
 557         return (0);
 558 }
 559 
 560 /*
 561  * netr_gen_password
 562  *
 563  * Generate a new pasword from the old password  and the session key.
 564  * The algorithm is a two stage hash. The session key is used in the
 565  * first hash but only part of the session key is used in the second
 566  * hash.
 567  *
 568  * If any difficulties occur using the cryptographic framework, the
 569  * function returns SMBAUTH_FAILURE.  Otherwise SMBAUTH_SUCCESS is
 570  * returned.
 571  */
 572 static int
 573 netr_gen_password(BYTE *session_key, BYTE *old_password, BYTE *new_password)
 574 {
 575         int rv;
 576 
 577         rv = smb_auth_DES(new_password, 8, session_key, NETR_DESKEY_LEN,
 578             old_password, 8);
 579         if (rv != SMBAUTH_SUCCESS)
 580                 return (rv);
 581 
 582         rv = smb_auth_DES(&new_password[8], 8, &session_key[NETR_DESKEY_LEN],
 583             NETR_DESKEY_LEN, &old_password[8], 8);
 584         return (rv);
 585 }
 586 
 587 /*
 588  * Todo: need netr_server_password_set2()
 589  * used by "unsecure join". (NX 11960)
 590  */