Spnego on the 'server' end of security=server just does not work, so set the
[samba.git] / source / auth / auth_server.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Authenticate to a remote server
5    Copyright (C) Andrew Tridgell 1992-1998
6    Copyright (C) Andrew Bartlett 2001
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24
25 extern pstring global_myname;
26
27 /****************************************************************************
28  Return the client state structure.
29 ****************************************************************************/
30
31 struct cli_state *server_client(void)
32 {
33         static struct cli_state pw_cli;
34         return &pw_cli;
35 }
36
37 /****************************************************************************
38  Support for server level security.
39 ****************************************************************************/
40
41 struct cli_state *server_cryptkey(void)
42 {
43         struct cli_state *cli;
44         fstring desthost;
45         struct in_addr dest_ip;
46         char *p, *pserver;
47         BOOL connected_ok = False;
48
49         cli = server_client();
50
51         if (!cli_initialise(cli))
52                 return NULL;
53
54         /* security = server just can't function with spnego */
55         cli->use_spnego = False;
56
57         pserver = strdup(lp_passwordserver());
58         p = pserver;
59
60         while(next_token( &p, desthost, LIST_SEP, sizeof(desthost))) {
61                 standard_sub_basic(desthost);
62                 strupper(desthost);
63
64                 if(!resolve_name( desthost, &dest_ip, 0x20)) {
65                         DEBUG(1,("server_cryptkey: Can't resolve address for %s\n",desthost));
66                         continue;
67                 }
68
69                 if (ismyip(dest_ip)) {
70                         DEBUG(1,("Password server loop - disabling password server %s\n",desthost));
71                         continue;
72                 }
73
74                 if (cli_connect(cli, desthost, &dest_ip)) {
75                         DEBUG(3,("connected to password server %s\n",desthost));
76                         connected_ok = True;
77                         break;
78                 }
79         }
80
81         SAFE_FREE(pserver);
82
83         if (!connected_ok) {
84                 DEBUG(0,("password server not available\n"));
85                 cli_shutdown(cli);
86                 return NULL;
87         }
88
89         if (!attempt_netbios_session_request(cli, global_myname, desthost, &dest_ip))
90                 return NULL;
91
92         DEBUG(3,("got session\n"));
93
94         if (!cli_negprot(cli)) {
95                 DEBUG(1,("%s rejected the negprot\n",desthost));
96                 cli_shutdown(cli);
97                 return NULL;
98         }
99
100         if (cli->protocol < PROTOCOL_LANMAN2 ||
101             !(cli->sec_mode & 1)) {
102                 DEBUG(1,("%s isn't in user level security mode\n",desthost));
103                 cli_shutdown(cli);
104                 return NULL;
105         }
106
107         DEBUG(3,("password server OK\n"));
108
109         return cli;
110 }
111
112
113 /****************************************************************************
114  Check for a valid username and password in security=server mode.
115   - Validate a password with the password server.
116 ****************************************************************************/
117
118 NTSTATUS check_server_security(const auth_usersupplied_info *user_info, auth_serversupplied_info *server_info)
119 {
120         struct cli_state *cli;
121         static unsigned char badpass[24];
122         static fstring baduser; 
123         static BOOL tested_password_server = False;
124         static BOOL bad_password_server = False;
125         NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
126
127         cli = server_client();
128
129         if (!cli->initialised) {
130                 DEBUG(1,("password server %s is not connected\n", cli->desthost));
131                 return(NT_STATUS_LOGON_FAILURE);
132         }  
133
134         if(badpass[0] == 0)
135                 memset(badpass, 0x1f, sizeof(badpass));
136
137         if((user_info->nt_resp.len == sizeof(badpass)) && 
138            !memcmp(badpass, user_info->nt_resp.buffer, sizeof(badpass))) {
139                 /* 
140                  * Very unlikely, our random bad password is the same as the users
141                  * password.
142                  */
143                 memset(badpass, badpass[0]+1, sizeof(badpass));
144         }
145
146         if(baduser[0] == 0) {
147                 fstrcpy(baduser, INVALID_USER_PREFIX);
148                 fstrcat(baduser, global_myname);
149         }
150
151         /*
152          * Attempt a session setup with a totally incorrect password.
153          * If this succeeds with the guest bit *NOT* set then the password
154          * server is broken and is not correctly setting the guest bit. We
155          * need to detect this as some versions of NT4.x are broken. JRA.
156          */
157
158         /* I sure as hell hope that there arn't servers out there that take 
159          * NTLMv2 and have this bug, as we don't test for that... 
160          *  - abartlet@samba.org
161          */
162
163         if ((!tested_password_server) && (lp_paranoid_server_security())) {
164                 if (cli_session_setup(cli, baduser, (char *)badpass, sizeof(badpass), 
165                                         (char *)badpass, sizeof(badpass), user_info->domain.str)) {
166
167                         /*
168                          * We connected to the password server so we
169                          * can say we've tested it.
170                          */
171                         tested_password_server = True;
172
173                         if ((SVAL(cli->inbuf,smb_vwv2) & 1) == 0) {
174                                 DEBUG(0,("server_validate: password server %s allows users as non-guest \
175 with a bad password.\n", cli->desthost));
176                                 DEBUG(0,("server_validate: This is broken (and insecure) behaviour. Please do not \
177 use this machine as the password server.\n"));
178                                 cli_ulogoff(cli);
179
180                                 /*
181                                  * Password server has the bug.
182                                  */
183                                 bad_password_server = True;
184                                 return NT_STATUS_LOGON_FAILURE;
185                         }
186                         cli_ulogoff(cli);
187                 }
188         } else {
189
190                 /*
191                  * We have already tested the password server.
192                  * Fail immediately if it has the bug.
193                  */
194
195                 if(bad_password_server) {
196                         DEBUG(0,("server_validate: [1] password server %s allows users as non-guest \
197 with a bad password.\n", cli->desthost));
198                         DEBUG(0,("server_validate: [1] This is broken (and insecure) behaviour. Please do not \
199 use this machine as the password server.\n"));
200                         return NT_STATUS_LOGON_FAILURE;
201                 }
202         }
203
204         /*
205          * Now we know the password server will correctly set the guest bit, or is
206          * not guest enabled, we can try with the real password.
207          */
208
209         if (!cli_session_setup(cli, user_info->smb_username.str, 
210                                (char *)user_info->lm_resp.buffer, 
211                                user_info->lm_resp.len, 
212                                (char *)user_info->nt_resp.buffer, 
213                                user_info->nt_resp.len, 
214                                user_info->domain.str)) {
215                 DEBUG(1,("password server %s rejected the password\n", cli->desthost));
216                 /* Make this cli_nt_error() when the conversion is in */
217                 nt_status = cli_nt_error(cli);
218         } else {
219                 nt_status = NT_STATUS_OK;
220         }
221
222         /* if logged in as guest then reject */
223         if ((SVAL(cli->inbuf,smb_vwv2) & 1) != 0) {
224                 DEBUG(1,("password server %s gave us guest only\n", cli->desthost));
225                 nt_status = NT_STATUS_LOGON_FAILURE;
226         }
227
228         cli_ulogoff(cli);
229
230         return(nt_status);
231 }