auth.c 18.3 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * auth.c
4
 *	  Routines to handle network authentication
5
 *
6
 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
B
Add:  
Bruce Momjian 已提交
7
 * Portions Copyright (c) 1994, Regents of the University of California
8 9 10
 *
 *
 * IDENTIFICATION
11
 *	  $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.51 2001/01/24 19:42:55 momjian Exp $
12 13 14 15 16 17
 *
 *-------------------------------------------------------------------------
 */
/*
 * INTERFACE ROUTINES
 *
18 19
 *	   backend (postmaster) routines:
 *		be_recvauth				receive authentication information
20
 */
21
#include <sys/param.h>			/* for MAXHOSTNAMELEN on most */
22
#ifndef  MAXHOSTNAMELEN
23
#include <netdb.h>				/* for MAXHOSTNAMELEN on some */
24
#endif
25
#include <pwd.h>
26
#include <ctype.h>
27

28
#include <sys/types.h>			/* needed by in.h on Ultrix */
29 30
#include <netinet/in.h>
#include <arpa/inet.h>
M
Marc G. Fournier 已提交
31

32
#include "postgres.h"
M
Marc G. Fournier 已提交
33

34
#include "libpq/auth.h"
B
Bruce Momjian 已提交
35
#include "libpq/crypt.h"
36
#include "libpq/hba.h"
B
Bruce Momjian 已提交
37
#include "libpq/libpq.h"
38
#include "libpq/password.h"
B
Bruce Momjian 已提交
39
#include "miscadmin.h"
40

M
 
Marc G. Fournier 已提交
41 42 43 44 45 46 47
static void sendAuthRequest(Port *port, AuthRequest areq, PacketDoneProc handler);
static int	handle_done_auth(void *arg, PacketLen len, void *pkt);
static int	handle_krb4_auth(void *arg, PacketLen len, void *pkt);
static int	handle_krb5_auth(void *arg, PacketLen len, void *pkt);
static int	handle_password_auth(void *arg, PacketLen len, void *pkt);
static int	readPasswordPacket(void *arg, PacketLen len, void *pkt);
static int	pg_passwordv0_recvauth(void *arg, PacketLen len, void *pkt);
48 49 50
static int	checkPassword(Port *port, char *user, char *password);
static int	old_be_recvauth(Port *port);
static int	map_old_to_new(Port *port, UserAuth old, int status);
51
static void auth_failed(Port *port);
52 53


54 55 56
char * pg_krb_server_keyfile;


57 58 59 60 61 62
#ifdef KRB4
/*----------------------------------------------------------------
 * MIT Kerberos authentication system - protocol version 4
 *----------------------------------------------------------------
 */

63
#include "krb.h"
64 65 66

/*
 * pg_krb4_recvauth -- server routine to receive authentication information
67
 *					   from the client
68 69 70 71 72 73 74
 *
 * Nothing unusual here, except that we compare the username obtained from
 * the client's setup packet to the authenticated name.  (We have to retain
 * the name in the setup packet since we have to retain the ability to handle
 * unauthenticated connections.)
 */
static int
B
Bruce Momjian 已提交
75
pg_krb4_recvauth(Port *port)
76
{
B
Bruce Momjian 已提交
77 78 79 80 81 82 83
	long		krbopts = 0;	/* one-way authentication */
	KTEXT_ST	clttkt;
	char		instance[INST_SZ + 1],
				version[KRB_SENDAUTH_VLEN + 1];
	AUTH_DAT	auth_data;
	Key_schedule key_sched;
	int			status;
84 85 86 87

	strcpy(instance, "*");		/* don't care, but arg gets expanded
								 * anyway */
	status = krb_recvauth(krbopts,
88
						  port->sock,
89 90 91
						  &clttkt,
						  PG_KRB_SRVNAM,
						  instance,
92 93
						  &port->raddr.in,
						  &port->laddr.in,
94
						  &auth_data,
95
						  pg_krb_server_keyfile,
96 97 98 99
						  key_sched,
						  version);
	if (status != KSUCCESS)
	{
100 101 102
		snprintf(PQerrormsg, PQERRORMSG_LENGTH,
				 "pg_krb4_recvauth: kerberos error: %s\n",
				 krb_err_txt[status]);
103 104
		fputs(PQerrormsg, stderr);
		pqdebug("%s", PQerrormsg);
105
		return STATUS_ERROR;
106 107 108
	}
	if (strncmp(version, PG_KRB4_VERSION, KRB_SENDAUTH_VLEN))
	{
109 110 111
		snprintf(PQerrormsg, PQERRORMSG_LENGTH,
				 "pg_krb4_recvauth: protocol version != \"%s\"\n",
				 PG_KRB4_VERSION);
112 113
		fputs(PQerrormsg, stderr);
		pqdebug("%s", PQerrormsg);
114
		return STATUS_ERROR;
115
	}
116
	if (strncmp(port->user, auth_data.pname, SM_USER))
117
	{
118
		snprintf(PQerrormsg, PQERRORMSG_LENGTH,
B
Bruce Momjian 已提交
119 120
				 "pg_krb4_recvauth: name \"%s\" != \"%s\"\n",
				 port->user, auth_data.pname);
121 122
		fputs(PQerrormsg, stderr);
		pqdebug("%s", PQerrormsg);
123
		return STATUS_ERROR;
124
	}
125
	return STATUS_OK;
126 127
}

128 129
#else
static int
130
pg_krb4_recvauth(Port *port)
131
{
132
	snprintf(PQerrormsg, PQERRORMSG_LENGTH,
133
		 "pg_krb4_recvauth: Kerberos not implemented on this server.\n");
134 135
	fputs(PQerrormsg, stderr);
	pqdebug("%s", PQerrormsg);
136

137
	return STATUS_ERROR;
138
}
139

140
#endif	 /* KRB4 */
141

142

143 144 145 146 147 148
#ifdef KRB5
/*----------------------------------------------------------------
 * MIT Kerberos authentication system - protocol version 5
 *----------------------------------------------------------------
 */

B
Bruce Momjian 已提交
149 150
#include <krb5.h>
#include <com_err.h>
151 152 153

/*
 * pg_an_to_ln -- return the local name corresponding to an authentication
154
 *				  name
155 156
 *
 * XXX Assumes that the first aname component is the user name.  This is NOT
157 158 159 160 161 162 163
 *	   necessarily so, since an aname can actually be something out of your
 *	   worst X.400 nightmare, like
 *		  ORGANIZATION=U. C. Berkeley/NAME=Paul M. Aoki@CS.BERKELEY.EDU
 *	   Note that the MIT an_to_ln code does the same thing if you don't
 *	   provide an aname mapping database...it may be a better idea to use
 *	   krb5_an_to_ln, except that it punts if multiple components are found,
 *	   and we can't afford to punt.
164
 */
165
static char *
166 167
pg_an_to_ln(char *aname)
{
168
	char	   *p;
169 170 171

	if ((p = strchr(aname, '/')) || (p = strchr(aname, '@')))
		*p = '\0';
172
	return aname;
173 174
}

B
Bruce Momjian 已提交
175

B
Bruce Momjian 已提交
176
/*
B
Bruce Momjian 已提交
177 178
 * Various krb5 state which is not connection specfic, and a flag to
 * indicate whether we have initialised it yet.
B
Bruce Momjian 已提交
179
 */
B
Bruce Momjian 已提交
180 181 182 183 184 185
static int pg_krb5_initialised;
static krb5_context pg_krb5_context;
static krb5_keytab pg_krb5_keytab;
static krb5_principal pg_krb5_server;


B
Bruce Momjian 已提交
186
static int
B
Bruce Momjian 已提交
187
pg_krb5_init(void)
B
Bruce Momjian 已提交
188
{
B
Bruce Momjian 已提交
189
	krb5_error_code retval;
190

B
Bruce Momjian 已提交
191 192 193 194 195
	if (pg_krb5_initialised)
		return STATUS_OK;

	retval = krb5_init_context(&pg_krb5_context);
	if (retval) {
B
Bruce Momjian 已提交
196
		snprintf(PQerrormsg, PQERRORMSG_LENGTH,
B
Bruce Momjian 已提交
197 198 199
				 "pg_krb5_init: krb5_init_context returned"
				 " Kerberos error %d\n", retval);
		com_err("postgres", retval, "while initializing krb5");
B
Bruce Momjian 已提交
200
		return STATUS_ERROR;
201 202
	}

203
	retval = krb5_kt_resolve(pg_krb5_context, pg_krb_server_keyfile, &pg_krb5_keytab);
B
Bruce Momjian 已提交
204 205 206 207 208
	if (retval) {
		snprintf(PQerrormsg, PQERRORMSG_LENGTH,
				 "pg_krb5_init: krb5_kt_resolve returned"
				 " Kerberos error %d\n", retval);
	    com_err("postgres", retval, "while resolving keytab file %s",
209
				pg_krb_server_keyfile);
B
Bruce Momjian 已提交
210 211
		krb5_free_context(pg_krb5_context);
		return STATUS_ERROR;
212 213
	}

B
Bruce Momjian 已提交
214 215 216
    retval = krb5_sname_to_principal(pg_krb5_context, NULL, PG_KRB_SRVNAM, 
									 KRB5_NT_SRV_HST, &pg_krb5_server);
	if (retval) {
217
		snprintf(PQerrormsg, PQERRORMSG_LENGTH,
B
Bruce Momjian 已提交
218 219 220 221
				 "pg_krb5_init: krb5_sname_to_principal returned"
				 " Kerberos error %d\n", retval);
	    com_err("postgres", retval, 
				"while getting server principal for service %s",
222
				pg_krb_server_keyfile);
B
Bruce Momjian 已提交
223 224
		krb5_kt_close(pg_krb5_context, pg_krb5_keytab);
		krb5_free_context(pg_krb5_context);
225 226
		return STATUS_ERROR;
	}
B
Bruce Momjian 已提交
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266

	pg_krb5_initialised = 1;
	return STATUS_OK;
}


/*
 * pg_krb5_recvauth -- server routine to receive authentication information
 *					   from the client
 *
 * We still need to compare the username obtained from the client's setup
 * packet to the authenticated name, as described in pg_krb4_recvauth.	This
 * is a bit more problematic in v5, as described above in pg_an_to_ln.
 *
 * We have our own keytab file because postgres is unlikely to run as root,
 * and so cannot read the default keytab.
 */
static int
pg_krb5_recvauth(Port *port)
{
	krb5_error_code retval;
	int ret;
	krb5_auth_context auth_context = NULL;
	krb5_ticket *ticket;
    char *kusername;

	ret = pg_krb5_init();
	if (ret != STATUS_OK)
		return ret;

	retval = krb5_recvauth(pg_krb5_context, &auth_context,
						   (krb5_pointer)&port->sock, PG_KRB_SRVNAM,
						   pg_krb5_server, 0, pg_krb5_keytab, &ticket);
	if (retval) {
		snprintf(PQerrormsg, PQERRORMSG_LENGTH,
				 "pg_krb5_recvauth: krb5_recvauth returned"
				 " Kerberos error %d\n", retval);
	    com_err("postgres", retval, "from krb5_recvauth");
		return STATUS_ERROR;
	}						   
267 268 269 270 271

	/*
	 * The "client" structure comes out of the ticket and is therefore
	 * authenticated.  Use it to check the username obtained from the
	 * postmaster startup packet.
B
Bruce Momjian 已提交
272 273
	 *
	 * I have no idea why this is considered necessary.
274
	 */
B
Bruce Momjian 已提交
275 276 277
    retval = krb5_unparse_name(pg_krb5_context, 
							   ticket->enc_part2->client, &kusername);
	if (retval) {
278
		snprintf(PQerrormsg, PQERRORMSG_LENGTH,
B
Bruce Momjian 已提交
279 280 281 282 283
				 "pg_krb5_recvauth: krb5_unparse_name returned"
				 " Kerberos error %d\n", retval);
	    com_err("postgres", retval, "while unparsing client name");
		krb5_free_ticket(pg_krb5_context, ticket);
		krb5_auth_con_free(pg_krb5_context, auth_context);
284
		return STATUS_ERROR;
285
	}
B
Bruce Momjian 已提交
286

287
	kusername = pg_an_to_ln(kusername);
B
Bruce Momjian 已提交
288
	if (strncmp(port->user, kusername, SM_USER))
289
	{
290
		snprintf(PQerrormsg, PQERRORMSG_LENGTH,
B
Bruce Momjian 已提交
291 292 293
				 "pg_krb5_recvauth: user name \"%s\" != krb5 name \"%s\"\n", 
				 port->user, kusername);
		ret = STATUS_ERROR;
294
	}
B
Bruce Momjian 已提交
295 296 297 298 299 300 301 302
	else
		ret = STATUS_OK;
	
	krb5_free_ticket(pg_krb5_context, ticket);
	krb5_auth_con_free(pg_krb5_context, auth_context);
	free(kusername);

	return ret;
303 304
}

305
#else
306
static int
307
pg_krb5_recvauth(Port *port)
308
{
309
	snprintf(PQerrormsg, PQERRORMSG_LENGTH,
B
Bruce Momjian 已提交
310
		 "pg_krb5_recvauth: Kerberos not implemented on this server.\n");
311 312
	fputs(PQerrormsg, stderr);
	pqdebug("%s", PQerrormsg);
313

314
	return STATUS_ERROR;
315
}
316

317
#endif	 /* KRB5 */
318

319 320 321 322 323

/*
 * Handle a v0 password packet.
 */

M
 
Marc G. Fournier 已提交
324 325
static int
pg_passwordv0_recvauth(void *arg, PacketLen len, void *pkt)
326
{
327
	Port	   *port;
328
	PasswordPacketV0 *pp;
329 330 331 332
	char	   *user,
			   *password,
			   *cp,
			   *start;
333

334 335
	port = (Port *) arg;
	pp = (PasswordPacketV0 *) pkt;
336 337 338 339 340 341 342 343

	/*
	 * The packet is supposed to comprise the user name and the password
	 * as C strings.  Be careful the check that this is the case.
	 */

	user = password = NULL;

344
	len -= sizeof(pp->unused);
345 346 347

	cp = start = pp->data;

348 349
	while (len-- > 0)
		if (*cp++ == '\0')
350
		{
351 352 353 354 355 356 357
			if (user == NULL)
				user = start;
			else
			{
				password = start;
				break;
			}
358

359 360
			start = cp;
		}
361 362

	if (user == NULL || password == NULL)
363
	{
364
		snprintf(PQerrormsg, PQERRORMSG_LENGTH,
B
Bruce Momjian 已提交
365
				 "pg_password_recvauth: badly formed password packet.\n");
366 367
		fputs(PQerrormsg, stderr);
		pqdebug("%s", PQerrormsg);
368 369

		auth_failed(port);
370
	}
371 372
	else
	{
373 374
		int			status;
		UserAuth	saved;
375 376 377 378 379 380 381 382 383 384 385 386 387 388 389

		/* Check the password. */

		saved = port->auth_method;
		port->auth_method = uaPassword;

		status = checkPassword(port, user, password);

		port->auth_method = saved;

		/* Adjust the result if necessary. */

		if (map_old_to_new(port, uaPassword, status) != STATUS_OK)
			auth_failed(port);
	}
M
 
Marc G. Fournier 已提交
390

391
	return STATUS_OK;			/* don't close the connection yet */
392
}
393 394


395
/*
396 397 398 399 400 401 402 403 404 405
 * Tell the user the authentication failed, but not (much about) why.
 *
 * There is a tradeoff here between security concerns and making life
 * unnecessarily difficult for legitimate users.  We would not, for example,
 * want to report the password we were expecting to receive...
 * But it seems useful to report the username and authorization method
 * in use, and these are items that must be presumed known to an attacker
 * anyway.
 * Note that many sorts of failure report additional information in the
 * postmaster log, which we hope is only readable by good guys.
406
 */
407

408
static void
409
auth_failed(Port *port)
410
{
B
Bruce Momjian 已提交
411
	char		buffer[512];
412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
	const char *authmethod = "Unknown auth method:";

	switch (port->auth_method)
	{
		case uaReject:
			authmethod = "Rejected host:";
			break;
		case uaKrb4:
			authmethod = "Kerberos4";
			break;
		case uaKrb5:
			authmethod = "Kerberos5";
			break;
		case uaTrust:
			authmethod = "Trusted";
			break;
		case uaIdent:
			authmethod = "IDENT";
			break;
		case uaPassword:
			authmethod = "Password";
			break;
		case uaCrypt:
			authmethod = "Password";
			break;
	}

	sprintf(buffer, "%s authentication failed for user '%s'",
			authmethod, port->user);

	PacketSendError(&port->pktInfo, buffer);
443 444
}

445

446 447 448
/*
 * be_recvauth -- server demux routine for incoming authentication information
 */
449 450
void
be_recvauth(Port *port)
451
{
452

453
	/*
454
	 * Get the authentication method to use for this frontend/database
B
Bruce Momjian 已提交
455 456 457
	 * combination.  Note: a failure return indicates a problem with the
	 * hba config file, not with the request.  hba.c should have dropped
	 * an error message into the postmaster logfile if it failed.
458
	 */
459

460
	if (hba_getauthmethod(port) != STATUS_OK)
461 462
		PacketSendError(&port->pktInfo,
						"Missing or erroneous pg_hba.conf file, see postmaster log for details");
463

464
	else if (PG_PROTOCOL_MAJOR(port->proto) == 0)
465
	{
466 467
		/* Handle old style authentication. */

468 469
		if (old_be_recvauth(port) != STATUS_OK)
			auth_failed(port);
470
	}
471
	else
472
	{
473 474
		/* Handle new style authentication. */

B
Bruce Momjian 已提交
475 476
		AuthRequest areq = AUTH_REQ_OK;
		PacketDoneProc auth_handler = NULL;
477

478
		switch (port->auth_method)
479
		{
480
			case uaReject:
B
Bruce Momjian 已提交
481

482
				/*
B
Bruce Momjian 已提交
483 484 485 486 487 488
				 * This could have come from an explicit "reject" entry in
				 * pg_hba.conf, but more likely it means there was no
				 * matching entry.	Take pity on the poor user and issue a
				 * helpful error message.  NOTE: this is not a security
				 * breach, because all the info reported here is known at
				 * the frontend and must be assumed known to bad guys.
489 490 491
				 * We're merely helping out the less clueful good guys.
				 * NOTE 2: libpq-be.h defines the maximum error message
				 * length as 99 characters.  It probably wouldn't hurt
B
Bruce Momjian 已提交
492 493
				 * anything to increase it, but there might be some client
				 * out there that will fail.  So, be terse.
494 495
				 */
				{
B
Bruce Momjian 已提交
496
					char		buffer[512];
497 498 499 500 501 502 503 504 505 506
					const char *hostinfo = "localhost";

					if (port->raddr.sa.sa_family == AF_INET)
						hostinfo = inet_ntoa(port->raddr.in.sin_addr);
					sprintf(buffer,
							"No pg_hba.conf entry for host %s, user %s, database %s",
							hostinfo, port->user, port->database);
					PacketSendError(&port->pktInfo, buffer);
					return;
				}
507
				break;
508

509 510 511 512
			case uaKrb4:
				areq = AUTH_REQ_KRB4;
				auth_handler = handle_krb4_auth;
				break;
513

514 515 516 517
			case uaKrb5:
				areq = AUTH_REQ_KRB5;
				auth_handler = handle_krb5_auth;
				break;
518

519
			case uaTrust:
520 521
				areq = AUTH_REQ_OK;
				auth_handler = handle_done_auth;
522
				break;
523

524 525 526 527 528 529 530
			case uaIdent:
				if (authident(&port->raddr.in, &port->laddr.in,
							  port->user, port->auth_arg) == STATUS_OK)
				{
					areq = AUTH_REQ_OK;
					auth_handler = handle_done_auth;
				}
531

532
				break;
533

534 535 536 537 538 539 540 541 542 543
			case uaPassword:
				areq = AUTH_REQ_PASSWORD;
				auth_handler = handle_password_auth;
				break;

			case uaCrypt:
				areq = AUTH_REQ_CRYPT;
				auth_handler = handle_password_auth;
				break;
		}
544 545 546 547 548 549 550 551

		/* Tell the frontend what we want next. */

		if (auth_handler != NULL)
			sendAuthRequest(port, areq, auth_handler);
		else
			auth_failed(port);
	}
552
}
553

554 555

/*
556
 * Send an authentication request packet to the frontend.
557
 */
558

559
static void
M
 
Marc G. Fournier 已提交
560
sendAuthRequest(Port *port, AuthRequest areq, PacketDoneProc handler)
561
{
562 563 564 565
	char	   *dp,
			   *sp;
	int			i;
	uint32		net_areq;
566

567 568 569 570 571
	/* Convert to a byte stream. */

	net_areq = htonl(areq);

	dp = port->pktInfo.pkt.ar.data;
572
	sp = (char *) &net_areq;
573 574 575 576 577 578 579 580 581

	*dp++ = 'R';

	for (i = 1; i <= 4; ++i)
		*dp++ = *sp++;

	/* Add the salt for encrypted passwords. */

	if (areq == AUTH_REQ_CRYPT)
582
	{
583 584 585
		*dp++ = port->salt[0];
		*dp++ = port->salt[1];
		i += 2;
586
	}
587

M
 
Marc G. Fournier 已提交
588
	PacketSendSetup(&port->pktInfo, i, handler, (void *) port);
589 590 591 592 593 594 595
}


/*
 * Called when we have told the front end that it is authorised.
 */

M
 
Marc G. Fournier 已提交
596 597
static int
handle_done_auth(void *arg, PacketLen len, void *pkt)
598
{
599

600 601 602 603 604
	/*
	 * Don't generate any more traffic.  This will cause the backend to
	 * start.
	 */

M
 
Marc G. Fournier 已提交
605
	return STATUS_OK;
606 607 608 609 610 611 612 613
}


/*
 * Called when we have told the front end that it should use Kerberos V4
 * authentication.
 */

M
 
Marc G. Fournier 已提交
614 615
static int
handle_krb4_auth(void *arg, PacketLen len, void *pkt)
616
{
M
 
Marc G. Fournier 已提交
617 618
	Port	   *port = (Port *) arg;

619 620 621 622
	if (pg_krb4_recvauth(port) != STATUS_OK)
		auth_failed(port);
	else
		sendAuthRequest(port, AUTH_REQ_OK, handle_done_auth);
M
 
Marc G. Fournier 已提交
623 624

	return STATUS_OK;
625 626 627 628 629 630 631 632
}


/*
 * Called when we have told the front end that it should use Kerberos V5
 * authentication.
 */

M
 
Marc G. Fournier 已提交
633 634
static int
handle_krb5_auth(void *arg, PacketLen len, void *pkt)
635
{
M
 
Marc G. Fournier 已提交
636 637
	Port	   *port = (Port *) arg;

638 639 640 641
	if (pg_krb5_recvauth(port) != STATUS_OK)
		auth_failed(port);
	else
		sendAuthRequest(port, AUTH_REQ_OK, handle_done_auth);
M
 
Marc G. Fournier 已提交
642 643

	return STATUS_OK;
644 645 646 647 648 649 650 651
}


/*
 * Called when we have told the front end that it should use password
 * authentication.
 */

M
 
Marc G. Fournier 已提交
652 653
static int
handle_password_auth(void *arg, PacketLen len, void *pkt)
654
{
M
 
Marc G. Fournier 已提交
655 656
	Port	   *port = (Port *) arg;

657 658
	/* Set up the read of the password packet. */

M
 
Marc G. Fournier 已提交
659 660 661
	PacketReceiveSetup(&port->pktInfo, readPasswordPacket, (void *) port);

	return STATUS_OK;
662 663 664 665 666 667 668
}


/*
 * Called when we have received the password packet.
 */

M
 
Marc G. Fournier 已提交
669 670
static int
readPasswordPacket(void *arg, PacketLen len, void *pkt)
671
{
672
	char		password[sizeof(PasswordPacket) + 1];
M
 
Marc G. Fournier 已提交
673
	Port	   *port = (Port *) arg;
674 675 676

	/* Silently truncate a password that is too big. */

677 678 679 680
	if (len > sizeof(PasswordPacket))
		len = sizeof(PasswordPacket);

	StrNCpy(password, ((PasswordPacket *) pkt)->passwd, len);
681

682
	if (checkPassword(port, port->user, password) != STATUS_OK)
683 684 685
		auth_failed(port);
	else
		sendAuthRequest(port, AUTH_REQ_OK, handle_done_auth);
M
 
Marc G. Fournier 已提交
686

687
	return STATUS_OK;			/* don't close the connection yet */
688 689
}

690

691
/*
692 693
 * Handle `password' and `crypt' records. If an auth argument was
 * specified, use the respective file. Else use pg_shadow passwords.
694
 */
695 696
static int
checkPassword(Port *port, char *user, char *password)
697
{
698 699
	if (port->auth_arg[0] != '\0')
		return verify_password(port, user, password);
700 701 702 703 704

	return crypt_verify(port, user, password);
}


705 706 707 708
/*
 * Server demux routine for incoming authentication information for protocol
 * version 0.
 */
709 710
static int
old_be_recvauth(Port *port)
711
{
712 713
	int			status;
	MsgType		msgtype = (MsgType) port->proto;
714 715 716 717

	/* Handle the authentication that's offered. */

	switch (msgtype)
718 719 720 721
	{
		case STARTUP_KRB4_MSG:
			status = map_old_to_new(port, uaKrb4, pg_krb4_recvauth(port));
			break;
722

723 724 725
		case STARTUP_KRB5_MSG:
			status = map_old_to_new(port, uaKrb5, pg_krb5_recvauth(port));
			break;
726

727 728 729
		case STARTUP_MSG:
			status = map_old_to_new(port, uaTrust, STATUS_OK);
			break;
730

731 732
		case STARTUP_PASSWORD_MSG:
			PacketReceiveSetup(&port->pktInfo, pg_passwordv0_recvauth,
M
 
Marc G. Fournier 已提交
733
							   (void *) port);
734

735
			return STATUS_OK;
736

737 738
		default:
			fprintf(stderr, "Invalid startup message type: %u\n", msgtype);
739

740 741
			return STATUS_OK;
	}
742 743 744

	return status;
}
745

746 747

/*
748
 * The old style authentication has been done.	Modify the result of this (eg.
749 750 751 752
 * allow the connection anyway, disallow it anyway, or use the result)
 * depending on what authentication we really want to use.
 */

753 754
static int
map_old_to_new(Port *port, UserAuth old, int status)
755 756 757
{
	switch (port->auth_method)
	{
758 759
			case uaCrypt:
			case uaReject:
760
			status = STATUS_ERROR;
761
			break;
762

763 764 765 766
		case uaKrb4:
			if (old != uaKrb4)
				status = STATUS_ERROR;
			break;
767

768 769 770 771
		case uaKrb5:
			if (old != uaKrb5)
				status = STATUS_ERROR;
			break;
772

773 774 775
		case uaTrust:
			status = STATUS_OK;
			break;
776

777 778 779 780 781 782 783 784
		case uaIdent:
			status = authident(&port->raddr.in, &port->laddr.in,
							   port->user, port->auth_arg);
			break;

		case uaPassword:
			if (old != uaPassword)
				status = STATUS_ERROR;
785

786
			break;
787
	}
788

789
	return status;
790
}