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