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 /*
 195  * netr_server_authenticate2
 196  */
 197 static int
 198 netr_server_authenticate2(mlsvc_handle_t *netr_handle, netr_info_t *netr_info)
 199 {
 200         struct netr_ServerAuthenticate2 arg;
 201         /* sizeof netr_info->hostname, + 1 for the '$' */
 202         char account_name[(NETBIOS_NAME_SZ * 2) + 1];
 203         int opnum;
 204         int rc;
 205 
 206         bzero(&arg, sizeof (struct netr_ServerAuthenticate2));
 207         opnum = NETR_OPNUM_ServerAuthenticate2;
 208 
 209         (void) snprintf(account_name, sizeof (account_name), "%s$",
 210             netr_info->hostname);
 211 
 212         smb_tracef("server=[%s] account_name=[%s] hostname=[%s]\n",
 213             netr_info->server, account_name, netr_info->hostname);
 214 
 215         arg.servername = (unsigned char *)netr_info->server;
 216         arg.account_name = (unsigned char *)account_name;
 217         arg.account_type = NETR_WKSTA_TRUST_ACCOUNT_TYPE;
 218         arg.hostname = (unsigned char *)netr_info->hostname;
 219         arg.negotiate_flags = NETR_NEGOTIATE_BASE_FLAGS;
 220 
 221         if (ndr_rpc_server_os(netr_handle) == NATIVE_OS_WIN2000) {
 222                 arg.negotiate_flags |= NETR_NEGOTIATE_STRONGKEY_FLAG;
 223                 if (netr_gen_skey128(netr_info) != SMBAUTH_SUCCESS)
 224                         return (-1);
 225         } else {
 226                 if (netr_gen_skey64(netr_info) != SMBAUTH_SUCCESS)
 227                         return (-1);
 228         }
 229 
 230         if (netr_gen_credentials(netr_info->session_key.key,
 231             &netr_info->client_challenge, 0,
 232             &netr_info->client_credential) != SMBAUTH_SUCCESS) {
 233                 return (-1);
 234         }
 235 
 236         if (netr_gen_credentials(netr_info->session_key.key,
 237             &netr_info->server_challenge, 0,
 238             &netr_info->server_credential) != SMBAUTH_SUCCESS) {
 239                 return (-1);
 240         }
 241 
 242         (void) memcpy(&arg.client_credential, &netr_info->client_credential,
 243             sizeof (struct netr_credential));
 244 
 245         if (ndr_rpc_call(netr_handle, opnum, &arg) != 0)
 246                 return (-1);
 247 
 248         if (arg.status != 0) {
 249                 ndr_rpc_status(netr_handle, opnum, arg.status);
 250                 ndr_rpc_release(netr_handle);
 251                 return (-1);
 252         }
 253 
 254         rc = memcmp(&netr_info->server_credential, &arg.server_credential,
 255             sizeof (struct netr_credential));
 256 
 257         ndr_rpc_release(netr_handle);
 258         return (rc);
 259 }
 260 
 261 /*
 262  * netr_gen_skey128
 263  *
 264  * Generate a 128-bit session key from the client and server challenges.
 265  * See "Session-Key Computation" section of MS-NRPC document.
 266  */
 267 int
 268 netr_gen_skey128(netr_info_t *netr_info)
 269 {
 270         unsigned char ntlmhash[SMBAUTH_HASH_SZ];
 271         int rc = SMBAUTH_FAILURE;
 272         CK_RV rv;
 273         CK_MECHANISM mechanism;
 274         CK_SESSION_HANDLE hSession;
 275         CK_ULONG diglen = MD_DIGEST_LEN;
 276         unsigned char md5digest[MD_DIGEST_LEN];
 277         unsigned char zerobuf[NETR_SESSKEY_ZEROBUF_SZ];
 278 
 279         bzero(ntlmhash, SMBAUTH_HASH_SZ);
 280         /*
 281          * We should check (netr_info->flags & NETR_FLG_INIT) and use
 282          * the appropriate password but it isn't working yet.  So we
 283          * always use the default one for now.
 284          */
 285         bzero(netr_info->password, sizeof (netr_info->password));
 286         rc = smb_config_getstr(SMB_CI_MACHINE_PASSWD,
 287             (char *)netr_info->password, sizeof (netr_info->password));
 288 
 289         if ((rc != SMBD_SMF_OK) || *netr_info->password == '\0') {
 290                 return (SMBAUTH_FAILURE);
 291         }
 292 
 293         rc = smb_auth_ntlm_hash((char *)netr_info->password, ntlmhash);
 294         if (rc != SMBAUTH_SUCCESS)
 295                 return (SMBAUTH_FAILURE);
 296 
 297         bzero(zerobuf, NETR_SESSKEY_ZEROBUF_SZ);
 298 
 299         mechanism.mechanism = CKM_MD5;
 300         mechanism.pParameter = 0;
 301         mechanism.ulParameterLen = 0;
 302 
 303         rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession);
 304         if (rv != CKR_OK)
 305                 return (SMBAUTH_FAILURE);
 306 
 307         rv = C_DigestInit(hSession, &mechanism);
 308         if (rv != CKR_OK)
 309                 goto cleanup;
 310 
 311         rv = C_DigestUpdate(hSession, (CK_BYTE_PTR)zerobuf,
 312             NETR_SESSKEY_ZEROBUF_SZ);
 313         if (rv != CKR_OK)
 314                 goto cleanup;
 315 
 316         rv = C_DigestUpdate(hSession,
 317             (CK_BYTE_PTR)netr_info->client_challenge.data, NETR_CRED_DATA_SZ);
 318         if (rv != CKR_OK)
 319                 goto cleanup;
 320 
 321         rv = C_DigestUpdate(hSession,
 322             (CK_BYTE_PTR)netr_info->server_challenge.data, NETR_CRED_DATA_SZ);
 323         if (rv != CKR_OK)
 324                 goto cleanup;
 325 
 326         rv = C_DigestFinal(hSession, (CK_BYTE_PTR)md5digest, &diglen);
 327         if (rv != CKR_OK)
 328                 goto cleanup;
 329 
 330         rc = smb_auth_hmac_md5(md5digest, diglen, ntlmhash, SMBAUTH_HASH_SZ,
 331             netr_info->session_key.key);
 332 
 333         netr_info->session_key.len = NETR_SESSKEY128_SZ;
 334 cleanup:
 335         (void) C_CloseSession(hSession);
 336         return (rc);
 337 
 338 }
 339 /*
 340  * netr_gen_skey64
 341  *
 342  * Generate a 64-bit session key from the client and server challenges.
 343  * See "Session-Key Computation" section of MS-NRPC document.
 344  *
 345  * The algorithm is a two stage hash. For the first hash, the input is
 346  * the combination of the client and server challenges, the key is
 347  * the first 7 bytes of the password. The initial password is formed
 348  * using the NT password hash on the local hostname in lower case.
 349  * The result is stored in a temporary buffer.
 350  *
 351  *              input:  challenge
 352  *              key:    passwd lower 7 bytes
 353  *              output: intermediate result
 354  *
 355  * For the second hash, the input is the result of the first hash and
 356  * the key is the last 7 bytes of the password.
 357  *
 358  *              input:  result of first hash
 359  *              key:    passwd upper 7 bytes
 360  *              output: session_key
 361  *
 362  * The final output should be the session key.
 363  *
 364  *              FYI: smb_auth_DES(output, key, input)
 365  *
 366  * If any difficulties occur using the cryptographic framework, the
 367  * function returns SMBAUTH_FAILURE.  Otherwise SMBAUTH_SUCCESS is
 368  * returned.
 369  */
 370 int
 371 netr_gen_skey64(netr_info_t *netr_info)
 372 {
 373         unsigned char md4hash[32];
 374         unsigned char buffer[8];
 375         DWORD data[2];
 376         DWORD *client_challenge;
 377         DWORD *server_challenge;
 378         int rc;
 379         DWORD le_data[2];
 380 
 381         client_challenge = (DWORD *)(uintptr_t)&netr_info->client_challenge;
 382         server_challenge = (DWORD *)(uintptr_t)&netr_info->server_challenge;
 383         bzero(md4hash, 32);
 384 
 385         /*
 386          * We should check (netr_info->flags & NETR_FLG_INIT) and use
 387          * the appropriate password but it isn't working yet.  So we
 388          * always use the default one for now.
 389          */
 390         bzero(netr_info->password, sizeof (netr_info->password));
 391         rc = smb_config_getstr(SMB_CI_MACHINE_PASSWD,
 392             (char *)netr_info->password, sizeof (netr_info->password));
 393 
 394         if ((rc != SMBD_SMF_OK) || *netr_info->password == '\0') {
 395                 return (SMBAUTH_FAILURE);
 396         }
 397 
 398         rc = smb_auth_ntlm_hash((char *)netr_info->password, md4hash);
 399 
 400         if (rc != SMBAUTH_SUCCESS)
 401                 return (SMBAUTH_FAILURE);
 402 
 403         data[0] = LE_IN32(&client_challenge[0]) + LE_IN32(&server_challenge[0]);
 404         data[1] = LE_IN32(&client_challenge[1]) + LE_IN32(&server_challenge[1]);
 405         LE_OUT32(&le_data[0], data[0]);
 406         LE_OUT32(&le_data[1], data[1]);
 407         rc = smb_auth_DES(buffer, 8, md4hash, NETR_DESKEY_LEN,
 408             (unsigned char *)le_data, 8);
 409 
 410         if (rc != SMBAUTH_SUCCESS)
 411                 return (rc);
 412 
 413         netr_info->session_key.len = NETR_SESSKEY64_SZ;
 414         rc = smb_auth_DES(netr_info->session_key.key,
 415             netr_info->session_key.len, &md4hash[9], NETR_DESKEY_LEN, buffer,
 416             8);
 417 
 418         return (rc);
 419 }
 420 
 421 /*
 422  * netr_gen_credentials
 423  *
 424  * Generate a set of credentials from a challenge and a session key.
 425  * The algorithm is a two stage hash. For the first hash, the
 426  * timestamp is added to the challenge and the result is stored in a
 427  * temporary buffer:
 428  *
 429  *              input:  challenge (including timestamp)
 430  *              key:    session_key
 431  *              output: intermediate result
 432  *
 433  * For the second hash, the input is the result of the first hash and
 434  * a strange partial key is used:
 435  *
 436  *              input:  result of first hash
 437  *              key:    funny partial key
 438  *              output: credentiails
 439  *
 440  * The final output should be an encrypted set of credentials.
 441  *
 442  *              FYI: smb_auth_DES(output, key, input)
 443  *
 444  * If any difficulties occur using the cryptographic framework, the
 445  * function returns SMBAUTH_FAILURE.  Otherwise SMBAUTH_SUCCESS is
 446  * returned.
 447  */
 448 int
 449 netr_gen_credentials(BYTE *session_key, netr_cred_t *challenge,
 450     DWORD timestamp, netr_cred_t *out_cred)
 451 {
 452         unsigned char buffer[8];
 453         DWORD data[2];
 454         DWORD le_data[2];
 455         DWORD *p;
 456         int rc;
 457 
 458         p = (DWORD *)(uintptr_t)challenge;
 459         data[0] = LE_IN32(&p[0]) + timestamp;
 460         data[1] = LE_IN32(&p[1]);
 461 
 462         LE_OUT32(&le_data[0], data[0]);
 463         LE_OUT32(&le_data[1], data[1]);
 464 
 465         if (smb_auth_DES(buffer, 8, session_key, NETR_DESKEY_LEN,
 466             (unsigned char *)le_data, 8) != SMBAUTH_SUCCESS)
 467                 return (SMBAUTH_FAILURE);
 468 
 469         rc = smb_auth_DES(out_cred->data, 8, &session_key[NETR_DESKEY_LEN],
 470             NETR_DESKEY_LEN, buffer, 8);
 471 
 472         return (rc);
 473 }
 474 
 475 /*
 476  * netr_server_password_set
 477  *
 478  * Attempt to change the trust account password for this system.
 479  *
 480  * Note that this call may legitimately fail if the registry on the
 481  * domain controller has been setup to deny attempts to change the
 482  * trust account password. In this case we should just continue to
 483  * use the original password.
 484  *
 485  * Possible status values:
 486  *      NT_STATUS_ACCESS_DENIED
 487  */
 488 int
 489 netr_server_password_set(mlsvc_handle_t *netr_handle, netr_info_t *netr_info)
 490 {
 491         struct netr_PasswordSet  arg;
 492         int opnum;
 493         BYTE new_password[NETR_OWF_PASSWORD_SZ];
 494         char account_name[NETBIOS_NAME_SZ * 2];
 495 
 496         bzero(&arg, sizeof (struct netr_PasswordSet));
 497         opnum = NETR_OPNUM_ServerPasswordSet;
 498 
 499         (void) snprintf(account_name, sizeof (account_name), "%s$",
 500             netr_info->hostname);
 501 
 502         arg.servername = (unsigned char *)netr_info->server;
 503         arg.account_name = (unsigned char *)account_name;
 504         arg.sec_chan_type = NETR_WKSTA_TRUST_ACCOUNT_TYPE;
 505         arg.hostname = (unsigned char *)netr_info->hostname;
 506 
 507         /*
 508          * Set up the client side authenticator.
 509          */
 510         if (netr_setup_authenticator(netr_info, &arg.auth, 0) !=
 511             SMBAUTH_SUCCESS) {
 512                 return (-1);
 513         }
 514 
 515         /*
 516          * Generate a new password from the old password.
 517          */
 518         if (netr_gen_password(netr_info->session_key.key,
 519             netr_info->password, new_password) == SMBAUTH_FAILURE) {
 520                 return (-1);
 521         }
 522 
 523         (void) memcpy(&arg.owf_password, &new_password,
 524             NETR_OWF_PASSWORD_SZ);
 525 
 526         if (ndr_rpc_call(netr_handle, opnum, &arg) != 0)
 527                 return (-1);
 528 
 529         if (arg.status != 0) {
 530                 ndr_rpc_status(netr_handle, opnum, arg.status);
 531                 ndr_rpc_release(netr_handle);
 532                 return (-1);
 533         }
 534 
 535         /*
 536          * Check the returned credentials.  The server returns the new
 537          * client credential rather than the new server credentiali,
 538          * as documented elsewhere.
 539          *
 540          * Generate the new seed for the credential chain.  Increment
 541          * the timestamp and add it to the client challenge.  Then we
 542          * need to copy the challenge to the credential field in
 543          * preparation for the next cycle.
 544          */
 545         if (netr_validate_chain(netr_info, &arg.auth) == 0) {
 546                 /*
 547                  * Save the new password.
 548                  */
 549                 (void) memcpy(netr_info->password, new_password,
 550                     NETR_OWF_PASSWORD_SZ);
 551         }
 552 
 553         ndr_rpc_release(netr_handle);
 554         return (0);
 555 }
 556 
 557 /*
 558  * netr_gen_password
 559  *
 560  * Generate a new pasword from the old password  and the session key.
 561  * The algorithm is a two stage hash. The session key is used in the
 562  * first hash but only part of the session key is used in the second
 563  * hash.
 564  *
 565  * If any difficulties occur using the cryptographic framework, the
 566  * function returns SMBAUTH_FAILURE.  Otherwise SMBAUTH_SUCCESS is
 567  * returned.
 568  */
 569 static int
 570 netr_gen_password(BYTE *session_key, BYTE *old_password, BYTE *new_password)
 571 {
 572         int rv;
 573 
 574         rv = smb_auth_DES(new_password, 8, session_key, NETR_DESKEY_LEN,
 575             old_password, 8);
 576         if (rv != SMBAUTH_SUCCESS)
 577                 return (rv);
 578 
 579         rv = smb_auth_DES(&new_password[8], 8, &session_key[NETR_DESKEY_LEN],
 580             NETR_DESKEY_LEN, &old_password[8], 8);
 581         return (rv);
 582 }
 583 
 584 /*
 585  * Todo: need netr_server_password_set2()
 586  * used by "unsecure join". (NX 11960)
 587  */