1*5331Samw /* 2*5331Samw * CDDL HEADER START 3*5331Samw * 4*5331Samw * The contents of this file are subject to the terms of the 5*5331Samw * Common Development and Distribution License (the "License"). 6*5331Samw * You may not use this file except in compliance with the License. 7*5331Samw * 8*5331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*5331Samw * or http://www.opensolaris.org/os/licensing. 10*5331Samw * See the License for the specific language governing permissions 11*5331Samw * and limitations under the License. 12*5331Samw * 13*5331Samw * When distributing Covered Code, include this CDDL HEADER in each 14*5331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*5331Samw * If applicable, add the following below this CDDL HEADER, with the 16*5331Samw * fields enclosed by brackets "[]" replaced with your own identifying 17*5331Samw * information: Portions Copyright [yyyy] [name of copyright owner] 18*5331Samw * 19*5331Samw * CDDL HEADER END 20*5331Samw */ 21*5331Samw /* 22*5331Samw * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23*5331Samw * Use is subject to license terms. 24*5331Samw */ 25*5331Samw 26*5331Samw #pragma ident "%Z%%M% %I% %E% SMI" 27*5331Samw 28*5331Samw /* 29*5331Samw * NETR challenge/response client functions. 30*5331Samw * 31*5331Samw * NT_STATUS_INVALID_PARAMETER 32*5331Samw * NT_STATUS_NO_TRUST_SAM_ACCOUNT 33*5331Samw * NT_STATUS_ACCESS_DENIED 34*5331Samw */ 35*5331Samw 36*5331Samw #include <stdio.h> 37*5331Samw #include <stdlib.h> 38*5331Samw #include <strings.h> 39*5331Samw #include <unistd.h> 40*5331Samw #include <ctype.h> 41*5331Samw 42*5331Samw #include <smbsrv/libsmb.h> 43*5331Samw #include <smbsrv/mlsvc_util.h> 44*5331Samw #include <smbsrv/ndl/netlogon.ndl> 45*5331Samw #include <smbsrv/ntstatus.h> 46*5331Samw #include <smbsrv/smbinfo.h> 47*5331Samw #include <smbsrv/mlsvc.h> 48*5331Samw #include <smbsrv/netrauth.h> 49*5331Samw 50*5331Samw int netr_setup_authenticator(netr_info_t *, struct netr_authenticator *, 51*5331Samw struct netr_authenticator *); 52*5331Samw DWORD netr_validate_chain(netr_info_t *, struct netr_authenticator *); 53*5331Samw 54*5331Samw static int netr_server_req_challenge(mlsvc_handle_t *, netr_info_t *); 55*5331Samw static int netr_server_authenticate2(mlsvc_handle_t *, netr_info_t *); 56*5331Samw static int netr_gen_password(BYTE *, BYTE *, BYTE *); 57*5331Samw 58*5331Samw /* 59*5331Samw * Shared with netr_logon.c 60*5331Samw */ 61*5331Samw netr_info_t netr_global_info; 62*5331Samw 63*5331Samw /* 64*5331Samw * netlogon_auth 65*5331Samw * 66*5331Samw * This is the core of the NETLOGON authentication protocol. 67*5331Samw * Do the challenge response authentication. 68*5331Samw * 69*5331Samw * Prior to calling this function, an anonymous session to the NETLOGON 70*5331Samw * pipe on a domain controller(server) should have already been opened. 71*5331Samw */ 72*5331Samw DWORD 73*5331Samw netlogon_auth(char *server, mlsvc_handle_t *netr_handle, DWORD flags) 74*5331Samw { 75*5331Samw netr_info_t *netr_info; 76*5331Samw int rc; 77*5331Samw DWORD random_challenge[2]; 78*5331Samw 79*5331Samw netr_info = &netr_global_info; 80*5331Samw bzero(netr_info, sizeof (netr_info_t)); 81*5331Samw 82*5331Samw netr_info->flags |= flags; 83*5331Samw 84*5331Samw rc = smb_getnetbiosname(netr_info->hostname, MLSVC_DOMAIN_NAME_MAX); 85*5331Samw if (rc != 0) 86*5331Samw return (NT_STATUS_UNSUCCESSFUL); 87*5331Samw 88*5331Samw (void) snprintf(netr_info->server, sizeof (netr_info->server), 89*5331Samw "\\\\%s", server); 90*5331Samw 91*5331Samw random_challenge[0] = random(); 92*5331Samw random_challenge[1] = random(); 93*5331Samw 94*5331Samw (void) memcpy(&netr_info->client_challenge, random_challenge, 95*5331Samw sizeof (struct netr_credential)); 96*5331Samw 97*5331Samw if ((rc = netr_server_req_challenge(netr_handle, netr_info)) == 0) { 98*5331Samw rc = netr_server_authenticate2(netr_handle, netr_info); 99*5331Samw if (rc == 0) 100*5331Samw netr_info->flags |= NETR_FLG_VALID; 101*5331Samw } 102*5331Samw 103*5331Samw return ((rc) ? NT_STATUS_UNSUCCESSFUL : NT_STATUS_SUCCESS); 104*5331Samw } 105*5331Samw 106*5331Samw /* 107*5331Samw * netr_open 108*5331Samw * 109*5331Samw * Open an anonymous session to the NETLOGON pipe on a domain 110*5331Samw * controller and bind to the NETR RPC interface. We store the 111*5331Samw * remote server's native OS type - we may need it due to 112*5331Samw * differences between versions of Windows. 113*5331Samw */ 114*5331Samw int 115*5331Samw netr_open(char *server, char *domain, mlsvc_handle_t *netr_handle) 116*5331Samw { 117*5331Samw int fid; 118*5331Samw int remote_os = 0; 119*5331Samw int remote_lm = 0; 120*5331Samw int server_pdc; 121*5331Samw char *username; 122*5331Samw 123*5331Samw if (mlsvc_anonymous_logon(server, domain, &username) != 0) 124*5331Samw return (-1); 125*5331Samw 126*5331Samw fid = mlsvc_open_pipe(server, domain, username, "\\NETLOGON"); 127*5331Samw if (fid < 0) 128*5331Samw return (-1); 129*5331Samw 130*5331Samw if (mlsvc_rpc_bind(netr_handle, fid, "NETR") < 0) { 131*5331Samw (void) mlsvc_close_pipe(fid); 132*5331Samw return (-1); 133*5331Samw } 134*5331Samw 135*5331Samw (void) mlsvc_session_native_values(fid, &remote_os, &remote_lm, 136*5331Samw &server_pdc); 137*5331Samw netr_handle->context->server_os = remote_os; 138*5331Samw netr_handle->context->server_pdc = server_pdc; 139*5331Samw return (0); 140*5331Samw } 141*5331Samw 142*5331Samw /* 143*5331Samw * netr_close 144*5331Samw * 145*5331Samw * Close a NETLOGON pipe and free the RPC context. 146*5331Samw */ 147*5331Samw int 148*5331Samw netr_close(mlsvc_handle_t *netr_handle) 149*5331Samw { 150*5331Samw (void) mlsvc_close_pipe(netr_handle->context->fid); 151*5331Samw free(netr_handle->context); 152*5331Samw return (0); 153*5331Samw } 154*5331Samw 155*5331Samw /* 156*5331Samw * netr_server_req_challenge 157*5331Samw */ 158*5331Samw static int 159*5331Samw netr_server_req_challenge(mlsvc_handle_t *netr_handle, netr_info_t *netr_info) 160*5331Samw { 161*5331Samw struct netr_ServerReqChallenge arg; 162*5331Samw mlrpc_heapref_t heap; 163*5331Samw int opnum; 164*5331Samw int rc; 165*5331Samw 166*5331Samw bzero(&arg, sizeof (struct netr_ServerReqChallenge)); 167*5331Samw opnum = NETR_OPNUM_ServerReqChallenge; 168*5331Samw 169*5331Samw arg.servername = (unsigned char *)netr_info->server; 170*5331Samw arg.hostname = (unsigned char *)netr_info->hostname; 171*5331Samw 172*5331Samw (void) memcpy(&arg.client_challenge, &netr_info->client_challenge, 173*5331Samw sizeof (struct netr_credential)); 174*5331Samw 175*5331Samw (void) mlsvc_rpc_init(&heap); 176*5331Samw rc = mlsvc_rpc_call(netr_handle->context, opnum, &arg, &heap); 177*5331Samw if (rc == 0) { 178*5331Samw if (arg.status != 0) { 179*5331Samw mlsvc_rpc_report_status(opnum, arg.status); 180*5331Samw rc = -1; 181*5331Samw } else { 182*5331Samw (void) memcpy(&netr_info->server_challenge, 183*5331Samw &arg.server_challenge, 184*5331Samw sizeof (struct netr_credential)); 185*5331Samw } 186*5331Samw } 187*5331Samw 188*5331Samw mlsvc_rpc_free(netr_handle->context, &heap); 189*5331Samw return (rc); 190*5331Samw } 191*5331Samw 192*5331Samw /* 193*5331Samw * netr_server_authenticate2 194*5331Samw */ 195*5331Samw static int 196*5331Samw netr_server_authenticate2(mlsvc_handle_t *netr_handle, netr_info_t *netr_info) 197*5331Samw { 198*5331Samw struct netr_ServerAuthenticate2 arg; 199*5331Samw mlrpc_heapref_t heap; 200*5331Samw int opnum; 201*5331Samw int rc; 202*5331Samw char account_name[MLSVC_DOMAIN_NAME_MAX * 2]; 203*5331Samw 204*5331Samw bzero(&arg, sizeof (struct netr_ServerAuthenticate2)); 205*5331Samw opnum = NETR_OPNUM_ServerAuthenticate2; 206*5331Samw 207*5331Samw (void) snprintf(account_name, sizeof (account_name), "%s$", 208*5331Samw netr_info->hostname); 209*5331Samw 210*5331Samw arg.servername = (unsigned char *)netr_info->server; 211*5331Samw arg.account_name = (unsigned char *)account_name; 212*5331Samw arg.account_type = NETR_WKSTA_TRUST_ACCOUNT_TYPE; 213*5331Samw arg.hostname = (unsigned char *)netr_info->hostname; 214*5331Samw arg.negotiate_flags = NETR_NEGOTIATE_FLAGS; 215*5331Samw 216*5331Samw smb_tracef("server=[%s] account_name=[%s] hostname=[%s]\n", 217*5331Samw netr_info->server, account_name, netr_info->hostname); 218*5331Samw 219*5331Samw if (netr_gen_session_key(netr_info) != SMBAUTH_SUCCESS) 220*5331Samw return (-1); 221*5331Samw 222*5331Samw if (netr_gen_credentials(netr_info->session_key, 223*5331Samw &netr_info->client_challenge, 224*5331Samw 0, 225*5331Samw &netr_info->client_credential) != SMBAUTH_SUCCESS) { 226*5331Samw return (-1); 227*5331Samw } 228*5331Samw 229*5331Samw if (netr_gen_credentials(netr_info->session_key, 230*5331Samw &netr_info->server_challenge, 231*5331Samw 0, 232*5331Samw &netr_info->server_credential) != SMBAUTH_SUCCESS) { 233*5331Samw return (-1); 234*5331Samw } 235*5331Samw 236*5331Samw (void) memcpy(&arg.client_credential, &netr_info->client_credential, 237*5331Samw sizeof (struct netr_credential)); 238*5331Samw 239*5331Samw (void) mlsvc_rpc_init(&heap); 240*5331Samw 241*5331Samw rc = mlsvc_rpc_call(netr_handle->context, opnum, &arg, &heap); 242*5331Samw if (rc == 0) { 243*5331Samw if (arg.status != 0) { 244*5331Samw mlsvc_rpc_report_status(opnum, arg.status); 245*5331Samw rc = -1; 246*5331Samw } else { 247*5331Samw rc = memcmp(&netr_info->server_credential, 248*5331Samw &arg.server_credential, 249*5331Samw sizeof (struct netr_credential)); 250*5331Samw } 251*5331Samw } 252*5331Samw 253*5331Samw mlsvc_rpc_free(netr_handle->context, &heap); 254*5331Samw return (rc); 255*5331Samw } 256*5331Samw 257*5331Samw /* 258*5331Samw * netr_gen_session_key 259*5331Samw * 260*5331Samw * Generate a session key from the client and server challenges. The 261*5331Samw * algorithm is a two stage hash. For the first hash, the input is 262*5331Samw * the combination of the client and server challenges, the key is 263*5331Samw * the first 8 bytes of the password. The initial password is formed 264*5331Samw * using the NT password hash on the local hostname in lower case. 265*5331Samw * The result is stored in a temporary buffer. 266*5331Samw * 267*5331Samw * input: challenge 268*5331Samw * key: passwd lower 8 bytes 269*5331Samw * output: intermediate result 270*5331Samw * 271*5331Samw * For the second hash, the input is the result of the first hash and 272*5331Samw * the key is the last 8 bytes of the password. 273*5331Samw * 274*5331Samw * input: result of first hash 275*5331Samw * key: passwd upper 8 bytes 276*5331Samw * output: session_key 277*5331Samw * 278*5331Samw * The final output should be the session key. 279*5331Samw * 280*5331Samw * FYI: smb_auth_DES(output, key, input) 281*5331Samw * 282*5331Samw * If any difficulties occur using the cryptographic framework, the 283*5331Samw * function returns SMBAUTH_FAILURE. Otherwise SMBAUTH_SUCCESS is 284*5331Samw * returned. 285*5331Samw */ 286*5331Samw int 287*5331Samw netr_gen_session_key(netr_info_t *netr_info) 288*5331Samw { 289*5331Samw unsigned char md4hash[32]; 290*5331Samw unsigned char buffer[8]; 291*5331Samw DWORD data[2]; 292*5331Samw DWORD *client_challenge; 293*5331Samw DWORD *server_challenge; 294*5331Samw int rc; 295*5331Samw char *machine_passwd; 296*5331Samw DWORD new_data[2]; 297*5331Samw 298*5331Samw client_challenge = (DWORD *)(uintptr_t)&netr_info->client_challenge; 299*5331Samw server_challenge = (DWORD *)(uintptr_t)&netr_info->server_challenge; 300*5331Samw bzero(md4hash, 32); 301*5331Samw 302*5331Samw /* 303*5331Samw * We should check (netr_info->flags & NETR_FLG_INIT) and use 304*5331Samw * the appropriate password but it isn't working yet. So we 305*5331Samw * always use the default one for now. 306*5331Samw */ 307*5331Samw smb_config_rdlock(); 308*5331Samw machine_passwd = smb_config_getstr(SMB_CI_MACHINE_PASSWD); 309*5331Samw 310*5331Samw if (!machine_passwd || *machine_passwd == 0) { 311*5331Samw smb_config_unlock(); 312*5331Samw return (-1); 313*5331Samw } 314*5331Samw 315*5331Samw bzero(netr_info->password, sizeof (netr_info->password)); 316*5331Samw (void) strlcpy((char *)netr_info->password, (char *)machine_passwd, 317*5331Samw sizeof (netr_info->password)); 318*5331Samw 319*5331Samw rc = smb_auth_ntlm_hash((char *)machine_passwd, md4hash); 320*5331Samw smb_config_unlock(); 321*5331Samw 322*5331Samw if (rc != SMBAUTH_SUCCESS) 323*5331Samw return (SMBAUTH_FAILURE); 324*5331Samw 325*5331Samw data[0] = LE_IN32(&client_challenge[0]) + LE_IN32(&server_challenge[0]); 326*5331Samw data[1] = LE_IN32(&client_challenge[1]) + LE_IN32(&server_challenge[1]); 327*5331Samw LE_OUT32(&new_data[0], data[0]); 328*5331Samw LE_OUT32(&new_data[1], data[1]); 329*5331Samw 330*5331Samw rc = smb_auth_DES(buffer, 8, md4hash, 8, (unsigned char *)new_data, 8); 331*5331Samw if (rc != SMBAUTH_SUCCESS) 332*5331Samw return (rc); 333*5331Samw 334*5331Samw rc = smb_auth_DES(netr_info->session_key, 8, &md4hash[9], 8, buffer, 8); 335*5331Samw return (rc); 336*5331Samw } 337*5331Samw 338*5331Samw /* 339*5331Samw * netr_gen_credentials 340*5331Samw * 341*5331Samw * Generate a set of credentials from a challenge and a session key. 342*5331Samw * The algorithm is a two stage hash. For the first hash, the 343*5331Samw * timestamp is added to the challenge and the result is stored in a 344*5331Samw * temporary buffer: 345*5331Samw * 346*5331Samw * input: challenge (including timestamp) 347*5331Samw * key: session_key 348*5331Samw * output: intermediate result 349*5331Samw * 350*5331Samw * For the second hash, the input is the result of the first hash and 351*5331Samw * a strange partial key is used: 352*5331Samw * 353*5331Samw * input: result of first hash 354*5331Samw * key: funny partial key 355*5331Samw * output: credentiails 356*5331Samw * 357*5331Samw * The final output should be an encrypted set of credentials. 358*5331Samw * 359*5331Samw * FYI: smb_auth_DES(output, key, input) 360*5331Samw * 361*5331Samw * If any difficulties occur using the cryptographic framework, the 362*5331Samw * function returns SMBAUTH_FAILURE. Otherwise SMBAUTH_SUCCESS is 363*5331Samw * returned. 364*5331Samw */ 365*5331Samw int 366*5331Samw netr_gen_credentials(BYTE *session_key, netr_cred_t *challenge, 367*5331Samw DWORD timestamp, netr_cred_t *out_cred) 368*5331Samw { 369*5331Samw unsigned char buffer[8]; 370*5331Samw unsigned char partial_key[8]; 371*5331Samw DWORD data[2]; 372*5331Samw DWORD *p; 373*5331Samw int rc; 374*5331Samw 375*5331Samw p = (DWORD *)(uintptr_t)challenge; 376*5331Samw data[0] = p[0] + LE_IN32(×tamp); 377*5331Samw data[1] = p[1]; 378*5331Samw 379*5331Samw if (smb_auth_DES(buffer, 8, session_key, 8, 380*5331Samw (unsigned char *)data, 8) != SMBAUTH_SUCCESS) 381*5331Samw return (SMBAUTH_FAILURE); 382*5331Samw 383*5331Samw bzero(partial_key, 8); 384*5331Samw partial_key[0] = session_key[7]; 385*5331Samw 386*5331Samw rc = smb_auth_DES((unsigned char *)out_cred, 8, partial_key, 8, 387*5331Samw buffer, 8); 388*5331Samw return (rc); 389*5331Samw } 390*5331Samw 391*5331Samw /* 392*5331Samw * netr_server_password_set 393*5331Samw * 394*5331Samw * Attempt to change the trust account password for this system. 395*5331Samw * 396*5331Samw * Note that this call may legitimately fail if the registry on the 397*5331Samw * domain controller has been setup to deny attempts to change the 398*5331Samw * trust account password. In this case we should just continue to 399*5331Samw * use the original password. 400*5331Samw * 401*5331Samw * Possible status values: 402*5331Samw * NT_STATUS_ACCESS_DENIED 403*5331Samw */ 404*5331Samw int 405*5331Samw netr_server_password_set(mlsvc_handle_t *netr_handle, netr_info_t *netr_info) 406*5331Samw { 407*5331Samw struct netr_PasswordSet arg; 408*5331Samw mlrpc_heapref_t heap; 409*5331Samw int opnum; 410*5331Samw int rc; 411*5331Samw BYTE new_password[NETR_OWF_PASSWORD_SZ]; 412*5331Samw char account_name[MLSVC_DOMAIN_NAME_MAX * 2]; 413*5331Samw 414*5331Samw bzero(&arg, sizeof (struct netr_PasswordSet)); 415*5331Samw opnum = NETR_OPNUM_ServerPasswordSet; 416*5331Samw 417*5331Samw (void) snprintf(account_name, sizeof (account_name), "%s$", 418*5331Samw netr_info->hostname); 419*5331Samw 420*5331Samw arg.servername = (unsigned char *)netr_info->server; 421*5331Samw arg.account_name = (unsigned char *)account_name; 422*5331Samw arg.account_type = NETR_WKSTA_TRUST_ACCOUNT_TYPE; 423*5331Samw arg.hostname = (unsigned char *)netr_info->hostname; 424*5331Samw 425*5331Samw /* 426*5331Samw * Set up the client side authenticator. 427*5331Samw */ 428*5331Samw if (netr_setup_authenticator(netr_info, &arg.auth, 0) != 429*5331Samw SMBAUTH_SUCCESS) { 430*5331Samw return (-1); 431*5331Samw } 432*5331Samw 433*5331Samw /* 434*5331Samw * Generate a new password from the old password. 435*5331Samw */ 436*5331Samw if (netr_gen_password(netr_info->session_key, 437*5331Samw netr_info->password, new_password) == SMBAUTH_FAILURE) { 438*5331Samw return (-1); 439*5331Samw } 440*5331Samw 441*5331Samw (void) memcpy(&arg.uas_new_password, &new_password, 442*5331Samw NETR_OWF_PASSWORD_SZ); 443*5331Samw 444*5331Samw (void) mlsvc_rpc_init(&heap); 445*5331Samw rc = mlsvc_rpc_call(netr_handle->context, opnum, &arg, &heap); 446*5331Samw if ((rc != 0) || (arg.status != 0)) { 447*5331Samw mlsvc_rpc_report_status(opnum, arg.status); 448*5331Samw mlsvc_rpc_free(netr_handle->context, &heap); 449*5331Samw return (-1); 450*5331Samw } 451*5331Samw 452*5331Samw /* 453*5331Samw * Check the returned credentials. The server returns the new 454*5331Samw * client credential rather than the new server credentiali, 455*5331Samw * as documented elsewhere. 456*5331Samw * 457*5331Samw * Generate the new seed for the credential chain. Increment 458*5331Samw * the timestamp and add it to the client challenge. Then we 459*5331Samw * need to copy the challenge to the credential field in 460*5331Samw * preparation for the next cycle. 461*5331Samw */ 462*5331Samw if (netr_validate_chain(netr_info, &arg.auth) == 0) { 463*5331Samw /* 464*5331Samw * Save the new password. 465*5331Samw */ 466*5331Samw (void) memcpy(netr_info->password, new_password, 467*5331Samw NETR_OWF_PASSWORD_SZ); 468*5331Samw } 469*5331Samw 470*5331Samw mlsvc_rpc_free(netr_handle->context, &heap); 471*5331Samw return (0); 472*5331Samw } 473*5331Samw 474*5331Samw /* 475*5331Samw * netr_gen_password 476*5331Samw * 477*5331Samw * Generate a new pasword from the old password and the session key. 478*5331Samw * The algorithm is a two stage hash. The session key is used in the 479*5331Samw * first hash but only part of the session key is used in the second 480*5331Samw * hash. 481*5331Samw * 482*5331Samw * If any difficulties occur using the cryptographic framework, the 483*5331Samw * function returns SMBAUTH_FAILURE. Otherwise SMBAUTH_SUCCESS is 484*5331Samw * returned. 485*5331Samw */ 486*5331Samw static int 487*5331Samw netr_gen_password(BYTE *session_key, BYTE *old_password, BYTE *new_password) 488*5331Samw { 489*5331Samw unsigned char partial_key[8]; 490*5331Samw int rv; 491*5331Samw 492*5331Samw rv = smb_auth_DES(new_password, 8, session_key, 8, old_password, 8); 493*5331Samw if (rv != SMBAUTH_SUCCESS) 494*5331Samw return (rv); 495*5331Samw 496*5331Samw bzero(partial_key, 8); 497*5331Samw partial_key[0] = session_key[7]; 498*5331Samw 499*5331Samw rv = smb_auth_DES(&new_password[8], 8, partial_key, 8, 500*5331Samw &old_password[8], 8); 501*5331Samw return (rv); 502*5331Samw } 503