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()))
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, current_user_info.domain,
53				   desthost, sizeof(desthost));
54		strupper_m(desthost);
55
56		if(!resolve_name( desthost, &dest_ip, 0x20)) {
57			DEBUG(1,("server_cryptkey: Can't resolve address for %s\n",desthost));
58			continue;
59		}
60
61		if (ismyip(dest_ip)) {
62			DEBUG(1,("Password server loop - disabling password server %s\n",desthost));
63			continue;
64		}
65
66		/* we use a mutex to prevent two connections at once - when a
67		   Win2k PDC get two connections where one hasn't completed a
68		   session setup yet it will send a TCP reset to the first
69		   connection (tridge) */
70
71		if (!grab_server_mutex(desthost)) {
72			return NULL;
73		}
74
75		if (cli_connect(cli, desthost, &dest_ip)) {
76			DEBUG(3,("connected to password server %s\n",desthost));
77			connected_ok = True;
78			break;
79		}
80	}
81
82	if (!connected_ok) {
83		release_server_mutex();
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(),
90					     desthost, &dest_ip)) {
91		release_server_mutex();
92		DEBUG(1,("password server fails session request\n"));
93		cli_shutdown(cli);
94		return NULL;
95	}
96
97	if (strequal(desthost,myhostname())) {
98		exit_server_cleanly("Password server loop!");
99	}
100
101	DEBUG(3,("got session\n"));
102
103	if (!cli_negprot(cli)) {
104		DEBUG(1,("%s rejected the negprot\n",desthost));
105		release_server_mutex();
106		cli_shutdown(cli);
107		return NULL;
108	}
109
110	if (cli->protocol < PROTOCOL_LANMAN2 ||
111	    !(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL)) {
112		DEBUG(1,("%s isn't in user level security mode\n",desthost));
113		release_server_mutex();
114		cli_shutdown(cli);
115		return NULL;
116	}
117
118	/* Get the first session setup done quickly, to avoid silly
119	   Win2k bugs.  (The next connection to the server will kill
120	   this one...
121	*/
122
123	if (!NT_STATUS_IS_OK(cli_session_setup(cli, "", "", 0, "", 0,
124					       ""))) {
125		DEBUG(0,("%s rejected the initial session setup (%s)\n",
126			 desthost, cli_errstr(cli)));
127		release_server_mutex();
128		cli_shutdown(cli);
129		return NULL;
130	}
131
132	release_server_mutex();
133
134	DEBUG(3,("password server OK\n"));
135
136	return cli;
137}
138
139/****************************************************************************
140 Clean up our allocated cli.
141****************************************************************************/
142
143static void free_server_private_data(void **private_data_pointer)
144{
145	struct cli_state **cli = (struct cli_state **)private_data_pointer;
146	if (*cli && (*cli)->initialised) {
147		DEBUG(10, ("Shutting down smbserver connection\n"));
148		cli_shutdown(*cli);
149	}
150	*private_data_pointer = NULL;
151}
152
153/****************************************************************************
154 Send a 'keepalive' packet down the cli pipe.
155****************************************************************************/
156
157static void send_server_keepalive(void **private_data_pointer)
158{
159	/* also send a keepalive to the password server if its still
160	   connected */
161	if (private_data_pointer) {
162		struct cli_state *cli = (struct cli_state *)(*private_data_pointer);
163		if (cli && cli->initialised) {
164			if (!send_keepalive(cli->fd)) {
165				DEBUG( 2, ( "send_server_keepalive: password server keepalive failed.\n"));
166				cli_shutdown(cli);
167				*private_data_pointer = NULL;
168			}
169		}
170	}
171}
172
173/****************************************************************************
174 Get the challenge out of a password server.
175****************************************************************************/
176
177static DATA_BLOB auth_get_challenge_server(const struct auth_context *auth_context,
178					   void **my_private_data,
179					   TALLOC_CTX *mem_ctx)
180{
181	struct cli_state *cli = server_cryptkey(mem_ctx);
182
183	if (cli) {
184		DEBUG(3,("using password server validation\n"));
185
186		if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) {
187			/* We can't work with unencrypted password servers
188			   unless 'encrypt passwords = no' */
189			DEBUG(5,("make_auth_info_server: Server is unencrypted, no challenge available..\n"));
190
191			/* However, it is still a perfectly fine connection
192			   to pass that unencrypted password over */
193			*my_private_data = (void *)cli;
194			return data_blob(NULL, 0);
195
196		} else if (cli->secblob.length < 8) {
197			/* We can't do much if we don't get a full challenge */
198			DEBUG(2,("make_auth_info_server: Didn't receive a full challenge from server\n"));
199			cli_shutdown(cli);
200			return data_blob(NULL, 0);
201		}
202
203		*my_private_data = (void *)cli;
204
205		/* The return must be allocated on the caller's mem_ctx, as our own will be
206		   destoyed just after the call. */
207		return data_blob_talloc(auth_context->mem_ctx, cli->secblob.data,8);
208	} else {
209		return data_blob(NULL, 0);
210	}
211}
212
213
214/****************************************************************************
215 Check for a valid username and password in security=server mode.
216  - Validate a password with the password server.
217****************************************************************************/
218
219static NTSTATUS check_smbserver_security(const struct auth_context *auth_context,
220					 void *my_private_data,
221					 TALLOC_CTX *mem_ctx,
222					 const auth_usersupplied_info *user_info,
223					 auth_serversupplied_info **server_info)
224{
225	struct cli_state *cli;
226	static unsigned char badpass[24];
227	static fstring baduser;
228	static BOOL tested_password_server = False;
229	static BOOL bad_password_server = False;
230	NTSTATUS nt_status = NT_STATUS_NOT_IMPLEMENTED;
231	BOOL locally_made_cli = False;
232
233	cli = (struct cli_state *)my_private_data;
234
235	if (cli) {
236	} else {
237		cli = server_cryptkey(mem_ctx);
238		locally_made_cli = True;
239	}
240
241	if (!cli || !cli->initialised) {
242		DEBUG(1,("password server is not connected (cli not initilised)\n"));
243		return NT_STATUS_LOGON_FAILURE;
244	}
245
246	if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) {
247		if (user_info->encrypted) {
248			DEBUG(1,("password server %s is plaintext, but we are encrypted. This just can't work :-(\n", cli->desthost));
249			return NT_STATUS_LOGON_FAILURE;
250		}
251	} else {
252		if (memcmp(cli->secblob.data, auth_context->challenge.data, 8) != 0) {
253			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));
254			return NT_STATUS_LOGON_FAILURE;
255		}
256	}
257
258	if(badpass[0] == 0)
259		memset(badpass, 0x1f, sizeof(badpass));
260
261	if((user_info->nt_resp.length == sizeof(badpass)) &&
262	   !memcmp(badpass, user_info->nt_resp.data, sizeof(badpass))) {
263		/*
264		 * Very unlikely, our random bad password is the same as the users
265		 * password.
266		 */
267		memset(badpass, badpass[0]+1, sizeof(badpass));
268	}
269
270	if(baduser[0] == 0) {
271		fstrcpy(baduser, INVALID_USER_PREFIX);
272		fstrcat(baduser, global_myname());
273	}
274
275	/*
276	 * Attempt a session setup with a totally incorrect password.
277	 * If this succeeds with the guest bit *NOT* set then the password
278	 * server is broken and is not correctly setting the guest bit. We
279	 * need to detect this as some versions of NT4.x are broken. JRA.
280	 */
281
282	/* I sure as hell hope that there aren't servers out there that take
283	 * NTLMv2 and have this bug, as we don't test for that...
284	 *  - abartlet@samba.org
285	 */
286
287	if ((!tested_password_server) && (lp_paranoid_server_security())) {
288		if (NT_STATUS_IS_OK(cli_session_setup(cli, baduser,
289						      (char *)badpass,
290						      sizeof(badpass),
291						      (char *)badpass,
292						      sizeof(badpass),
293						      user_info->domain))) {
294
295			/*
296			 * We connected to the password server so we
297			 * can say we've tested it.
298			 */
299			tested_password_server = True;
300
301			if ((SVAL(cli->inbuf,smb_vwv2) & 1) == 0) {
302				DEBUG(0,("server_validate: password server %s allows users as non-guest \
303with a bad password.\n", cli->desthost));
304				DEBUG(0,("server_validate: This is broken (and insecure) behaviour. Please do not \
305use this machine as the password server.\n"));
306				cli_ulogoff(cli);
307
308				/*
309				 * Password server has the bug.
310				 */
311				bad_password_server = True;
312				return NT_STATUS_LOGON_FAILURE;
313			}
314			cli_ulogoff(cli);
315		}
316	} else {
317
318		/*
319		 * We have already tested the password server.
320		 * Fail immediately if it has the bug.
321		 */
322
323		if(bad_password_server) {
324			DEBUG(0,("server_validate: [1] password server %s allows users as non-guest \
325with a bad password.\n", cli->desthost));
326			DEBUG(0,("server_validate: [1] This is broken (and insecure) behaviour. Please do not \
327use this machine as the password server.\n"));
328			return NT_STATUS_LOGON_FAILURE;
329		}
330	}
331
332	/*
333	 * Now we know the password server will correctly set the guest bit, or is
334	 * not guest enabled, we can try with the real password.
335	 */
336
337	if (!user_info->encrypted) {
338		/* Plaintext available */
339		nt_status = cli_session_setup(
340			cli, user_info->smb_name,
341			(char *)user_info->plaintext_password.data,
342			user_info->plaintext_password.length,
343			NULL, 0, user_info->domain);
344
345	} else {
346		nt_status = cli_session_setup(
347			cli, user_info->smb_name,
348			(char *)user_info->lm_resp.data,
349			user_info->lm_resp.length,
350			(char *)user_info->nt_resp.data,
351			user_info->nt_resp.length,
352			user_info->domain);
353	}
354
355	if (!NT_STATUS_IS_OK(nt_status)) {
356		DEBUG(1,("password server %s rejected the password: %s\n",
357			 cli->desthost, nt_errstr(nt_status)));
358	}
359
360	/* if logged in as guest then reject */
361	if ((SVAL(cli->inbuf,smb_vwv2) & 1) != 0) {
362		DEBUG(1,("password server %s gave us guest only\n", cli->desthost));
363		nt_status = NT_STATUS_LOGON_FAILURE;
364	}
365
366	cli_ulogoff(cli);
367
368	if (NT_STATUS_IS_OK(nt_status)) {
369		fstring real_username;
370		struct passwd *pass;
371
372		if ( (pass = smb_getpwnam( NULL, user_info->internal_username,
373			real_username, True )) != NULL )
374		{
375			/* if a real user check pam account restrictions */
376			/* only really perfomed if "obey pam restriction" is true */
377			nt_status = smb_pam_accountcheck(pass->pw_name);
378			if (  !NT_STATUS_IS_OK(nt_status)) {
379				DEBUG(1, ("PAM account restriction prevents user login\n"));
380			} else {
381
382				nt_status = make_server_info_pw(server_info, pass->pw_name, pass);
383			}
384			TALLOC_FREE(pass);
385		}
386		else
387		{
388			nt_status = NT_STATUS_NO_SUCH_USER;
389		}
390	}
391
392	if (locally_made_cli) {
393		cli_shutdown(cli);
394	}
395
396	return(nt_status);
397}
398
399static NTSTATUS auth_init_smbserver(struct auth_context *auth_context, const char* param, auth_methods **auth_method)
400{
401	if (!make_auth_methods(auth_context, auth_method)) {
402		return NT_STATUS_NO_MEMORY;
403	}
404	(*auth_method)->name = "smbserver";
405	(*auth_method)->auth = check_smbserver_security;
406	(*auth_method)->get_chal = auth_get_challenge_server;
407	(*auth_method)->send_keepalive = send_server_keepalive;
408	(*auth_method)->free_private_data = free_server_private_data;
409	return NT_STATUS_OK;
410}
411
412NTSTATUS auth_server_init(void)
413{
414	return smb_register_auth(AUTH_INTERFACE_VERSION, "smbserver", auth_init_smbserver);
415}
416