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