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