1 /*-------------------------------------------------------------------------
4 * Routines to handle network authentication
6 * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $PostgreSQL: pgsql/src/backend/libpq/auth.c,v 1.140 2006/08/21 19:21:38 tgl Exp $
13 *-------------------------------------------------------------------------
18 #include <sys/param.h>
19 #include <sys/socket.h>
20 #if defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || defined(HAVE_STRUCT_SOCKCRED)
22 #include <sys/ucred.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
27 #include "libpq/auth.h"
28 #include "libpq/crypt.h"
30 #include "libpq/libpq.h"
31 #include "libpq/pqformat.h"
32 #include "storage/ipc.h"
35 static void sendAuthRequest(Port *port, AuthRequest areq);
36 static void auth_failed(Port *port, int status);
37 static char *recv_password_packet(Port *port);
38 static int recv_and_check_password_packet(Port *port);
40 char *pg_krb_server_keyfile;
42 bool pg_krb_caseins_users;
43 char *pg_krb_server_hostname = NULL;
46 #ifdef HAVE_PAM_PAM_APPL_H
47 #include <pam/pam_appl.h>
49 #ifdef HAVE_SECURITY_PAM_APPL_H
50 #include <security/pam_appl.h>
53 #define PGSQL_PAM_SERVICE "postgresql" /* Service name passed to PAM */
55 static int CheckPAMAuth(Port *port, char *user, char *password);
56 static int pam_passwd_conv_proc(int num_msg, const struct pam_message ** msg,
57 struct pam_response ** resp, void *appdata_ptr);
59 static struct pam_conv pam_passw_conv = {
60 &pam_passwd_conv_proc,
64 static char *pam_passwd = NULL; /* Workaround for Solaris 2.6 brokenness */
65 static Port *pam_port_cludge; /* Workaround for passing "Port *port" into
66 * pam_passwd_conv_proc */
71 /* We use a deprecated function to keep the codepaths the same as the
73 #define LDAP_DEPRECATED 1
78 /* Correct header from the Platform SDK */
79 typedef ULONG (WINLDAPAPI *__ldap_start_tls_sA)(
80 IN PLDAP ExternalHandle,
81 OUT PULONG ServerReturnValue,
82 OUT LDAPMessage **result,
83 IN PLDAPControlA *ServerControls,
84 IN PLDAPControlA *ClientControls
88 static int CheckLDAPAuth(Port *port);
93 /*----------------------------------------------------------------
94 * MIT Kerberos authentication system - protocol version 5
95 *----------------------------------------------------------------
99 /* Some old versions of Kerberos do not include <com_err.h> in <krb5.h> */
100 #if !defined(__COM_ERR_H) && !defined(__COM_ERR_H__)
105 * pg_an_to_ln -- return the local name corresponding to an authentication
108 * XXX Assumes that the first aname component is the user name. This is NOT
109 * necessarily so, since an aname can actually be something out of your
110 * worst X.400 nightmare, like
111 * ORGANIZATION=U. C. Berkeley/NAME=Paul M. Aoki@CS.BERKELEY.EDU
112 * Note that the MIT an_to_ln code does the same thing if you don't
113 * provide an aname mapping database...it may be a better idea to use
114 * krb5_an_to_ln, except that it punts if multiple components are found,
115 * and we can't afford to punt.
118 pg_an_to_ln(char *aname)
122 if ((p = strchr(aname, '/')) || (p = strchr(aname, '@')))
129 * Various krb5 state which is not connection specfic, and a flag to
130 * indicate whether we have initialised it yet.
132 static int pg_krb5_initialised;
133 static krb5_context pg_krb5_context;
134 static krb5_keytab pg_krb5_keytab;
135 static krb5_principal pg_krb5_server;
141 krb5_error_code retval;
144 if (pg_krb5_initialised)
147 retval = krb5_init_context(&pg_krb5_context);
151 (errmsg("Kerberos initialization returned error %d",
153 com_err("postgres", retval, "while initializing krb5");
157 retval = krb5_kt_resolve(pg_krb5_context, pg_krb_server_keyfile, &pg_krb5_keytab);
161 (errmsg("Kerberos keytab resolving returned error %d",
163 com_err("postgres", retval, "while resolving keytab file \"%s\"",
164 pg_krb_server_keyfile);
165 krb5_free_context(pg_krb5_context);
170 * If no hostname was specified, pg_krb_server_hostname is already NULL.
171 * If it's set to blank, force it to NULL.
173 khostname = pg_krb_server_hostname;
174 if (khostname && khostname[0] == '\0')
177 retval = krb5_sname_to_principal(pg_krb5_context,
185 (errmsg("Kerberos sname_to_principal(\"%s\", \"%s\") returned error %d",
186 khostname ? khostname : "server hostname", pg_krb_srvnam, retval)));
187 com_err("postgres", retval,
188 "while getting server principal for server \"%s\" for service \"%s\"",
189 khostname ? khostname : "server hostname", pg_krb_srvnam);
190 krb5_kt_close(pg_krb5_context, pg_krb5_keytab);
191 krb5_free_context(pg_krb5_context);
195 pg_krb5_initialised = 1;
201 * pg_krb5_recvauth -- server routine to receive authentication information
204 * We still need to compare the username obtained from the client's setup
205 * packet to the authenticated name.
207 * We have our own keytab file because postgres is unlikely to run as root,
208 * and so cannot read the default keytab.
211 pg_krb5_recvauth(Port *port)
213 krb5_error_code retval;
215 krb5_auth_context auth_context = NULL;
219 ret = pg_krb5_init();
220 if (ret != STATUS_OK)
223 retval = krb5_recvauth(pg_krb5_context, &auth_context,
224 (krb5_pointer) & port->sock, pg_krb_srvnam,
225 pg_krb5_server, 0, pg_krb5_keytab, &ticket);
229 (errmsg("Kerberos recvauth returned error %d",
231 com_err("postgres", retval, "from krb5_recvauth");
236 * The "client" structure comes out of the ticket and is therefore
237 * authenticated. Use it to check the username obtained from the
238 * postmaster startup packet.
240 * I have no idea why this is considered necessary.
242 #if defined(HAVE_KRB5_TICKET_ENC_PART2)
243 retval = krb5_unparse_name(pg_krb5_context,
244 ticket->enc_part2->client, &kusername);
245 #elif defined(HAVE_KRB5_TICKET_CLIENT)
246 retval = krb5_unparse_name(pg_krb5_context,
247 ticket->client, &kusername);
249 #error "bogus configuration"
254 (errmsg("Kerberos unparse_name returned error %d",
256 com_err("postgres", retval, "while unparsing client name");
257 krb5_free_ticket(pg_krb5_context, ticket);
258 krb5_auth_con_free(pg_krb5_context, auth_context);
262 kusername = pg_an_to_ln(kusername);
263 if (pg_krb_caseins_users)
264 ret = pg_strncasecmp(port->user_name, kusername, SM_DATABASE_USER);
266 ret = strncmp(port->user_name, kusername, SM_DATABASE_USER);
270 (errmsg("unexpected Kerberos user name received from client (received \"%s\", expected \"%s\")",
271 port->user_name, kusername)));
277 krb5_free_ticket(pg_krb5_context, ticket);
278 krb5_auth_con_free(pg_krb5_context, auth_context);
286 pg_krb5_recvauth(Port *port)
289 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
290 errmsg("Kerberos 5 not implemented on this server")));
297 * Tell the user the authentication failed, but not (much about) why.
299 * There is a tradeoff here between security concerns and making life
300 * unnecessarily difficult for legitimate users. We would not, for example,
301 * want to report the password we were expecting to receive...
302 * But it seems useful to report the username and authorization method
303 * in use, and these are items that must be presumed known to an attacker
305 * Note that many sorts of failure report additional information in the
306 * postmaster log, which we hope is only readable by good guys.
309 auth_failed(Port *port, int status)
314 * If we failed due to EOF from client, just quit; there's no point in
315 * trying to send a message to the client, and not much point in logging
316 * the failure in the postmaster log. (Logging the failure might be
317 * desirable, were it not for the fact that libpq closes the connection
318 * unceremoniously if challenged for a password when it hasn't got one to
319 * send. We'll get a useless log entry for every psql connection under
320 * password auth, even if it's perfectly successful, if we log STATUS_EOF
323 if (status == STATUS_EOF)
326 switch (port->auth_method)
329 errstr = gettext_noop("authentication failed for user \"%s\": host rejected");
332 errstr = gettext_noop("Kerberos 5 authentication failed for user \"%s\"");
335 errstr = gettext_noop("\"trust\" authentication failed for user \"%s\"");
338 errstr = gettext_noop("Ident authentication failed for user \"%s\"");
343 errstr = gettext_noop("password authentication failed for user \"%s\"");
347 errstr = gettext_noop("PAM authentication failed for user \"%s\"");
352 errstr = gettext_noop("LDAP authentication failed for user \"%s\"");
354 #endif /* USE_LDAP */
356 errstr = gettext_noop("authentication failed for user \"%s\": invalid authentication method");
361 (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
362 errmsg(errstr, port->user_name)));
368 * Client authentication starts here. If there is an error, this
369 * function does not return and the backend process is terminated.
372 ClientAuthentication(Port *port)
374 int status = STATUS_ERROR;
377 * Get the authentication method to use for this frontend/database
378 * combination. Note: a failure return indicates a problem with the hba
379 * config file, not with the request. hba.c should have dropped an error
380 * message into the postmaster logfile if it failed.
382 if (hba_getauthmethod(port) != STATUS_OK)
384 (errcode(ERRCODE_CONFIG_FILE_ERROR),
385 errmsg("missing or erroneous pg_hba.conf file"),
386 errhint("See server log for details.")));
388 switch (port->auth_method)
393 * This could have come from an explicit "reject" entry in
394 * pg_hba.conf, but more likely it means there was no matching
395 * entry. Take pity on the poor user and issue a helpful error
396 * message. NOTE: this is not a security breach, because all the
397 * info reported here is known at the frontend and must be assumed
398 * known to bad guys. We're merely helping out the less clueful
402 char hostinfo[NI_MAXHOST];
404 pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
405 hostinfo, sizeof(hostinfo),
411 (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
412 errmsg("no pg_hba.conf entry for host \"%s\", user \"%s\", database \"%s\", %s",
413 hostinfo, port->user_name, port->database_name,
414 port->ssl ? _("SSL on") : _("SSL off"))));
417 (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
418 errmsg("no pg_hba.conf entry for host \"%s\", user \"%s\", database \"%s\"",
419 hostinfo, port->user_name, port->database_name)));
425 sendAuthRequest(port, AUTH_REQ_KRB5);
426 status = pg_krb5_recvauth(port);
432 * If we are doing ident on unix-domain sockets, use SCM_CREDS
433 * only if it is defined and SO_PEERCRED isn't.
435 #if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED) && \
436 (defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || \
437 (defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS)))
438 if (port->raddr.addr.ss_family == AF_UNIX)
440 #if defined(HAVE_STRUCT_FCRED) || defined(HAVE_STRUCT_SOCKCRED)
443 * Receive credentials on next message receipt, BSD/OS,
444 * NetBSD. We need to set this before the client sends the
449 if (setsockopt(port->sock, 0, LOCAL_CREDS, &on, sizeof(on)) < 0)
451 (errcode_for_socket_access(),
452 errmsg("could not enable credential reception: %m")));
455 sendAuthRequest(port, AUTH_REQ_SCM_CREDS);
458 status = authident(port);
462 sendAuthRequest(port, AUTH_REQ_MD5);
463 status = recv_and_check_password_packet(port);
467 sendAuthRequest(port, AUTH_REQ_CRYPT);
468 status = recv_and_check_password_packet(port);
472 sendAuthRequest(port, AUTH_REQ_PASSWORD);
473 status = recv_and_check_password_packet(port);
478 pam_port_cludge = port;
479 status = CheckPAMAuth(port, port->user_name, "");
485 status = CheckLDAPAuth(port);
494 if (status == STATUS_OK)
495 sendAuthRequest(port, AUTH_REQ_OK);
497 auth_failed(port, status);
502 * Send an authentication request packet to the frontend.
505 sendAuthRequest(Port *port, AuthRequest areq)
509 pq_beginmessage(&buf, 'R');
510 pq_sendint(&buf, (int32) areq, sizeof(int32));
512 /* Add the salt for encrypted passwords. */
513 if (areq == AUTH_REQ_MD5)
514 pq_sendbytes(&buf, port->md5Salt, 4);
515 else if (areq == AUTH_REQ_CRYPT)
516 pq_sendbytes(&buf, port->cryptSalt, 2);
521 * Flush message so client will see it, except for AUTH_REQ_OK, which need
522 * not be sent until we are ready for queries.
524 if (areq != AUTH_REQ_OK)
532 * PAM conversation function
536 pam_passwd_conv_proc(int num_msg, const struct pam_message ** msg,
537 struct pam_response ** resp, void *appdata_ptr)
539 if (num_msg != 1 || msg[0]->msg_style != PAM_PROMPT_ECHO_OFF)
541 switch (msg[0]->msg_style)
545 (errmsg("error from underlying PAM layer: %s",
550 (errmsg("unsupported PAM conversation %d/%s",
551 msg[0]->msg_style, msg[0]->msg)));
559 * Workaround for Solaris 2.6 where the PAM library is broken and does
560 * not pass appdata_ptr to the conversation routine
562 appdata_ptr = pam_passwd;
566 * Password wasn't passed to PAM the first time around - let's go ask the
567 * client to send a password, which we then stuff into PAM.
569 if (strlen(appdata_ptr) == 0)
573 sendAuthRequest(pam_port_cludge, AUTH_REQ_PASSWORD);
574 passwd = recv_password_packet(pam_port_cludge);
577 return PAM_CONV_ERR; /* client didn't want to send password */
579 if (strlen(passwd) == 0)
582 (errmsg("empty password returned by client")));
585 appdata_ptr = passwd;
589 * Explicitly not using palloc here - PAM will free this memory in
592 *resp = calloc(num_msg, sizeof(struct pam_response));
596 (errcode(ERRCODE_OUT_OF_MEMORY),
597 errmsg("out of memory")));
601 (*resp)[0].resp = strdup((char *) appdata_ptr);
602 (*resp)[0].resp_retcode = 0;
604 return ((*resp)[0].resp ? PAM_SUCCESS : PAM_CONV_ERR);
609 * Check authentication against PAM.
612 CheckPAMAuth(Port *port, char *user, char *password)
615 pam_handle_t *pamh = NULL;
618 * Apparently, Solaris 2.6 is broken, and needs ugly static variable
621 pam_passwd = password;
624 * Set the application data portion of the conversation struct This is
625 * later used inside the PAM conversation to pass the password to the
626 * authentication module.
628 pam_passw_conv.appdata_ptr = (char *) password; /* from password above,
631 /* Optionally, one can set the service name in pg_hba.conf */
632 if (port->auth_arg && port->auth_arg[0] != '\0')
633 retval = pam_start(port->auth_arg, "pgsql@",
634 &pam_passw_conv, &pamh);
636 retval = pam_start(PGSQL_PAM_SERVICE, "pgsql@",
637 &pam_passw_conv, &pamh);
639 if (retval != PAM_SUCCESS)
642 (errmsg("could not create PAM authenticator: %s",
643 pam_strerror(pamh, retval))));
644 pam_passwd = NULL; /* Unset pam_passwd */
648 retval = pam_set_item(pamh, PAM_USER, user);
650 if (retval != PAM_SUCCESS)
653 (errmsg("pam_set_item(PAM_USER) failed: %s",
654 pam_strerror(pamh, retval))));
655 pam_passwd = NULL; /* Unset pam_passwd */
659 retval = pam_set_item(pamh, PAM_CONV, &pam_passw_conv);
661 if (retval != PAM_SUCCESS)
664 (errmsg("pam_set_item(PAM_CONV) failed: %s",
665 pam_strerror(pamh, retval))));
666 pam_passwd = NULL; /* Unset pam_passwd */
670 retval = pam_authenticate(pamh, 0);
672 if (retval != PAM_SUCCESS)
675 (errmsg("pam_authenticate failed: %s",
676 pam_strerror(pamh, retval))));
677 pam_passwd = NULL; /* Unset pam_passwd */
681 retval = pam_acct_mgmt(pamh, 0);
683 if (retval != PAM_SUCCESS)
686 (errmsg("pam_acct_mgmt failed: %s",
687 pam_strerror(pamh, retval))));
688 pam_passwd = NULL; /* Unset pam_passwd */
692 retval = pam_end(pamh, retval);
694 if (retval != PAM_SUCCESS)
697 (errmsg("could not release PAM authenticator: %s",
698 pam_strerror(pamh, retval))));
701 pam_passwd = NULL; /* Unset pam_passwd */
703 return (retval == PAM_SUCCESS ? STATUS_OK : STATUS_ERROR);
711 CheckLDAPAuth(Port *port)
713 static __ldap_start_tls_sA _ldap_start_tls_sA = NULL;
723 int ldapversion = LDAP_VERSION3;
724 int ldapport = LDAP_PORT;
727 if (!port->auth_arg || port->auth_arg[0] == '\0')
730 (errmsg("LDAP configuration URL not specified")));
735 * Crack the LDAP url. We do a very trivial parse..
736 * ldap[s]://<server>[:<port>]/<basedn>[;prefix[;suffix]]
744 /* ldap, including port number */
745 r = sscanf(port->auth_arg,
746 "ldap://%127[^:]:%i/%127[^;];%127[^;];%127s",
747 server, &ldapport, basedn, prefix, suffix);
750 /* ldaps, including port number */
751 r = sscanf(port->auth_arg,
752 "ldaps://%127[^:]:%i/%127[^;];%127[^;];%127s",
753 server, &ldapport, basedn, prefix, suffix);
758 /* ldap, no port number */
759 r = sscanf(port->auth_arg,
760 "ldap://%127[^/]/%127[^;];%127[^;];%127s",
761 server, basedn, prefix, suffix);
765 /* ldaps, no port number */
766 r = sscanf(port->auth_arg,
767 "ldaps://%127[^/]/%127[^;];%127[^;];%127s",
768 server, basedn, prefix, suffix);
774 (errmsg("invalid LDAP URL: \"%s\"",
779 sendAuthRequest(port, AUTH_REQ_PASSWORD);
781 passwd = recv_password_packet(port);
783 return STATUS_EOF; /* client wouldn't send password */
785 ldap = ldap_init(server, ldapport);
790 (errmsg("could not initialize LDAP: error %d",
794 (errmsg("could not initialize LDAP: error %d",
795 (int) LdapGetLastError())));
800 if ((r = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &ldapversion)) != LDAP_SUCCESS)
803 (errmsg("could not set LDAP protocol version: error %d", r)));
810 if ((r = ldap_start_tls_s(ldap, NULL, NULL)) != LDAP_SUCCESS)
812 if (_ldap_start_tls_sA == NULL)
815 * Need to load this function dynamically because it does not
816 * exist on Windows 2000, and causes a load error for the whole
821 ldaphandle = LoadLibrary("WLDAP32.DLL");
822 if (ldaphandle == NULL)
824 /* should never happen since we import other files from wldap32, but check anyway */
826 (errmsg("could not load wldap32.dll")));
829 _ldap_start_tls_sA = (__ldap_start_tls_sA)GetProcAddress(ldaphandle, "ldap_start_tls_sA");
830 if (_ldap_start_tls_sA == NULL)
833 (errmsg("could not load function _ldap_start_tls_sA in wldap32.dll. LDAP over SSL is not supported on this platform.")));
838 * Leak ldaphandle on purpose, because we need the library to stay
839 * open. This is ok because it will only ever be leaked once per
840 * process and is automatically cleaned up on process exit.
843 if ((r = _ldap_start_tls_sA(ldap, NULL, NULL, NULL, NULL)) != LDAP_SUCCESS)
847 (errmsg("could not start LDAP TLS session: error %d", r)));
852 snprintf(fulluser, sizeof(fulluser)-1, "%s%s%s",
853 prefix, port->user_name, suffix);
854 fulluser[sizeof(fulluser)-1] = '\0';
856 r = ldap_simple_bind_s(ldap, fulluser, passwd);
859 if (r != LDAP_SUCCESS)
862 (errmsg("LDAP login failed for user \"%s\" on server \"%s\": error %d",
863 fulluser, server, r)));
870 #endif /* USE_LDAP */
873 * Collect password response packet from frontend.
875 * Returns NULL if couldn't get password, else palloc'd string.
878 recv_password_packet(Port *port)
882 if (PG_PROTOCOL_MAJOR(port->proto) >= 3)
884 /* Expect 'p' message type */
887 mtype = pq_getbyte();
891 * If the client just disconnects without offering a password,
892 * don't make a log entry. This is legal per protocol spec and in
893 * fact commonly done by psql, so complaining just clutters the
898 (errcode(ERRCODE_PROTOCOL_VIOLATION),
899 errmsg("expected password response, got message type %d",
901 return NULL; /* EOF or bad message type */
906 /* For pre-3.0 clients, avoid log entry if they just disconnect */
907 if (pq_peekbyte() == EOF)
908 return NULL; /* EOF */
911 initStringInfo(&buf);
912 if (pq_getmessage(&buf, 1000)) /* receive password */
914 /* EOF - pq_getmessage already logged a suitable message */
920 * Apply sanity check: password packet length should agree with length of
921 * contained string. Note it is safe to use strlen here because
922 * StringInfo is guaranteed to have an appended '\0'.
924 if (strlen(buf.data) + 1 != buf.len)
926 (errcode(ERRCODE_PROTOCOL_VIOLATION),
927 errmsg("invalid password packet size")));
929 /* Do not echo password to logs, for security. */
931 (errmsg("received password packet")));
934 * Return the received string. Note we do not attempt to do any
935 * character-set conversion on it; since we don't yet know the client's
936 * encoding, there wouldn't be much point.
943 * Called when we have sent an authorization request for a password.
944 * Get the response and check it.
947 recv_and_check_password_packet(Port *port)
952 passwd = recv_password_packet(port);
955 return STATUS_EOF; /* client wouldn't send password */
957 result = md5_crypt_verify(port, port->user_name, passwd);