15331Samw /* 25331Samw * CDDL HEADER START 35331Samw * 45331Samw * The contents of this file are subject to the terms of the 55331Samw * Common Development and Distribution License (the "License"). 65331Samw * You may not use this file except in compliance with the License. 75331Samw * 85331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95331Samw * or http://www.opensolaris.org/os/licensing. 105331Samw * See the License for the specific language governing permissions 115331Samw * and limitations under the License. 125331Samw * 135331Samw * When distributing Covered Code, include this CDDL HEADER in each 145331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155331Samw * If applicable, add the following below this CDDL HEADER, with the 165331Samw * fields enclosed by brackets "[]" replaced with your own identifying 175331Samw * information: Portions Copyright [yyyy] [name of copyright owner] 185331Samw * 195331Samw * CDDL HEADER END 205331Samw */ 215331Samw /* 225772Sas200622 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 235331Samw * Use is subject to license terms. 245331Samw */ 255331Samw 265331Samw #pragma ident "%Z%%M% %I% %E% SMI" 275331Samw 285331Samw /* 295331Samw * NETR challenge/response client functions. 305331Samw * 315331Samw * NT_STATUS_INVALID_PARAMETER 325331Samw * NT_STATUS_NO_TRUST_SAM_ACCOUNT 335331Samw * NT_STATUS_ACCESS_DENIED 345331Samw */ 355331Samw 365331Samw #include <stdio.h> 375331Samw #include <stdlib.h> 385331Samw #include <strings.h> 395331Samw #include <unistd.h> 405331Samw #include <ctype.h> 415331Samw 425331Samw #include <smbsrv/libsmb.h> 435521Sas200622 #include <smbsrv/libsmbrdr.h> 44*6432Sas200622 #include <smbsrv/libsmbns.h> 455331Samw #include <smbsrv/mlsvc_util.h> 465331Samw #include <smbsrv/ndl/netlogon.ndl> 475331Samw #include <smbsrv/ntstatus.h> 485331Samw #include <smbsrv/smbinfo.h> 495331Samw #include <smbsrv/mlsvc.h> 505331Samw #include <smbsrv/netrauth.h> 515331Samw 525331Samw int netr_setup_authenticator(netr_info_t *, struct netr_authenticator *, 535331Samw struct netr_authenticator *); 545331Samw DWORD netr_validate_chain(netr_info_t *, struct netr_authenticator *); 555331Samw 565331Samw static int netr_server_req_challenge(mlsvc_handle_t *, netr_info_t *); 575331Samw static int netr_server_authenticate2(mlsvc_handle_t *, netr_info_t *); 585331Samw static int netr_gen_password(BYTE *, BYTE *, BYTE *); 595331Samw 605331Samw /* 615331Samw * Shared with netr_logon.c 625331Samw */ 635331Samw netr_info_t netr_global_info; 645331Samw 655331Samw /* 665331Samw * netlogon_auth 675331Samw * 685331Samw * This is the core of the NETLOGON authentication protocol. 695331Samw * Do the challenge response authentication. 705331Samw * 715331Samw * Prior to calling this function, an anonymous session to the NETLOGON 725331Samw * pipe on a domain controller(server) should have already been opened. 736139Sjb150015 * 746139Sjb150015 * Upon a successful NETLOGON credential chain establishment, the 756139Sjb150015 * netlogon sequence number will be set to match the kpasswd sequence 766139Sjb150015 * number. 776139Sjb150015 * 785331Samw */ 795331Samw DWORD 805331Samw netlogon_auth(char *server, mlsvc_handle_t *netr_handle, DWORD flags) 815331Samw { 825331Samw netr_info_t *netr_info; 835331Samw int rc; 845521Sas200622 DWORD leout_rc[2]; 855331Samw 865331Samw netr_info = &netr_global_info; 875331Samw bzero(netr_info, sizeof (netr_info_t)); 885331Samw 895331Samw netr_info->flags |= flags; 905331Samw 915331Samw rc = smb_getnetbiosname(netr_info->hostname, MLSVC_DOMAIN_NAME_MAX); 925331Samw if (rc != 0) 935331Samw return (NT_STATUS_UNSUCCESSFUL); 945331Samw 955331Samw (void) snprintf(netr_info->server, sizeof (netr_info->server), 965331Samw "\\\\%s", server); 975331Samw 985521Sas200622 LE_OUT32(&leout_rc[0], random()); 995521Sas200622 LE_OUT32(&leout_rc[1], random()); 1005521Sas200622 (void) memcpy(&netr_info->client_challenge, leout_rc, 1015331Samw sizeof (struct netr_credential)); 1025331Samw 1035331Samw if ((rc = netr_server_req_challenge(netr_handle, netr_info)) == 0) { 1045331Samw rc = netr_server_authenticate2(netr_handle, netr_info); 1056139Sjb150015 if (rc == 0) { 1066139Sjb150015 smb_update_netlogon_seqnum(); 1075331Samw netr_info->flags |= NETR_FLG_VALID; 1086139Sjb150015 1096139Sjb150015 } 1105331Samw } 1115331Samw 112*6432Sas200622 /* 113*6432Sas200622 * The NETLOGON credential chain establishment has unset 114*6432Sas200622 * both ServerPrincipalName and dNSHostName attributes of the 115*6432Sas200622 * workstation trust account. Those attributes will be updated 116*6432Sas200622 * here to avoid any Kerberos authentication errors from happening. 117*6432Sas200622 * 118*6432Sas200622 * Later, when NT4 domain controller is supported, we need to 119*6432Sas200622 * find a way to disable the following code. 120*6432Sas200622 */ 121*6432Sas200622 if (ads_update_attrs() == -1) 122*6432Sas200622 syslog(LOG_DEBUG, "netlogon_auth: ServerPrincipalName" 123*6432Sas200622 " and dNSHostName attributes might have been unset."); 124*6432Sas200622 1255331Samw return ((rc) ? NT_STATUS_UNSUCCESSFUL : NT_STATUS_SUCCESS); 1265331Samw } 1275331Samw 1285331Samw /* 1295331Samw * netr_open 1305331Samw * 1315331Samw * Open an anonymous session to the NETLOGON pipe on a domain 1325331Samw * controller and bind to the NETR RPC interface. We store the 1335331Samw * remote server's native OS type - we may need it due to 1345331Samw * differences between versions of Windows. 1355331Samw */ 1365331Samw int 1375331Samw netr_open(char *server, char *domain, mlsvc_handle_t *netr_handle) 1385331Samw { 1395331Samw int fid; 1405331Samw int remote_os = 0; 1415331Samw int remote_lm = 0; 1425331Samw int server_pdc; 1435521Sas200622 char *user = smbrdr_ipc_get_user(); 1445331Samw 1455521Sas200622 if (mlsvc_logon(server, domain, user) != 0) 1465331Samw return (-1); 1475331Samw 1485521Sas200622 fid = mlsvc_open_pipe(server, domain, user, "\\NETLOGON"); 1495331Samw if (fid < 0) 1505331Samw return (-1); 1515331Samw 1525331Samw if (mlsvc_rpc_bind(netr_handle, fid, "NETR") < 0) { 1535331Samw (void) mlsvc_close_pipe(fid); 1545331Samw return (-1); 1555331Samw } 1565331Samw 1575331Samw (void) mlsvc_session_native_values(fid, &remote_os, &remote_lm, 1585331Samw &server_pdc); 1595331Samw netr_handle->context->server_os = remote_os; 1605331Samw netr_handle->context->server_pdc = server_pdc; 1615331Samw return (0); 1625331Samw } 1635331Samw 1645331Samw /* 1655331Samw * netr_close 1665331Samw * 1675331Samw * Close a NETLOGON pipe and free the RPC context. 1685331Samw */ 1695331Samw int 1705331Samw netr_close(mlsvc_handle_t *netr_handle) 1715331Samw { 1725331Samw (void) mlsvc_close_pipe(netr_handle->context->fid); 1735331Samw free(netr_handle->context); 1745331Samw return (0); 1755331Samw } 1765331Samw 1775331Samw /* 1785331Samw * netr_server_req_challenge 1795331Samw */ 1805331Samw static int 1815331Samw netr_server_req_challenge(mlsvc_handle_t *netr_handle, netr_info_t *netr_info) 1825331Samw { 1835331Samw struct netr_ServerReqChallenge arg; 1845331Samw mlrpc_heapref_t heap; 1855331Samw int opnum; 1865331Samw int rc; 1875331Samw 1885331Samw bzero(&arg, sizeof (struct netr_ServerReqChallenge)); 1895331Samw opnum = NETR_OPNUM_ServerReqChallenge; 1905331Samw 1915331Samw arg.servername = (unsigned char *)netr_info->server; 1925331Samw arg.hostname = (unsigned char *)netr_info->hostname; 1935331Samw 1945331Samw (void) memcpy(&arg.client_challenge, &netr_info->client_challenge, 1955331Samw sizeof (struct netr_credential)); 1965331Samw 1975331Samw (void) mlsvc_rpc_init(&heap); 1985331Samw rc = mlsvc_rpc_call(netr_handle->context, opnum, &arg, &heap); 1995331Samw if (rc == 0) { 2005331Samw if (arg.status != 0) { 2015331Samw mlsvc_rpc_report_status(opnum, arg.status); 2025331Samw rc = -1; 2035331Samw } else { 2045331Samw (void) memcpy(&netr_info->server_challenge, 2055331Samw &arg.server_challenge, 2065331Samw sizeof (struct netr_credential)); 2075331Samw } 2085331Samw } 2095331Samw 2105331Samw mlsvc_rpc_free(netr_handle->context, &heap); 2115331Samw return (rc); 2125331Samw } 2135331Samw 2145331Samw /* 2155331Samw * netr_server_authenticate2 2165331Samw */ 2175331Samw static int 2185331Samw netr_server_authenticate2(mlsvc_handle_t *netr_handle, netr_info_t *netr_info) 2195331Samw { 2205331Samw struct netr_ServerAuthenticate2 arg; 2215331Samw mlrpc_heapref_t heap; 2225331Samw int opnum; 2235331Samw int rc; 2245331Samw char account_name[MLSVC_DOMAIN_NAME_MAX * 2]; 2255331Samw 2265331Samw bzero(&arg, sizeof (struct netr_ServerAuthenticate2)); 2275331Samw opnum = NETR_OPNUM_ServerAuthenticate2; 2285331Samw 2295331Samw (void) snprintf(account_name, sizeof (account_name), "%s$", 2305331Samw netr_info->hostname); 2315331Samw 2325331Samw arg.servername = (unsigned char *)netr_info->server; 2335331Samw arg.account_name = (unsigned char *)account_name; 2345331Samw arg.account_type = NETR_WKSTA_TRUST_ACCOUNT_TYPE; 2355331Samw arg.hostname = (unsigned char *)netr_info->hostname; 2365331Samw arg.negotiate_flags = NETR_NEGOTIATE_FLAGS; 2375331Samw 2385331Samw smb_tracef("server=[%s] account_name=[%s] hostname=[%s]\n", 2395331Samw netr_info->server, account_name, netr_info->hostname); 2405331Samw 2415331Samw if (netr_gen_session_key(netr_info) != SMBAUTH_SUCCESS) 2425331Samw return (-1); 2435331Samw 2445331Samw if (netr_gen_credentials(netr_info->session_key, 2455331Samw &netr_info->client_challenge, 2465331Samw 0, 2475331Samw &netr_info->client_credential) != SMBAUTH_SUCCESS) { 2485331Samw return (-1); 2495331Samw } 2505331Samw 2515331Samw if (netr_gen_credentials(netr_info->session_key, 2525331Samw &netr_info->server_challenge, 2535331Samw 0, 2545331Samw &netr_info->server_credential) != SMBAUTH_SUCCESS) { 2555331Samw return (-1); 2565331Samw } 2575331Samw 2585331Samw (void) memcpy(&arg.client_credential, &netr_info->client_credential, 2595331Samw sizeof (struct netr_credential)); 2605331Samw 2615331Samw (void) mlsvc_rpc_init(&heap); 2625331Samw 2635331Samw rc = mlsvc_rpc_call(netr_handle->context, opnum, &arg, &heap); 2645331Samw if (rc == 0) { 2655331Samw if (arg.status != 0) { 2665331Samw mlsvc_rpc_report_status(opnum, arg.status); 2675331Samw rc = -1; 2685331Samw } else { 2695331Samw rc = memcmp(&netr_info->server_credential, 2705331Samw &arg.server_credential, 2715331Samw sizeof (struct netr_credential)); 2725331Samw } 2735331Samw } 2745331Samw 2755331Samw mlsvc_rpc_free(netr_handle->context, &heap); 2765331Samw return (rc); 2775331Samw } 2785331Samw 2795331Samw /* 2805331Samw * netr_gen_session_key 2815331Samw * 2825331Samw * Generate a session key from the client and server challenges. The 2835331Samw * algorithm is a two stage hash. For the first hash, the input is 2845331Samw * the combination of the client and server challenges, the key is 2855331Samw * the first 8 bytes of the password. The initial password is formed 2865331Samw * using the NT password hash on the local hostname in lower case. 2875331Samw * The result is stored in a temporary buffer. 2885331Samw * 2895331Samw * input: challenge 2905331Samw * key: passwd lower 8 bytes 2915331Samw * output: intermediate result 2925331Samw * 2935331Samw * For the second hash, the input is the result of the first hash and 2945331Samw * the key is the last 8 bytes of the password. 2955331Samw * 2965331Samw * input: result of first hash 2975331Samw * key: passwd upper 8 bytes 2985331Samw * output: session_key 2995331Samw * 3005331Samw * The final output should be the session key. 3015331Samw * 3025331Samw * FYI: smb_auth_DES(output, key, input) 3035331Samw * 3045331Samw * If any difficulties occur using the cryptographic framework, the 3055331Samw * function returns SMBAUTH_FAILURE. Otherwise SMBAUTH_SUCCESS is 3065331Samw * returned. 3075331Samw */ 3085331Samw int 3095331Samw netr_gen_session_key(netr_info_t *netr_info) 3105331Samw { 3115331Samw unsigned char md4hash[32]; 3125331Samw unsigned char buffer[8]; 3135331Samw DWORD data[2]; 3145331Samw DWORD *client_challenge; 3155331Samw DWORD *server_challenge; 3165331Samw int rc; 3175521Sas200622 DWORD le_data[2]; 3185331Samw 3195331Samw client_challenge = (DWORD *)(uintptr_t)&netr_info->client_challenge; 3205331Samw server_challenge = (DWORD *)(uintptr_t)&netr_info->server_challenge; 3215331Samw bzero(md4hash, 32); 3225331Samw 3235331Samw /* 3245331Samw * We should check (netr_info->flags & NETR_FLG_INIT) and use 3255331Samw * the appropriate password but it isn't working yet. So we 3265331Samw * always use the default one for now. 3275331Samw */ 3285772Sas200622 bzero(netr_info->password, sizeof (netr_info->password)); 3295772Sas200622 rc = smb_config_getstr(SMB_CI_MACHINE_PASSWD, 3305772Sas200622 (char *)netr_info->password, sizeof (netr_info->password)); 3315331Samw 3325772Sas200622 if ((rc != SMBD_SMF_OK) || *netr_info->password == '\0') { 3335331Samw return (-1); 3345331Samw } 3355331Samw 3365772Sas200622 rc = smb_auth_ntlm_hash((char *)netr_info->password, md4hash); 3375331Samw 3385331Samw if (rc != SMBAUTH_SUCCESS) 3395331Samw return (SMBAUTH_FAILURE); 3405331Samw 3415331Samw data[0] = LE_IN32(&client_challenge[0]) + LE_IN32(&server_challenge[0]); 3425331Samw data[1] = LE_IN32(&client_challenge[1]) + LE_IN32(&server_challenge[1]); 3435521Sas200622 LE_OUT32(&le_data[0], data[0]); 3445521Sas200622 LE_OUT32(&le_data[1], data[1]); 3455331Samw 3465521Sas200622 rc = smb_auth_DES(buffer, 8, md4hash, 8, (unsigned char *)le_data, 8); 3475331Samw if (rc != SMBAUTH_SUCCESS) 3485331Samw return (rc); 3495331Samw 3505331Samw rc = smb_auth_DES(netr_info->session_key, 8, &md4hash[9], 8, buffer, 8); 3515331Samw return (rc); 3525331Samw } 3535331Samw 3545331Samw /* 3555331Samw * netr_gen_credentials 3565331Samw * 3575331Samw * Generate a set of credentials from a challenge and a session key. 3585331Samw * The algorithm is a two stage hash. For the first hash, the 3595331Samw * timestamp is added to the challenge and the result is stored in a 3605331Samw * temporary buffer: 3615331Samw * 3625331Samw * input: challenge (including timestamp) 3635331Samw * key: session_key 3645331Samw * output: intermediate result 3655331Samw * 3665331Samw * For the second hash, the input is the result of the first hash and 3675331Samw * a strange partial key is used: 3685331Samw * 3695331Samw * input: result of first hash 3705331Samw * key: funny partial key 3715331Samw * output: credentiails 3725331Samw * 3735331Samw * The final output should be an encrypted set of credentials. 3745331Samw * 3755331Samw * FYI: smb_auth_DES(output, key, input) 3765331Samw * 3775331Samw * If any difficulties occur using the cryptographic framework, the 3785331Samw * function returns SMBAUTH_FAILURE. Otherwise SMBAUTH_SUCCESS is 3795331Samw * returned. 3805331Samw */ 3815331Samw int 3825331Samw netr_gen_credentials(BYTE *session_key, netr_cred_t *challenge, 3835331Samw DWORD timestamp, netr_cred_t *out_cred) 3845331Samw { 3855331Samw unsigned char buffer[8]; 3865331Samw unsigned char partial_key[8]; 3875331Samw DWORD data[2]; 3885521Sas200622 DWORD le_data[2]; 3895331Samw DWORD *p; 3905331Samw int rc; 3915331Samw 3925331Samw p = (DWORD *)(uintptr_t)challenge; 3935521Sas200622 data[0] = LE_IN32(&p[0]) + timestamp; 3945521Sas200622 data[1] = LE_IN32(&p[1]); 3955521Sas200622 3965521Sas200622 LE_OUT32(&le_data[0], data[0]); 3975521Sas200622 LE_OUT32(&le_data[1], data[1]); 3985331Samw 3995331Samw if (smb_auth_DES(buffer, 8, session_key, 8, 4005521Sas200622 (unsigned char *)le_data, 8) != SMBAUTH_SUCCESS) 4015331Samw return (SMBAUTH_FAILURE); 4025331Samw 4035331Samw bzero(partial_key, 8); 4045331Samw partial_key[0] = session_key[7]; 4055331Samw 4065331Samw rc = smb_auth_DES((unsigned char *)out_cred, 8, partial_key, 8, 4075331Samw buffer, 8); 4085331Samw return (rc); 4095331Samw } 4105331Samw 4115331Samw /* 4125331Samw * netr_server_password_set 4135331Samw * 4145331Samw * Attempt to change the trust account password for this system. 4155331Samw * 4165331Samw * Note that this call may legitimately fail if the registry on the 4175331Samw * domain controller has been setup to deny attempts to change the 4185331Samw * trust account password. In this case we should just continue to 4195331Samw * use the original password. 4205331Samw * 4215331Samw * Possible status values: 4225331Samw * NT_STATUS_ACCESS_DENIED 4235331Samw */ 4245331Samw int 4255331Samw netr_server_password_set(mlsvc_handle_t *netr_handle, netr_info_t *netr_info) 4265331Samw { 4275331Samw struct netr_PasswordSet arg; 4285331Samw mlrpc_heapref_t heap; 4295331Samw int opnum; 4305331Samw int rc; 4315331Samw BYTE new_password[NETR_OWF_PASSWORD_SZ]; 4325331Samw char account_name[MLSVC_DOMAIN_NAME_MAX * 2]; 4335331Samw 4345331Samw bzero(&arg, sizeof (struct netr_PasswordSet)); 4355331Samw opnum = NETR_OPNUM_ServerPasswordSet; 4365331Samw 4375331Samw (void) snprintf(account_name, sizeof (account_name), "%s$", 4385331Samw netr_info->hostname); 4395331Samw 4405331Samw arg.servername = (unsigned char *)netr_info->server; 4415331Samw arg.account_name = (unsigned char *)account_name; 4425331Samw arg.account_type = NETR_WKSTA_TRUST_ACCOUNT_TYPE; 4435331Samw arg.hostname = (unsigned char *)netr_info->hostname; 4445331Samw 4455331Samw /* 4465331Samw * Set up the client side authenticator. 4475331Samw */ 4485331Samw if (netr_setup_authenticator(netr_info, &arg.auth, 0) != 4495331Samw SMBAUTH_SUCCESS) { 4505331Samw return (-1); 4515331Samw } 4525331Samw 4535331Samw /* 4545331Samw * Generate a new password from the old password. 4555331Samw */ 4565331Samw if (netr_gen_password(netr_info->session_key, 4575331Samw netr_info->password, new_password) == SMBAUTH_FAILURE) { 4585331Samw return (-1); 4595331Samw } 4605331Samw 4615331Samw (void) memcpy(&arg.uas_new_password, &new_password, 4625331Samw NETR_OWF_PASSWORD_SZ); 4635331Samw 4645331Samw (void) mlsvc_rpc_init(&heap); 4655331Samw rc = mlsvc_rpc_call(netr_handle->context, opnum, &arg, &heap); 4665331Samw if ((rc != 0) || (arg.status != 0)) { 4675331Samw mlsvc_rpc_report_status(opnum, arg.status); 4685331Samw mlsvc_rpc_free(netr_handle->context, &heap); 4695331Samw return (-1); 4705331Samw } 4715331Samw 4725331Samw /* 4735331Samw * Check the returned credentials. The server returns the new 4745331Samw * client credential rather than the new server credentiali, 4755331Samw * as documented elsewhere. 4765331Samw * 4775331Samw * Generate the new seed for the credential chain. Increment 4785331Samw * the timestamp and add it to the client challenge. Then we 4795331Samw * need to copy the challenge to the credential field in 4805331Samw * preparation for the next cycle. 4815331Samw */ 4825331Samw if (netr_validate_chain(netr_info, &arg.auth) == 0) { 4835331Samw /* 4845331Samw * Save the new password. 4855331Samw */ 4865331Samw (void) memcpy(netr_info->password, new_password, 4875331Samw NETR_OWF_PASSWORD_SZ); 4885331Samw } 4895331Samw 4905331Samw mlsvc_rpc_free(netr_handle->context, &heap); 4915331Samw return (0); 4925331Samw } 4935331Samw 4945331Samw /* 4955331Samw * netr_gen_password 4965331Samw * 4975331Samw * Generate a new pasword from the old password and the session key. 4985331Samw * The algorithm is a two stage hash. The session key is used in the 4995331Samw * first hash but only part of the session key is used in the second 5005331Samw * hash. 5015331Samw * 5025331Samw * If any difficulties occur using the cryptographic framework, the 5035331Samw * function returns SMBAUTH_FAILURE. Otherwise SMBAUTH_SUCCESS is 5045331Samw * returned. 5055331Samw */ 5065331Samw static int 5075331Samw netr_gen_password(BYTE *session_key, BYTE *old_password, BYTE *new_password) 5085331Samw { 5095331Samw unsigned char partial_key[8]; 5105331Samw int rv; 5115331Samw 5125331Samw rv = smb_auth_DES(new_password, 8, session_key, 8, old_password, 8); 5135331Samw if (rv != SMBAUTH_SUCCESS) 5145331Samw return (rv); 5155331Samw 5165331Samw bzero(partial_key, 8); 5175331Samw partial_key[0] = session_key[7]; 5185331Samw 5195331Samw rv = smb_auth_DES(&new_password[8], 8, partial_key, 8, 5205331Samw &old_password[8], 8); 5215331Samw return (rv); 5225331Samw } 523