Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * auth.c
4 : * Routines to handle network authentication
5 : *
6 : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : *
10 : * IDENTIFICATION
11 : * src/backend/libpq/auth.c
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 :
16 : #include "postgres.h"
17 :
18 : #include <sys/param.h>
19 : #include <sys/select.h>
20 : #include <sys/socket.h>
21 : #include <netinet/in.h>
22 : #include <netdb.h>
23 : #include <pwd.h>
24 : #include <unistd.h>
25 :
26 : #include "commands/user.h"
27 : #include "common/ip.h"
28 : #include "common/md5.h"
29 : #include "libpq/auth.h"
30 : #include "libpq/crypt.h"
31 : #include "libpq/libpq.h"
32 : #include "libpq/pqformat.h"
33 : #include "libpq/sasl.h"
34 : #include "libpq/scram.h"
35 : #include "miscadmin.h"
36 : #include "port/pg_bswap.h"
37 : #include "postmaster/postmaster.h"
38 : #include "replication/walsender.h"
39 : #include "storage/ipc.h"
40 : #include "utils/memutils.h"
41 :
42 : /*----------------------------------------------------------------
43 : * Global authentication functions
44 : *----------------------------------------------------------------
45 : */
46 : static void auth_failed(Port *port, int status, const char *logdetail);
47 : static char *recv_password_packet(Port *port);
48 : static void set_authn_id(Port *port, const char *id);
49 :
50 :
51 : /*----------------------------------------------------------------
52 : * Password-based authentication methods (password, md5, and scram-sha-256)
53 : *----------------------------------------------------------------
54 : */
55 : static int CheckPasswordAuth(Port *port, const char **logdetail);
56 : static int CheckPWChallengeAuth(Port *port, const char **logdetail);
57 :
58 : static int CheckMD5Auth(Port *port, char *shadow_pass,
59 : const char **logdetail);
60 :
61 :
62 : /*----------------------------------------------------------------
63 : * Ident authentication
64 : *----------------------------------------------------------------
65 : */
66 : /* Max size of username ident server can return (per RFC 1413) */
67 : #define IDENT_USERNAME_MAX 512
68 :
69 : /* Standard TCP port number for Ident service. Assigned by IANA */
70 : #define IDENT_PORT 113
71 :
72 : static int ident_inet(hbaPort *port);
73 :
74 :
75 : /*----------------------------------------------------------------
76 : * Peer authentication
77 : *----------------------------------------------------------------
78 : */
79 : static int auth_peer(hbaPort *port);
80 :
81 :
82 : /*----------------------------------------------------------------
83 : * PAM authentication
84 : *----------------------------------------------------------------
85 : */
86 : #ifdef USE_PAM
87 : #ifdef HAVE_PAM_PAM_APPL_H
88 : #include <pam/pam_appl.h>
89 : #endif
90 : #ifdef HAVE_SECURITY_PAM_APPL_H
91 : #include <security/pam_appl.h>
92 : #endif
93 :
94 : #define PGSQL_PAM_SERVICE "postgresql" /* Service name passed to PAM */
95 :
96 : static int CheckPAMAuth(Port *port, const char *user, const char *password);
97 : static int pam_passwd_conv_proc(int num_msg, const struct pam_message **msg,
98 : struct pam_response **resp, void *appdata_ptr);
99 :
100 : static struct pam_conv pam_passw_conv = {
101 : &pam_passwd_conv_proc,
102 : NULL
103 : };
104 :
105 : static const char *pam_passwd = NULL; /* Workaround for Solaris 2.6
106 : * brokenness */
107 : static Port *pam_port_cludge; /* Workaround for passing "Port *port" into
108 : * pam_passwd_conv_proc */
109 : static bool pam_no_password; /* For detecting no-password-given */
110 : #endif /* USE_PAM */
111 :
112 :
113 : /*----------------------------------------------------------------
114 : * BSD authentication
115 : *----------------------------------------------------------------
116 : */
117 : #ifdef USE_BSD_AUTH
118 : #include <bsd_auth.h>
119 :
120 : static int CheckBSDAuth(Port *port, char *user);
121 : #endif /* USE_BSD_AUTH */
122 :
123 :
124 : /*----------------------------------------------------------------
125 : * LDAP authentication
126 : *----------------------------------------------------------------
127 : */
128 : #ifdef USE_LDAP
129 : #ifndef WIN32
130 : /* We use a deprecated function to keep the codepath the same as win32. */
131 : #define LDAP_DEPRECATED 1
132 : #include <ldap.h>
133 : #else
134 : #include <winldap.h>
135 :
136 : #endif
137 :
138 : static int CheckLDAPAuth(Port *port);
139 :
140 : /* LDAP_OPT_DIAGNOSTIC_MESSAGE is the newer spelling */
141 : #ifndef LDAP_OPT_DIAGNOSTIC_MESSAGE
142 : #define LDAP_OPT_DIAGNOSTIC_MESSAGE LDAP_OPT_ERROR_STRING
143 : #endif
144 :
145 : /* Default LDAP password mutator hook, can be overridden by a shared library */
146 : static char *dummy_ldap_password_mutator(char *input);
147 : auth_password_hook_typ ldap_password_hook = dummy_ldap_password_mutator;
148 :
149 : #endif /* USE_LDAP */
150 :
151 : /*----------------------------------------------------------------
152 : * Cert authentication
153 : *----------------------------------------------------------------
154 : */
155 : #ifdef USE_SSL
156 : static int CheckCertAuth(Port *port);
157 : #endif
158 :
159 :
160 : /*----------------------------------------------------------------
161 : * Kerberos and GSSAPI GUCs
162 : *----------------------------------------------------------------
163 : */
164 : char *pg_krb_server_keyfile;
165 : bool pg_krb_caseins_users;
166 : bool pg_gss_accept_delegation;
167 :
168 :
169 : /*----------------------------------------------------------------
170 : * GSSAPI Authentication
171 : *----------------------------------------------------------------
172 : */
173 : #ifdef ENABLE_GSS
174 : #include "libpq/be-gssapi-common.h"
175 :
176 : static int pg_GSS_checkauth(Port *port);
177 : static int pg_GSS_recvauth(Port *port);
178 : #endif /* ENABLE_GSS */
179 :
180 :
181 : /*----------------------------------------------------------------
182 : * SSPI Authentication
183 : *----------------------------------------------------------------
184 : */
185 : #ifdef ENABLE_SSPI
186 : typedef SECURITY_STATUS
187 : (WINAPI * QUERY_SECURITY_CONTEXT_TOKEN_FN) (PCtxtHandle, void **);
188 : static int pg_SSPI_recvauth(Port *port);
189 : static int pg_SSPI_make_upn(char *accountname,
190 : size_t accountnamesize,
191 : char *domainname,
192 : size_t domainnamesize,
193 : bool update_accountname);
194 : #endif
195 :
196 : /*----------------------------------------------------------------
197 : * RADIUS Authentication
198 : *----------------------------------------------------------------
199 : */
200 : static int CheckRADIUSAuth(Port *port);
201 : static int PerformRadiusTransaction(const char *server, const char *secret, const char *portstr, const char *identifier, const char *user_name, const char *passwd);
202 :
203 :
204 : /*
205 : * Maximum accepted size of GSS and SSPI authentication tokens.
206 : * We also use this as a limit on ordinary password packet lengths.
207 : *
208 : * Kerberos tickets are usually quite small, but the TGTs issued by Windows
209 : * domain controllers include an authorization field known as the Privilege
210 : * Attribute Certificate (PAC), which contains the user's Windows permissions
211 : * (group memberships etc.). The PAC is copied into all tickets obtained on
212 : * the basis of this TGT (even those issued by Unix realms which the Windows
213 : * realm trusts), and can be several kB in size. The maximum token size
214 : * accepted by Windows systems is determined by the MaxAuthToken Windows
215 : * registry setting. Microsoft recommends that it is not set higher than
216 : * 65535 bytes, so that seems like a reasonable limit for us as well.
217 : */
218 : #define PG_MAX_AUTH_TOKEN_LENGTH 65535
219 :
220 : /*----------------------------------------------------------------
221 : * Global authentication functions
222 : *----------------------------------------------------------------
223 : */
224 :
225 : /*
226 : * This hook allows plugins to get control following client authentication,
227 : * but before the user has been informed about the results. It could be used
228 : * to record login events, insert a delay after failed authentication, etc.
229 : */
230 : ClientAuthentication_hook_type ClientAuthentication_hook = NULL;
231 :
232 : /*
233 : * Tell the user the authentication failed, but not (much about) why.
234 : *
235 : * There is a tradeoff here between security concerns and making life
236 : * unnecessarily difficult for legitimate users. We would not, for example,
237 : * want to report the password we were expecting to receive...
238 : * But it seems useful to report the username and authorization method
239 : * in use, and these are items that must be presumed known to an attacker
240 : * anyway.
241 : * Note that many sorts of failure report additional information in the
242 : * postmaster log, which we hope is only readable by good guys. In
243 : * particular, if logdetail isn't NULL, we send that string to the log.
244 : */
245 : static void
246 96 : auth_failed(Port *port, int status, const char *logdetail)
247 : {
248 : const char *errstr;
249 : char *cdetail;
250 96 : int errcode_return = ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION;
251 :
252 : /*
253 : * If we failed due to EOF from client, just quit; there's no point in
254 : * trying to send a message to the client, and not much point in logging
255 : * the failure in the postmaster log. (Logging the failure might be
256 : * desirable, were it not for the fact that libpq closes the connection
257 : * unceremoniously if challenged for a password when it hasn't got one to
258 : * send. We'll get a useless log entry for every psql connection under
259 : * password auth, even if it's perfectly successful, if we log STATUS_EOF
260 : * events.)
261 : */
262 96 : if (status == STATUS_EOF)
263 42 : proc_exit(0);
264 :
265 54 : switch (port->hba->auth_method)
266 : {
267 0 : case uaReject:
268 : case uaImplicitReject:
269 0 : errstr = gettext_noop("authentication failed for user \"%s\": host rejected");
270 0 : break;
271 2 : case uaTrust:
272 2 : errstr = gettext_noop("\"trust\" authentication failed for user \"%s\"");
273 2 : break;
274 0 : case uaIdent:
275 0 : errstr = gettext_noop("Ident authentication failed for user \"%s\"");
276 0 : break;
277 12 : case uaPeer:
278 12 : errstr = gettext_noop("Peer authentication failed for user \"%s\"");
279 12 : break;
280 10 : case uaPassword:
281 : case uaMD5:
282 : case uaSCRAM:
283 10 : errstr = gettext_noop("password authentication failed for user \"%s\"");
284 : /* We use it to indicate if a .pgpass password failed. */
285 10 : errcode_return = ERRCODE_INVALID_PASSWORD;
286 10 : break;
287 0 : case uaGSS:
288 0 : errstr = gettext_noop("GSSAPI authentication failed for user \"%s\"");
289 0 : break;
290 0 : case uaSSPI:
291 0 : errstr = gettext_noop("SSPI authentication failed for user \"%s\"");
292 0 : break;
293 0 : case uaPAM:
294 0 : errstr = gettext_noop("PAM authentication failed for user \"%s\"");
295 0 : break;
296 0 : case uaBSD:
297 0 : errstr = gettext_noop("BSD authentication failed for user \"%s\"");
298 0 : break;
299 28 : case uaLDAP:
300 28 : errstr = gettext_noop("LDAP authentication failed for user \"%s\"");
301 28 : break;
302 2 : case uaCert:
303 2 : errstr = gettext_noop("certificate authentication failed for user \"%s\"");
304 2 : break;
305 0 : case uaRADIUS:
306 0 : errstr = gettext_noop("RADIUS authentication failed for user \"%s\"");
307 0 : break;
308 0 : default:
309 0 : errstr = gettext_noop("authentication failed for user \"%s\": invalid authentication method");
310 0 : break;
311 : }
312 :
313 54 : cdetail = psprintf(_("Connection matched file \"%s\" line %d: \"%s\""),
314 54 : port->hba->sourcefile, port->hba->linenumber,
315 54 : port->hba->rawline);
316 54 : if (logdetail)
317 2 : logdetail = psprintf("%s\n%s", logdetail, cdetail);
318 : else
319 52 : logdetail = cdetail;
320 :
321 54 : ereport(FATAL,
322 : (errcode(errcode_return),
323 : errmsg(errstr, port->user_name),
324 : logdetail ? errdetail_log("%s", logdetail) : 0));
325 :
326 : /* doesn't return */
327 : }
328 :
329 :
330 : /*
331 : * Sets the authenticated identity for the current user. The provided string
332 : * will be stored into MyClientConnectionInfo, alongside the current HBA
333 : * method in use. The ID will be logged if log_connections is enabled.
334 : *
335 : * Auth methods should call this routine exactly once, as soon as the user is
336 : * successfully authenticated, even if they have reasons to know that
337 : * authorization will fail later.
338 : *
339 : * The provided string will be copied into TopMemoryContext, to match the
340 : * lifetime of MyClientConnectionInfo, so it is safe to pass a string that is
341 : * managed by an external library.
342 : */
343 : static void
344 222 : set_authn_id(Port *port, const char *id)
345 : {
346 : Assert(id);
347 :
348 222 : if (MyClientConnectionInfo.authn_id)
349 : {
350 : /*
351 : * An existing authn_id should never be overwritten; that means two
352 : * authentication providers are fighting (or one is fighting itself).
353 : * Don't leak any authn details to the client, but don't let the
354 : * connection continue, either.
355 : */
356 0 : ereport(FATAL,
357 : (errmsg("authentication identifier set more than once"),
358 : errdetail_log("previous identifier: \"%s\"; new identifier: \"%s\"",
359 : MyClientConnectionInfo.authn_id, id)));
360 : }
361 :
362 222 : MyClientConnectionInfo.authn_id = MemoryContextStrdup(TopMemoryContext, id);
363 222 : MyClientConnectionInfo.auth_method = port->hba->auth_method;
364 :
365 222 : if (Log_connections)
366 : {
367 204 : ereport(LOG,
368 : errmsg("connection authenticated: identity=\"%s\" method=%s "
369 : "(%s:%d)",
370 : MyClientConnectionInfo.authn_id,
371 : hba_authname(MyClientConnectionInfo.auth_method),
372 : port->hba->sourcefile, port->hba->linenumber));
373 : }
374 222 : }
375 :
376 :
377 : /*
378 : * Client authentication starts here. If there is an error, this
379 : * function does not return and the backend process is terminated.
380 : */
381 : void
382 21094 : ClientAuthentication(Port *port)
383 : {
384 21094 : int status = STATUS_ERROR;
385 21094 : const char *logdetail = NULL;
386 :
387 : /*
388 : * Get the authentication method to use for this frontend/database
389 : * combination. Note: we do not parse the file at this point; this has
390 : * already been done elsewhere. hba.c dropped an error message into the
391 : * server logfile if parsing the hba config file failed.
392 : */
393 21094 : hba_getauthmethod(port);
394 :
395 21094 : CHECK_FOR_INTERRUPTS();
396 :
397 : /*
398 : * This is the first point where we have access to the hba record for the
399 : * current connection, so perform any verifications based on the hba
400 : * options field that should be done *before* the authentication here.
401 : */
402 21094 : if (port->hba->clientcert != clientCertOff)
403 : {
404 : /* If we haven't loaded a root certificate store, fail */
405 60 : if (!secure_loaded_verify_locations())
406 0 : ereport(FATAL,
407 : (errcode(ERRCODE_CONFIG_FILE_ERROR),
408 : errmsg("client certificates can only be checked if a root certificate store is available")));
409 :
410 : /*
411 : * If we loaded a root certificate store, and if a certificate is
412 : * present on the client, then it has been verified against our root
413 : * certificate store, and the connection would have been aborted
414 : * already if it didn't verify ok.
415 : */
416 60 : if (!port->peer_cert_valid)
417 4 : ereport(FATAL,
418 : (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
419 : errmsg("connection requires a valid client certificate")));
420 : }
421 :
422 : /*
423 : * Now proceed to do the actual authentication check
424 : */
425 21090 : switch (port->hba->auth_method)
426 : {
427 0 : case uaReject:
428 :
429 : /*
430 : * An explicit "reject" entry in pg_hba.conf. This report exposes
431 : * the fact that there's an explicit reject entry, which is
432 : * perhaps not so desirable from a security standpoint; but the
433 : * message for an implicit reject could confuse the DBA a lot when
434 : * the true situation is a match to an explicit reject. And we
435 : * don't want to change the message for an implicit reject. As
436 : * noted below, the additional information shown here doesn't
437 : * expose anything not known to an attacker.
438 : */
439 : {
440 : char hostinfo[NI_MAXHOST];
441 : const char *encryption_state;
442 :
443 0 : pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
444 : hostinfo, sizeof(hostinfo),
445 : NULL, 0,
446 : NI_NUMERICHOST);
447 :
448 0 : encryption_state =
449 : #ifdef ENABLE_GSS
450 : (port->gss && port->gss->enc) ? _("GSS encryption") :
451 : #endif
452 : #ifdef USE_SSL
453 0 : port->ssl_in_use ? _("SSL encryption") :
454 : #endif
455 0 : _("no encryption");
456 :
457 0 : if (am_walsender && !am_db_walsender)
458 0 : ereport(FATAL,
459 : (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
460 : /* translator: last %s describes encryption state */
461 : errmsg("pg_hba.conf rejects replication connection for host \"%s\", user \"%s\", %s",
462 : hostinfo, port->user_name,
463 : encryption_state)));
464 : else
465 0 : ereport(FATAL,
466 : (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
467 : /* translator: last %s describes encryption state */
468 : errmsg("pg_hba.conf rejects connection for host \"%s\", user \"%s\", database \"%s\", %s",
469 : hostinfo, port->user_name,
470 : port->database_name,
471 : encryption_state)));
472 : break;
473 : }
474 :
475 14 : case uaImplicitReject:
476 :
477 : /*
478 : * No matching entry, so tell the user we fell through.
479 : *
480 : * NOTE: the extra info reported here is not a security breach,
481 : * because all that info is known at the frontend and must be
482 : * assumed known to bad guys. We're merely helping out the less
483 : * clueful good guys.
484 : */
485 : {
486 : char hostinfo[NI_MAXHOST];
487 : const char *encryption_state;
488 :
489 14 : pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
490 : hostinfo, sizeof(hostinfo),
491 : NULL, 0,
492 : NI_NUMERICHOST);
493 :
494 28 : encryption_state =
495 : #ifdef ENABLE_GSS
496 : (port->gss && port->gss->enc) ? _("GSS encryption") :
497 : #endif
498 : #ifdef USE_SSL
499 14 : port->ssl_in_use ? _("SSL encryption") :
500 : #endif
501 14 : _("no encryption");
502 :
503 : #define HOSTNAME_LOOKUP_DETAIL(port) \
504 : (port->remote_hostname ? \
505 : (port->remote_hostname_resolv == +1 ? \
506 : errdetail_log("Client IP address resolved to \"%s\", forward lookup matches.", \
507 : port->remote_hostname) : \
508 : port->remote_hostname_resolv == 0 ? \
509 : errdetail_log("Client IP address resolved to \"%s\", forward lookup not checked.", \
510 : port->remote_hostname) : \
511 : port->remote_hostname_resolv == -1 ? \
512 : errdetail_log("Client IP address resolved to \"%s\", forward lookup does not match.", \
513 : port->remote_hostname) : \
514 : port->remote_hostname_resolv == -2 ? \
515 : errdetail_log("Could not translate client host name \"%s\" to IP address: %s.", \
516 : port->remote_hostname, \
517 : gai_strerror(port->remote_hostname_errcode)) : \
518 : 0) \
519 : : (port->remote_hostname_resolv == -2 ? \
520 : errdetail_log("Could not resolve client IP address to a host name: %s.", \
521 : gai_strerror(port->remote_hostname_errcode)) : \
522 : 0))
523 :
524 14 : if (am_walsender && !am_db_walsender)
525 0 : ereport(FATAL,
526 : (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
527 : /* translator: last %s describes encryption state */
528 : errmsg("no pg_hba.conf entry for replication connection from host \"%s\", user \"%s\", %s",
529 : hostinfo, port->user_name,
530 : encryption_state),
531 : HOSTNAME_LOOKUP_DETAIL(port)));
532 : else
533 14 : ereport(FATAL,
534 : (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
535 : /* translator: last %s describes encryption state */
536 : errmsg("no pg_hba.conf entry for host \"%s\", user \"%s\", database \"%s\", %s",
537 : hostinfo, port->user_name,
538 : port->database_name,
539 : encryption_state),
540 : HOSTNAME_LOOKUP_DETAIL(port)));
541 : break;
542 : }
543 :
544 0 : case uaGSS:
545 : #ifdef ENABLE_GSS
546 : /* We might or might not have the gss workspace already */
547 : if (port->gss == NULL)
548 : port->gss = (pg_gssinfo *)
549 : MemoryContextAllocZero(TopMemoryContext,
550 : sizeof(pg_gssinfo));
551 : port->gss->auth = true;
552 :
553 : /*
554 : * If GSS state was set up while enabling encryption, we can just
555 : * check the client's principal. Otherwise, ask for it.
556 : */
557 : if (port->gss->enc)
558 : status = pg_GSS_checkauth(port);
559 : else
560 : {
561 : sendAuthRequest(port, AUTH_REQ_GSS, NULL, 0);
562 : status = pg_GSS_recvauth(port);
563 : }
564 : #else
565 : Assert(false);
566 : #endif
567 0 : break;
568 :
569 0 : case uaSSPI:
570 : #ifdef ENABLE_SSPI
571 : if (port->gss == NULL)
572 : port->gss = (pg_gssinfo *)
573 : MemoryContextAllocZero(TopMemoryContext,
574 : sizeof(pg_gssinfo));
575 : sendAuthRequest(port, AUTH_REQ_SSPI, NULL, 0);
576 : status = pg_SSPI_recvauth(port);
577 : #else
578 : Assert(false);
579 : #endif
580 0 : break;
581 :
582 54 : case uaPeer:
583 54 : status = auth_peer(port);
584 54 : break;
585 :
586 0 : case uaIdent:
587 0 : status = ident_inet(port);
588 0 : break;
589 :
590 106 : case uaMD5:
591 : case uaSCRAM:
592 106 : status = CheckPWChallengeAuth(port, &logdetail);
593 106 : break;
594 :
595 34 : case uaPassword:
596 34 : status = CheckPasswordAuth(port, &logdetail);
597 34 : break;
598 :
599 0 : case uaPAM:
600 : #ifdef USE_PAM
601 0 : status = CheckPAMAuth(port, port->user_name, "");
602 : #else
603 : Assert(false);
604 : #endif /* USE_PAM */
605 0 : break;
606 :
607 0 : case uaBSD:
608 : #ifdef USE_BSD_AUTH
609 : status = CheckBSDAuth(port, port->user_name);
610 : #else
611 : Assert(false);
612 : #endif /* USE_BSD_AUTH */
613 0 : break;
614 :
615 60 : case uaLDAP:
616 : #ifdef USE_LDAP
617 60 : status = CheckLDAPAuth(port);
618 : #else
619 : Assert(false);
620 : #endif
621 60 : break;
622 0 : case uaRADIUS:
623 0 : status = CheckRADIUSAuth(port);
624 0 : break;
625 20822 : case uaCert:
626 : /* uaCert will be treated as if clientcert=verify-full (uaTrust) */
627 : case uaTrust:
628 20822 : status = STATUS_OK;
629 20822 : break;
630 : }
631 :
632 21076 : if ((status == STATUS_OK && port->hba->clientcert == clientCertFull)
633 21022 : || port->hba->auth_method == uaCert)
634 : {
635 : /*
636 : * Make sure we only check the certificate if we use the cert method
637 : * or verify-full option.
638 : */
639 : #ifdef USE_SSL
640 54 : status = CheckCertAuth(port);
641 : #else
642 : Assert(false);
643 : #endif
644 : }
645 :
646 21076 : if (Log_connections && status == STATUS_OK &&
647 514 : !MyClientConnectionInfo.authn_id)
648 : {
649 : /*
650 : * Normally, if log_connections is set, the call to set_authn_id()
651 : * will log the connection. However, if that function is never
652 : * called, perhaps because the trust method is in use, then we handle
653 : * the logging here instead.
654 : */
655 324 : ereport(LOG,
656 : errmsg("connection authenticated: user=\"%s\" method=%s "
657 : "(%s:%d)",
658 : port->user_name, hba_authname(port->hba->auth_method),
659 : port->hba->sourcefile, port->hba->linenumber));
660 : }
661 :
662 21076 : if (ClientAuthentication_hook)
663 0 : (*ClientAuthentication_hook) (port, status);
664 :
665 21076 : if (status == STATUS_OK)
666 20980 : sendAuthRequest(port, AUTH_REQ_OK, NULL, 0);
667 : else
668 96 : auth_failed(port, status, logdetail);
669 20980 : }
670 :
671 :
672 : /*
673 : * Send an authentication request packet to the frontend.
674 : */
675 : void
676 21326 : sendAuthRequest(Port *port, AuthRequest areq, const char *extradata, int extralen)
677 : {
678 : StringInfoData buf;
679 :
680 21326 : CHECK_FOR_INTERRUPTS();
681 :
682 21326 : pq_beginmessage(&buf, PqMsg_AuthenticationRequest);
683 21326 : pq_sendint32(&buf, (int32) areq);
684 21326 : if (extralen > 0)
685 252 : pq_sendbytes(&buf, extradata, extralen);
686 :
687 21326 : pq_endmessage(&buf);
688 :
689 : /*
690 : * Flush message so client will see it, except for AUTH_REQ_OK and
691 : * AUTH_REQ_SASL_FIN, which need not be sent until we are ready for
692 : * queries.
693 : */
694 21326 : if (areq != AUTH_REQ_OK && areq != AUTH_REQ_SASL_FIN)
695 278 : pq_flush();
696 :
697 21326 : CHECK_FOR_INTERRUPTS();
698 21326 : }
699 :
700 : /*
701 : * Collect password response packet from frontend.
702 : *
703 : * Returns NULL if couldn't get password, else palloc'd string.
704 : */
705 : static char *
706 100 : recv_password_packet(Port *port)
707 : {
708 : StringInfoData buf;
709 : int mtype;
710 :
711 100 : pq_startmsgread();
712 :
713 : /* Expect 'p' message type */
714 100 : mtype = pq_getbyte();
715 100 : if (mtype != PqMsg_PasswordMessage)
716 : {
717 : /*
718 : * If the client just disconnects without offering a password, don't
719 : * make a log entry. This is legal per protocol spec and in fact
720 : * commonly done by psql, so complaining just clutters the log.
721 : */
722 20 : if (mtype != EOF)
723 0 : ereport(ERROR,
724 : (errcode(ERRCODE_PROTOCOL_VIOLATION),
725 : errmsg("expected password response, got message type %d",
726 : mtype)));
727 20 : return NULL; /* EOF or bad message type */
728 : }
729 :
730 80 : initStringInfo(&buf);
731 80 : if (pq_getmessage(&buf, PG_MAX_AUTH_TOKEN_LENGTH)) /* receive password */
732 : {
733 : /* EOF - pq_getmessage already logged a suitable message */
734 0 : pfree(buf.data);
735 0 : return NULL;
736 : }
737 :
738 : /*
739 : * Apply sanity check: password packet length should agree with length of
740 : * contained string. Note it is safe to use strlen here because
741 : * StringInfo is guaranteed to have an appended '\0'.
742 : */
743 80 : if (strlen(buf.data) + 1 != buf.len)
744 0 : ereport(ERROR,
745 : (errcode(ERRCODE_PROTOCOL_VIOLATION),
746 : errmsg("invalid password packet size")));
747 :
748 : /*
749 : * Don't allow an empty password. Libpq treats an empty password the same
750 : * as no password at all, and won't even try to authenticate. But other
751 : * clients might, so allowing it would be confusing.
752 : *
753 : * Note that this only catches an empty password sent by the client in
754 : * plaintext. There's also a check in CREATE/ALTER USER that prevents an
755 : * empty string from being stored as a user's password in the first place.
756 : * We rely on that for MD5 and SCRAM authentication, but we still need
757 : * this check here, to prevent an empty password from being used with
758 : * authentication methods that check the password against an external
759 : * system, like PAM, LDAP and RADIUS.
760 : */
761 80 : if (buf.len == 1)
762 0 : ereport(ERROR,
763 : (errcode(ERRCODE_INVALID_PASSWORD),
764 : errmsg("empty password returned by client")));
765 :
766 : /* Do not echo password to logs, for security. */
767 80 : elog(DEBUG5, "received password packet");
768 :
769 : /*
770 : * Return the received string. Note we do not attempt to do any
771 : * character-set conversion on it; since we don't yet know the client's
772 : * encoding, there wouldn't be much point.
773 : */
774 80 : return buf.data;
775 : }
776 :
777 :
778 : /*----------------------------------------------------------------
779 : * Password-based authentication mechanisms
780 : *----------------------------------------------------------------
781 : */
782 :
783 : /*
784 : * Plaintext password authentication.
785 : */
786 : static int
787 34 : CheckPasswordAuth(Port *port, const char **logdetail)
788 : {
789 : char *passwd;
790 : int result;
791 : char *shadow_pass;
792 :
793 34 : sendAuthRequest(port, AUTH_REQ_PASSWORD, NULL, 0);
794 :
795 34 : passwd = recv_password_packet(port);
796 34 : if (passwd == NULL)
797 14 : return STATUS_EOF; /* client wouldn't send password */
798 :
799 20 : shadow_pass = get_role_password(port->user_name, logdetail);
800 20 : if (shadow_pass)
801 : {
802 20 : result = plain_crypt_verify(port->user_name, shadow_pass, passwd,
803 : logdetail);
804 : }
805 : else
806 0 : result = STATUS_ERROR;
807 :
808 20 : if (shadow_pass)
809 20 : pfree(shadow_pass);
810 20 : pfree(passwd);
811 :
812 20 : if (result == STATUS_OK)
813 20 : set_authn_id(port, port->user_name);
814 :
815 20 : return result;
816 : }
817 :
818 : /*
819 : * MD5 and SCRAM authentication.
820 : */
821 : static int
822 106 : CheckPWChallengeAuth(Port *port, const char **logdetail)
823 : {
824 : int auth_result;
825 : char *shadow_pass;
826 : PasswordType pwtype;
827 :
828 : Assert(port->hba->auth_method == uaSCRAM ||
829 : port->hba->auth_method == uaMD5);
830 :
831 : /* First look up the user's password. */
832 106 : shadow_pass = get_role_password(port->user_name, logdetail);
833 :
834 : /*
835 : * If the user does not exist, or has no password or it's expired, we
836 : * still go through the motions of authentication, to avoid revealing to
837 : * the client that the user didn't exist. If 'md5' is allowed, we choose
838 : * whether to use 'md5' or 'scram-sha-256' authentication based on current
839 : * password_encryption setting. The idea is that most genuine users
840 : * probably have a password of that type, and if we pretend that this user
841 : * had a password of that type, too, it "blends in" best.
842 : */
843 106 : if (!shadow_pass)
844 0 : pwtype = Password_encryption;
845 : else
846 106 : pwtype = get_password_type(shadow_pass);
847 :
848 : /*
849 : * If 'md5' authentication is allowed, decide whether to perform 'md5' or
850 : * 'scram-sha-256' authentication based on the type of password the user
851 : * has. If it's an MD5 hash, we must do MD5 authentication, and if it's a
852 : * SCRAM secret, we must do SCRAM authentication.
853 : *
854 : * If MD5 authentication is not allowed, always use SCRAM. If the user
855 : * had an MD5 password, CheckSASLAuth() with the SCRAM mechanism will
856 : * fail.
857 : */
858 106 : if (port->hba->auth_method == uaMD5 && pwtype == PASSWORD_TYPE_MD5)
859 6 : auth_result = CheckMD5Auth(port, shadow_pass, logdetail);
860 : else
861 100 : auth_result = CheckSASLAuth(&pg_be_scram_mech, port, shadow_pass,
862 : logdetail);
863 :
864 106 : if (shadow_pass)
865 106 : pfree(shadow_pass);
866 : else
867 : {
868 : /*
869 : * If get_role_password() returned error, authentication better not
870 : * have succeeded.
871 : */
872 : Assert(auth_result != STATUS_OK);
873 : }
874 :
875 106 : if (auth_result == STATUS_OK)
876 70 : set_authn_id(port, port->user_name);
877 :
878 106 : return auth_result;
879 : }
880 :
881 : static int
882 6 : CheckMD5Auth(Port *port, char *shadow_pass, const char **logdetail)
883 : {
884 : char md5Salt[4]; /* Password salt */
885 : char *passwd;
886 : int result;
887 :
888 : /* include the salt to use for computing the response */
889 6 : if (!pg_strong_random(md5Salt, 4))
890 : {
891 0 : ereport(LOG,
892 : (errmsg("could not generate random MD5 salt")));
893 0 : return STATUS_ERROR;
894 : }
895 :
896 6 : sendAuthRequest(port, AUTH_REQ_MD5, md5Salt, 4);
897 :
898 6 : passwd = recv_password_packet(port);
899 6 : if (passwd == NULL)
900 4 : return STATUS_EOF; /* client wouldn't send password */
901 :
902 2 : if (shadow_pass)
903 2 : result = md5_crypt_verify(port->user_name, shadow_pass, passwd,
904 : md5Salt, 4, logdetail);
905 : else
906 0 : result = STATUS_ERROR;
907 :
908 2 : pfree(passwd);
909 :
910 2 : return result;
911 : }
912 :
913 :
914 : /*----------------------------------------------------------------
915 : * GSSAPI authentication system
916 : *----------------------------------------------------------------
917 : */
918 : #ifdef ENABLE_GSS
919 : static int
920 : pg_GSS_recvauth(Port *port)
921 : {
922 : OM_uint32 maj_stat,
923 : min_stat,
924 : lmin_s,
925 : gflags;
926 : int mtype;
927 : StringInfoData buf;
928 : gss_buffer_desc gbuf;
929 : gss_cred_id_t delegated_creds;
930 :
931 : /*
932 : * Use the configured keytab, if there is one. As we now require MIT
933 : * Kerberos, we might consider using the credential store extensions in
934 : * the future instead of the environment variable.
935 : */
936 : if (pg_krb_server_keyfile != NULL && pg_krb_server_keyfile[0] != '\0')
937 : {
938 : if (setenv("KRB5_KTNAME", pg_krb_server_keyfile, 1) != 0)
939 : {
940 : /* The only likely failure cause is OOM, so use that errcode */
941 : ereport(FATAL,
942 : (errcode(ERRCODE_OUT_OF_MEMORY),
943 : errmsg("could not set environment: %m")));
944 : }
945 : }
946 :
947 : /*
948 : * We accept any service principal that's present in our keytab. This
949 : * increases interoperability between kerberos implementations that see
950 : * for example case sensitivity differently, while not really opening up
951 : * any vector of attack.
952 : */
953 : port->gss->cred = GSS_C_NO_CREDENTIAL;
954 :
955 : /*
956 : * Initialize sequence with an empty context
957 : */
958 : port->gss->ctx = GSS_C_NO_CONTEXT;
959 :
960 : delegated_creds = GSS_C_NO_CREDENTIAL;
961 : port->gss->delegated_creds = false;
962 :
963 : /*
964 : * Loop through GSSAPI message exchange. This exchange can consist of
965 : * multiple messages sent in both directions. First message is always from
966 : * the client. All messages from client to server are password packets
967 : * (type 'p').
968 : */
969 : do
970 : {
971 : pq_startmsgread();
972 :
973 : CHECK_FOR_INTERRUPTS();
974 :
975 : mtype = pq_getbyte();
976 : if (mtype != PqMsg_GSSResponse)
977 : {
978 : /* Only log error if client didn't disconnect. */
979 : if (mtype != EOF)
980 : ereport(ERROR,
981 : (errcode(ERRCODE_PROTOCOL_VIOLATION),
982 : errmsg("expected GSS response, got message type %d",
983 : mtype)));
984 : return STATUS_ERROR;
985 : }
986 :
987 : /* Get the actual GSS token */
988 : initStringInfo(&buf);
989 : if (pq_getmessage(&buf, PG_MAX_AUTH_TOKEN_LENGTH))
990 : {
991 : /* EOF - pq_getmessage already logged error */
992 : pfree(buf.data);
993 : return STATUS_ERROR;
994 : }
995 :
996 : /* Map to GSSAPI style buffer */
997 : gbuf.length = buf.len;
998 : gbuf.value = buf.data;
999 :
1000 : elog(DEBUG4, "processing received GSS token of length %u",
1001 : (unsigned int) gbuf.length);
1002 :
1003 : maj_stat = gss_accept_sec_context(&min_stat,
1004 : &port->gss->ctx,
1005 : port->gss->cred,
1006 : &gbuf,
1007 : GSS_C_NO_CHANNEL_BINDINGS,
1008 : &port->gss->name,
1009 : NULL,
1010 : &port->gss->outbuf,
1011 : &gflags,
1012 : NULL,
1013 : pg_gss_accept_delegation ? &delegated_creds : NULL);
1014 :
1015 : /* gbuf no longer used */
1016 : pfree(buf.data);
1017 :
1018 : elog(DEBUG5, "gss_accept_sec_context major: %u, "
1019 : "minor: %u, outlen: %u, outflags: %x",
1020 : maj_stat, min_stat,
1021 : (unsigned int) port->gss->outbuf.length, gflags);
1022 :
1023 : CHECK_FOR_INTERRUPTS();
1024 :
1025 : if (delegated_creds != GSS_C_NO_CREDENTIAL && gflags & GSS_C_DELEG_FLAG)
1026 : {
1027 : pg_store_delegated_credential(delegated_creds);
1028 : port->gss->delegated_creds = true;
1029 : }
1030 :
1031 : if (port->gss->outbuf.length != 0)
1032 : {
1033 : /*
1034 : * Negotiation generated data to be sent to the client.
1035 : */
1036 : elog(DEBUG4, "sending GSS response token of length %u",
1037 : (unsigned int) port->gss->outbuf.length);
1038 :
1039 : sendAuthRequest(port, AUTH_REQ_GSS_CONT,
1040 : port->gss->outbuf.value, port->gss->outbuf.length);
1041 :
1042 : gss_release_buffer(&lmin_s, &port->gss->outbuf);
1043 : }
1044 :
1045 : if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
1046 : {
1047 : gss_delete_sec_context(&lmin_s, &port->gss->ctx, GSS_C_NO_BUFFER);
1048 : pg_GSS_error(_("accepting GSS security context failed"),
1049 : maj_stat, min_stat);
1050 : return STATUS_ERROR;
1051 : }
1052 :
1053 : if (maj_stat == GSS_S_CONTINUE_NEEDED)
1054 : elog(DEBUG4, "GSS continue needed");
1055 :
1056 : } while (maj_stat == GSS_S_CONTINUE_NEEDED);
1057 :
1058 : if (port->gss->cred != GSS_C_NO_CREDENTIAL)
1059 : {
1060 : /*
1061 : * Release service principal credentials
1062 : */
1063 : gss_release_cred(&min_stat, &port->gss->cred);
1064 : }
1065 : return pg_GSS_checkauth(port);
1066 : }
1067 :
1068 : /*
1069 : * Check whether the GSSAPI-authenticated user is allowed to connect as the
1070 : * claimed username.
1071 : */
1072 : static int
1073 : pg_GSS_checkauth(Port *port)
1074 : {
1075 : int ret;
1076 : OM_uint32 maj_stat,
1077 : min_stat,
1078 : lmin_s;
1079 : gss_buffer_desc gbuf;
1080 : char *princ;
1081 :
1082 : /*
1083 : * Get the name of the user that authenticated, and compare it to the pg
1084 : * username that was specified for the connection.
1085 : */
1086 : maj_stat = gss_display_name(&min_stat, port->gss->name, &gbuf, NULL);
1087 : if (maj_stat != GSS_S_COMPLETE)
1088 : {
1089 : pg_GSS_error(_("retrieving GSS user name failed"),
1090 : maj_stat, min_stat);
1091 : return STATUS_ERROR;
1092 : }
1093 :
1094 : /*
1095 : * gbuf.value might not be null-terminated, so turn it into a regular
1096 : * null-terminated string.
1097 : */
1098 : princ = palloc(gbuf.length + 1);
1099 : memcpy(princ, gbuf.value, gbuf.length);
1100 : princ[gbuf.length] = '\0';
1101 : gss_release_buffer(&lmin_s, &gbuf);
1102 :
1103 : /*
1104 : * Copy the original name of the authenticated principal into our backend
1105 : * memory for display later.
1106 : *
1107 : * This is also our authenticated identity. Set it now, rather than
1108 : * waiting for the usermap check below, because authentication has already
1109 : * succeeded and we want the log file to reflect that.
1110 : */
1111 : port->gss->princ = MemoryContextStrdup(TopMemoryContext, princ);
1112 : set_authn_id(port, princ);
1113 :
1114 : /*
1115 : * Split the username at the realm separator
1116 : */
1117 : if (strchr(princ, '@'))
1118 : {
1119 : char *cp = strchr(princ, '@');
1120 :
1121 : /*
1122 : * If we are not going to include the realm in the username that is
1123 : * passed to the ident map, destructively modify it here to remove the
1124 : * realm. Then advance past the separator to check the realm.
1125 : */
1126 : if (!port->hba->include_realm)
1127 : *cp = '\0';
1128 : cp++;
1129 :
1130 : if (port->hba->krb_realm != NULL && strlen(port->hba->krb_realm))
1131 : {
1132 : /*
1133 : * Match the realm part of the name first
1134 : */
1135 : if (pg_krb_caseins_users)
1136 : ret = pg_strcasecmp(port->hba->krb_realm, cp);
1137 : else
1138 : ret = strcmp(port->hba->krb_realm, cp);
1139 :
1140 : if (ret)
1141 : {
1142 : /* GSS realm does not match */
1143 : elog(DEBUG2,
1144 : "GSSAPI realm (%s) and configured realm (%s) don't match",
1145 : cp, port->hba->krb_realm);
1146 : pfree(princ);
1147 : return STATUS_ERROR;
1148 : }
1149 : }
1150 : }
1151 : else if (port->hba->krb_realm && strlen(port->hba->krb_realm))
1152 : {
1153 : elog(DEBUG2,
1154 : "GSSAPI did not return realm but realm matching was requested");
1155 : pfree(princ);
1156 : return STATUS_ERROR;
1157 : }
1158 :
1159 : ret = check_usermap(port->hba->usermap, port->user_name, princ,
1160 : pg_krb_caseins_users);
1161 :
1162 : pfree(princ);
1163 :
1164 : return ret;
1165 : }
1166 : #endif /* ENABLE_GSS */
1167 :
1168 :
1169 : /*----------------------------------------------------------------
1170 : * SSPI authentication system
1171 : *----------------------------------------------------------------
1172 : */
1173 : #ifdef ENABLE_SSPI
1174 :
1175 : /*
1176 : * Generate an error for SSPI authentication. The caller should apply
1177 : * _() to errmsg to make it translatable.
1178 : */
1179 : static void
1180 : pg_SSPI_error(int severity, const char *errmsg, SECURITY_STATUS r)
1181 : {
1182 : char sysmsg[256];
1183 :
1184 : if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS |
1185 : FORMAT_MESSAGE_FROM_SYSTEM,
1186 : NULL, r, 0,
1187 : sysmsg, sizeof(sysmsg), NULL) == 0)
1188 : ereport(severity,
1189 : (errmsg_internal("%s", errmsg),
1190 : errdetail_internal("SSPI error %x", (unsigned int) r)));
1191 : else
1192 : ereport(severity,
1193 : (errmsg_internal("%s", errmsg),
1194 : errdetail_internal("%s (%x)", sysmsg, (unsigned int) r)));
1195 : }
1196 :
1197 : static int
1198 : pg_SSPI_recvauth(Port *port)
1199 : {
1200 : int mtype;
1201 : StringInfoData buf;
1202 : SECURITY_STATUS r;
1203 : CredHandle sspicred;
1204 : CtxtHandle *sspictx = NULL,
1205 : newctx;
1206 : TimeStamp expiry;
1207 : ULONG contextattr;
1208 : SecBufferDesc inbuf;
1209 : SecBufferDesc outbuf;
1210 : SecBuffer OutBuffers[1];
1211 : SecBuffer InBuffers[1];
1212 : HANDLE token;
1213 : TOKEN_USER *tokenuser;
1214 : DWORD retlen;
1215 : char accountname[MAXPGPATH];
1216 : char domainname[MAXPGPATH];
1217 : DWORD accountnamesize = sizeof(accountname);
1218 : DWORD domainnamesize = sizeof(domainname);
1219 : SID_NAME_USE accountnameuse;
1220 : char *authn_id;
1221 :
1222 : /*
1223 : * Acquire a handle to the server credentials.
1224 : */
1225 : r = AcquireCredentialsHandle(NULL,
1226 : "negotiate",
1227 : SECPKG_CRED_INBOUND,
1228 : NULL,
1229 : NULL,
1230 : NULL,
1231 : NULL,
1232 : &sspicred,
1233 : &expiry);
1234 : if (r != SEC_E_OK)
1235 : pg_SSPI_error(ERROR, _("could not acquire SSPI credentials"), r);
1236 :
1237 : /*
1238 : * Loop through SSPI message exchange. This exchange can consist of
1239 : * multiple messages sent in both directions. First message is always from
1240 : * the client. All messages from client to server are password packets
1241 : * (type 'p').
1242 : */
1243 : do
1244 : {
1245 : pq_startmsgread();
1246 : mtype = pq_getbyte();
1247 : if (mtype != PqMsg_GSSResponse)
1248 : {
1249 : if (sspictx != NULL)
1250 : {
1251 : DeleteSecurityContext(sspictx);
1252 : free(sspictx);
1253 : }
1254 : FreeCredentialsHandle(&sspicred);
1255 :
1256 : /* Only log error if client didn't disconnect. */
1257 : if (mtype != EOF)
1258 : ereport(ERROR,
1259 : (errcode(ERRCODE_PROTOCOL_VIOLATION),
1260 : errmsg("expected SSPI response, got message type %d",
1261 : mtype)));
1262 : return STATUS_ERROR;
1263 : }
1264 :
1265 : /* Get the actual SSPI token */
1266 : initStringInfo(&buf);
1267 : if (pq_getmessage(&buf, PG_MAX_AUTH_TOKEN_LENGTH))
1268 : {
1269 : /* EOF - pq_getmessage already logged error */
1270 : pfree(buf.data);
1271 : if (sspictx != NULL)
1272 : {
1273 : DeleteSecurityContext(sspictx);
1274 : free(sspictx);
1275 : }
1276 : FreeCredentialsHandle(&sspicred);
1277 : return STATUS_ERROR;
1278 : }
1279 :
1280 : /* Map to SSPI style buffer */
1281 : inbuf.ulVersion = SECBUFFER_VERSION;
1282 : inbuf.cBuffers = 1;
1283 : inbuf.pBuffers = InBuffers;
1284 : InBuffers[0].pvBuffer = buf.data;
1285 : InBuffers[0].cbBuffer = buf.len;
1286 : InBuffers[0].BufferType = SECBUFFER_TOKEN;
1287 :
1288 : /* Prepare output buffer */
1289 : OutBuffers[0].pvBuffer = NULL;
1290 : OutBuffers[0].BufferType = SECBUFFER_TOKEN;
1291 : OutBuffers[0].cbBuffer = 0;
1292 : outbuf.cBuffers = 1;
1293 : outbuf.pBuffers = OutBuffers;
1294 : outbuf.ulVersion = SECBUFFER_VERSION;
1295 :
1296 : elog(DEBUG4, "processing received SSPI token of length %u",
1297 : (unsigned int) buf.len);
1298 :
1299 : r = AcceptSecurityContext(&sspicred,
1300 : sspictx,
1301 : &inbuf,
1302 : ASC_REQ_ALLOCATE_MEMORY,
1303 : SECURITY_NETWORK_DREP,
1304 : &newctx,
1305 : &outbuf,
1306 : &contextattr,
1307 : NULL);
1308 :
1309 : /* input buffer no longer used */
1310 : pfree(buf.data);
1311 :
1312 : if (outbuf.cBuffers > 0 && outbuf.pBuffers[0].cbBuffer > 0)
1313 : {
1314 : /*
1315 : * Negotiation generated data to be sent to the client.
1316 : */
1317 : elog(DEBUG4, "sending SSPI response token of length %u",
1318 : (unsigned int) outbuf.pBuffers[0].cbBuffer);
1319 :
1320 : port->gss->outbuf.length = outbuf.pBuffers[0].cbBuffer;
1321 : port->gss->outbuf.value = outbuf.pBuffers[0].pvBuffer;
1322 :
1323 : sendAuthRequest(port, AUTH_REQ_GSS_CONT,
1324 : port->gss->outbuf.value, port->gss->outbuf.length);
1325 :
1326 : FreeContextBuffer(outbuf.pBuffers[0].pvBuffer);
1327 : }
1328 :
1329 : if (r != SEC_E_OK && r != SEC_I_CONTINUE_NEEDED)
1330 : {
1331 : if (sspictx != NULL)
1332 : {
1333 : DeleteSecurityContext(sspictx);
1334 : free(sspictx);
1335 : }
1336 : FreeCredentialsHandle(&sspicred);
1337 : pg_SSPI_error(ERROR,
1338 : _("could not accept SSPI security context"), r);
1339 : }
1340 :
1341 : /*
1342 : * Overwrite the current context with the one we just received. If
1343 : * sspictx is NULL it was the first loop and we need to allocate a
1344 : * buffer for it. On subsequent runs, we can just overwrite the buffer
1345 : * contents since the size does not change.
1346 : */
1347 : if (sspictx == NULL)
1348 : {
1349 : sspictx = malloc(sizeof(CtxtHandle));
1350 : if (sspictx == NULL)
1351 : ereport(ERROR,
1352 : (errmsg("out of memory")));
1353 : }
1354 :
1355 : memcpy(sspictx, &newctx, sizeof(CtxtHandle));
1356 :
1357 : if (r == SEC_I_CONTINUE_NEEDED)
1358 : elog(DEBUG4, "SSPI continue needed");
1359 :
1360 : } while (r == SEC_I_CONTINUE_NEEDED);
1361 :
1362 :
1363 : /*
1364 : * Release service principal credentials
1365 : */
1366 : FreeCredentialsHandle(&sspicred);
1367 :
1368 :
1369 : /*
1370 : * SEC_E_OK indicates that authentication is now complete.
1371 : *
1372 : * Get the name of the user that authenticated, and compare it to the pg
1373 : * username that was specified for the connection.
1374 : */
1375 :
1376 : r = QuerySecurityContextToken(sspictx, &token);
1377 : if (r != SEC_E_OK)
1378 : pg_SSPI_error(ERROR,
1379 : _("could not get token from SSPI security context"), r);
1380 :
1381 : /*
1382 : * No longer need the security context, everything from here on uses the
1383 : * token instead.
1384 : */
1385 : DeleteSecurityContext(sspictx);
1386 : free(sspictx);
1387 :
1388 : if (!GetTokenInformation(token, TokenUser, NULL, 0, &retlen) && GetLastError() != 122)
1389 : ereport(ERROR,
1390 : (errmsg_internal("could not get token information buffer size: error code %lu",
1391 : GetLastError())));
1392 :
1393 : tokenuser = malloc(retlen);
1394 : if (tokenuser == NULL)
1395 : ereport(ERROR,
1396 : (errmsg("out of memory")));
1397 :
1398 : if (!GetTokenInformation(token, TokenUser, tokenuser, retlen, &retlen))
1399 : ereport(ERROR,
1400 : (errmsg_internal("could not get token information: error code %lu",
1401 : GetLastError())));
1402 :
1403 : CloseHandle(token);
1404 :
1405 : if (!LookupAccountSid(NULL, tokenuser->User.Sid, accountname, &accountnamesize,
1406 : domainname, &domainnamesize, &accountnameuse))
1407 : ereport(ERROR,
1408 : (errmsg_internal("could not look up account SID: error code %lu",
1409 : GetLastError())));
1410 :
1411 : free(tokenuser);
1412 :
1413 : if (!port->hba->compat_realm)
1414 : {
1415 : int status = pg_SSPI_make_upn(accountname, sizeof(accountname),
1416 : domainname, sizeof(domainname),
1417 : port->hba->upn_username);
1418 :
1419 : if (status != STATUS_OK)
1420 : /* Error already reported from pg_SSPI_make_upn */
1421 : return status;
1422 : }
1423 :
1424 : /*
1425 : * We have all of the information necessary to construct the authenticated
1426 : * identity. Set it now, rather than waiting for check_usermap below,
1427 : * because authentication has already succeeded and we want the log file
1428 : * to reflect that.
1429 : */
1430 : if (port->hba->compat_realm)
1431 : {
1432 : /* SAM-compatible format. */
1433 : authn_id = psprintf("%s\\%s", domainname, accountname);
1434 : }
1435 : else
1436 : {
1437 : /* Kerberos principal format. */
1438 : authn_id = psprintf("%s@%s", accountname, domainname);
1439 : }
1440 :
1441 : set_authn_id(port, authn_id);
1442 : pfree(authn_id);
1443 :
1444 : /*
1445 : * Compare realm/domain if requested. In SSPI, always compare case
1446 : * insensitive.
1447 : */
1448 : if (port->hba->krb_realm && strlen(port->hba->krb_realm))
1449 : {
1450 : if (pg_strcasecmp(port->hba->krb_realm, domainname) != 0)
1451 : {
1452 : elog(DEBUG2,
1453 : "SSPI domain (%s) and configured domain (%s) don't match",
1454 : domainname, port->hba->krb_realm);
1455 :
1456 : return STATUS_ERROR;
1457 : }
1458 : }
1459 :
1460 : /*
1461 : * We have the username (without domain/realm) in accountname, compare to
1462 : * the supplied value. In SSPI, always compare case insensitive.
1463 : *
1464 : * If set to include realm, append it in <username>@<realm> format.
1465 : */
1466 : if (port->hba->include_realm)
1467 : {
1468 : char *namebuf;
1469 : int retval;
1470 :
1471 : namebuf = psprintf("%s@%s", accountname, domainname);
1472 : retval = check_usermap(port->hba->usermap, port->user_name, namebuf, true);
1473 : pfree(namebuf);
1474 : return retval;
1475 : }
1476 : else
1477 : return check_usermap(port->hba->usermap, port->user_name, accountname, true);
1478 : }
1479 :
1480 : /*
1481 : * Replaces the domainname with the Kerberos realm name,
1482 : * and optionally the accountname with the Kerberos user name.
1483 : */
1484 : static int
1485 : pg_SSPI_make_upn(char *accountname,
1486 : size_t accountnamesize,
1487 : char *domainname,
1488 : size_t domainnamesize,
1489 : bool update_accountname)
1490 : {
1491 : char *samname;
1492 : char *upname = NULL;
1493 : char *p = NULL;
1494 : ULONG upnamesize = 0;
1495 : size_t upnamerealmsize;
1496 : BOOLEAN res;
1497 :
1498 : /*
1499 : * Build SAM name (DOMAIN\user), then translate to UPN
1500 : * (user@kerberos.realm). The realm name is returned in lower case, but
1501 : * that is fine because in SSPI auth, string comparisons are always
1502 : * case-insensitive.
1503 : */
1504 :
1505 : samname = psprintf("%s\\%s", domainname, accountname);
1506 : res = TranslateName(samname, NameSamCompatible, NameUserPrincipal,
1507 : NULL, &upnamesize);
1508 :
1509 : if ((!res && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1510 : || upnamesize == 0)
1511 : {
1512 : pfree(samname);
1513 : ereport(LOG,
1514 : (errcode(ERRCODE_INVALID_ROLE_SPECIFICATION),
1515 : errmsg("could not translate name")));
1516 : return STATUS_ERROR;
1517 : }
1518 :
1519 : /* upnamesize includes the terminating NUL. */
1520 : upname = palloc(upnamesize);
1521 :
1522 : res = TranslateName(samname, NameSamCompatible, NameUserPrincipal,
1523 : upname, &upnamesize);
1524 :
1525 : pfree(samname);
1526 : if (res)
1527 : p = strchr(upname, '@');
1528 :
1529 : if (!res || p == NULL)
1530 : {
1531 : pfree(upname);
1532 : ereport(LOG,
1533 : (errcode(ERRCODE_INVALID_ROLE_SPECIFICATION),
1534 : errmsg("could not translate name")));
1535 : return STATUS_ERROR;
1536 : }
1537 :
1538 : /* Length of realm name after the '@', including the NUL. */
1539 : upnamerealmsize = upnamesize - (p - upname + 1);
1540 :
1541 : /* Replace domainname with realm name. */
1542 : if (upnamerealmsize > domainnamesize)
1543 : {
1544 : pfree(upname);
1545 : ereport(LOG,
1546 : (errcode(ERRCODE_INVALID_ROLE_SPECIFICATION),
1547 : errmsg("realm name too long")));
1548 : return STATUS_ERROR;
1549 : }
1550 :
1551 : /* Length is now safe. */
1552 : strcpy(domainname, p + 1);
1553 :
1554 : /* Replace account name as well (in case UPN != SAM)? */
1555 : if (update_accountname)
1556 : {
1557 : if ((p - upname + 1) > accountnamesize)
1558 : {
1559 : pfree(upname);
1560 : ereport(LOG,
1561 : (errcode(ERRCODE_INVALID_ROLE_SPECIFICATION),
1562 : errmsg("translated account name too long")));
1563 : return STATUS_ERROR;
1564 : }
1565 :
1566 : *p = 0;
1567 : strcpy(accountname, upname);
1568 : }
1569 :
1570 : pfree(upname);
1571 : return STATUS_OK;
1572 : }
1573 : #endif /* ENABLE_SSPI */
1574 :
1575 :
1576 :
1577 : /*----------------------------------------------------------------
1578 : * Ident authentication system
1579 : *----------------------------------------------------------------
1580 : */
1581 :
1582 : /*
1583 : * Parse the string "*ident_response" as a response from a query to an Ident
1584 : * server. If it's a normal response indicating a user name, return true
1585 : * and store the user name at *ident_user. If it's anything else,
1586 : * return false.
1587 : */
1588 : static bool
1589 0 : interpret_ident_response(const char *ident_response,
1590 : char *ident_user)
1591 : {
1592 0 : const char *cursor = ident_response; /* Cursor into *ident_response */
1593 :
1594 : /*
1595 : * Ident's response, in the telnet tradition, should end in crlf (\r\n).
1596 : */
1597 0 : if (strlen(ident_response) < 2)
1598 0 : return false;
1599 0 : else if (ident_response[strlen(ident_response) - 2] != '\r')
1600 0 : return false;
1601 : else
1602 : {
1603 0 : while (*cursor != ':' && *cursor != '\r')
1604 0 : cursor++; /* skip port field */
1605 :
1606 0 : if (*cursor != ':')
1607 0 : return false;
1608 : else
1609 : {
1610 : /* We're positioned to colon before response type field */
1611 : char response_type[80];
1612 : int i; /* Index into *response_type */
1613 :
1614 0 : cursor++; /* Go over colon */
1615 0 : while (pg_isblank(*cursor))
1616 0 : cursor++; /* skip blanks */
1617 0 : i = 0;
1618 0 : while (*cursor != ':' && *cursor != '\r' && !pg_isblank(*cursor) &&
1619 : i < (int) (sizeof(response_type) - 1))
1620 0 : response_type[i++] = *cursor++;
1621 0 : response_type[i] = '\0';
1622 0 : while (pg_isblank(*cursor))
1623 0 : cursor++; /* skip blanks */
1624 0 : if (strcmp(response_type, "USERID") != 0)
1625 0 : return false;
1626 : else
1627 : {
1628 : /*
1629 : * It's a USERID response. Good. "cursor" should be pointing
1630 : * to the colon that precedes the operating system type.
1631 : */
1632 0 : if (*cursor != ':')
1633 0 : return false;
1634 : else
1635 : {
1636 0 : cursor++; /* Go over colon */
1637 : /* Skip over operating system field. */
1638 0 : while (*cursor != ':' && *cursor != '\r')
1639 0 : cursor++;
1640 0 : if (*cursor != ':')
1641 0 : return false;
1642 : else
1643 : {
1644 0 : cursor++; /* Go over colon */
1645 0 : while (pg_isblank(*cursor))
1646 0 : cursor++; /* skip blanks */
1647 : /* Rest of line is user name. Copy it over. */
1648 0 : i = 0;
1649 0 : while (*cursor != '\r' && i < IDENT_USERNAME_MAX)
1650 0 : ident_user[i++] = *cursor++;
1651 0 : ident_user[i] = '\0';
1652 0 : return true;
1653 : }
1654 : }
1655 : }
1656 : }
1657 : }
1658 : }
1659 :
1660 :
1661 : /*
1662 : * Talk to the ident server on "remote_addr" and find out who
1663 : * owns the tcp connection to "local_addr"
1664 : * If the username is successfully retrieved, check the usermap.
1665 : *
1666 : * XXX: Using WaitLatchOrSocket() and doing a CHECK_FOR_INTERRUPTS() if the
1667 : * latch was set would improve the responsiveness to timeouts/cancellations.
1668 : */
1669 : static int
1670 0 : ident_inet(hbaPort *port)
1671 : {
1672 0 : const SockAddr remote_addr = port->raddr;
1673 0 : const SockAddr local_addr = port->laddr;
1674 : char ident_user[IDENT_USERNAME_MAX + 1];
1675 0 : pgsocket sock_fd = PGINVALID_SOCKET; /* for talking to Ident server */
1676 : int rc; /* Return code from a locally called function */
1677 : bool ident_return;
1678 : char remote_addr_s[NI_MAXHOST];
1679 : char remote_port[NI_MAXSERV];
1680 : char local_addr_s[NI_MAXHOST];
1681 : char local_port[NI_MAXSERV];
1682 : char ident_port[NI_MAXSERV];
1683 : char ident_query[80];
1684 : char ident_response[80 + IDENT_USERNAME_MAX];
1685 0 : struct addrinfo *ident_serv = NULL,
1686 0 : *la = NULL,
1687 : hints;
1688 :
1689 : /*
1690 : * Might look a little weird to first convert it to text and then back to
1691 : * sockaddr, but it's protocol independent.
1692 : */
1693 0 : pg_getnameinfo_all(&remote_addr.addr, remote_addr.salen,
1694 : remote_addr_s, sizeof(remote_addr_s),
1695 : remote_port, sizeof(remote_port),
1696 : NI_NUMERICHOST | NI_NUMERICSERV);
1697 0 : pg_getnameinfo_all(&local_addr.addr, local_addr.salen,
1698 : local_addr_s, sizeof(local_addr_s),
1699 : local_port, sizeof(local_port),
1700 : NI_NUMERICHOST | NI_NUMERICSERV);
1701 :
1702 0 : snprintf(ident_port, sizeof(ident_port), "%d", IDENT_PORT);
1703 0 : hints.ai_flags = AI_NUMERICHOST;
1704 0 : hints.ai_family = remote_addr.addr.ss_family;
1705 0 : hints.ai_socktype = SOCK_STREAM;
1706 0 : hints.ai_protocol = 0;
1707 0 : hints.ai_addrlen = 0;
1708 0 : hints.ai_canonname = NULL;
1709 0 : hints.ai_addr = NULL;
1710 0 : hints.ai_next = NULL;
1711 0 : rc = pg_getaddrinfo_all(remote_addr_s, ident_port, &hints, &ident_serv);
1712 0 : if (rc || !ident_serv)
1713 : {
1714 : /* we don't expect this to happen */
1715 0 : ident_return = false;
1716 0 : goto ident_inet_done;
1717 : }
1718 :
1719 0 : hints.ai_flags = AI_NUMERICHOST;
1720 0 : hints.ai_family = local_addr.addr.ss_family;
1721 0 : hints.ai_socktype = SOCK_STREAM;
1722 0 : hints.ai_protocol = 0;
1723 0 : hints.ai_addrlen = 0;
1724 0 : hints.ai_canonname = NULL;
1725 0 : hints.ai_addr = NULL;
1726 0 : hints.ai_next = NULL;
1727 0 : rc = pg_getaddrinfo_all(local_addr_s, NULL, &hints, &la);
1728 0 : if (rc || !la)
1729 : {
1730 : /* we don't expect this to happen */
1731 0 : ident_return = false;
1732 0 : goto ident_inet_done;
1733 : }
1734 :
1735 0 : sock_fd = socket(ident_serv->ai_family, ident_serv->ai_socktype,
1736 0 : ident_serv->ai_protocol);
1737 0 : if (sock_fd == PGINVALID_SOCKET)
1738 : {
1739 0 : ereport(LOG,
1740 : (errcode_for_socket_access(),
1741 : errmsg("could not create socket for Ident connection: %m")));
1742 0 : ident_return = false;
1743 0 : goto ident_inet_done;
1744 : }
1745 :
1746 : /*
1747 : * Bind to the address which the client originally contacted, otherwise
1748 : * the ident server won't be able to match up the right connection. This
1749 : * is necessary if the PostgreSQL server is running on an IP alias.
1750 : */
1751 0 : rc = bind(sock_fd, la->ai_addr, la->ai_addrlen);
1752 0 : if (rc != 0)
1753 : {
1754 0 : ereport(LOG,
1755 : (errcode_for_socket_access(),
1756 : errmsg("could not bind to local address \"%s\": %m",
1757 : local_addr_s)));
1758 0 : ident_return = false;
1759 0 : goto ident_inet_done;
1760 : }
1761 :
1762 0 : rc = connect(sock_fd, ident_serv->ai_addr,
1763 0 : ident_serv->ai_addrlen);
1764 0 : if (rc != 0)
1765 : {
1766 0 : ereport(LOG,
1767 : (errcode_for_socket_access(),
1768 : errmsg("could not connect to Ident server at address \"%s\", port %s: %m",
1769 : remote_addr_s, ident_port)));
1770 0 : ident_return = false;
1771 0 : goto ident_inet_done;
1772 : }
1773 :
1774 : /* The query we send to the Ident server */
1775 0 : snprintf(ident_query, sizeof(ident_query), "%s,%s\r\n",
1776 : remote_port, local_port);
1777 :
1778 : /* loop in case send is interrupted */
1779 : do
1780 : {
1781 0 : CHECK_FOR_INTERRUPTS();
1782 :
1783 0 : rc = send(sock_fd, ident_query, strlen(ident_query), 0);
1784 0 : } while (rc < 0 && errno == EINTR);
1785 :
1786 0 : if (rc < 0)
1787 : {
1788 0 : ereport(LOG,
1789 : (errcode_for_socket_access(),
1790 : errmsg("could not send query to Ident server at address \"%s\", port %s: %m",
1791 : remote_addr_s, ident_port)));
1792 0 : ident_return = false;
1793 0 : goto ident_inet_done;
1794 : }
1795 :
1796 : do
1797 : {
1798 0 : CHECK_FOR_INTERRUPTS();
1799 :
1800 0 : rc = recv(sock_fd, ident_response, sizeof(ident_response) - 1, 0);
1801 0 : } while (rc < 0 && errno == EINTR);
1802 :
1803 0 : if (rc < 0)
1804 : {
1805 0 : ereport(LOG,
1806 : (errcode_for_socket_access(),
1807 : errmsg("could not receive response from Ident server at address \"%s\", port %s: %m",
1808 : remote_addr_s, ident_port)));
1809 0 : ident_return = false;
1810 0 : goto ident_inet_done;
1811 : }
1812 :
1813 0 : ident_response[rc] = '\0';
1814 0 : ident_return = interpret_ident_response(ident_response, ident_user);
1815 0 : if (!ident_return)
1816 0 : ereport(LOG,
1817 : (errmsg("invalidly formatted response from Ident server: \"%s\"",
1818 : ident_response)));
1819 :
1820 0 : ident_inet_done:
1821 0 : if (sock_fd != PGINVALID_SOCKET)
1822 0 : closesocket(sock_fd);
1823 0 : if (ident_serv)
1824 0 : pg_freeaddrinfo_all(remote_addr.addr.ss_family, ident_serv);
1825 0 : if (la)
1826 0 : pg_freeaddrinfo_all(local_addr.addr.ss_family, la);
1827 :
1828 0 : if (ident_return)
1829 : {
1830 : /*
1831 : * Success! Store the identity, then check the usermap. Note that
1832 : * setting the authenticated identity is done before checking the
1833 : * usermap, because at this point authentication has succeeded.
1834 : */
1835 0 : set_authn_id(port, ident_user);
1836 0 : return check_usermap(port->hba->usermap, port->user_name, ident_user, false);
1837 : }
1838 0 : return STATUS_ERROR;
1839 : }
1840 :
1841 :
1842 : /*----------------------------------------------------------------
1843 : * Peer authentication system
1844 : *----------------------------------------------------------------
1845 : */
1846 :
1847 : /*
1848 : * Ask kernel about the credentials of the connecting process,
1849 : * determine the symbolic name of the corresponding user, and check
1850 : * if valid per the usermap.
1851 : *
1852 : * Iff authorized, return STATUS_OK, otherwise return STATUS_ERROR.
1853 : */
1854 : static int
1855 54 : auth_peer(hbaPort *port)
1856 : {
1857 : uid_t uid;
1858 : gid_t gid;
1859 : #ifndef WIN32
1860 : struct passwd pwbuf;
1861 : struct passwd *pw;
1862 : char buf[1024];
1863 : int rc;
1864 : int ret;
1865 : #endif
1866 :
1867 54 : if (getpeereid(port->sock, &uid, &gid) != 0)
1868 : {
1869 : /* Provide special error message if getpeereid is a stub */
1870 0 : if (errno == ENOSYS)
1871 0 : ereport(LOG,
1872 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1873 : errmsg("peer authentication is not supported on this platform")));
1874 : else
1875 0 : ereport(LOG,
1876 : (errcode_for_socket_access(),
1877 : errmsg("could not get peer credentials: %m")));
1878 0 : return STATUS_ERROR;
1879 : }
1880 :
1881 : #ifndef WIN32
1882 54 : rc = getpwuid_r(uid, &pwbuf, buf, sizeof buf, &pw);
1883 54 : if (rc != 0)
1884 : {
1885 0 : errno = rc;
1886 0 : ereport(LOG,
1887 : errmsg("could not look up local user ID %ld: %m", (long) uid));
1888 0 : return STATUS_ERROR;
1889 : }
1890 54 : else if (!pw)
1891 : {
1892 0 : ereport(LOG,
1893 : errmsg("local user with ID %ld does not exist", (long) uid));
1894 0 : return STATUS_ERROR;
1895 : }
1896 :
1897 : /*
1898 : * Make a copy of static getpw*() result area; this is our authenticated
1899 : * identity. Set it before calling check_usermap, because authentication
1900 : * has already succeeded and we want the log file to reflect that.
1901 : */
1902 54 : set_authn_id(port, pw->pw_name);
1903 :
1904 54 : ret = check_usermap(port->hba->usermap, port->user_name,
1905 : MyClientConnectionInfo.authn_id, false);
1906 :
1907 54 : return ret;
1908 : #else
1909 : /* should have failed with ENOSYS above */
1910 : Assert(false);
1911 : return STATUS_ERROR;
1912 : #endif
1913 : }
1914 :
1915 :
1916 : /*----------------------------------------------------------------
1917 : * PAM authentication system
1918 : *----------------------------------------------------------------
1919 : */
1920 : #ifdef USE_PAM
1921 :
1922 : /*
1923 : * PAM conversation function
1924 : */
1925 :
1926 : static int
1927 0 : pam_passwd_conv_proc(int num_msg, const struct pam_message **msg,
1928 : struct pam_response **resp, void *appdata_ptr)
1929 : {
1930 : const char *passwd;
1931 : struct pam_response *reply;
1932 : int i;
1933 :
1934 0 : if (appdata_ptr)
1935 0 : passwd = (char *) appdata_ptr;
1936 : else
1937 : {
1938 : /*
1939 : * Workaround for Solaris 2.6 where the PAM library is broken and does
1940 : * not pass appdata_ptr to the conversation routine
1941 : */
1942 0 : passwd = pam_passwd;
1943 : }
1944 :
1945 0 : *resp = NULL; /* in case of error exit */
1946 :
1947 0 : if (num_msg <= 0 || num_msg > PAM_MAX_NUM_MSG)
1948 0 : return PAM_CONV_ERR;
1949 :
1950 : /*
1951 : * Explicitly not using palloc here - PAM will free this memory in
1952 : * pam_end()
1953 : */
1954 0 : if ((reply = calloc(num_msg, sizeof(struct pam_response))) == NULL)
1955 : {
1956 0 : ereport(LOG,
1957 : (errcode(ERRCODE_OUT_OF_MEMORY),
1958 : errmsg("out of memory")));
1959 0 : return PAM_CONV_ERR;
1960 : }
1961 :
1962 0 : for (i = 0; i < num_msg; i++)
1963 : {
1964 0 : switch (msg[i]->msg_style)
1965 : {
1966 0 : case PAM_PROMPT_ECHO_OFF:
1967 0 : if (strlen(passwd) == 0)
1968 : {
1969 : /*
1970 : * Password wasn't passed to PAM the first time around -
1971 : * let's go ask the client to send a password, which we
1972 : * then stuff into PAM.
1973 : */
1974 0 : sendAuthRequest(pam_port_cludge, AUTH_REQ_PASSWORD, NULL, 0);
1975 0 : passwd = recv_password_packet(pam_port_cludge);
1976 0 : if (passwd == NULL)
1977 : {
1978 : /*
1979 : * Client didn't want to send password. We
1980 : * intentionally do not log anything about this,
1981 : * either here or at higher levels.
1982 : */
1983 0 : pam_no_password = true;
1984 0 : goto fail;
1985 : }
1986 : }
1987 0 : if ((reply[i].resp = strdup(passwd)) == NULL)
1988 0 : goto fail;
1989 0 : reply[i].resp_retcode = PAM_SUCCESS;
1990 0 : break;
1991 0 : case PAM_ERROR_MSG:
1992 0 : ereport(LOG,
1993 : (errmsg("error from underlying PAM layer: %s",
1994 : msg[i]->msg)));
1995 : /* FALL THROUGH */
1996 : case PAM_TEXT_INFO:
1997 : /* we don't bother to log TEXT_INFO messages */
1998 0 : if ((reply[i].resp = strdup("")) == NULL)
1999 0 : goto fail;
2000 0 : reply[i].resp_retcode = PAM_SUCCESS;
2001 0 : break;
2002 0 : default:
2003 0 : ereport(LOG,
2004 : (errmsg("unsupported PAM conversation %d/\"%s\"",
2005 : msg[i]->msg_style,
2006 : msg[i]->msg ? msg[i]->msg : "(none)")));
2007 0 : goto fail;
2008 : }
2009 : }
2010 :
2011 0 : *resp = reply;
2012 0 : return PAM_SUCCESS;
2013 :
2014 0 : fail:
2015 : /* free up whatever we allocated */
2016 0 : for (i = 0; i < num_msg; i++)
2017 0 : free(reply[i].resp);
2018 0 : free(reply);
2019 :
2020 0 : return PAM_CONV_ERR;
2021 : }
2022 :
2023 :
2024 : /*
2025 : * Check authentication against PAM.
2026 : */
2027 : static int
2028 0 : CheckPAMAuth(Port *port, const char *user, const char *password)
2029 : {
2030 : int retval;
2031 0 : pam_handle_t *pamh = NULL;
2032 :
2033 : /*
2034 : * We can't entirely rely on PAM to pass through appdata --- it appears
2035 : * not to work on at least Solaris 2.6. So use these ugly static
2036 : * variables instead.
2037 : */
2038 0 : pam_passwd = password;
2039 0 : pam_port_cludge = port;
2040 0 : pam_no_password = false;
2041 :
2042 : /*
2043 : * Set the application data portion of the conversation struct. This is
2044 : * later used inside the PAM conversation to pass the password to the
2045 : * authentication module.
2046 : */
2047 0 : pam_passw_conv.appdata_ptr = unconstify(char *, password); /* from password above,
2048 : * not allocated */
2049 :
2050 : /* Optionally, one can set the service name in pg_hba.conf */
2051 0 : if (port->hba->pamservice && port->hba->pamservice[0] != '\0')
2052 0 : retval = pam_start(port->hba->pamservice, "pgsql@",
2053 : &pam_passw_conv, &pamh);
2054 : else
2055 0 : retval = pam_start(PGSQL_PAM_SERVICE, "pgsql@",
2056 : &pam_passw_conv, &pamh);
2057 :
2058 0 : if (retval != PAM_SUCCESS)
2059 : {
2060 0 : ereport(LOG,
2061 : (errmsg("could not create PAM authenticator: %s",
2062 : pam_strerror(pamh, retval))));
2063 0 : pam_passwd = NULL; /* Unset pam_passwd */
2064 0 : return STATUS_ERROR;
2065 : }
2066 :
2067 0 : retval = pam_set_item(pamh, PAM_USER, user);
2068 :
2069 0 : if (retval != PAM_SUCCESS)
2070 : {
2071 0 : ereport(LOG,
2072 : (errmsg("pam_set_item(PAM_USER) failed: %s",
2073 : pam_strerror(pamh, retval))));
2074 0 : pam_passwd = NULL; /* Unset pam_passwd */
2075 0 : return STATUS_ERROR;
2076 : }
2077 :
2078 0 : if (port->hba->conntype != ctLocal)
2079 : {
2080 : char hostinfo[NI_MAXHOST];
2081 : int flags;
2082 :
2083 0 : if (port->hba->pam_use_hostname)
2084 0 : flags = 0;
2085 : else
2086 0 : flags = NI_NUMERICHOST | NI_NUMERICSERV;
2087 :
2088 0 : retval = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
2089 : hostinfo, sizeof(hostinfo), NULL, 0,
2090 : flags);
2091 0 : if (retval != 0)
2092 : {
2093 0 : ereport(WARNING,
2094 : (errmsg_internal("pg_getnameinfo_all() failed: %s",
2095 : gai_strerror(retval))));
2096 0 : return STATUS_ERROR;
2097 : }
2098 :
2099 0 : retval = pam_set_item(pamh, PAM_RHOST, hostinfo);
2100 :
2101 0 : if (retval != PAM_SUCCESS)
2102 : {
2103 0 : ereport(LOG,
2104 : (errmsg("pam_set_item(PAM_RHOST) failed: %s",
2105 : pam_strerror(pamh, retval))));
2106 0 : pam_passwd = NULL;
2107 0 : return STATUS_ERROR;
2108 : }
2109 : }
2110 :
2111 0 : retval = pam_set_item(pamh, PAM_CONV, &pam_passw_conv);
2112 :
2113 0 : if (retval != PAM_SUCCESS)
2114 : {
2115 0 : ereport(LOG,
2116 : (errmsg("pam_set_item(PAM_CONV) failed: %s",
2117 : pam_strerror(pamh, retval))));
2118 0 : pam_passwd = NULL; /* Unset pam_passwd */
2119 0 : return STATUS_ERROR;
2120 : }
2121 :
2122 0 : retval = pam_authenticate(pamh, 0);
2123 :
2124 0 : if (retval != PAM_SUCCESS)
2125 : {
2126 : /* If pam_passwd_conv_proc saw EOF, don't log anything */
2127 0 : if (!pam_no_password)
2128 0 : ereport(LOG,
2129 : (errmsg("pam_authenticate failed: %s",
2130 : pam_strerror(pamh, retval))));
2131 0 : pam_passwd = NULL; /* Unset pam_passwd */
2132 0 : return pam_no_password ? STATUS_EOF : STATUS_ERROR;
2133 : }
2134 :
2135 0 : retval = pam_acct_mgmt(pamh, 0);
2136 :
2137 0 : if (retval != PAM_SUCCESS)
2138 : {
2139 : /* If pam_passwd_conv_proc saw EOF, don't log anything */
2140 0 : if (!pam_no_password)
2141 0 : ereport(LOG,
2142 : (errmsg("pam_acct_mgmt failed: %s",
2143 : pam_strerror(pamh, retval))));
2144 0 : pam_passwd = NULL; /* Unset pam_passwd */
2145 0 : return pam_no_password ? STATUS_EOF : STATUS_ERROR;
2146 : }
2147 :
2148 0 : retval = pam_end(pamh, retval);
2149 :
2150 0 : if (retval != PAM_SUCCESS)
2151 : {
2152 0 : ereport(LOG,
2153 : (errmsg("could not release PAM authenticator: %s",
2154 : pam_strerror(pamh, retval))));
2155 : }
2156 :
2157 0 : pam_passwd = NULL; /* Unset pam_passwd */
2158 :
2159 0 : if (retval == PAM_SUCCESS)
2160 0 : set_authn_id(port, user);
2161 :
2162 0 : return (retval == PAM_SUCCESS ? STATUS_OK : STATUS_ERROR);
2163 : }
2164 : #endif /* USE_PAM */
2165 :
2166 :
2167 : /*----------------------------------------------------------------
2168 : * BSD authentication system
2169 : *----------------------------------------------------------------
2170 : */
2171 : #ifdef USE_BSD_AUTH
2172 : static int
2173 : CheckBSDAuth(Port *port, char *user)
2174 : {
2175 : char *passwd;
2176 : int retval;
2177 :
2178 : /* Send regular password request to client, and get the response */
2179 : sendAuthRequest(port, AUTH_REQ_PASSWORD, NULL, 0);
2180 :
2181 : passwd = recv_password_packet(port);
2182 : if (passwd == NULL)
2183 : return STATUS_EOF;
2184 :
2185 : /*
2186 : * Ask the BSD auth system to verify password. Note that auth_userokay
2187 : * will overwrite the password string with zeroes, but it's just a
2188 : * temporary string so we don't care.
2189 : */
2190 : retval = auth_userokay(user, NULL, "auth-postgresql", passwd);
2191 :
2192 : pfree(passwd);
2193 :
2194 : if (!retval)
2195 : return STATUS_ERROR;
2196 :
2197 : set_authn_id(port, user);
2198 : return STATUS_OK;
2199 : }
2200 : #endif /* USE_BSD_AUTH */
2201 :
2202 :
2203 : /*----------------------------------------------------------------
2204 : * LDAP authentication system
2205 : *----------------------------------------------------------------
2206 : */
2207 : #ifdef USE_LDAP
2208 :
2209 : static int errdetail_for_ldap(LDAP *ldap);
2210 :
2211 : /*
2212 : * Initialize a connection to the LDAP server, including setting up
2213 : * TLS if requested.
2214 : */
2215 : static int
2216 58 : InitializeLDAPConnection(Port *port, LDAP **ldap)
2217 : {
2218 : const char *scheme;
2219 58 : int ldapversion = LDAP_VERSION3;
2220 : int r;
2221 :
2222 58 : scheme = port->hba->ldapscheme;
2223 58 : if (scheme == NULL)
2224 36 : scheme = "ldap";
2225 : #ifdef WIN32
2226 : if (strcmp(scheme, "ldaps") == 0)
2227 : *ldap = ldap_sslinit(port->hba->ldapserver, port->hba->ldapport, 1);
2228 : else
2229 : *ldap = ldap_init(port->hba->ldapserver, port->hba->ldapport);
2230 : if (!*ldap)
2231 : {
2232 : ereport(LOG,
2233 : (errmsg("could not initialize LDAP: error code %d",
2234 : (int) LdapGetLastError())));
2235 :
2236 : return STATUS_ERROR;
2237 : }
2238 : #else
2239 : #ifdef HAVE_LDAP_INITIALIZE
2240 :
2241 : /*
2242 : * OpenLDAP provides a non-standard extension ldap_initialize() that takes
2243 : * a list of URIs, allowing us to request "ldaps" instead of "ldap". It
2244 : * also provides ldap_domain2hostlist() to find LDAP servers automatically
2245 : * using DNS SRV. They were introduced in the same version, so for now we
2246 : * don't have an extra configure check for the latter.
2247 : */
2248 : {
2249 : StringInfoData uris;
2250 58 : char *hostlist = NULL;
2251 : char *p;
2252 : bool append_port;
2253 :
2254 : /* We'll build a space-separated scheme://hostname:port list here */
2255 58 : initStringInfo(&uris);
2256 :
2257 : /*
2258 : * If pg_hba.conf provided no hostnames, we can ask OpenLDAP to try to
2259 : * find some by extracting a domain name from the base DN and looking
2260 : * up DSN SRV records for _ldap._tcp.<domain>.
2261 : */
2262 58 : if (!port->hba->ldapserver || port->hba->ldapserver[0] == '\0')
2263 0 : {
2264 : char *domain;
2265 :
2266 : /* ou=blah,dc=foo,dc=bar -> foo.bar */
2267 0 : if (ldap_dn2domain(port->hba->ldapbasedn, &domain))
2268 : {
2269 0 : ereport(LOG,
2270 : (errmsg("could not extract domain name from ldapbasedn")));
2271 0 : return STATUS_ERROR;
2272 : }
2273 :
2274 : /* Look up a list of LDAP server hosts and port numbers */
2275 0 : if (ldap_domain2hostlist(domain, &hostlist))
2276 : {
2277 0 : ereport(LOG,
2278 : (errmsg("LDAP authentication could not find DNS SRV records for \"%s\"",
2279 : domain),
2280 : (errhint("Set an LDAP server name explicitly."))));
2281 0 : ldap_memfree(domain);
2282 0 : return STATUS_ERROR;
2283 : }
2284 0 : ldap_memfree(domain);
2285 :
2286 : /* We have a space-separated list of host:port entries */
2287 0 : p = hostlist;
2288 0 : append_port = false;
2289 : }
2290 : else
2291 : {
2292 : /* We have a space-separated list of hosts from pg_hba.conf */
2293 58 : p = port->hba->ldapserver;
2294 58 : append_port = true;
2295 : }
2296 :
2297 : /* Convert the list of host[:port] entries to full URIs */
2298 : do
2299 : {
2300 : size_t size;
2301 :
2302 : /* Find the span of the next entry */
2303 64 : size = strcspn(p, " ");
2304 :
2305 : /* Append a space separator if this isn't the first URI */
2306 64 : if (uris.len > 0)
2307 6 : appendStringInfoChar(&uris, ' ');
2308 :
2309 : /* Append scheme://host:port */
2310 64 : appendStringInfoString(&uris, scheme);
2311 64 : appendStringInfoString(&uris, "://");
2312 64 : appendBinaryStringInfo(&uris, p, size);
2313 64 : if (append_port)
2314 64 : appendStringInfo(&uris, ":%d", port->hba->ldapport);
2315 :
2316 : /* Step over this entry and any number of trailing spaces */
2317 64 : p += size;
2318 70 : while (*p == ' ')
2319 6 : ++p;
2320 64 : } while (*p);
2321 :
2322 : /* Free memory from OpenLDAP if we looked up SRV records */
2323 58 : if (hostlist)
2324 0 : ldap_memfree(hostlist);
2325 :
2326 : /* Finally, try to connect using the URI list */
2327 58 : r = ldap_initialize(ldap, uris.data);
2328 58 : pfree(uris.data);
2329 58 : if (r != LDAP_SUCCESS)
2330 : {
2331 0 : ereport(LOG,
2332 : (errmsg("could not initialize LDAP: %s",
2333 : ldap_err2string(r))));
2334 :
2335 0 : return STATUS_ERROR;
2336 : }
2337 : }
2338 : #else
2339 : if (strcmp(scheme, "ldaps") == 0)
2340 : {
2341 : ereport(LOG,
2342 : (errmsg("ldaps not supported with this LDAP library")));
2343 :
2344 : return STATUS_ERROR;
2345 : }
2346 : *ldap = ldap_init(port->hba->ldapserver, port->hba->ldapport);
2347 : if (!*ldap)
2348 : {
2349 : ereport(LOG,
2350 : (errmsg("could not initialize LDAP: %m")));
2351 :
2352 : return STATUS_ERROR;
2353 : }
2354 : #endif
2355 : #endif
2356 :
2357 58 : if ((r = ldap_set_option(*ldap, LDAP_OPT_PROTOCOL_VERSION, &ldapversion)) != LDAP_SUCCESS)
2358 : {
2359 0 : ereport(LOG,
2360 : (errmsg("could not set LDAP protocol version: %s",
2361 : ldap_err2string(r)),
2362 : errdetail_for_ldap(*ldap)));
2363 0 : ldap_unbind(*ldap);
2364 0 : return STATUS_ERROR;
2365 : }
2366 :
2367 58 : if (port->hba->ldaptls)
2368 : {
2369 : #ifndef WIN32
2370 2 : if ((r = ldap_start_tls_s(*ldap, NULL, NULL)) != LDAP_SUCCESS)
2371 : #else
2372 : if ((r = ldap_start_tls_s(*ldap, NULL, NULL, NULL, NULL)) != LDAP_SUCCESS)
2373 : #endif
2374 : {
2375 0 : ereport(LOG,
2376 : (errmsg("could not start LDAP TLS session: %s",
2377 : ldap_err2string(r)),
2378 : errdetail_for_ldap(*ldap)));
2379 0 : ldap_unbind(*ldap);
2380 0 : return STATUS_ERROR;
2381 : }
2382 : }
2383 :
2384 58 : return STATUS_OK;
2385 : }
2386 :
2387 : /* Placeholders recognized by FormatSearchFilter. For now just one. */
2388 : #define LPH_USERNAME "$username"
2389 : #define LPH_USERNAME_LEN (sizeof(LPH_USERNAME) - 1)
2390 :
2391 : /* Not all LDAP implementations define this. */
2392 : #ifndef LDAP_NO_ATTRS
2393 : #define LDAP_NO_ATTRS "1.1"
2394 : #endif
2395 :
2396 : /* Not all LDAP implementations define this. */
2397 : #ifndef LDAPS_PORT
2398 : #define LDAPS_PORT 636
2399 : #endif
2400 :
2401 : static char *
2402 0 : dummy_ldap_password_mutator(char *input)
2403 : {
2404 0 : return input;
2405 : }
2406 :
2407 : /*
2408 : * Return a newly allocated C string copied from "pattern" with all
2409 : * occurrences of the placeholder "$username" replaced with "user_name".
2410 : */
2411 : static char *
2412 16 : FormatSearchFilter(const char *pattern, const char *user_name)
2413 : {
2414 : StringInfoData output;
2415 :
2416 16 : initStringInfo(&output);
2417 238 : while (*pattern != '\0')
2418 : {
2419 222 : if (strncmp(pattern, LPH_USERNAME, LPH_USERNAME_LEN) == 0)
2420 : {
2421 26 : appendStringInfoString(&output, user_name);
2422 26 : pattern += LPH_USERNAME_LEN;
2423 : }
2424 : else
2425 196 : appendStringInfoChar(&output, *pattern++);
2426 : }
2427 :
2428 16 : return output.data;
2429 : }
2430 :
2431 : /*
2432 : * Perform LDAP authentication
2433 : */
2434 : static int
2435 60 : CheckLDAPAuth(Port *port)
2436 : {
2437 : char *passwd;
2438 : LDAP *ldap;
2439 : int r;
2440 : char *fulluser;
2441 : const char *server_name;
2442 :
2443 : #ifdef HAVE_LDAP_INITIALIZE
2444 :
2445 : /*
2446 : * For OpenLDAP, allow empty hostname if we have a basedn. We'll look for
2447 : * servers with DNS SRV records via OpenLDAP library facilities.
2448 : */
2449 60 : if ((!port->hba->ldapserver || port->hba->ldapserver[0] == '\0') &&
2450 0 : (!port->hba->ldapbasedn || port->hba->ldapbasedn[0] == '\0'))
2451 : {
2452 0 : ereport(LOG,
2453 : (errmsg("LDAP server not specified, and no ldapbasedn")));
2454 0 : return STATUS_ERROR;
2455 : }
2456 : #else
2457 : if (!port->hba->ldapserver || port->hba->ldapserver[0] == '\0')
2458 : {
2459 : ereport(LOG,
2460 : (errmsg("LDAP server not specified")));
2461 : return STATUS_ERROR;
2462 : }
2463 : #endif
2464 :
2465 : /*
2466 : * If we're using SRV records, we don't have a server name so we'll just
2467 : * show an empty string in error messages.
2468 : */
2469 60 : server_name = port->hba->ldapserver ? port->hba->ldapserver : "";
2470 :
2471 60 : if (port->hba->ldapport == 0)
2472 : {
2473 0 : if (port->hba->ldapscheme != NULL &&
2474 0 : strcmp(port->hba->ldapscheme, "ldaps") == 0)
2475 0 : port->hba->ldapport = LDAPS_PORT;
2476 : else
2477 0 : port->hba->ldapport = LDAP_PORT;
2478 : }
2479 :
2480 60 : sendAuthRequest(port, AUTH_REQ_PASSWORD, NULL, 0);
2481 :
2482 60 : passwd = recv_password_packet(port);
2483 60 : if (passwd == NULL)
2484 2 : return STATUS_EOF; /* client wouldn't send password */
2485 :
2486 58 : if (InitializeLDAPConnection(port, &ldap) == STATUS_ERROR)
2487 : {
2488 : /* Error message already sent */
2489 0 : pfree(passwd);
2490 0 : return STATUS_ERROR;
2491 : }
2492 :
2493 58 : if (port->hba->ldapbasedn)
2494 : {
2495 : /*
2496 : * First perform an LDAP search to find the DN for the user we are
2497 : * trying to log in as.
2498 : */
2499 : char *filter;
2500 : LDAPMessage *search_message;
2501 : LDAPMessage *entry;
2502 42 : char *attributes[] = {LDAP_NO_ATTRS, NULL};
2503 : char *dn;
2504 : char *c;
2505 : int count;
2506 :
2507 : /*
2508 : * Disallow any characters that we would otherwise need to escape,
2509 : * since they aren't really reasonable in a username anyway. Allowing
2510 : * them would make it possible to inject any kind of custom filters in
2511 : * the LDAP filter.
2512 : */
2513 300 : for (c = port->user_name; *c; c++)
2514 : {
2515 258 : if (*c == '*' ||
2516 258 : *c == '(' ||
2517 258 : *c == ')' ||
2518 258 : *c == '\\' ||
2519 258 : *c == '/')
2520 : {
2521 0 : ereport(LOG,
2522 : (errmsg("invalid character in user name for LDAP authentication")));
2523 0 : ldap_unbind(ldap);
2524 0 : pfree(passwd);
2525 12 : return STATUS_ERROR;
2526 : }
2527 : }
2528 :
2529 : /*
2530 : * Bind with a pre-defined username/password (if available) for
2531 : * searching. If none is specified, this turns into an anonymous bind.
2532 : */
2533 78 : r = ldap_simple_bind_s(ldap,
2534 42 : port->hba->ldapbinddn ? port->hba->ldapbinddn : "",
2535 42 : port->hba->ldapbindpasswd ? ldap_password_hook(port->hba->ldapbindpasswd) : "");
2536 42 : if (r != LDAP_SUCCESS)
2537 : {
2538 6 : ereport(LOG,
2539 : (errmsg("could not perform initial LDAP bind for ldapbinddn \"%s\" on server \"%s\": %s",
2540 : port->hba->ldapbinddn ? port->hba->ldapbinddn : "",
2541 : server_name,
2542 : ldap_err2string(r)),
2543 : errdetail_for_ldap(ldap)));
2544 6 : ldap_unbind(ldap);
2545 6 : pfree(passwd);
2546 6 : return STATUS_ERROR;
2547 : }
2548 :
2549 : /* Build a custom filter or a single attribute filter? */
2550 36 : if (port->hba->ldapsearchfilter)
2551 16 : filter = FormatSearchFilter(port->hba->ldapsearchfilter, port->user_name);
2552 20 : else if (port->hba->ldapsearchattribute)
2553 6 : filter = psprintf("(%s=%s)", port->hba->ldapsearchattribute, port->user_name);
2554 : else
2555 14 : filter = psprintf("(uid=%s)", port->user_name);
2556 :
2557 36 : search_message = NULL;
2558 36 : r = ldap_search_s(ldap,
2559 36 : port->hba->ldapbasedn,
2560 36 : port->hba->ldapscope,
2561 : filter,
2562 : attributes,
2563 : 0,
2564 : &search_message);
2565 :
2566 36 : if (r != LDAP_SUCCESS)
2567 : {
2568 0 : ereport(LOG,
2569 : (errmsg("could not search LDAP for filter \"%s\" on server \"%s\": %s",
2570 : filter, server_name, ldap_err2string(r)),
2571 : errdetail_for_ldap(ldap)));
2572 0 : if (search_message != NULL)
2573 0 : ldap_msgfree(search_message);
2574 0 : ldap_unbind(ldap);
2575 0 : pfree(passwd);
2576 0 : pfree(filter);
2577 0 : return STATUS_ERROR;
2578 : }
2579 :
2580 36 : count = ldap_count_entries(ldap, search_message);
2581 36 : if (count != 1)
2582 : {
2583 6 : if (count == 0)
2584 6 : ereport(LOG,
2585 : (errmsg("LDAP user \"%s\" does not exist", port->user_name),
2586 : errdetail("LDAP search for filter \"%s\" on server \"%s\" returned no entries.",
2587 : filter, server_name)));
2588 : else
2589 0 : ereport(LOG,
2590 : (errmsg("LDAP user \"%s\" is not unique", port->user_name),
2591 : errdetail_plural("LDAP search for filter \"%s\" on server \"%s\" returned %d entry.",
2592 : "LDAP search for filter \"%s\" on server \"%s\" returned %d entries.",
2593 : count,
2594 : filter, server_name, count)));
2595 :
2596 6 : ldap_unbind(ldap);
2597 6 : pfree(passwd);
2598 6 : pfree(filter);
2599 6 : ldap_msgfree(search_message);
2600 6 : return STATUS_ERROR;
2601 : }
2602 :
2603 30 : entry = ldap_first_entry(ldap, search_message);
2604 30 : dn = ldap_get_dn(ldap, entry);
2605 30 : if (dn == NULL)
2606 : {
2607 : int error;
2608 :
2609 0 : (void) ldap_get_option(ldap, LDAP_OPT_ERROR_NUMBER, &error);
2610 0 : ereport(LOG,
2611 : (errmsg("could not get dn for the first entry matching \"%s\" on server \"%s\": %s",
2612 : filter, server_name,
2613 : ldap_err2string(error)),
2614 : errdetail_for_ldap(ldap)));
2615 0 : ldap_unbind(ldap);
2616 0 : pfree(passwd);
2617 0 : pfree(filter);
2618 0 : ldap_msgfree(search_message);
2619 0 : return STATUS_ERROR;
2620 : }
2621 30 : fulluser = pstrdup(dn);
2622 :
2623 30 : pfree(filter);
2624 30 : ldap_memfree(dn);
2625 30 : ldap_msgfree(search_message);
2626 : }
2627 : else
2628 16 : fulluser = psprintf("%s%s%s",
2629 16 : port->hba->ldapprefix ? port->hba->ldapprefix : "",
2630 : port->user_name,
2631 16 : port->hba->ldapsuffix ? port->hba->ldapsuffix : "");
2632 :
2633 46 : r = ldap_simple_bind_s(ldap, fulluser, passwd);
2634 :
2635 46 : if (r != LDAP_SUCCESS)
2636 : {
2637 16 : ereport(LOG,
2638 : (errmsg("LDAP login failed for user \"%s\" on server \"%s\": %s",
2639 : fulluser, server_name, ldap_err2string(r)),
2640 : errdetail_for_ldap(ldap)));
2641 16 : ldap_unbind(ldap);
2642 16 : pfree(passwd);
2643 16 : pfree(fulluser);
2644 16 : return STATUS_ERROR;
2645 : }
2646 :
2647 : /* Save the original bind DN as the authenticated identity. */
2648 30 : set_authn_id(port, fulluser);
2649 :
2650 30 : ldap_unbind(ldap);
2651 30 : pfree(passwd);
2652 30 : pfree(fulluser);
2653 :
2654 30 : return STATUS_OK;
2655 : }
2656 :
2657 : /*
2658 : * Add a detail error message text to the current error if one can be
2659 : * constructed from the LDAP 'diagnostic message'.
2660 : */
2661 : static int
2662 22 : errdetail_for_ldap(LDAP *ldap)
2663 : {
2664 : char *message;
2665 : int rc;
2666 :
2667 22 : rc = ldap_get_option(ldap, LDAP_OPT_DIAGNOSTIC_MESSAGE, &message);
2668 22 : if (rc == LDAP_SUCCESS && message != NULL)
2669 : {
2670 4 : errdetail("LDAP diagnostics: %s", message);
2671 4 : ldap_memfree(message);
2672 : }
2673 :
2674 22 : return 0;
2675 : }
2676 :
2677 : #endif /* USE_LDAP */
2678 :
2679 :
2680 : /*----------------------------------------------------------------
2681 : * SSL client certificate authentication
2682 : *----------------------------------------------------------------
2683 : */
2684 : #ifdef USE_SSL
2685 : static int
2686 54 : CheckCertAuth(Port *port)
2687 : {
2688 54 : int status_check_usermap = STATUS_ERROR;
2689 54 : char *peer_username = NULL;
2690 :
2691 : Assert(port->ssl);
2692 :
2693 : /* select the correct field to compare */
2694 54 : switch (port->hba->clientcertname)
2695 : {
2696 4 : case clientCertDN:
2697 4 : peer_username = port->peer_dn;
2698 4 : break;
2699 50 : case clientCertCN:
2700 50 : peer_username = port->peer_cn;
2701 : }
2702 :
2703 : /* Make sure we have received a username in the certificate */
2704 54 : if (peer_username == NULL ||
2705 54 : strlen(peer_username) <= 0)
2706 : {
2707 0 : ereport(LOG,
2708 : (errmsg("certificate authentication failed for user \"%s\": client certificate contains no user name",
2709 : port->user_name)));
2710 0 : return STATUS_ERROR;
2711 : }
2712 :
2713 54 : if (port->hba->auth_method == uaCert)
2714 : {
2715 : /*
2716 : * For cert auth, the client's Subject DN is always our authenticated
2717 : * identity, even if we're only using its CN for authorization. Set
2718 : * it now, rather than waiting for check_usermap() below, because
2719 : * authentication has already succeeded and we want the log file to
2720 : * reflect that.
2721 : */
2722 48 : if (!port->peer_dn)
2723 : {
2724 : /*
2725 : * This should not happen as both peer_dn and peer_cn should be
2726 : * set in this context.
2727 : */
2728 0 : ereport(LOG,
2729 : (errmsg("certificate authentication failed for user \"%s\": unable to retrieve subject DN",
2730 : port->user_name)));
2731 0 : return STATUS_ERROR;
2732 : }
2733 :
2734 48 : set_authn_id(port, port->peer_dn);
2735 : }
2736 :
2737 : /* Just pass the certificate cn/dn to the usermap check */
2738 54 : status_check_usermap = check_usermap(port->hba->usermap, port->user_name, peer_username, false);
2739 54 : if (status_check_usermap != STATUS_OK)
2740 : {
2741 : /*
2742 : * If clientcert=verify-full was specified and the authentication
2743 : * method is other than uaCert, log the reason for rejecting the
2744 : * authentication.
2745 : */
2746 4 : if (port->hba->clientcert == clientCertFull && port->hba->auth_method != uaCert)
2747 : {
2748 2 : switch (port->hba->clientcertname)
2749 : {
2750 0 : case clientCertDN:
2751 0 : ereport(LOG,
2752 : (errmsg("certificate validation (clientcert=verify-full) failed for user \"%s\": DN mismatch",
2753 : port->user_name)));
2754 0 : break;
2755 2 : case clientCertCN:
2756 2 : ereport(LOG,
2757 : (errmsg("certificate validation (clientcert=verify-full) failed for user \"%s\": CN mismatch",
2758 : port->user_name)));
2759 : }
2760 : }
2761 : }
2762 54 : return status_check_usermap;
2763 : }
2764 : #endif
2765 :
2766 :
2767 : /*----------------------------------------------------------------
2768 : * RADIUS authentication
2769 : *----------------------------------------------------------------
2770 : */
2771 :
2772 : /*
2773 : * RADIUS authentication is described in RFC2865 (and several others).
2774 : */
2775 :
2776 : #define RADIUS_VECTOR_LENGTH 16
2777 : #define RADIUS_HEADER_LENGTH 20
2778 : #define RADIUS_MAX_PASSWORD_LENGTH 128
2779 :
2780 : /* Maximum size of a RADIUS packet we will create or accept */
2781 : #define RADIUS_BUFFER_SIZE 1024
2782 :
2783 : typedef struct
2784 : {
2785 : uint8 attribute;
2786 : uint8 length;
2787 : uint8 data[FLEXIBLE_ARRAY_MEMBER];
2788 : } radius_attribute;
2789 :
2790 : typedef struct
2791 : {
2792 : uint8 code;
2793 : uint8 id;
2794 : uint16 length;
2795 : uint8 vector[RADIUS_VECTOR_LENGTH];
2796 : /* this is a bit longer than strictly necessary: */
2797 : char pad[RADIUS_BUFFER_SIZE - RADIUS_VECTOR_LENGTH];
2798 : } radius_packet;
2799 :
2800 : /* RADIUS packet types */
2801 : #define RADIUS_ACCESS_REQUEST 1
2802 : #define RADIUS_ACCESS_ACCEPT 2
2803 : #define RADIUS_ACCESS_REJECT 3
2804 :
2805 : /* RADIUS attributes */
2806 : #define RADIUS_USER_NAME 1
2807 : #define RADIUS_PASSWORD 2
2808 : #define RADIUS_SERVICE_TYPE 6
2809 : #define RADIUS_NAS_IDENTIFIER 32
2810 :
2811 : /* RADIUS service types */
2812 : #define RADIUS_AUTHENTICATE_ONLY 8
2813 :
2814 : /* Seconds to wait - XXX: should be in a config variable! */
2815 : #define RADIUS_TIMEOUT 3
2816 :
2817 : static void
2818 0 : radius_add_attribute(radius_packet *packet, uint8 type, const unsigned char *data, int len)
2819 : {
2820 : radius_attribute *attr;
2821 :
2822 0 : if (packet->length + len > RADIUS_BUFFER_SIZE)
2823 : {
2824 : /*
2825 : * With remotely realistic data, this can never happen. But catch it
2826 : * just to make sure we don't overrun a buffer. We'll just skip adding
2827 : * the broken attribute, which will in the end cause authentication to
2828 : * fail.
2829 : */
2830 0 : elog(WARNING,
2831 : "adding attribute code %d with length %d to radius packet would create oversize packet, ignoring",
2832 : type, len);
2833 0 : return;
2834 : }
2835 :
2836 0 : attr = (radius_attribute *) ((unsigned char *) packet + packet->length);
2837 0 : attr->attribute = type;
2838 0 : attr->length = len + 2; /* total size includes type and length */
2839 0 : memcpy(attr->data, data, len);
2840 0 : packet->length += attr->length;
2841 : }
2842 :
2843 : static int
2844 0 : CheckRADIUSAuth(Port *port)
2845 : {
2846 : char *passwd;
2847 : ListCell *server,
2848 : *secrets,
2849 : *radiusports,
2850 : *identifiers;
2851 :
2852 : /* Make sure struct alignment is correct */
2853 : Assert(offsetof(radius_packet, vector) == 4);
2854 :
2855 : /* Verify parameters */
2856 0 : if (port->hba->radiusservers == NIL)
2857 : {
2858 0 : ereport(LOG,
2859 : (errmsg("RADIUS server not specified")));
2860 0 : return STATUS_ERROR;
2861 : }
2862 :
2863 0 : if (port->hba->radiussecrets == NIL)
2864 : {
2865 0 : ereport(LOG,
2866 : (errmsg("RADIUS secret not specified")));
2867 0 : return STATUS_ERROR;
2868 : }
2869 :
2870 : /* Send regular password request to client, and get the response */
2871 0 : sendAuthRequest(port, AUTH_REQ_PASSWORD, NULL, 0);
2872 :
2873 0 : passwd = recv_password_packet(port);
2874 0 : if (passwd == NULL)
2875 0 : return STATUS_EOF; /* client wouldn't send password */
2876 :
2877 0 : if (strlen(passwd) > RADIUS_MAX_PASSWORD_LENGTH)
2878 : {
2879 0 : ereport(LOG,
2880 : (errmsg("RADIUS authentication does not support passwords longer than %d characters", RADIUS_MAX_PASSWORD_LENGTH)));
2881 0 : pfree(passwd);
2882 0 : return STATUS_ERROR;
2883 : }
2884 :
2885 : /*
2886 : * Loop over and try each server in order.
2887 : */
2888 0 : secrets = list_head(port->hba->radiussecrets);
2889 0 : radiusports = list_head(port->hba->radiusports);
2890 0 : identifiers = list_head(port->hba->radiusidentifiers);
2891 0 : foreach(server, port->hba->radiusservers)
2892 : {
2893 0 : int ret = PerformRadiusTransaction(lfirst(server),
2894 0 : lfirst(secrets),
2895 : radiusports ? lfirst(radiusports) : NULL,
2896 : identifiers ? lfirst(identifiers) : NULL,
2897 0 : port->user_name,
2898 : passwd);
2899 :
2900 : /*------
2901 : * STATUS_OK = Login OK
2902 : * STATUS_ERROR = Login not OK, but try next server
2903 : * STATUS_EOF = Login not OK, and don't try next server
2904 : *------
2905 : */
2906 0 : if (ret == STATUS_OK)
2907 : {
2908 0 : set_authn_id(port, port->user_name);
2909 :
2910 0 : pfree(passwd);
2911 0 : return STATUS_OK;
2912 : }
2913 0 : else if (ret == STATUS_EOF)
2914 : {
2915 0 : pfree(passwd);
2916 0 : return STATUS_ERROR;
2917 : }
2918 :
2919 : /*
2920 : * secret, port and identifiers either have length 0 (use default),
2921 : * length 1 (use the same everywhere) or the same length as servers.
2922 : * So if the length is >1, we advance one step. In other cases, we
2923 : * don't and will then reuse the correct value.
2924 : */
2925 0 : if (list_length(port->hba->radiussecrets) > 1)
2926 0 : secrets = lnext(port->hba->radiussecrets, secrets);
2927 0 : if (list_length(port->hba->radiusports) > 1)
2928 0 : radiusports = lnext(port->hba->radiusports, radiusports);
2929 0 : if (list_length(port->hba->radiusidentifiers) > 1)
2930 0 : identifiers = lnext(port->hba->radiusidentifiers, identifiers);
2931 : }
2932 :
2933 : /* No servers left to try, so give up */
2934 0 : pfree(passwd);
2935 0 : return STATUS_ERROR;
2936 : }
2937 :
2938 : static int
2939 0 : PerformRadiusTransaction(const char *server, const char *secret, const char *portstr, const char *identifier, const char *user_name, const char *passwd)
2940 : {
2941 : radius_packet radius_send_pack;
2942 : radius_packet radius_recv_pack;
2943 0 : radius_packet *packet = &radius_send_pack;
2944 0 : radius_packet *receivepacket = &radius_recv_pack;
2945 0 : char *radius_buffer = (char *) &radius_send_pack;
2946 0 : char *receive_buffer = (char *) &radius_recv_pack;
2947 0 : int32 service = pg_hton32(RADIUS_AUTHENTICATE_ONLY);
2948 : uint8 *cryptvector;
2949 : int encryptedpasswordlen;
2950 : uint8 encryptedpassword[RADIUS_MAX_PASSWORD_LENGTH];
2951 : uint8 *md5trailer;
2952 : int packetlength;
2953 : pgsocket sock;
2954 :
2955 : struct sockaddr_in6 localaddr;
2956 : struct sockaddr_in6 remoteaddr;
2957 : struct addrinfo hint;
2958 : struct addrinfo *serveraddrs;
2959 : int port;
2960 : socklen_t addrsize;
2961 : fd_set fdset;
2962 : struct timeval endtime;
2963 : int i,
2964 : j,
2965 : r;
2966 :
2967 : /* Assign default values */
2968 0 : if (portstr == NULL)
2969 0 : portstr = "1812";
2970 0 : if (identifier == NULL)
2971 0 : identifier = "postgresql";
2972 :
2973 0 : MemSet(&hint, 0, sizeof(hint));
2974 0 : hint.ai_socktype = SOCK_DGRAM;
2975 0 : hint.ai_family = AF_UNSPEC;
2976 0 : port = atoi(portstr);
2977 :
2978 0 : r = pg_getaddrinfo_all(server, portstr, &hint, &serveraddrs);
2979 0 : if (r || !serveraddrs)
2980 : {
2981 0 : ereport(LOG,
2982 : (errmsg("could not translate RADIUS server name \"%s\" to address: %s",
2983 : server, gai_strerror(r))));
2984 0 : if (serveraddrs)
2985 0 : pg_freeaddrinfo_all(hint.ai_family, serveraddrs);
2986 0 : return STATUS_ERROR;
2987 : }
2988 : /* XXX: add support for multiple returned addresses? */
2989 :
2990 : /* Construct RADIUS packet */
2991 0 : packet->code = RADIUS_ACCESS_REQUEST;
2992 0 : packet->length = RADIUS_HEADER_LENGTH;
2993 0 : if (!pg_strong_random(packet->vector, RADIUS_VECTOR_LENGTH))
2994 : {
2995 0 : ereport(LOG,
2996 : (errmsg("could not generate random encryption vector")));
2997 0 : pg_freeaddrinfo_all(hint.ai_family, serveraddrs);
2998 0 : return STATUS_ERROR;
2999 : }
3000 0 : packet->id = packet->vector[0];
3001 0 : radius_add_attribute(packet, RADIUS_SERVICE_TYPE, (const unsigned char *) &service, sizeof(service));
3002 0 : radius_add_attribute(packet, RADIUS_USER_NAME, (const unsigned char *) user_name, strlen(user_name));
3003 0 : radius_add_attribute(packet, RADIUS_NAS_IDENTIFIER, (const unsigned char *) identifier, strlen(identifier));
3004 :
3005 : /*
3006 : * RADIUS password attributes are calculated as: e[0] = p[0] XOR
3007 : * MD5(secret + Request Authenticator) for the first group of 16 octets,
3008 : * and then: e[i] = p[i] XOR MD5(secret + e[i-1]) for the following ones
3009 : * (if necessary)
3010 : */
3011 0 : encryptedpasswordlen = ((strlen(passwd) + RADIUS_VECTOR_LENGTH - 1) / RADIUS_VECTOR_LENGTH) * RADIUS_VECTOR_LENGTH;
3012 0 : cryptvector = palloc(strlen(secret) + RADIUS_VECTOR_LENGTH);
3013 0 : memcpy(cryptvector, secret, strlen(secret));
3014 :
3015 : /* for the first iteration, we use the Request Authenticator vector */
3016 0 : md5trailer = packet->vector;
3017 0 : for (i = 0; i < encryptedpasswordlen; i += RADIUS_VECTOR_LENGTH)
3018 : {
3019 0 : const char *errstr = NULL;
3020 :
3021 0 : memcpy(cryptvector + strlen(secret), md5trailer, RADIUS_VECTOR_LENGTH);
3022 :
3023 : /*
3024 : * .. and for subsequent iterations the result of the previous XOR
3025 : * (calculated below)
3026 : */
3027 0 : md5trailer = encryptedpassword + i;
3028 :
3029 0 : if (!pg_md5_binary(cryptvector, strlen(secret) + RADIUS_VECTOR_LENGTH,
3030 : encryptedpassword + i, &errstr))
3031 : {
3032 0 : ereport(LOG,
3033 : (errmsg("could not perform MD5 encryption of password: %s",
3034 : errstr)));
3035 0 : pfree(cryptvector);
3036 0 : pg_freeaddrinfo_all(hint.ai_family, serveraddrs);
3037 0 : return STATUS_ERROR;
3038 : }
3039 :
3040 0 : for (j = i; j < i + RADIUS_VECTOR_LENGTH; j++)
3041 : {
3042 0 : if (j < strlen(passwd))
3043 0 : encryptedpassword[j] = passwd[j] ^ encryptedpassword[j];
3044 : else
3045 0 : encryptedpassword[j] = '\0' ^ encryptedpassword[j];
3046 : }
3047 : }
3048 0 : pfree(cryptvector);
3049 :
3050 0 : radius_add_attribute(packet, RADIUS_PASSWORD, encryptedpassword, encryptedpasswordlen);
3051 :
3052 : /* Length needs to be in network order on the wire */
3053 0 : packetlength = packet->length;
3054 0 : packet->length = pg_hton16(packet->length);
3055 :
3056 0 : sock = socket(serveraddrs[0].ai_family, SOCK_DGRAM, 0);
3057 0 : if (sock == PGINVALID_SOCKET)
3058 : {
3059 0 : ereport(LOG,
3060 : (errmsg("could not create RADIUS socket: %m")));
3061 0 : pg_freeaddrinfo_all(hint.ai_family, serveraddrs);
3062 0 : return STATUS_ERROR;
3063 : }
3064 :
3065 0 : memset(&localaddr, 0, sizeof(localaddr));
3066 0 : localaddr.sin6_family = serveraddrs[0].ai_family;
3067 0 : localaddr.sin6_addr = in6addr_any;
3068 0 : if (localaddr.sin6_family == AF_INET6)
3069 0 : addrsize = sizeof(struct sockaddr_in6);
3070 : else
3071 0 : addrsize = sizeof(struct sockaddr_in);
3072 :
3073 0 : if (bind(sock, (struct sockaddr *) &localaddr, addrsize))
3074 : {
3075 0 : ereport(LOG,
3076 : (errmsg("could not bind local RADIUS socket: %m")));
3077 0 : closesocket(sock);
3078 0 : pg_freeaddrinfo_all(hint.ai_family, serveraddrs);
3079 0 : return STATUS_ERROR;
3080 : }
3081 :
3082 0 : if (sendto(sock, radius_buffer, packetlength, 0,
3083 0 : serveraddrs[0].ai_addr, serveraddrs[0].ai_addrlen) < 0)
3084 : {
3085 0 : ereport(LOG,
3086 : (errmsg("could not send RADIUS packet: %m")));
3087 0 : closesocket(sock);
3088 0 : pg_freeaddrinfo_all(hint.ai_family, serveraddrs);
3089 0 : return STATUS_ERROR;
3090 : }
3091 :
3092 : /* Don't need the server address anymore */
3093 0 : pg_freeaddrinfo_all(hint.ai_family, serveraddrs);
3094 :
3095 : /*
3096 : * Figure out at what time we should time out. We can't just use a single
3097 : * call to select() with a timeout, since somebody can be sending invalid
3098 : * packets to our port thus causing us to retry in a loop and never time
3099 : * out.
3100 : *
3101 : * XXX: Using WaitLatchOrSocket() and doing a CHECK_FOR_INTERRUPTS() if
3102 : * the latch was set would improve the responsiveness to
3103 : * timeouts/cancellations.
3104 : */
3105 0 : gettimeofday(&endtime, NULL);
3106 0 : endtime.tv_sec += RADIUS_TIMEOUT;
3107 :
3108 : while (true)
3109 0 : {
3110 : struct timeval timeout;
3111 : struct timeval now;
3112 : int64 timeoutval;
3113 0 : const char *errstr = NULL;
3114 :
3115 0 : gettimeofday(&now, NULL);
3116 0 : timeoutval = (endtime.tv_sec * 1000000 + endtime.tv_usec) - (now.tv_sec * 1000000 + now.tv_usec);
3117 0 : if (timeoutval <= 0)
3118 : {
3119 0 : ereport(LOG,
3120 : (errmsg("timeout waiting for RADIUS response from %s",
3121 : server)));
3122 0 : closesocket(sock);
3123 0 : return STATUS_ERROR;
3124 : }
3125 0 : timeout.tv_sec = timeoutval / 1000000;
3126 0 : timeout.tv_usec = timeoutval % 1000000;
3127 :
3128 0 : FD_ZERO(&fdset);
3129 0 : FD_SET(sock, &fdset);
3130 :
3131 0 : r = select(sock + 1, &fdset, NULL, NULL, &timeout);
3132 0 : if (r < 0)
3133 : {
3134 0 : if (errno == EINTR)
3135 0 : continue;
3136 :
3137 : /* Anything else is an actual error */
3138 0 : ereport(LOG,
3139 : (errmsg("could not check status on RADIUS socket: %m")));
3140 0 : closesocket(sock);
3141 0 : return STATUS_ERROR;
3142 : }
3143 0 : if (r == 0)
3144 : {
3145 0 : ereport(LOG,
3146 : (errmsg("timeout waiting for RADIUS response from %s",
3147 : server)));
3148 0 : closesocket(sock);
3149 0 : return STATUS_ERROR;
3150 : }
3151 :
3152 : /*
3153 : * Attempt to read the response packet, and verify the contents.
3154 : *
3155 : * Any packet that's not actually a RADIUS packet, or otherwise does
3156 : * not validate as an explicit reject, is just ignored and we retry
3157 : * for another packet (until we reach the timeout). This is to avoid
3158 : * the possibility to denial-of-service the login by flooding the
3159 : * server with invalid packets on the port that we're expecting the
3160 : * RADIUS response on.
3161 : */
3162 :
3163 0 : addrsize = sizeof(remoteaddr);
3164 0 : packetlength = recvfrom(sock, receive_buffer, RADIUS_BUFFER_SIZE, 0,
3165 : (struct sockaddr *) &remoteaddr, &addrsize);
3166 0 : if (packetlength < 0)
3167 : {
3168 0 : ereport(LOG,
3169 : (errmsg("could not read RADIUS response: %m")));
3170 0 : closesocket(sock);
3171 0 : return STATUS_ERROR;
3172 : }
3173 :
3174 0 : if (remoteaddr.sin6_port != pg_hton16(port))
3175 : {
3176 0 : ereport(LOG,
3177 : (errmsg("RADIUS response from %s was sent from incorrect port: %d",
3178 : server, pg_ntoh16(remoteaddr.sin6_port))));
3179 0 : continue;
3180 : }
3181 :
3182 0 : if (packetlength < RADIUS_HEADER_LENGTH)
3183 : {
3184 0 : ereport(LOG,
3185 : (errmsg("RADIUS response from %s too short: %d", server, packetlength)));
3186 0 : continue;
3187 : }
3188 :
3189 0 : if (packetlength != pg_ntoh16(receivepacket->length))
3190 : {
3191 0 : ereport(LOG,
3192 : (errmsg("RADIUS response from %s has corrupt length: %d (actual length %d)",
3193 : server, pg_ntoh16(receivepacket->length), packetlength)));
3194 0 : continue;
3195 : }
3196 :
3197 0 : if (packet->id != receivepacket->id)
3198 : {
3199 0 : ereport(LOG,
3200 : (errmsg("RADIUS response from %s is to a different request: %d (should be %d)",
3201 : server, receivepacket->id, packet->id)));
3202 0 : continue;
3203 : }
3204 :
3205 : /*
3206 : * Verify the response authenticator, which is calculated as
3207 : * MD5(Code+ID+Length+RequestAuthenticator+Attributes+Secret)
3208 : */
3209 0 : cryptvector = palloc(packetlength + strlen(secret));
3210 :
3211 0 : memcpy(cryptvector, receivepacket, 4); /* code+id+length */
3212 0 : memcpy(cryptvector + 4, packet->vector, RADIUS_VECTOR_LENGTH); /* request
3213 : * authenticator, from
3214 : * original packet */
3215 0 : if (packetlength > RADIUS_HEADER_LENGTH) /* there may be no
3216 : * attributes at all */
3217 0 : memcpy(cryptvector + RADIUS_HEADER_LENGTH, receive_buffer + RADIUS_HEADER_LENGTH, packetlength - RADIUS_HEADER_LENGTH);
3218 0 : memcpy(cryptvector + packetlength, secret, strlen(secret));
3219 :
3220 0 : if (!pg_md5_binary(cryptvector,
3221 0 : packetlength + strlen(secret),
3222 : encryptedpassword, &errstr))
3223 : {
3224 0 : ereport(LOG,
3225 : (errmsg("could not perform MD5 encryption of received packet: %s",
3226 : errstr)));
3227 0 : pfree(cryptvector);
3228 0 : continue;
3229 : }
3230 0 : pfree(cryptvector);
3231 :
3232 0 : if (memcmp(receivepacket->vector, encryptedpassword, RADIUS_VECTOR_LENGTH) != 0)
3233 : {
3234 0 : ereport(LOG,
3235 : (errmsg("RADIUS response from %s has incorrect MD5 signature",
3236 : server)));
3237 0 : continue;
3238 : }
3239 :
3240 0 : if (receivepacket->code == RADIUS_ACCESS_ACCEPT)
3241 : {
3242 0 : closesocket(sock);
3243 0 : return STATUS_OK;
3244 : }
3245 0 : else if (receivepacket->code == RADIUS_ACCESS_REJECT)
3246 : {
3247 0 : closesocket(sock);
3248 0 : return STATUS_EOF;
3249 : }
3250 : else
3251 : {
3252 0 : ereport(LOG,
3253 : (errmsg("RADIUS response from %s has invalid code (%d) for user \"%s\"",
3254 : server, receivepacket->code, user_name)));
3255 0 : continue;
3256 : }
3257 : } /* while (true) */
3258 : }
|