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