8bce9c86a1e336460e62b414d6d9876e10f834b6
[ira/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 BOOL 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 }