r10656: BIG merge from trunk. Features not copied over
[metze/samba/wip.git] / source3 / libsmb / passchange.c
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 /*************************************************************
24  Change a password on a remote machine using IPC calls.
25 *************************************************************/
26
27 BOOL remote_password_change(const char *remote_machine, const char *user_name, 
28                             const char *old_passwd, const char *new_passwd,
29                             char *err_str, size_t err_str_len)
30 {
31         struct nmb_name calling, called;
32         struct cli_state cli;
33         struct rpc_pipe_client *pipe_hnd;
34         struct in_addr ip;
35
36         NTSTATUS result;
37
38         *err_str = '\0';
39
40         if(!resolve_name( remote_machine, &ip, 0x20)) {
41                 slprintf(err_str, err_str_len-1, "unable to find an IP address for machine %s.\n",
42                         remote_machine );
43                 return False;
44         }
45  
46         ZERO_STRUCT(cli);
47  
48         if (!cli_initialise(&cli) || !cli_connect(&cli, remote_machine, &ip)) {
49                 slprintf(err_str, err_str_len-1, "unable to connect to SMB server on machine %s. Error was : %s.\n",
50                         remote_machine, cli_errstr(&cli) );
51                 return False;
52         }
53   
54         make_nmb_name(&calling, global_myname() , 0x0);
55         make_nmb_name(&called , remote_machine, 0x20);
56         
57         if (!cli_session_request(&cli, &calling, &called)) {
58                 slprintf(err_str, err_str_len-1, "machine %s rejected the session setup. Error was : %s.\n",
59                         remote_machine, cli_errstr(&cli) );
60                 cli_shutdown(&cli);
61                 return False;
62         }
63   
64         cli.protocol = PROTOCOL_NT1;
65
66         if (!cli_negprot(&cli)) {
67                 slprintf(err_str, err_str_len-1, "machine %s rejected the negotiate protocol. Error was : %s.\n",        
68                         remote_machine, cli_errstr(&cli) );
69                 cli_shutdown(&cli);
70                 return False;
71         }
72   
73         /* Given things like SMB signing, restrict anonymous and the like, 
74            try an authenticated connection first */
75         if (!cli_session_setup(&cli, user_name, old_passwd, strlen(old_passwd)+1, old_passwd, strlen(old_passwd)+1, "")) {
76                 /*
77                  * We should connect as the anonymous user here, in case
78                  * the server has "must change password" checked...
79                  * Thanks to <Nicholas.S.Jenkins@cdc.com> for this fix.
80                  */
81
82                 if (!cli_session_setup(&cli, "", "", 0, "", 0, "")) {
83                         slprintf(err_str, err_str_len-1, "machine %s rejected the session setup. Error was : %s.\n",        
84                                  remote_machine, cli_errstr(&cli) );
85                         cli_shutdown(&cli);
86                         return False;
87                 }
88
89                 cli_init_creds(&cli, "", "", NULL);
90         } else {
91                 cli_init_creds(&cli, user_name, "", old_passwd);
92         }
93
94         if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) {
95                 slprintf(err_str, err_str_len-1, "machine %s rejected the tconX on the IPC$ share. Error was : %s.\n",
96                         remote_machine, cli_errstr(&cli) );
97                 cli_shutdown(&cli);
98                 return False;
99         }
100
101         /* Try not to give the password away too easily */
102
103         pipe_hnd = cli_rpc_pipe_open_ntlmssp(&cli,
104                                                 PI_SAMR,
105                                                 PIPE_AUTH_LEVEL_PRIVACY,
106                                                 "", /* what domain... ? */
107                                                 user_name,
108                                                 old_passwd,
109                                                 &result);
110
111         if (!pipe_hnd) {
112                 if (lp_client_lanman_auth()) {
113                         /* Use the old RAP method. */
114                         if (!cli_oem_change_password(&cli, user_name, new_passwd, old_passwd)) {
115                                 slprintf(err_str, err_str_len-1, "machine %s rejected the password change: Error was : %s.\n",
116                                          remote_machine, cli_errstr(&cli) );
117                                 cli_shutdown(&cli);
118                                 return False;
119                         }
120                 } else {
121                         slprintf(err_str, err_str_len-1,
122                                 "SAMR connection to machine %s failed. Error was %s, "
123                                 "but LANMAN password changed are disabled\n",
124                                 nt_errstr(result), remote_machine);
125                         cli_shutdown(&cli);
126                         return False;
127                 }
128         }
129
130         if (NT_STATUS_IS_OK(result = rpccli_samr_chgpasswd_user(pipe_hnd, cli.mem_ctx, user_name, 
131                                                              new_passwd, old_passwd))) {
132                 /* Great - it all worked! */
133                 cli_shutdown(&cli);
134                 return True;
135
136         } else if (!(NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) 
137                      || NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))) {
138                 /* it failed, but for reasons such as wrong password, too short etc ... */
139                 
140                 slprintf(err_str, err_str_len-1, "machine %s rejected the password change: Error was : %s.\n",
141                          remote_machine, get_friendly_nt_error_msg(result));
142                 cli_shutdown(&cli);
143                 return False;
144         }
145
146         /* OK, that failed, so try again... */
147         cli_rpc_pipe_close(pipe_hnd);
148         
149         /* Try anonymous NTLMSSP... */
150         cli_init_creds(&cli, "", "", NULL);
151         
152         result = NT_STATUS_UNSUCCESSFUL;
153         
154         /* OK, this is ugly, but... try an anonymous pipe. */
155         pipe_hnd = cli_rpc_pipe_open_noauth(&cli, PI_SAMR, &result);
156
157         if ( pipe_hnd &&
158                 (NT_STATUS_IS_OK(result = rpccli_samr_chgpasswd_user(pipe_hnd,
159                                                 cli.mem_ctx,
160                                                 user_name, 
161                                                 new_passwd,
162                                                 old_passwd)))) {
163                 /* Great - it all worked! */
164                 cli_shutdown(&cli);
165                 return True;
166         } else {
167                 if (!(NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) 
168                       || NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))) {
169                         /* it failed, but again it was due to things like new password too short */
170
171                         slprintf(err_str, err_str_len-1, 
172                                  "machine %s rejected the (anonymous) password change: Error was : %s.\n",
173                                  remote_machine, get_friendly_nt_error_msg(result));
174                         cli_shutdown(&cli);
175                         return False;
176                 }
177                 
178                 /* We have failed to change the user's password, and we think the server
179                    just might not support SAMR password changes, so fall back */
180                 
181                 if (lp_client_lanman_auth()) {
182                         /* Use the old RAP method. */
183                         if (cli_oem_change_password(&cli, user_name, new_passwd, old_passwd)) {
184                                 /* SAMR failed, but the old LanMan protocol worked! */
185
186                                 cli_shutdown(&cli);
187                                 return True;
188                         }
189                         slprintf(err_str, err_str_len-1, 
190                                  "machine %s rejected the password change: Error was : %s.\n",
191                                  remote_machine, cli_errstr(&cli) );
192                         cli_shutdown(&cli);
193                         return False;
194                 } else {
195                         slprintf(err_str, err_str_len-1,
196                                 "SAMR connection to machine %s failed. Error was %s, "
197                                 "but LANMAN password changed are disabled\n",
198                                 nt_errstr(result), remote_machine);
199                         cli_shutdown(&cli);
200                         return False;
201                 }
202         }
203 }