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