1/* 2 Unix SMB/CIFS implementation. 3 SMB client password change routine 4 Copyright (C) Andrew Tridgell 1994-1998 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19*/ 20 21#include "includes.h" 22 23/************************************************************* 24change a password on a remote machine using IPC calls 25*************************************************************/ 26BOOL remote_password_change(const char *remote_machine, const char *user_name, 27 const char *old_passwd, const char *new_passwd, 28 char *err_str, size_t err_str_len) 29{ 30 struct nmb_name calling, called; 31 struct cli_state cli; 32 struct in_addr ip; 33 struct ntuser_creds creds; 34 35 NTSTATUS result; 36 37 *err_str = '\0'; 38 39 if(!resolve_name( remote_machine, &ip, 0x20)) { 40 slprintf(err_str, err_str_len-1, "unable to find an IP address for machine %s.\n", 41 remote_machine ); 42 return False; 43 } 44 45 ZERO_STRUCT(cli); 46 47 if (!cli_initialise(&cli) || !cli_connect(&cli, remote_machine, &ip)) { 48 slprintf(err_str, err_str_len-1, "unable to connect to SMB server on machine %s. Error was : %s.\n", 49 remote_machine, cli_errstr(&cli) ); 50 return False; 51 } 52 53 make_nmb_name(&calling, global_myname() , 0x0); 54 make_nmb_name(&called , remote_machine, 0x20); 55 56 if (!cli_session_request(&cli, &calling, &called)) { 57 slprintf(err_str, err_str_len-1, "machine %s rejected the session setup. Error was : %s.\n", 58 remote_machine, cli_errstr(&cli) ); 59 cli_shutdown(&cli); 60 return False; 61 } 62 63 cli.protocol = PROTOCOL_NT1; 64 65 if (!cli_negprot(&cli)) { 66 slprintf(err_str, err_str_len-1, "machine %s rejected the negotiate protocol. Error was : %s.\n", 67 remote_machine, cli_errstr(&cli) ); 68 cli_shutdown(&cli); 69 return False; 70 } 71 72 /* Given things like SMB signing, restrict anonymous and the like, 73 try an authenticated connection first */ 74 if (!cli_session_setup(&cli, user_name, old_passwd, strlen(old_passwd)+1, old_passwd, strlen(old_passwd)+1, "")) { 75 /* 76 * We should connect as the anonymous user here, in case 77 * the server has "must change password" checked... 78 * Thanks to <Nicholas.S.Jenkins@cdc.com> for this fix. 79 */ 80 81 if (!cli_session_setup(&cli, "", "", 0, "", 0, "")) { 82 slprintf(err_str, err_str_len-1, "machine %s rejected the session setup. Error was : %s.\n", 83 remote_machine, cli_errstr(&cli) ); 84 cli_shutdown(&cli); 85 return False; 86 } 87 88 init_creds(&creds, "", "", NULL); 89 cli_init_creds(&cli, &creds); 90 } else { 91 init_creds(&creds, user_name, "", old_passwd); 92 cli_init_creds(&cli, &creds); 93 } 94 95 if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) { 96 slprintf(err_str, err_str_len-1, "machine %s rejected the tconX on the IPC$ share. Error was : %s.\n", 97 remote_machine, cli_errstr(&cli) ); 98 cli_shutdown(&cli); 99 return False; 100 } 101 102 /* Try not to give the password away to easily */ 103 104 cli.pipe_auth_flags = AUTH_PIPE_NTLMSSP; 105 cli.pipe_auth_flags |= AUTH_PIPE_SIGN; 106 cli.pipe_auth_flags |= AUTH_PIPE_SEAL; 107 108 if ( !cli_nt_session_open( &cli, PI_SAMR ) ) { 109 if (lp_client_lanman_auth()) { 110 if (!cli_oem_change_password(&cli, user_name, new_passwd, old_passwd)) { 111 slprintf(err_str, err_str_len-1, "machine %s rejected the password change: Error was : %s.\n", 112 remote_machine, cli_errstr(&cli) ); 113 cli_shutdown(&cli); 114 return False; 115 } 116 } else { 117 slprintf(err_str, err_str_len-1, "machine %s does not support SAMR connections, but LANMAN password changed are disabled\n", 118 remote_machine); 119 cli_shutdown(&cli); 120 return False; 121 } 122 } 123 124 if (NT_STATUS_IS_OK(result = cli_samr_chgpasswd_user(&cli, cli.mem_ctx, user_name, 125 new_passwd, old_passwd))) { 126 /* Great - it all worked! */ 127 cli_shutdown(&cli); 128 return True; 129 130 } else if (!(NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) 131 || NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))) { 132 /* it failed, but for reasons such as wrong password, too short etc ... */ 133 134 slprintf(err_str, err_str_len-1, "machine %s rejected the password change: Error was : %s.\n", 135 remote_machine, get_friendly_nt_error_msg(result)); 136 cli_shutdown(&cli); 137 return False; 138 } 139 140 /* OK, that failed, so try again... */ 141 cli_nt_session_close(&cli); 142 143 /* Try anonymous NTLMSSP... */ 144 init_creds(&creds, "", "", NULL); 145 cli_init_creds(&cli, &creds); 146 147 cli.pipe_auth_flags = 0; 148 149 result = NT_STATUS_UNSUCCESSFUL; 150 151 /* OK, this is ugly, but... */ 152 if ( cli_nt_session_open( &cli, PI_SAMR ) 153 && NT_STATUS_IS_OK(result 154 = cli_samr_chgpasswd_user(&cli, cli.mem_ctx, user_name, 155 new_passwd, old_passwd))) { 156 /* Great - it all worked! */ 157 cli_shutdown(&cli); 158 return True; 159 160 } else { 161 if (!(NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) 162 || NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))) { 163 /* it failed, but again it was due to things like new password too short */ 164 165 slprintf(err_str, err_str_len-1, 166 "machine %s rejected the (anonymous) password change: Error was : %s.\n", 167 remote_machine, get_friendly_nt_error_msg(result)); 168 cli_shutdown(&cli); 169 return False; 170 } 171 172 /* We have failed to change the user's password, and we think the server 173 just might not support SAMR password changes, so fall back */ 174 175 if (lp_client_lanman_auth()) { 176 if (cli_oem_change_password(&cli, user_name, new_passwd, old_passwd)) { 177 /* SAMR failed, but the old LanMan protocol worked! */ 178 179 cli_shutdown(&cli); 180 return True; 181 } 182 slprintf(err_str, err_str_len-1, 183 "machine %s rejected the password change: Error was : %s.\n", 184 remote_machine, cli_errstr(&cli) ); 185 cli_shutdown(&cli); 186 return False; 187 } else { 188 slprintf(err_str, err_str_len-1, 189 "machine %s does not support SAMR connections, but LANMAN password changed are disabled\n", 190 remote_machine); 191 cli_shutdown(&cli); 192 return False; 193 } 194 } 195} 196