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