1/* 2 Unix SMB/CIFS implementation. 3 Authenticate to a remote server 4 Copyright (C) Andrew Tridgell 1992-1998 5 Copyright (C) Andrew Bartlett 2001 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 2 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program; if not, write to the Free Software 19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20*/ 21 22#include "includes.h" 23 24#undef DBGC_CLASS 25#define DBGC_CLASS DBGC_AUTH 26 27extern userdom_struct current_user_info; 28 29/**************************************************************************** 30 Support for server level security. 31****************************************************************************/ 32 33static struct cli_state *server_cryptkey(TALLOC_CTX *mem_ctx) 34{ 35 struct cli_state *cli = NULL; 36 fstring desthost; 37 struct in_addr dest_ip; 38 const char *p; 39 char *pserver; 40 BOOL connected_ok = False; 41 42 if (!(cli = cli_initialise(cli))) 43 return NULL; 44 45 /* security = server just can't function with spnego */ 46 cli->use_spnego = False; 47 48 pserver = talloc_strdup(mem_ctx, lp_passwordserver()); 49 p = pserver; 50 51 while(next_token( &p, desthost, LIST_SEP, sizeof(desthost))) { 52 standard_sub_basic(current_user_info.smb_name, desthost, sizeof(desthost)); 53 strupper_m(desthost); 54 55 if(!resolve_name( desthost, &dest_ip, 0x20)) { 56 DEBUG(1,("server_cryptkey: Can't resolve address for %s\n",desthost)); 57 continue; 58 } 59 60 if (ismyip(dest_ip)) { 61 DEBUG(1,("Password server loop - disabling password server %s\n",desthost)); 62 continue; 63 } 64 65 /* we use a mutex to prevent two connections at once - when a 66 Win2k PDC get two connections where one hasn't completed a 67 session setup yet it will send a TCP reset to the first 68 connection (tridge) */ 69 70 if (!grab_server_mutex(desthost)) { 71 return NULL; 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 if (!connected_ok) { 82 release_server_mutex(); 83 DEBUG(0,("password server not available\n")); 84 cli_shutdown(cli); 85 return NULL; 86 } 87 88 if (!attempt_netbios_session_request(cli, global_myname(), 89 desthost, &dest_ip)) { 90 release_server_mutex(); 91 DEBUG(1,("password server fails session request\n")); 92 cli_shutdown(cli); 93 return NULL; 94 } 95 96 if (strequal(desthost,myhostname())) { 97 exit_server("Password server loop!"); 98 } 99 100 DEBUG(3,("got session\n")); 101 102 if (!cli_negprot(cli)) { 103 DEBUG(1,("%s rejected the negprot\n",desthost)); 104 release_server_mutex(); 105 cli_shutdown(cli); 106 return NULL; 107 } 108 109 if (cli->protocol < PROTOCOL_LANMAN2 || 110 !(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL)) { 111 DEBUG(1,("%s isn't in user level security mode\n",desthost)); 112 release_server_mutex(); 113 cli_shutdown(cli); 114 return NULL; 115 } 116 117 /* Get the first session setup done quickly, to avoid silly 118 Win2k bugs. (The next connection to the server will kill 119 this one... 120 */ 121 122 if (!cli_session_setup(cli, "", "", 0, "", 0, 123 "")) { 124 DEBUG(0,("%s rejected the initial session setup (%s)\n", 125 desthost, cli_errstr(cli))); 126 release_server_mutex(); 127 cli_shutdown(cli); 128 return NULL; 129 } 130 131 release_server_mutex(); 132 133 DEBUG(3,("password server OK\n")); 134 135 return cli; 136} 137 138/**************************************************************************** 139 Clean up our allocated cli. 140****************************************************************************/ 141 142static void free_server_private_data(void **private_data_pointer) 143{ 144 struct cli_state **cli = (struct cli_state **)private_data_pointer; 145 if (*cli && (*cli)->initialised) { 146 DEBUG(10, ("Shutting down smbserver connection\n")); 147 cli_shutdown(*cli); 148 } 149 *private_data_pointer = NULL; 150} 151 152/**************************************************************************** 153 Send a 'keepalive' packet down the cli pipe. 154****************************************************************************/ 155 156static void send_server_keepalive(void **private_data_pointer) 157{ 158 /* also send a keepalive to the password server if its still 159 connected */ 160 if (private_data_pointer) { 161 struct cli_state *cli = (struct cli_state *)(*private_data_pointer); 162 if (cli && cli->initialised) { 163 if (!send_keepalive(cli->fd)) { 164 DEBUG( 2, ( "send_server_keepalive: password server keepalive failed.\n")); 165 cli_shutdown(cli); 166 *private_data_pointer = NULL; 167 } 168 } 169 } 170} 171 172/**************************************************************************** 173 Get the challenge out of a password server. 174****************************************************************************/ 175 176static DATA_BLOB auth_get_challenge_server(const struct auth_context *auth_context, 177 void **my_private_data, 178 TALLOC_CTX *mem_ctx) 179{ 180 struct cli_state *cli = server_cryptkey(mem_ctx); 181 182 if (cli) { 183 DEBUG(3,("using password server validation\n")); 184 185 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) { 186 /* We can't work with unencrypted password servers 187 unless 'encrypt passwords = no' */ 188 DEBUG(5,("make_auth_info_server: Server is unencrypted, no challenge available..\n")); 189 190 /* However, it is still a perfectly fine connection 191 to pass that unencrypted password over */ 192 *my_private_data = (void *)cli; 193 return data_blob(NULL, 0); 194 195 } else if (cli->secblob.length < 8) { 196 /* We can't do much if we don't get a full challenge */ 197 DEBUG(2,("make_auth_info_server: Didn't receive a full challenge from server\n")); 198 cli_shutdown(cli); 199 return data_blob(NULL, 0); 200 } 201 202 *my_private_data = (void *)cli; 203 204 /* The return must be allocated on the caller's mem_ctx, as our own will be 205 destoyed just after the call. */ 206 return data_blob_talloc(auth_context->mem_ctx, cli->secblob.data,8); 207 } else { 208 return data_blob(NULL, 0); 209 } 210} 211 212 213/**************************************************************************** 214 Check for a valid username and password in security=server mode. 215 - Validate a password with the password server. 216****************************************************************************/ 217 218static NTSTATUS check_smbserver_security(const struct auth_context *auth_context, 219 void *my_private_data, 220 TALLOC_CTX *mem_ctx, 221 const auth_usersupplied_info *user_info, 222 auth_serversupplied_info **server_info) 223{ 224 struct cli_state *cli; 225 static unsigned char badpass[24]; 226 static fstring baduser; 227 static BOOL tested_password_server = False; 228 static BOOL bad_password_server = False; 229 NTSTATUS nt_status = NT_STATUS_NOT_IMPLEMENTED; 230 BOOL locally_made_cli = False; 231 232 /* 233 * Check that the requested domain is not our own machine name. 234 * If it is, we should never check the PDC here, we use our own local 235 * password file. 236 */ 237 238 if(is_myname(user_info->domain.str)) { 239 DEBUG(3,("check_smbserver_security: Requested domain was for this machine.\n")); 240 return nt_status; 241 } 242 243 cli = my_private_data; 244 245 if (cli) { 246 } else { 247 cli = server_cryptkey(mem_ctx); 248 locally_made_cli = True; 249 } 250 251 if (!cli || !cli->initialised) { 252 DEBUG(1,("password server is not connected (cli not initilised)\n")); 253 return NT_STATUS_LOGON_FAILURE; 254 } 255 256 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) { 257 if (user_info->encrypted) { 258 DEBUG(1,("password server %s is plaintext, but we are encrypted. This just can't work :-(\n", cli->desthost)); 259 return NT_STATUS_LOGON_FAILURE; 260 } 261 } else { 262 if (memcmp(cli->secblob.data, auth_context->challenge.data, 8) != 0) { 263 DEBUG(1,("the challenge that the password server (%s) supplied us is not the one we gave our client. This just can't work :-(\n", cli->desthost)); 264 return NT_STATUS_LOGON_FAILURE; 265 } 266 } 267 268 if(badpass[0] == 0) 269 memset(badpass, 0x1f, sizeof(badpass)); 270 271 if((user_info->nt_resp.length == sizeof(badpass)) && 272 !memcmp(badpass, user_info->nt_resp.data, sizeof(badpass))) { 273 /* 274 * Very unlikely, our random bad password is the same as the users 275 * password. 276 */ 277 memset(badpass, badpass[0]+1, sizeof(badpass)); 278 } 279 280 if(baduser[0] == 0) { 281 fstrcpy(baduser, INVALID_USER_PREFIX); 282 fstrcat(baduser, global_myname()); 283 } 284 285 /* 286 * Attempt a session setup with a totally incorrect password. 287 * If this succeeds with the guest bit *NOT* set then the password 288 * server is broken and is not correctly setting the guest bit. We 289 * need to detect this as some versions of NT4.x are broken. JRA. 290 */ 291 292 /* I sure as hell hope that there aren't servers out there that take 293 * NTLMv2 and have this bug, as we don't test for that... 294 * - abartlet@samba.org 295 */ 296 297 if ((!tested_password_server) && (lp_paranoid_server_security())) { 298 if (cli_session_setup(cli, baduser, (char *)badpass, sizeof(badpass), 299 (char *)badpass, sizeof(badpass), user_info->domain.str)) { 300 301 /* 302 * We connected to the password server so we 303 * can say we've tested it. 304 */ 305 tested_password_server = True; 306 307 if ((SVAL(cli->inbuf,smb_vwv2) & 1) == 0) { 308 DEBUG(0,("server_validate: password server %s allows users as non-guest \ 309with a bad password.\n", cli->desthost)); 310 DEBUG(0,("server_validate: This is broken (and insecure) behaviour. Please do not \ 311use this machine as the password server.\n")); 312 cli_ulogoff(cli); 313 314 /* 315 * Password server has the bug. 316 */ 317 bad_password_server = True; 318 return NT_STATUS_LOGON_FAILURE; 319 } 320 cli_ulogoff(cli); 321 } 322 } else { 323 324 /* 325 * We have already tested the password server. 326 * Fail immediately if it has the bug. 327 */ 328 329 if(bad_password_server) { 330 DEBUG(0,("server_validate: [1] password server %s allows users as non-guest \ 331with a bad password.\n", cli->desthost)); 332 DEBUG(0,("server_validate: [1] This is broken (and insecure) behaviour. Please do not \ 333use this machine as the password server.\n")); 334 return NT_STATUS_LOGON_FAILURE; 335 } 336 } 337 338 /* 339 * Now we know the password server will correctly set the guest bit, or is 340 * not guest enabled, we can try with the real password. 341 */ 342 343 if (!user_info->encrypted) { 344 /* Plaintext available */ 345 if (!cli_session_setup(cli, user_info->smb_name.str, 346 (char *)user_info->plaintext_password.data, 347 user_info->plaintext_password.length, 348 NULL, 0, 349 user_info->domain.str)) { 350 DEBUG(1,("password server %s rejected the password\n", cli->desthost)); 351 /* Make this cli_nt_error() when the conversion is in */ 352 nt_status = cli_nt_error(cli); 353 } else { 354 nt_status = NT_STATUS_OK; 355 } 356 } else { 357 if (!cli_session_setup(cli, user_info->smb_name.str, 358 (char *)user_info->lm_resp.data, 359 user_info->lm_resp.length, 360 (char *)user_info->nt_resp.data, 361 user_info->nt_resp.length, 362 user_info->domain.str)) { 363 DEBUG(1,("password server %s rejected the password\n", cli->desthost)); 364 /* Make this cli_nt_error() when the conversion is in */ 365 nt_status = cli_nt_error(cli); 366 } else { 367 nt_status = NT_STATUS_OK; 368 } 369 } 370 371 /* if logged in as guest then reject */ 372 if ((SVAL(cli->inbuf,smb_vwv2) & 1) != 0) { 373 DEBUG(1,("password server %s gave us guest only\n", cli->desthost)); 374 nt_status = NT_STATUS_LOGON_FAILURE; 375 } 376 377 cli_ulogoff(cli); 378 379 if (NT_STATUS_IS_OK(nt_status)) { 380 fstring real_username; 381 struct passwd *pass; 382 383 if ( (pass = smb_getpwnam( user_info->internal_username.str, 384 real_username, True )) != NULL ) 385 { 386 nt_status = make_server_info_pw(server_info, pass->pw_name, pass); 387 } 388 else 389 { 390 nt_status = NT_STATUS_NO_SUCH_USER; 391 } 392 } 393 394 if (locally_made_cli) { 395 cli_shutdown(cli); 396 } 397 398 return(nt_status); 399} 400 401static NTSTATUS auth_init_smbserver(struct auth_context *auth_context, const char* param, auth_methods **auth_method) 402{ 403 if (!make_auth_methods(auth_context, auth_method)) { 404 return NT_STATUS_NO_MEMORY; 405 } 406 (*auth_method)->name = "smbserver"; 407 (*auth_method)->auth = check_smbserver_security; 408 (*auth_method)->get_chal = auth_get_challenge_server; 409 (*auth_method)->send_keepalive = send_server_keepalive; 410 (*auth_method)->free_private_data = free_server_private_data; 411 return NT_STATUS_OK; 412} 413 414NTSTATUS auth_server_init(void) 415{ 416 return smb_register_auth(AUTH_INTERFACE_VERSION, "smbserver", auth_init_smbserver); 417} 418