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