libsmb/passchange.c

説明を見る。
00001 /* 
00002    Unix SMB/CIFS implementation.
00003    SMB client password change routine
00004    Copyright (C) Andrew Tridgell 1994-1998
00005    
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    
00011    This program is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014    GNU General Public License for more details.
00015    
00016    You should have received a copy of the GNU General Public License
00017    along with this program; if not, write to the Free Software
00018    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019 */
00020 
00021 #include "includes.h"
00022 
00023 /*************************************************************
00024  Change a password on a remote machine using IPC calls.
00025 *************************************************************/
00026 
00027 NTSTATUS remote_password_change(const char *remote_machine, const char *user_name, 
00028                             const char *old_passwd, const char *new_passwd,
00029                             char *err_str, size_t err_str_len)
00030 {
00031         struct nmb_name calling, called;
00032         struct cli_state *cli;
00033         struct rpc_pipe_client *pipe_hnd;
00034         struct in_addr ip;
00035 
00036         NTSTATUS result;
00037         BOOL pass_must_change = False;
00038 
00039         *err_str = '\0';
00040 
00041         if(!resolve_name( remote_machine, &ip, 0x20)) {
00042                 slprintf(err_str, err_str_len-1, "Unable to find an IP address for machine %s.\n",
00043                         remote_machine );
00044                 return NT_STATUS_UNSUCCESSFUL;
00045         }
00046  
00047         cli = cli_initialise();
00048         if (!cli) {
00049                 return NT_STATUS_NO_MEMORY;
00050         }
00051 
00052         result = cli_connect(cli, remote_machine, &ip);
00053         if (!NT_STATUS_IS_OK(result)) {
00054                 slprintf(err_str, err_str_len-1, "Unable to connect to SMB server on machine %s. Error was : %s.\n",
00055                         remote_machine, nt_errstr(result) );
00056                 cli_shutdown(cli);
00057                 return result;
00058         }
00059   
00060         make_nmb_name(&calling, global_myname() , 0x0);
00061         make_nmb_name(&called , remote_machine, 0x20);
00062         
00063         if (!cli_session_request(cli, &calling, &called)) {
00064                 slprintf(err_str, err_str_len-1, "machine %s rejected the session setup. Error was : %s.\n",
00065                         remote_machine, cli_errstr(cli) );
00066                 result = cli_nt_error(cli);
00067                 cli_shutdown(cli);
00068                 return result;
00069         }
00070   
00071         cli->protocol = PROTOCOL_NT1;
00072 
00073         if (!cli_negprot(cli)) {
00074                 slprintf(err_str, err_str_len-1, "machine %s rejected the negotiate protocol. Error was : %s.\n",        
00075                         remote_machine, cli_errstr(cli) );
00076                 result = cli_nt_error(cli);
00077                 cli_shutdown(cli);
00078                 return result;
00079         }
00080   
00081         /* Given things like SMB signing, restrict anonymous and the like, 
00082            try an authenticated connection first */
00083         result = cli_session_setup(cli, user_name,
00084                                    old_passwd, strlen(old_passwd)+1,
00085                                    old_passwd, strlen(old_passwd)+1, "");
00086 
00087         if (!NT_STATUS_IS_OK(result)) {
00088 
00089                 /* Password must change or Password expired are the only valid
00090                  * error conditions here from where we can proceed, the rest like
00091                  * account locked out or logon failure will lead to errors later
00092                  * anyway */
00093 
00094                 if (!NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_MUST_CHANGE) &&
00095                     !NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_EXPIRED)) {
00096                         slprintf(err_str, err_str_len-1, "Could not "
00097                                  "connect to machine %s: %s\n",
00098                                  remote_machine, cli_errstr(cli));
00099                         cli_shutdown(cli);
00100                         return result;
00101                 }
00102 
00103                 pass_must_change = True;
00104 
00105                 /*
00106                  * We should connect as the anonymous user here, in case
00107                  * the server has "must change password" checked...
00108                  * Thanks to <Nicholas.S.Jenkins@cdc.com> for this fix.
00109                  */
00110 
00111                 result = cli_session_setup(cli, "", "", 0, "", 0, "");
00112 
00113                 if (!NT_STATUS_IS_OK(result)) {
00114                         slprintf(err_str, err_str_len-1, "machine %s rejected the session setup. Error was : %s.\n",        
00115                                  remote_machine, cli_errstr(cli) );
00116                         cli_shutdown(cli);
00117                         return result;
00118                 }
00119 
00120                 cli_init_creds(cli, "", "", NULL);
00121         } else {
00122                 cli_init_creds(cli, user_name, "", old_passwd);
00123         }
00124 
00125         if (!cli_send_tconX(cli, "IPC$", "IPC", "", 1)) {
00126                 slprintf(err_str, err_str_len-1, "machine %s rejected the tconX on the IPC$ share. Error was : %s.\n",
00127                         remote_machine, cli_errstr(cli) );
00128                 result = cli_nt_error(cli);
00129                 cli_shutdown(cli);
00130                 return result;
00131         }
00132 
00133         /* Try not to give the password away too easily */
00134 
00135         if (!pass_must_change) {
00136                 pipe_hnd = cli_rpc_pipe_open_ntlmssp(cli,
00137                                                 PI_SAMR,
00138                                                 PIPE_AUTH_LEVEL_PRIVACY,
00139                                                 "", /* what domain... ? */
00140                                                 user_name,
00141                                                 old_passwd,
00142                                                 &result);
00143         } else {
00144                 /*
00145                  * If the user password must be changed the ntlmssp bind will
00146                  * fail the same way as the session setup above did. The
00147                  * difference ist that with a pipe bind we don't get a good
00148                  * error message, the result will be that the rpc call below
00149                  * will just fail. So we do it anonymously, there's no other
00150                  * way.
00151                  */
00152                 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &result);
00153         }
00154 
00155         if (!pipe_hnd) {
00156                 if (lp_client_lanman_auth()) {
00157                         /* Use the old RAP method. */
00158                         if (!cli_oem_change_password(cli, user_name, new_passwd, old_passwd)) {
00159                                 slprintf(err_str, err_str_len-1, "machine %s rejected the password change: Error was : %s.\n",
00160                                          remote_machine, cli_errstr(cli) );
00161                                 result = cli_nt_error(cli);
00162                                 cli_shutdown(cli);
00163                                 return result;
00164                         }
00165                 } else {
00166                         slprintf(err_str, err_str_len-1,
00167                                 "SAMR connection to machine %s failed. Error was %s, "
00168                                 "but LANMAN password changed are disabled\n",
00169                                 nt_errstr(result), remote_machine);
00170                         result = cli_nt_error(cli);
00171                         cli_shutdown(cli);
00172                         return result;
00173                 }
00174         }
00175 
00176         if (NT_STATUS_IS_OK(result = rpccli_samr_chgpasswd_user(pipe_hnd, cli->mem_ctx, user_name, 
00177                                                              new_passwd, old_passwd))) {
00178                 /* Great - it all worked! */
00179                 cli_shutdown(cli);
00180                 return NT_STATUS_OK;
00181 
00182         } else if (!(NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) 
00183                      || NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))) {
00184                 /* it failed, but for reasons such as wrong password, too short etc ... */
00185                 
00186                 slprintf(err_str, err_str_len-1, "machine %s rejected the password change: Error was : %s.\n",
00187                          remote_machine, get_friendly_nt_error_msg(result));
00188                 cli_shutdown(cli);
00189                 return result;
00190         }
00191 
00192         /* OK, that failed, so try again... */
00193         cli_rpc_pipe_close(pipe_hnd);
00194         
00195         /* Try anonymous NTLMSSP... */
00196         cli_init_creds(cli, "", "", NULL);
00197         
00198         result = NT_STATUS_UNSUCCESSFUL;
00199         
00200         /* OK, this is ugly, but... try an anonymous pipe. */
00201         pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &result);
00202 
00203         if ( pipe_hnd &&
00204                 (NT_STATUS_IS_OK(result = rpccli_samr_chgpasswd_user(pipe_hnd,
00205                                                 cli->mem_ctx,
00206                                                 user_name, 
00207                                                 new_passwd,
00208                                                 old_passwd)))) {
00209                 /* Great - it all worked! */
00210                 cli_shutdown(cli);
00211                 return NT_STATUS_OK;
00212         } else {
00213                 if (!(NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) 
00214                       || NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))) {
00215                         /* it failed, but again it was due to things like new password too short */
00216 
00217                         slprintf(err_str, err_str_len-1, 
00218                                  "machine %s rejected the (anonymous) password change: Error was : %s.\n",
00219                                  remote_machine, get_friendly_nt_error_msg(result));
00220                         cli_shutdown(cli);
00221                         return result;
00222                 }
00223                 
00224                 /* We have failed to change the user's password, and we think the server
00225                    just might not support SAMR password changes, so fall back */
00226                 
00227                 if (lp_client_lanman_auth()) {
00228                         /* Use the old RAP method. */
00229                         if (cli_oem_change_password(cli, user_name, new_passwd, old_passwd)) {
00230                                 /* SAMR failed, but the old LanMan protocol worked! */
00231 
00232                                 cli_shutdown(cli);
00233                                 return NT_STATUS_OK;
00234                         }
00235                         slprintf(err_str, err_str_len-1, 
00236                                  "machine %s rejected the password change: Error was : %s.\n",
00237                                  remote_machine, cli_errstr(cli) );
00238                         result = cli_nt_error(cli);
00239                         cli_shutdown(cli);
00240                         return result;
00241                 } else {
00242                         slprintf(err_str, err_str_len-1,
00243                                 "SAMR connection to machine %s failed. Error was %s, "
00244                                 "but LANMAN password changed are disabled\n",
00245                                 nt_errstr(result), remote_machine);
00246                         cli_shutdown(cli);
00247                         return NT_STATUS_UNSUCCESSFUL;
00248                 }
00249         }
00250 }

Sambaに対してSat Aug 29 21:23:06 2009に生成されました。  doxygen 1.4.7